def test_join(self, m_create_veth, m_set_mac): """ Test the join() processing correctly creates the veth. """ # Actually make the request to the plugin. rv = self.app.post('/NetworkDriver.Join', data='{"EndpointID": "%s", "NetworkID": "%s"}' % (TEST_ENDPOINT_ID, TEST_NETWORK_ID)) host_interface_name = generate_cali_interface_name( IF_PREFIX, TEST_ENDPOINT_ID) temp_interface_name = generate_cali_interface_name( "tmp", TEST_ENDPOINT_ID) m_create_veth.assert_called_once_with(host_interface_name, temp_interface_name) m_set_mac.assert_called_once_with(temp_interface_name, "EE:EE:EE:EE:EE:EE") expected_response = """ { "Gateway": "", "InterfaceName": { "DstPrefix": "cali", "SrcName": "tmpTEST_ENDPOI" } }""" self.maxDiff = None self.assertDictEqual(json.loads(rv.data), json.loads(expected_response))
def test_join_veth_fail(self, m_del_veth, m_create_veth, m_set_veth_mac, m_next_hops): """ Test the join() processing when create_veth fails. """ m_create_veth.side_effect = CalledProcessError(2, "testcmd") m_next_hops.return_value = {4: IPAddress("1.2.3.4"), 6: None} # Actually make the request to the plugin. rv = self.app.post('/NetworkDriver.Join', data='{"EndpointID": "%s", "NetworkID": "%s"}' % (TEST_ENDPOINT_ID, TEST_NETWORK_ID)) # Expect a 500 response. self.assertDictEqual(json.loads(rv.data), {u'Err': u"Command 'testcmd' returned non-zero exit status 2"}) # Check that create veth is called with the expected endpoint, and # that set_endpoint is not (since create_veth is raising an exception). host_interface_name = generate_cali_interface_name(IF_PREFIX, TEST_ENDPOINT_ID) temp_interface_name = generate_cali_interface_name("tmp", TEST_ENDPOINT_ID) m_create_veth.assert_called_once_with(host_interface_name, temp_interface_name) # Check that we delete the veth. m_del_veth.assert_called_once_with(host_interface_name)
def test_join_veth_fail(self, m_del_veth, m_create_veth, m_set_veth_mac, m_next_hops): """ Test the join() processing when create_veth fails. """ m_create_veth.side_effect = CalledProcessError(2, "testcmd") m_next_hops.return_value = {4: IPAddress("1.2.3.4"), 6: None} # Actually make the request to the plugin. rv = self.app.post('/NetworkDriver.Join', data='{"EndpointID": "%s", "NetworkID": "%s"}' % (TEST_ENDPOINT_ID, TEST_NETWORK_ID)) # Expect a 500 response. self.assertDictEqual( json.loads(rv.data), {u'Err': u"Command 'testcmd' returned non-zero exit status 2"}) # Check that create veth is called with the expected endpoint, and # that set_endpoint is not (since create_veth is raising an exception). host_interface_name = generate_cali_interface_name( IF_PREFIX, TEST_ENDPOINT_ID) temp_interface_name = generate_cali_interface_name( "tmp", TEST_ENDPOINT_ID) m_create_veth.assert_called_once_with(host_interface_name, temp_interface_name) # Check that we delete the veth. m_del_veth.assert_called_once_with(host_interface_name)
def test_join_calico_ipam(self, m_create_veth, m_set_mac, m_get_network, m_get_endpoint, m_get_link_local, m_intf_up): """ Test the join() processing with Calico IPAM. """ m_get_network.return_value = { "NetworkID": TEST_NETWORK_ID, "IPv4Data": [{ "Gateway": "0.0.0.0/0", "Pool": "0.0.0.0/0" }], "IPv6Data": [{ "Gateway": "::/0", "Pool": "::/0" }] } m_get_endpoint.return_value = Endpoint(hostname, "libnetwork", "docker", TEST_ENDPOINT_ID, None, None) # Actually make the request to the plugin. rv = self.app.post('/NetworkDriver.Join', data='{"EndpointID": "%s", "NetworkID": "%s"}' % (TEST_ENDPOINT_ID, TEST_NETWORK_ID)) host_interface_name = generate_cali_interface_name( IF_PREFIX, TEST_ENDPOINT_ID) temp_interface_name = generate_cali_interface_name( "tmp", TEST_ENDPOINT_ID) m_create_veth.assert_called_once_with(host_interface_name, temp_interface_name) m_set_mac.assert_called_once_with(temp_interface_name, "EE:EE:EE:EE:EE:EE") expected_data = { "Gateway": "169.254.1.1", "GatewayIPv6": "fe80::1/128", "InterfaceName": { "DstPrefix": "cali", "SrcName": "tmpTEST_ENDPOI" }, "StaticRoutes": [{ "Destination": "169.254.1.1/32", "RouteType": 1, "NextHop": "" }, { "Destination": "fe80::1/128", "RouteType": 1, "NextHop": "" }] } self.maxDiff = None self.assertDictEqual(json.loads(rv.data), expected_data)
def test_join_calico_ipam(self, m_create_veth, m_set_mac, m_get_network, m_get_endpoint): """ Test the join() processing with Calico IPAM. """ m_get_network.return_value = { "NetworkID": TEST_NETWORK_ID, "IPv4Data":[{ "Gateway": "0.0.0.0/0", "Pool": "0.0.0.0/0" }], "IPv6Data":[{ "Gateway": "::/0", "Pool": "::/0" }]} m_get_endpoint.return_value = Endpoint(hostname, "libnetwork", "docker", TEST_ENDPOINT_ID, None, None) m_get_endpoint.return_value.ipv4_gateway = IPAddress("1.2.3.4") m_get_endpoint.return_value.ipv6_gateway = IPAddress("aa::ff") # Actually make the request to the plugin. rv = self.app.post('/NetworkDriver.Join', data='{"EndpointID": "%s", "NetworkID": "%s"}' % (TEST_ENDPOINT_ID, TEST_NETWORK_ID)) host_interface_name = generate_cali_interface_name(IF_PREFIX, TEST_ENDPOINT_ID) temp_interface_name = generate_cali_interface_name("tmp", TEST_ENDPOINT_ID) m_create_veth.assert_called_once_with(host_interface_name, temp_interface_name) m_set_mac.assert_called_once_with(temp_interface_name, "EE:EE:EE:EE:EE:EE") expected_data = { "Gateway": str(m_get_endpoint.return_value.ipv4_gateway), "GatewayIPv6": str(m_get_endpoint.return_value.ipv6_gateway), "InterfaceName": { "DstPrefix": "cali", "SrcName": "tmpTEST_ENDPOI" }, "StaticRoutes": [{ "Destination": str(m_get_endpoint.return_value.ipv4_gateway) +"/32", "RouteType": 1, "NextHop": "" }, { "Destination": str(m_get_endpoint.return_value.ipv6_gateway) + "/128", "RouteType": 1, "NextHop": "" }] } self.maxDiff = None self.assertDictEqual(json.loads(rv.data), expected_data)
def __init__(self, hostname, orchestrator_id, workload_id, endpoint_id, state, mac, name=None, active_instance_id=""): self.hostname = hostname self.orchestrator_id = orchestrator_id self.workload_id = workload_id self.endpoint_id = endpoint_id self.state = state self.mac = mac self.name = name or generate_cali_interface_name( IF_PREFIX, endpoint_id) self.active_instance_id = active_instance_id self.ipv4_nets = set() self.ipv6_nets = set() self.profile_ids = [] self._original_json = None self.labels = {}
def _configure_interface(self): """Configure the Calico interface for a pod. This involves the following steps: 1) Determine the IP that docker assigned to the interface inside the container 2) Delete the docker-assigned veth pair that's attached to the docker bridge 3) Create a new calico veth pair, using the docker-assigned IP for the end in the container's namespace 4) Assign the node's IP to the host end of the veth pair (required for compatibility with kube-proxy REDIRECT iptables rules). """ container_ip = self._read_docker_ip() self._delete_docker_interface() print('Configuring Calico network interface') ep = container_add(self.docker_id, container_ip, 'eth0') interface_name = generate_cali_interface_name(IF_PREFIX, ep.endpoint_id) node_ip = self._get_node_ip() print('Adding IP %s to interface %s' % (node_ip, interface_name)) # This is slightly tricky. Since the kube-proxy sometimes # programs REDIRECT iptables rules, we MUST have an IP on the host end # of the caliXXX veth pairs. This is because the REDIRECT rule # rewrites the destination ip/port of traffic from a pod to a service # VIP. The destination port is rewriten to an arbitrary high-numbered # port, and the destination IP is rewritten to one of the IPs allocated # to the interface. This fails if the interface doesn't have an IP, # so we allocate an IP which is already allocated to the node. We set # the subnet to /32 so that the routing table is not affected; # no traffic for the node_ip's subnet will use the /32 route. check_call(['ip', 'addr', 'add', node_ip + '/32', 'dev', interface_name]) print('Finished configuring network interface') return ep
def test_join_default_ipam(self, m_create_veth, m_set_mac, m_get_network, m_intf_up): """ Test the join() processing with default IPAM. """ request_data = { "EndpointID": TEST_ENDPOINT_ID, "NetworkID": TEST_NETWORK_ID } m_get_network.return_value = { "NetworkID": TEST_NETWORK_ID, "IPv4Data": [{ "Gateway": "6.5.4.3/21", "Pool": "6.5.4.3/21" }], "IPv6Data": [] } # Actually make the request to the plugin. rv = self.app.post('/NetworkDriver.Join', data=json.dumps(request_data)) # Check the expected response. response_data = { "Gateway": "", "GatewayIPv6": "", "InterfaceName": { "DstPrefix": "cali", "SrcName": "tmpTEST_ENDPOI" } } self.maxDiff = None self.assertDictEqual(json.loads(rv.data), response_data) # Check appropriate netns calls. host_interface_name = generate_cali_interface_name( IF_PREFIX, TEST_ENDPOINT_ID) temp_interface_name = generate_cali_interface_name( "tmp", TEST_ENDPOINT_ID) m_create_veth.assert_called_once_with(host_interface_name, temp_interface_name) m_set_mac.assert_called_once_with(temp_interface_name, "EE:EE:EE:EE:EE:EE")
def test_leave(self, m_veth): """ Test leave() processing removes the veth. """ # Send the leave request. rv = self.app.post("/NetworkDriver.Leave", data='{"EndpointID": "%s"}' % TEST_ENDPOINT_ID) self.assertDictEqual(json.loads(rv.data), {}) m_veth.assert_called_once_with(generate_cali_interface_name(IF_PREFIX, TEST_ENDPOINT_ID))
def test_remove_veth_fail(self, m_remove): """ Test remove_veth calls through to netns to remove the veth. Fail with a CalledProcessError to write the log. """ name = generate_cali_interface_name(IF_PREFIX, TEST_ENDPOINT_ID) driver_plugin.remove_veth(name) m_remove.assert_called_once_with(name)
def leave(): json_data = request.get_json(force=True) app.logger.debug("Leave JSON=%s", json_data) ep_id = json_data["EndpointID"] app.logger.info("Leaving endpoint %s", ep_id) remove_veth(generate_cali_interface_name(IF_PREFIX, ep_id)) app.logger.debug("Leave response JSON=%s", "{}") return jsonify({})
def test_leave(self, m_veth): """ Test leave() processing removes the veth. """ # Send the leave request. rv = self.app.post('/NetworkDriver.Leave', data='{"EndpointID": "%s"}' % TEST_ENDPOINT_ID) self.assertDictEqual(json.loads(rv.data), {}) m_veth.assert_called_once_with( generate_cali_interface_name(IF_PREFIX, TEST_ENDPOINT_ID))
def test_join(self, m_create_veth, m_set_mac): """ Test the join() processing correctly creates the veth. """ # Actually make the request to the plugin. rv = self.app.post( "/NetworkDriver.Join", data='{"EndpointID": "%s", "NetworkID": "%s"}' % (TEST_ENDPOINT_ID, TEST_NETWORK_ID) ) host_interface_name = generate_cali_interface_name(IF_PREFIX, TEST_ENDPOINT_ID) temp_interface_name = generate_cali_interface_name("tmp", TEST_ENDPOINT_ID) m_create_veth.assert_called_once_with(host_interface_name, temp_interface_name) m_set_mac.assert_called_once_with(temp_interface_name, "EE:EE:EE:EE:EE:EE") expected_response = """ { "Gateway": "", "InterfaceName": { "DstPrefix": "cali", "SrcName": "tmpTEST_ENDPOI" } }""" self.maxDiff = None self.assertDictEqual(json.loads(rv.data), json.loads(expected_response))
def join(): json_data = request.get_json(force=True) app.logger.debug("Join JSON=%s", json_data) endpoint_id = json_data["EndpointID"] app.logger.info("Joining endpoint %s", endpoint_id) network_id = json_data["NetworkID"] network_data = client.get_network(network_id) ipv4_gateway = "" if network_data and "IPv4Data" in network_data.keys(): ipv4_gateway = str(IPNetwork(network_data["IPv4Data"][0]["Gateway"]).ip) # The host interface name matches the name given when creating the endpoint # during CreateEndpoint host_interface_name = generate_cali_interface_name(IF_PREFIX, endpoint_id) # The temporary interface name is what gets passed to libnetwork. # Libnetwork renames the interface using the DstPrefix (e.g. cali0) temp_interface_name = generate_cali_interface_name("tmp", endpoint_id) try: # Create the veth pair. netns.create_veth(host_interface_name, temp_interface_name) # Set the mac as libnetwork doesn't do this for us (even if we return # it on the CreateNetwork) netns.set_veth_mac(temp_interface_name, FIXED_MAC) except CalledProcessError as e: # Failed to create or configure the veth, ensure veth is removed. remove_veth(host_interface_name) raise e return_json = { "InterfaceName": {"SrcName": temp_interface_name, "DstPrefix": IF_PREFIX}, "Gateway": ipv4_gateway, # Leave gateway empty to trigger auto-gateway behaviour } app.logger.debug("Join Response JSON=%s", return_json) return jsonify(return_json)
def test_join_default_ipam(self, m_create_veth, m_set_mac, m_get_network): """ Test the join() processing with default IPAM. """ request_data = { "EndpointID": TEST_ENDPOINT_ID, "NetworkID": TEST_NETWORK_ID } m_get_network.return_value = { "NetworkID": TEST_NETWORK_ID, "IPv4Data": [{ "Gateway": "6.5.4.3/21", "Pool": "6.5.4.3/21" }], "IPv6Data": []} # Actually make the request to the plugin. rv = self.app.post('/NetworkDriver.Join', data=json.dumps(request_data)) # Check the expected response. response_data = { "Gateway": "", "GatewayIPv6": "", "InterfaceName": { "DstPrefix": "cali", "SrcName": "tmpTEST_ENDPOI" } } self.maxDiff = None self.assertDictEqual(json.loads(rv.data), response_data) # Check appropriate netns calls. host_interface_name = generate_cali_interface_name(IF_PREFIX, TEST_ENDPOINT_ID) temp_interface_name = generate_cali_interface_name("tmp", TEST_ENDPOINT_ID) m_create_veth.assert_called_once_with(host_interface_name, temp_interface_name) m_set_mac.assert_called_once_with(temp_interface_name, "EE:EE:EE:EE:EE:EE")
def join(): json_data = request.get_json(force=True) app.logger.debug("Join JSON=%s", json_data) endpoint_id = json_data["EndpointID"] app.logger.info("Joining endpoint %s", endpoint_id) # The host interface name matches the name given when creating the endpoint # during CreateEndpoint host_interface_name = generate_cali_interface_name(IF_PREFIX, endpoint_id) # The temporary interface name is what gets passed to libnetwork. # Libnetwork renames the interface using the DstPrefix (e.g. cali0) temp_interface_name = generate_cali_interface_name("tmp", endpoint_id) try: # Create the veth pair. netns.create_veth(host_interface_name, temp_interface_name) # Set the mac as libnetwork doesn't do this for us (even if we return # it on the CreateNetwork) netns.set_veth_mac(temp_interface_name, FIXED_MAC) except CalledProcessError as e: # Failed to create or configure the veth, ensure veth is removed. remove_veth(host_interface_name) raise e return_json = { "InterfaceName": { "SrcName": temp_interface_name, "DstPrefix": IF_PREFIX }, "Gateway": "", # Leave gateway empty to trigger auto-gateway behaviour } app.logger.debug("Join Response JSON=%s", return_json) return jsonify(return_json)
def __init__(self, hostname, orchestrator_id, workload_id, endpoint_id, state, mac): self.hostname = hostname self.orchestrator_id = orchestrator_id self.workload_id = workload_id self.endpoint_id = endpoint_id self.state = state self.mac = mac self.name = generate_cali_interface_name(IF_PREFIX, endpoint_id) self.ipv4_nets = set() self.ipv6_nets = set() self.ipv4_gateway = None self.ipv6_gateway = None self.profile_ids = [] self._original_json = None
def _configure_interface(self): """Configure the Calico interface for a pod. This involves the following steps: 1) Determine the IP that docker assigned to the interface inside the container 2) Delete the docker-assigned veth pair that's attached to the docker bridge 3) Create a new calico veth pair, using the docker-assigned IP for the end in the container's namespace 4) Assign the node's IP to the host end of the veth pair (required for compatibility with kube-proxy REDIRECT iptables rules). """ # Set up parameters container_pid = self._get_container_pid(self.docker_id) interface = 'eth0' self._delete_docker_interface() logger.info('Configuring Calico network interface') ep = self._container_add(container_pid, interface) # Log our container's interfaces after adding the new interface. _log_interfaces(container_pid) interface_name = generate_cali_interface_name(IF_PREFIX, ep.endpoint_id) node_ip = self._get_node_ip() logger.debug('Adding node IP %s to host-side veth %s', node_ip, interface_name) # This is slightly tricky. Since the kube-proxy sometimes # programs REDIRECT iptables rules, we MUST have an IP on the host end # of the caliXXX veth pairs. This is because the REDIRECT rule # rewrites the destination ip/port of traffic from a pod to a service # VIP. The destination port is rewriten to an arbitrary high-numbered # port, and the destination IP is rewritten to one of the IPs allocated # to the interface. This fails if the interface doesn't have an IP, # so we allocate an IP which is already allocated to the node. We set # the subnet to /32 so that the routing table is not affected; # no traffic for the node_ip's subnet will use the /32 route. check_call(['ip', 'addr', 'add', node_ip + '/32', 'dev', interface_name]) logger.info('Finished configuring network interface') return ep
def temp_interface_name(self): return generate_cali_interface_name("tmp", self.endpoint_id)
def join(): json_data = request.get_json(force=True) app.logger.debug("Join JSON=%s", json_data) network_id = json_data["NetworkID"] endpoint_id = json_data["EndpointID"] app.logger.info("Joining endpoint %s", endpoint_id) # The host interface name matches the name given when creating the endpoint # during CreateEndpoint host_interface_name = generate_cali_interface_name(IF_PREFIX, endpoint_id) # The temporary interface name is what gets passed to libnetwork. # Libnetwork renames the interface using the DstPrefix (e.g. cali0) temp_interface_name = generate_cali_interface_name("tmp", endpoint_id) try: # Create the veth pair. netns.create_veth(host_interface_name, temp_interface_name) # Set the mac as libnetwork doesn't do this for us (even if we return # it on the CreateNetwork) netns.set_veth_mac(temp_interface_name, FIXED_MAC) except CalledProcessError as e: # Failed to create or configure the veth, ensure veth is removed. remove_veth(host_interface_name) raise e # Initialise our response data. json_response = { "InterfaceName": { "SrcName": temp_interface_name, "DstPrefix": "eth", } } # Extract relevant data from the Network data. network_data = get_network_data(network_id) gateway_ip4, _ = get_gateway_pool_from_network_data(network_data, 4) gateway_ip6, _ = get_gateway_pool_from_network_data(network_data, 6) if (gateway_ip4 and is_using_calico_ipam(gateway_ip4)) or \ (gateway_ip6 and is_using_calico_ipam(gateway_ip6)): # 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). app.logger.debug("Using Calico IPAM driver, configure gateway and " "static routes to the host") static_routes = [] if gateway_ip4: json_response["Gateway"] = DUMMY_IPV4_NEXTHOP static_routes.append({ "Destination": DUMMY_IPV4_NEXTHOP + "/32", "RouteType": 1, # 1 = CONNECTED "NextHop": "" }) if gateway_ip6: # Here, we'll report the link local address of the host's cali interface to libnetwork # as our IPv6 gateway. IPv6 link local addresses are automatically assigned to interfaces # when they are brought up. Unfortunately, the container link must be up as well. So # bring it up now # TODO: create_veth should already bring up both links bring_up_interface(temp_interface_name) # Then extract the link local address that was just assigned to our host's interface next_hop_6 = get_next_hop_6(host_interface_name) json_response["GatewayIPv6"] = next_hop_6 static_routes.append({ "Destination": str(IPNetwork(next_hop_6)), "RouteType": 1, # 1 = CONNECTED "NextHop": "" }) json_response["StaticRoutes"] = static_routes else: # We are not using Calico IPAM driver, so configure blank gateways to # set up auto-gateway behavior. app.logger.debug("Not using Calico IPAM driver") json_response["Gateway"] = "" json_response["GatewayIPv6"] = "" app.logger.debug("Join Response JSON=%s", json_response) return jsonify(json_response)
def join(): json_data = request.get_json(force=True) app.logger.debug("Join JSON=%s", json_data) network_id = json_data["NetworkID"] endpoint_id = json_data["EndpointID"] app.logger.info("Joining endpoint %s", endpoint_id) # The host interface name matches the name given when creating the endpoint # during CreateEndpoint host_interface_name = generate_cali_interface_name(IF_PREFIX, endpoint_id) # The temporary interface name is what gets passed to libnetwork. # Libnetwork renames the interface using the DstPrefix (e.g. cali0) temp_interface_name = generate_cali_interface_name("tmp", endpoint_id) try: # Create the veth pair. netns.create_veth(host_interface_name, temp_interface_name) # Set the mac as libnetwork doesn't do this for us (even if we return # it on the CreateNetwork) netns.set_veth_mac(temp_interface_name, FIXED_MAC) except CalledProcessError as e: # Failed to create or configure the veth, ensure veth is removed. remove_veth(host_interface_name) raise e # Initialise our response data. json_response = { "InterfaceName": { "SrcName": temp_interface_name, "DstPrefix": IF_PREFIX, } } # Extract relevant data from the Network data. network_data = get_network_data(network_id) gateway_ip4, _ = get_gateway_pool_from_network_data(network_data, 4) gateway_ip6, _ = get_gateway_pool_from_network_data(network_data, 6) if (gateway_ip4 and is_using_calico_ipam(gateway_ip4)) or \ (gateway_ip6 and is_using_calico_ipam(gateway_ip6)): # 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). app.logger.debug("Using Calico IPAM driver, configure gateway and " "static routes to the host") static_routes = [] if gateway_ip4: json_response["Gateway"] = DUMMY_IPV4_NEXTHOP static_routes.append({ "Destination": DUMMY_IPV4_NEXTHOP + "/32", "RouteType": 1, # 1 = CONNECTED "NextHop": "" }) if gateway_ip6: # Here, we'll report the link local address of the host's cali interface to libnetwork # as our IPv6 gateway. IPv6 link local addresses are automatically assigned to interfaces # when they are brought up. Unfortunately, the container link must be up as well. So # bring it up now # TODO: create_veth should already bring up both links bring_up_interface(temp_interface_name) # Then extract the link local address that was just assigned to our host's interface next_hop_6 = get_ipv6_link_local(host_interface_name) json_response["GatewayIPv6"] = next_hop_6 static_routes.append({ "Destination": str(IPNetwork(next_hop_6)), "RouteType": 1, # 1 = CONNECTED "NextHop": "" }) json_response["StaticRoutes"] = static_routes else: # We are not using Calico IPAM driver, so configure blank gateways to # set up auto-gateway behavior. app.logger.debug("Not using Calico IPAM driver") json_response["Gateway"] = "" json_response["GatewayIPv6"] = "" app.logger.debug("Join Response JSON=%s", json_response) return jsonify(json_response)
def join(): json_data = request.get_json(force=True) app.logger.debug("Join JSON=%s", json_data) network_id = json_data["NetworkID"] endpoint_id = json_data["EndpointID"] app.logger.info("Joining endpoint %s", endpoint_id) # The host interface name matches the name given when creating the endpoint # during CreateEndpoint host_interface_name = generate_cali_interface_name(IF_PREFIX, endpoint_id) # The temporary interface name is what gets passed to libnetwork. # Libnetwork renames the interface using the DstPrefix (e.g. cali0) temp_interface_name = generate_cali_interface_name("tmp", endpoint_id) try: # Create the veth pair. netns.create_veth(host_interface_name, temp_interface_name) # Set the mac as libnetwork doesn't do this for us (even if we return # it on the CreateNetwork) netns.set_veth_mac(temp_interface_name, FIXED_MAC) except CalledProcessError as e: # Failed to create or configure the veth, ensure veth is removed. remove_veth(host_interface_name) raise e # Initialise our response data. json_response = { "InterfaceName": { "SrcName": temp_interface_name, "DstPrefix": IF_PREFIX, } } # Extract relevant data from the Network data. network_data = get_network_data(network_id) gateway_ip4, _ = get_gateway_pool_from_network_data(network_data, 4) gateway_ip6, _ = get_gateway_pool_from_network_data(network_data, 6) if (gateway_ip4 and is_using_calico_ipam(gateway_ip4)) or \ (gateway_ip6 and is_using_calico_ipam(gateway_ip6)): # 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). app.logger.debug("Using Calico IPAM driver, configure gateway and " "static routes to the host") ep = client.get_endpoint(hostname=hostname, orchestrator_id=ORCHESTRATOR_ID, workload_id=CONTAINER_NAME, endpoint_id=endpoint_id) static_routes = [] if ep.ipv4_gateway: json_response["Gateway"] = str(ep.ipv4_gateway) static_routes.append({ "Destination": str(IPNetwork(ep.ipv4_gateway)), "RouteType": 1, # 1 = CONNECTED "NextHop": "" }) if ep.ipv6_gateway: json_response["GatewayIPv6"] = str(ep.ipv6_gateway) static_routes.append({ "Destination": str(IPNetwork(ep.ipv6_gateway)), "RouteType": 1, # 1 = CONNECTED "NextHop": "" }) json_response["StaticRoutes"] = static_routes else: # We are not using Calico IPAM driver, so configure blank gateways to # set up auto-gateway behavior. app.logger.debug("Not using Calico IPAM driver") json_response["Gateway"] = "" json_response["GatewayIPv6"] = "" app.logger.debug("Join Response JSON=%s", json_response) return jsonify(json_response)