func (d NetworkDriver) DeleteEndpoint(request *network.DeleteEndpointRequest) error { logutils.JSONMessage("DeleteEndpoint", request) log.Debugf("Removing endpoint %v\n", request.EndpointID) hostname, err := osutils.GetHostname() if err != nil { err = errors.Wrap(err, "Hostname fetching error") log.Errorln(err) return err } if err = d.client.WorkloadEndpoints().Delete( api.WorkloadEndpointMetadata{ Name: request.EndpointID, Node: hostname, Orchestrator: d.orchestratorID, Workload: d.containerName}); err != nil { err = errors.Wrapf(err, "Endpoint %v removal error", request.EndpointID) log.Errorln(err) return err } logutils.JSONMessage("DeleteEndpoint response JSON=%v", map[string]string{}) return err }
func (d NetworkDriver) CreateEndpoint(request *network.CreateEndpointRequest) (*network.CreateEndpointResponse, error) { logutils.JSONMessage("CreateEndpoint", request) hostname, err := osutils.GetHostname() if err != nil { err = errors.Wrap(err, "Hostname fetching error") log.Errorln(err) return nil, err } log.Debugf("Creating endpoint %v\n", request.EndpointID) if request.Interface.Address == "" { err := errors.New("No address assigned for endpoint") log.Errorln(err) return nil, err } var addresses []caliconet.IPNet if request.Interface.Address != "" { // Parse the address this function was passed. Ignore the subnet - Calico always uses /32 (for IPv4) ip4, _, err := net.ParseCIDR(request.Interface.Address) log.Debugf("Parsed IP %v from (%v) \n", ip4, request.Interface.Address) if err != nil { err = errors.Wrapf(err, "Parsing %v as CIDR failed", request.Interface.Address) log.Errorln(err) return nil, err } addresses = append(addresses, caliconet.IPNet{IPNet: net.IPNet{IP: ip4, Mask: net.CIDRMask(32, 32)}}) } endpoint := api.NewWorkloadEndpoint() endpoint.Metadata.Node = hostname endpoint.Metadata.Orchestrator = d.orchestratorID endpoint.Metadata.Workload = d.containerName endpoint.Metadata.Name = request.EndpointID endpoint.Spec.InterfaceName = "cali" + request.EndpointID[:mathutils.MinInt(11, len(request.EndpointID))] mac, _ := net.ParseMAC(d.fixedMac) endpoint.Spec.MAC = &caliconet.MAC{HardwareAddr: mac} endpoint.Spec.IPNetworks = append(endpoint.Spec.IPNetworks, addresses...) // Use the Docker API to fetch the network name (so we don't have to use an ID everywhere) dockerCli, err := dockerClient.NewEnvClient() if err != nil { err = errors.Wrap(err, "Error while attempting to instantiate docker client from env") log.Errorln(err) return nil, err } defer dockerCli.Close() networkData, err := dockerCli.NetworkInspect(context.Background(), request.NetworkID) if err != nil { err = errors.Wrapf(err, "Network %v inspection error", request.NetworkID) log.Errorln(err) return nil, err } // Now that we know the network name, set it on the endpoint. endpoint.Spec.Profiles = append(endpoint.Spec.Profiles, networkData.Name) // If a profile for the network name doesn't exist then it needs to be created. // We always attempt to create the profile and rely on the datastore to reject // the request if the profile already exists. profile := &api.Profile{ Metadata: api.ProfileMetadata{ Name: networkData.Name, Tags: []string{networkData.Name}, }, Spec: api.ProfileSpec{ EgressRules: []api.Rule{{Action: "allow"}}, IngressRules: []api.Rule{{Action: "allow", Source: api.EntityRule{Tag: networkData.Name}}}, }, } if _, err := d.client.Profiles().Create(profile); err != nil { if _, ok := err.(libcalicoErrors.ErrorResourceAlreadyExists); !ok { log.Errorln(err) return nil, err } } // Create the endpoint last to minimize side-effects if something goes wrong. _, err = d.client.WorkloadEndpoints().Create(endpoint) if err != nil { err = errors.Wrapf(err, "Workload endpoints creation error, data: %+v", endpoint) log.Errorln(err) return nil, err } log.Debugf("Workload created, data: %+v\n", endpoint) response := &network.CreateEndpointResponse{ Interface: &network.EndpointInterface{ MacAddress: string(d.fixedMac), }, } logutils.JSONMessage("CreateEndpoint response", response) return response, nil }
func (i IpamDriver) RequestAddress(request *ipam.RequestAddressRequest) (*ipam.RequestAddressResponse, error) { logutils.JSONMessage("RequestAddress", request) hostname, err := osutils.GetHostname() if err != nil { log.Errorln(err) return nil, err } var IPs []caliconet.IP if request.Address == "" { // No address requested, so auto assign from our pools. log.Println("Auto assigning IP from Calico pools") // If the poolID isn't the fixed one then find the pool to assign from. // poolV4 defaults to nil to assign from across all pools. var poolV4 []caliconet.IPNet if request.PoolID != PoolIDV4 { poolsClient := i.client.IPPools() _, ipNet, err := caliconet.ParseCIDR(request.PoolID) if err != nil { err = errors.Wrapf(err, "Invalid CIDR - %v", request.PoolID) log.Errorln(err) return nil, err } pool, err := poolsClient.Get(api.IPPoolMetadata{CIDR: *ipNet}) if err != nil { err := errors.New("The network references a Calico pool which " + "has been deleted. Please re-instate the " + "Calico pool before using the network.") log.Errorln(err) return nil, err } poolV4 = []caliconet.IPNet{caliconet.IPNet{IPNet: pool.Metadata.CIDR.IPNet}} log.Debugln("Using specific pool ", poolV4) } // Auto assign an IP address. // IPv4 pool will be nil if the docker network doesn't have a subnet associated with. // Otherwise, it will be set to the Calico pool to assign from. IPsV4, IPsV6, err := i.client.IPAM().AutoAssign( datastoreClient.AutoAssignArgs{ Num4: 1, Num6: 0, Hostname: hostname, IPv4Pools: poolV4, }, ) if err != nil { err = errors.Wrapf(err, "IP assignment error") log.Errorln(err) return nil, err } IPs = append(IPsV4, IPsV6...) } else { // Docker allows the users to specify any address. // We'll return an error if the address isn't in a Calico pool, but we don't care which pool it's in // (i.e. it doesn't need to match the subnet from the docker network). log.Debugln("Reserving a specific address in Calico pools") ip := net.ParseIP(request.Address) ipArgs := datastoreClient.AssignIPArgs{ IP: caliconet.IP{IP: ip}, Hostname: hostname, } err := i.client.IPAM().AssignIP(ipArgs) if err != nil { err = errors.Wrapf(err, "IP assignment error, data: %+v", ipArgs) log.Errorln(err) return nil, err } IPs = []caliconet.IP{{IP: ip}} } // We should only have one IP address assigned at this point. if len(IPs) != 1 { err := errors.New(fmt.Sprintf("Unexpected number of assigned IP addresses. "+ "A single address should be assigned. Got %v", IPs)) log.Errorln(err) return nil, err } // Return the IP as a CIDR. resp := &ipam.RequestAddressResponse{ Address: fmt.Sprintf("%v/%v", IPs[0], "32"), } logutils.JSONMessage("RequestAddress response", resp) return resp, nil }