def test_initial_snapshot(self): # Create the DHCP agent. agent = CalicoDhcpAgent() # Check that running it invokes the etcd watcher loop. with mock.patch.object(agent, 'etcd') as etcdobj: agent.run() etcdobj.start.assert_called_with() with mock.patch.object(agent, 'call_driver') as call_driver: # Notify a non-empty initial snapshot. snapshot_data = agent.etcd._pre_snapshot_hook() agent.etcd.on_endpoint_set( EtcdResponse(value=json.dumps({ 'spec': { 'interfaceName': 'tap1234', 'mac': 'fe:16:65:12:33:44', 'profiles': ['profile-1'], 'ipNetworks': ['10.28.0.2/32'], 'ipv4Gateway': '10.28.0.1', } })), make_endpoint_name('endpoint-4')) agent.etcd._post_snapshot_hook(snapshot_data) # Check DHCP driver was not troubled - because the subnet data was # missing and so the port could not be processed further. call_driver.assert_not_called()
def test_initial_snapshot(self, etcd_client_cls): # Create the DHCP agent. agent = CalicoDhcpAgent() etcd_client = etcd_client_cls.return_value # Check that running it invokes the etcd watcher loop. with mock.patch.object(agent, 'etcd') as etcdobj: agent.run() etcdobj.loop.assert_called_with() # Arrange for subnet read to fail. etcd_client.read.side_effect = etcd.EtcdKeyNotFound with mock.patch.object(agent, 'call_driver') as call_driver: # Notify a non-empty initial snapshot. etcd_snapshot_node = mock.Mock() etcd_snapshot_node.action = 'exist' etcd_snapshot_node.key = ("/calico/v1/host/" + socket.gethostname() + "/workload/openstack" + "/workload_id/endpoint/endpoint-4") etcd_snapshot_node.value = json.dumps({ 'state': 'active', 'name': 'tap1234', 'mac': 'fe:16:65:12:33:44', 'profile_ids': ['profile-1'], 'ipv4_nets': ['10.28.0.2/32'], 'ipv4_subnet_ids': ['v4subnet-4'], 'ipv4_gateway': '10.28.0.1', 'ipv6_nets': [], 'ipv6_subnet_ids': [] }) etcd_snapshot_response = mock.Mock() etcd_snapshot_response.leaves = [etcd_snapshot_node] agent.etcd._on_snapshot_loaded(etcd_snapshot_response) # Check expected subnet was read from etcd. etcd_client.read.assert_has_calls([ mock.call(datamodel_v1.key_for_subnet('v4subnet-4'), consistent=True) ]) etcd_client.read.reset_mock() # Check DHCP driver was not troubled - because the subnet data was # missing and so the port could not be processed further. call_driver.assert_not_called()
def test_initial_snapshot(self, etcd_client_cls): # Create the DHCP agent. agent = CalicoDhcpAgent() etcd_client = etcd_client_cls.return_value # Check that running it invokes the etcd watcher loop. with mock.patch.object(agent, 'etcd') as etcdobj: agent.run() etcdobj.loop.assert_called_with() # Arrange for subnet read to fail. etcd_client.read.side_effect = etcd.EtcdKeyNotFound with mock.patch.object(agent, 'call_driver') as call_driver: # Notify a non-empty initial snapshot. etcd_snapshot_node = mock.Mock() etcd_snapshot_node.action = 'exist' etcd_snapshot_node.key = ("/calico/v1/host/" + socket.gethostname() + "/workload/openstack" + "/workload_id/endpoint/endpoint-4") etcd_snapshot_node.value = json.dumps({ 'state': 'active', 'name': 'tap1234', 'mac': 'fe:16:65:12:33:44', 'profile_ids': ['profile-1'], 'ipv4_nets': ['10.28.0.2/32'], 'ipv4_subnet_ids': ['v4subnet-4'], 'ipv4_gateway': '10.28.0.1', 'ipv6_nets': [], 'ipv6_subnet_ids': [] }) etcd_snapshot_response = mock.Mock() etcd_snapshot_response.leaves = [etcd_snapshot_node] agent.etcd._on_snapshot_loaded(etcd_snapshot_response) # Check expected subnet was read from etcd. etcd_client.read.assert_has_calls([ mock.call(datamodel_v1.key_for_subnet('v4subnet-4'), consistent=True) ]) etcd_client.read.reset_mock() # Check DHCP driver was not troubled - because the subnet data was # missing and so the port could not be processed further. call_driver.assert_not_called()
def test_mainline(self, etcd_client_cls): # Create the DHCP agent. agent = CalicoDhcpAgent() etcd_client = etcd_client_cls.return_value # Check that running it invokes the etcd watcher loop. with mock.patch.object(agent, 'etcd') as etcdobj: agent.run() etcdobj.loop.assert_called_with() # Notify initial snapshot (empty). with mock.patch.object(agent, 'call_driver') as call_driver: etcd_snapshot_response = mock.Mock() etcd_snapshot_response.leaves = [] agent.etcd._on_snapshot_loaded(etcd_snapshot_response) call_driver.assert_not_called() # Prepare subnet reads for the endpoints that we will notify. self.first_workload_read = True def etcd_client_read(key, **kwargs): LOG.info('etcd_client_read %s %s', key, kwargs) if 'v4subnet-1' in key: self.assertEqual('/calico/dhcp/v1/subnet/v4subnet-1', key) return EtcdResponse(value=json.dumps({ 'cidr': '10.28.0.0/24', 'gateway_ip': '10.28.0.1', 'host_routes': [] })) if 'v6subnet-1' in key: return EtcdResponse( value=json.dumps({ 'cidr': '2001:db8:1::/80', 'gateway_ip': '2001:db8:1::1' })) if 'v4subnet-2' in key: return EtcdResponse(value=json.dumps({ 'cidr': '10.29.0.0/24', 'gateway_ip': '10.29.0.1', 'host_routes': [{ 'destination': '11.11.0.0/16', 'nexthop': '10.65.0.1' }] })) if key == '/calico/v1/host/nj-ubuntu/workload': if self.first_workload_read: # This is the recursive read that the CalicoEtcdWatcher # loop makes after we've triggered it to resync. etcd_snapshot_node = mock.Mock() etcd_snapshot_node.action = 'exist' etcd_snapshot_node.key = ( "/calico/v1/host/" + socket.gethostname() + "/workload/openstack" + "/workload_id/endpoint/endpoint-4") etcd_snapshot_node.value = json.dumps({ 'state': 'active', 'name': 'tap1234', 'mac': 'fe:16:65:12:33:44', 'profile_ids': ['profile-1'], 'ipv4_nets': ['10.28.0.2/32'], 'ipv4_subnet_ids': ['v4subnet-1'], 'ipv4_gateway': '10.28.0.1', 'ipv6_nets': [], 'ipv6_subnet_ids': [] }) etcd_snapshot_response = mock.Mock() etcd_snapshot_response.etcd_index = 99 etcd_snapshot_response.leaves = [etcd_snapshot_node] self.first_workload_read = False return etcd_snapshot_response eventlet.sleep(10) return None etcd_client.read.side_effect = etcd_client_read with mock.patch.object(agent, 'call_driver') as call_driver: # Notify an endpoint. agent.etcd.on_endpoint_set( EtcdResponse( value=json.dumps({ 'state': 'active', 'name': 'tap1234', 'mac': 'fe:16:65:12:33:44', 'profile_ids': ['profile-1'], 'ipv4_nets': ['10.28.0.2/32'], 'ipv4_subnet_ids': ['v4subnet-1'], 'ipv4_gateway': '10.28.0.1', 'ipv6_nets': ['2001:db8:1::2/128'], 'ipv6_subnet_ids': ['v6subnet-1'], 'ipv6_gateway': '2001:db8:1::1' })), 'hostname-ignored', 'openstack', 'workload-id-ignored', 'endpoint-1') # Check expected subnets were read from etcd. etcd_client.read.assert_has_calls([ mock.call(datamodel_v1.key_for_subnet('v4subnet-1'), consistent=True), mock.call(datamodel_v1.key_for_subnet('v6subnet-1'), consistent=True) ], any_order=True) etcd_client.read.reset_mock() # Check DHCP driver was asked to restart. call_driver.assert_called_with('restart', mock.ANY) # Notify another endpoint (using the same subnets). agent.etcd.on_endpoint_set( EtcdResponse( value=json.dumps({ 'state': 'active', 'name': 'tap5678', 'mac': 'fe:16:65:12:33:55', 'profile_ids': ['profile-1'], 'ipv4_nets': ['10.28.0.3/32'], 'ipv4_subnet_ids': ['v4subnet-1'], 'ipv4_gateway': '10.28.0.1', 'ipv6_nets': ['2001:db8:1::3/128'], 'ipv6_subnet_ids': ['v6subnet-1'], 'ipv6_gateway': '2001:db8:1::1', 'fqdn': 'calico-vm17.datcon.co.uk' })), 'hostname-ignored', 'openstack', 'workload-id-ignored', 'endpoint-2') # Check no further etcd reads. etcd_client.read.assert_not_called() # Check DHCP driver was asked to restart. call_driver.assert_called_with('restart', mock.ANY) # Notify deletion of the first endpoint. agent.etcd.on_endpoint_delete(None, 'hostname-ignored', 'openstack', 'workload-id-ignored', 'endpoint-1') # Check no further etcd reads. etcd_client.read.assert_not_called() # Check DHCP driver was asked to reload allocations. call_driver.assert_called_with('restart', mock.ANY) # Notify another endpoint using a new subnet. agent.etcd.on_endpoint_set( EtcdResponse(value=json.dumps({ 'state': 'active', 'name': 'tapABCD', 'mac': 'fe:16:65:12:33:66', 'profile_ids': ['profile-1'], 'ipv4_nets': ['10.29.0.3/32'], 'ipv4_subnet_ids': ['v4subnet-2'], 'ipv4_gateway': '10.29.0.1', 'ipv6_nets': [], 'ipv6_subnet_ids': [] })), 'hostname-ignored', 'openstack', 'workload-id-ignored', 'endpoint-3') # Check expected new subnet was read from etcd. etcd_client.read.assert_has_calls([ mock.call(datamodel_v1.key_for_subnet('v4subnet-2'), consistent=True) ]) etcd_client.read.reset_mock() # Check DHCP driver was asked to restart. call_driver.assert_called_with('restart', mock.ANY) # Set the endpoint watcher loop running. eventlet.spawn(agent.etcd.loop) # Report that the subnet watcher noticed a change. agent.etcd.on_subnet_set(None, 'some-subnet-X') eventlet.sleep(0.2) # Check DHCP driver was asked to restart. call_driver.assert_called_with('restart', mock.ANY) # Report that the subnet watcher loaded a new snapshot. agent.etcd.subnet_watcher._on_snapshot_loaded('ignored') eventlet.sleep(0.2) # Check DHCP driver was asked to restart. call_driver.assert_called_with('restart', mock.ANY)
def test_mainline(self, etcd_client_cls): # Create the DHCP agent. agent = CalicoDhcpAgent() etcd_client = etcd_client_cls.return_value # Check that running it invokes the etcd watcher loop. with mock.patch.object(agent, 'etcd') as etcdobj: agent.run() etcdobj.loop.assert_called_with() # Notify initial snapshot (empty). with mock.patch.object(agent, 'call_driver') as call_driver: etcd_snapshot_response = mock.Mock() etcd_snapshot_response.leaves = [] agent.etcd._on_snapshot_loaded(etcd_snapshot_response) call_driver.assert_not_called() # Prepare subnet reads for the endpoints that we will notify. self.first_workload_read = True def etcd_client_read(key, **kwargs): LOG.info('etcd_client_read %s %s', key, kwargs) if 'v4subnet-1' in key: self.assertEqual('/calico/dhcp/v1/subnet/v4subnet-1', key) return EtcdResponse(value=json.dumps({ 'cidr': '10.28.0.0/24', 'gateway_ip': '10.28.0.1', 'host_routes': [] })) if 'v6subnet-1' in key: return EtcdResponse(value=json.dumps({ 'cidr': '2001:db8:1::/80', 'gateway_ip': '2001:db8:1::1' })) if 'v4subnet-2' in key: return EtcdResponse(value=json.dumps({ 'cidr': '10.29.0.0/24', 'gateway_ip': '10.29.0.1', 'host_routes': [{'destination': '11.11.0.0/16', 'nexthop': '10.65.0.1'}] })) if key == '/calico/v1/host/nj-ubuntu/workload': if self.first_workload_read: # This is the recursive read that the CalicoEtcdWatcher # loop makes after we've triggered it to resync. etcd_snapshot_node = mock.Mock() etcd_snapshot_node.action = 'exist' etcd_snapshot_node.key = ( "/calico/v1/host/" + socket.gethostname() + "/workload/openstack" + "/workload_id/endpoint/endpoint-4" ) etcd_snapshot_node.value = json.dumps({ 'state': 'active', 'name': 'tap1234', 'mac': 'fe:16:65:12:33:44', 'profile_ids': ['profile-1'], 'ipv4_nets': ['10.28.0.2/32'], 'ipv4_subnet_ids': ['v4subnet-1'], 'ipv4_gateway': '10.28.0.1', 'ipv6_nets': [], 'ipv6_subnet_ids': [] }) etcd_snapshot_response = mock.Mock() etcd_snapshot_response.etcd_index = 99 etcd_snapshot_response.leaves = [etcd_snapshot_node] self.first_workload_read = False return etcd_snapshot_response eventlet.sleep(10) return None etcd_client.read.side_effect = etcd_client_read with mock.patch.object(agent, 'call_driver') as call_driver: # Notify an endpoint. agent.etcd.on_endpoint_set(EtcdResponse(value=json.dumps({ 'state': 'active', 'name': 'tap1234', 'mac': 'fe:16:65:12:33:44', 'profile_ids': ['profile-1'], 'ipv4_nets': ['10.28.0.2/32'], 'ipv4_subnet_ids': ['v4subnet-1'], 'ipv4_gateway': '10.28.0.1', 'ipv6_nets': ['2001:db8:1::2/128'], 'ipv6_subnet_ids': ['v6subnet-1'], 'ipv6_gateway': '2001:db8:1::1' })), 'hostname-ignored', 'openstack', 'workload-id-ignored', 'endpoint-1' ) # Check expected subnets were read from etcd. etcd_client.read.assert_has_calls([ mock.call(datamodel_v1.key_for_subnet('v4subnet-1'), consistent=True), mock.call(datamodel_v1.key_for_subnet('v6subnet-1'), consistent=True) ], any_order=True) etcd_client.read.reset_mock() # Check DHCP driver was asked to restart. call_driver.assert_called_with('restart', mock.ANY) # Notify another endpoint (using the same subnets). agent.etcd.on_endpoint_set(EtcdResponse(value=json.dumps({ 'state': 'active', 'name': 'tap5678', 'mac': 'fe:16:65:12:33:55', 'profile_ids': ['profile-1'], 'ipv4_nets': ['10.28.0.3/32'], 'ipv4_subnet_ids': ['v4subnet-1'], 'ipv4_gateway': '10.28.0.1', 'ipv6_nets': ['2001:db8:1::3/128'], 'ipv6_subnet_ids': ['v6subnet-1'], 'ipv6_gateway': '2001:db8:1::1', 'fqdn': 'calico-vm17.datcon.co.uk' })), 'hostname-ignored', 'openstack', 'workload-id-ignored', 'endpoint-2' ) # Check no further etcd reads. etcd_client.read.assert_not_called() # Check DHCP driver was asked to restart. call_driver.assert_called_with('restart', mock.ANY) # Notify deletion of the first endpoint. agent.etcd.on_endpoint_delete(None, 'hostname-ignored', 'openstack', 'workload-id-ignored', 'endpoint-1') # Check no further etcd reads. etcd_client.read.assert_not_called() # Check DHCP driver was asked to reload allocations. call_driver.assert_called_with('restart', mock.ANY) # Notify another endpoint using a new subnet. agent.etcd.on_endpoint_set(EtcdResponse(value=json.dumps({ 'state': 'active', 'name': 'tapABCD', 'mac': 'fe:16:65:12:33:66', 'profile_ids': ['profile-1'], 'ipv4_nets': ['10.29.0.3/32'], 'ipv4_subnet_ids': ['v4subnet-2'], 'ipv4_gateway': '10.29.0.1', 'ipv6_nets': [], 'ipv6_subnet_ids': [] })), 'hostname-ignored', 'openstack', 'workload-id-ignored', 'endpoint-3' ) # Check expected new subnet was read from etcd. etcd_client.read.assert_has_calls([ mock.call(datamodel_v1.key_for_subnet('v4subnet-2'), consistent=True) ]) etcd_client.read.reset_mock() # Check DHCP driver was asked to restart. call_driver.assert_called_with('restart', mock.ANY) # Set the endpoint watcher loop running. eventlet.spawn(agent.etcd.loop) # Report that the subnet watcher noticed a change. agent.etcd.on_subnet_set(None, 'some-subnet-X') eventlet.sleep(0.2) # Check DHCP driver was asked to restart. call_driver.assert_called_with('restart', mock.ANY) # Report that the subnet watcher loaded a new snapshot. agent.etcd.subnet_watcher._on_snapshot_loaded('ignored') eventlet.sleep(0.2) # Check DHCP driver was asked to restart. call_driver.assert_called_with('restart', mock.ANY)
def test_mainline(self): # Create the DHCP agent. agent = CalicoDhcpAgent() # Check that running it invokes the etcd watcher loop. with mock.patch.object(agent, 'etcd') as etcdobj: agent.run() etcdobj.start.assert_called_with() # Notify initial snapshot (empty). with mock.patch.object(agent, 'call_driver') as call_driver: snapshot_data = agent.etcd._pre_snapshot_hook() agent.etcd._post_snapshot_hook(snapshot_data) call_driver.assert_not_called() with mock.patch.object(agent, 'call_driver') as call_driver: # Notify subnets. agent.etcd.subnet_watcher.on_subnet_set( EtcdResponse(value=json.dumps({ 'cidr': '10.28.0.0/24', 'gateway_ip': '10.28.0.1', 'host_routes': [] })), 'v4subnet-1') agent.etcd.subnet_watcher.on_subnet_set( EtcdResponse(value=json.dumps({ 'cidr': '2001:db8:1::/80', 'gateway_ip': '2001:db8:1::1' })), 'v6subnet-1') agent.etcd.subnet_watcher.on_subnet_set( EtcdResponse(value=json.dumps({ 'cidr': '10.29.0.0/24', 'gateway_ip': '10.29.0.1', 'host_routes': [{ 'destination': '11.11.0.0/16', 'nexthop': '10.65.0.1' }] })), 'v4subnet-2') # Notify an endpoint. agent.etcd.on_endpoint_set( EtcdResponse(value=json.dumps({ 'spec': { 'interfaceName': 'tap1234', 'mac': 'fe:16:65:12:33:44', 'profiles': ['profile-1'], 'ipNetworks': ['10.28.0.2/32', '2001:db8:1::2/128'], 'ipv4Gateway': '10.28.0.1', 'ipv6Gateway': '2001:db8:1::1' } })), make_endpoint_name('endpoint-1')) # Check DHCP driver was asked to restart. call_driver.assert_called_with('restart', mock.ANY) # Notify another endpoint (using the same subnets). agent.etcd.on_endpoint_set( EtcdResponse(value=json.dumps({ 'spec': { 'interfaceName': 'tap5678', 'mac': 'fe:16:65:12:33:55', 'profiles': ['profile-1'], 'ipNetworks': ['10.28.0.3/32', '2001:db8:1::3/128'], 'ipv4Gateway': '10.28.0.1', 'ipv6Gateway': '2001:db8:1::1', 'fqdn': 'calico-vm17.datcon.co.uk' } })), make_endpoint_name('endpoint-2')) # Check DHCP driver was asked to restart. call_driver.assert_called_with('restart', mock.ANY) # Notify deletion of the first endpoint. agent.etcd.on_endpoint_delete(None, make_endpoint_name('endpoint-1')) # Check DHCP driver was asked to reload allocations. call_driver.assert_called_with('restart', mock.ANY) # Notify another endpoint using a new subnet. agent.etcd.on_endpoint_set( EtcdResponse(value=json.dumps({ 'spec': { 'interfaceName': 'tapABCD', 'mac': 'fe:16:65:12:33:66', 'profiles': ['profile-1'], 'ipNetworks': ['10.29.0.3/32'], 'ipv4Gateway': '10.29.0.1', } })), make_endpoint_name('endpoint-3')) # Check DHCP driver was asked to restart. call_driver.assert_called_with('restart', mock.ANY)