func (d NetworkDriver) Join(request *network.JoinRequest) (*network.JoinResponse, error) { logutils.JSONMessage("Join", request) // 1) Set up a veth pair // The one end will stay in the host network namespace - named caliXXXXX // The other end is given a temporary name. It's moved into the final network namespace by libnetwork itself. var err error prefix := request.EndpointID[:mathutils.MinInt(11, len(request.EndpointID))] hostInterfaceName := "cali" + prefix tempInterfaceName := "temp" + prefix if err = netns.CreateVeth(hostInterfaceName, tempInterfaceName); err != nil { err = errors.Wrapf( err, "Veth creation error, hostInterfaceName=%v, tempInterfaceName=%v", hostInterfaceName, tempInterfaceName) log.Errorln(err) return nil, err } // libnetwork doesn't set the MAC address properly, so set it here. if err = netns.SetVethMac(tempInterfaceName, d.fixedMac); err != nil { log.Debugf("Veth mac setting for %v failed, removing veth for %v\n", tempInterfaceName, hostInterfaceName) err = netns.RemoveVeth(hostInterfaceName) err = errors.Wrapf(err, "Veth removing for %v error", hostInterfaceName) log.Errorln(err) return nil, err } resp := &network.JoinResponse{ InterfaceName: network.InterfaceName{ SrcName: tempInterfaceName, DstPrefix: IFPrefix, }, } // One of the network gateway addresses indicate that we are using // Calico IPAM driver. In this case we setup routes using the gateways // configured on the endpoint (which will be our host IPs). log.Debugln("Using Calico IPAM driver, configure gateway and static routes to the host") resp.Gateway = d.DummyIPV4Nexthop resp.StaticRoutes = append(resp.StaticRoutes, &network.StaticRoute{ Destination: d.DummyIPV4Nexthop + "/32", RouteType: 1, // 1 = CONNECTED NextHop: "", }) logutils.JSONMessage("Join response", resp) return resp, nil }
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 (d NetworkDriver) Leave(request *network.LeaveRequest) error { logutils.JSONMessage("Leave response", request) caliName := "cali" + request.EndpointID[:mathutils.MinInt(11, len(request.EndpointID))] err := netns.RemoveVeth(caliName) return err }
DockerString(fmt.Sprintf("docker network create %s -d calico --ipam-driver calico-ipam", name)) }) AfterEach(func() { DockerString(fmt.Sprintf("docker network rm %s", name)) }) It("creates a container on a network and checks all assertions", func() { // Create a container that will just sit in the background DockerString(fmt.Sprintf("docker run --net %s -tid --name %s busybox", name, name)) // Gather information for assertions docker_endpoint := GetDockerEndpoint(name, name) ip := docker_endpoint.IPAddress mac := docker_endpoint.MacAddress endpoint_id := docker_endpoint.EndpointID interface_name := "cali" + endpoint_id[:mathutils.MinInt(11, len(endpoint_id))] // Check that the endpoint is created in etcd etcd_endpoint := GetEtcdString(fmt.Sprintf("/calico/v1/host/test/workload/libnetwork/libnetwork/endpoint/%s", endpoint_id)) Expect(etcd_endpoint).Should(MatchJSON(fmt.Sprintf( `{"state":"active","name":"%s","mac":"%s","profile_ids":["%s"],"ipv4_nets":["%s/32"],"ipv6_nets":[]}`, interface_name, mac, name, ip))) // Check profile tags := GetEtcdString(fmt.Sprintf("/calico/v1/policy/profile/%s/tags", name)) labels := GetEtcdString(fmt.Sprintf("/calico/v1/policy/profile/%s/labels", name)) rules := GetEtcdString(fmt.Sprintf("/calico/v1/policy/profile/%s/rules", name)) Expect(tags).Should(MatchJSON(fmt.Sprintf(`["%s"]`, name))) Expect(labels).Should(MatchJSON("{}")) Expect(rules).Should(MatchJSON(fmt.Sprintf(`{"inbound_rules": [{"action": "allow","src_tag": "%s"}],"outbound_rules":[{"action": "allow"}]}`, name)))