Merge "Reimplement DHCPAgent as net's property"

This commit is contained in:
Jenkins 2014-03-25 04:28:43 +00:00 committed by Gerrit Code Review
commit 0d19394458
2 changed files with 109 additions and 190 deletions

View File

@ -27,8 +27,10 @@ logger = logging.getLogger(__name__)
class Net(neutron.NeutronResource):
PROPERTIES = (
NAME, VALUE_SPECS, ADMIN_STATE_UP, TENANT_ID, SHARED,
DHCP_AGENT_IDS,
) = (
'name', 'value_specs', 'admin_state_up', 'tenant_id', 'shared',
'dhcp_agent_ids',
)
properties_schema = {
@ -67,6 +69,13 @@ class Net(neutron.NeutronResource):
default=False,
update_allowed=True
),
DHCP_AGENT_IDS: properties.Schema(
properties.Schema.LIST,
_('The IDs of the DHCP agent to schedule the network. Note that '
'the default policy setting in Neutron restricts usage of this '
'property to administrative users only.'),
update_allowed=True
),
}
attributes_schema = {
@ -84,9 +93,15 @@ class Net(neutron.NeutronResource):
props = self.prepare_properties(
self.properties,
self.physical_resource_name())
dhcp_agent_ids = props.pop(self.DHCP_AGENT_IDS, None)
net = self.neutron().create_network({'network': props})['network']
self.resource_id_set(net['id'])
if dhcp_agent_ids:
self._replace_dhcp_agents(dhcp_agent_ids)
def _show_resource(self):
return self.neutron().show_network(
self.resource_id)['network']
@ -107,7 +122,16 @@ class Net(neutron.NeutronResource):
def handle_update(self, json_snippet, tmpl_diff, prop_diff):
props = self.prepare_update_properties(json_snippet)
self.neutron().update_network(self.resource_id, {'network': props})
dhcp_agent_ids = props.pop(self.DHCP_AGENT_IDS, None)
if self.DHCP_AGENT_IDS in prop_diff:
if dhcp_agent_ids is not None:
self._replace_dhcp_agents(dhcp_agent_ids)
del prop_diff[self.DHCP_AGENT_IDS]
if len(prop_diff) > 0:
self.neutron().update_network(
self.resource_id, {'network': props})
def check_update_complete(self, *args):
attributes = self._show_resource()
@ -119,59 +143,31 @@ class Net(neutron.NeutronResource):
isinstance(ex, neutron_exp.NetworkNotFoundClient)):
raise ex
def _replace_dhcp_agents(self, dhcp_agent_ids):
ret = self.neutron().list_dhcp_agent_hosting_networks(
self.resource_id)
old = set([agent['id'] for agent in ret['agents']])
new = set(dhcp_agent_ids)
class NetDHCPAgent(neutron.NeutronResource):
PROPERTIES = (
NETWORK_ID, DHCP_AGENT_ID,
) = (
'network_id', 'dhcp_agent_id',
)
for dhcp_agent_id in new - old:
try:
self.neutron().add_network_to_dhcp_agent(
dhcp_agent_id, {'network_id': self.resource_id})
except neutron_exp.NeutronClientException as ex:
# if 409 is happened, the agent is already associated.
if ex.status_code != 409:
raise ex
properties_schema = {
NETWORK_ID: properties.Schema(
properties.Schema.STRING,
_('The ID of the network you want to be scheduled by the '
'dhcp_agent. Note that the default policy setting in Neutron '
'restricts usage of this property to administrative users '
'only.'),
required=True
),
DHCP_AGENT_ID: properties.Schema(
properties.Schema.STRING,
_('The ID of the dhcp-agent to schedule the network. Note that '
'the default policy setting in Neutron restricts usage of this '
'property to administrative users only.'),
required=True
),
}
def handle_create(self):
network_id = self.properties[self.NETWORK_ID]
dhcp_agent_id = self.properties[self.DHCP_AGENT_ID]
try:
self.neutron().add_network_to_dhcp_agent(
dhcp_agent_id, {'network_id': network_id})
except neutron_exp.NeutronClientException as ex:
# if 409 is happened, the agent is already associated.
if ex.status_code != 409:
raise ex
self.resource_id_set('%(net)s:%(agt)s' %
{'net': network_id, 'agt': dhcp_agent_id})
def handle_delete(self):
if not self.resource_id:
return
client = self.neutron()
network_id, dhcp_agent_id = self.resource_id.split(':')
try:
client.remove_network_from_dhcp_agent(
dhcp_agent_id, network_id)
except neutron_exp.NeutronClientException as ex:
# assume 2 patterns about status_code following:
# 404: the network or agent is already gone
# 409: the network isn't scheduled by the dhcp_agent
if ex.status_code not in (404, 409):
raise ex
for dhcp_agent_id in old - new:
try:
self.neutron().remove_network_from_dhcp_agent(
dhcp_agent_id, self.resource_id)
except neutron_exp.NeutronClientException as ex:
# assume 2 patterns about status_code following:
# 404: the network or agent is already gone
# 409: the network isn't scheduled by the dhcp_agent
if ex.status_code not in (404, 409):
raise ex
class NetworkConstraint(object):
@ -199,5 +195,4 @@ def resource_mapping():
return {
'OS::Neutron::Net': Net,
'OS::Neutron::NetDHCPAgent': NetDHCPAgent,
}

View File

@ -46,7 +46,10 @@ neutron_template = '''
"Properties": {
"name": "the_network",
"tenant_id": "c1210485b2424d48804aad5d39c61b8f",
"shared": true
"shared": true,
"dhcp_agent_ids": [
"28c25a04-3f73-45a7-a2b4-59e183943ddc"
]
}
},
"unnamed_network": {
@ -133,22 +136,6 @@ provider_network_template = '''
}
'''
neutron_dhcp_agent_template = '''
{
"AWSTemplateFormatVersion" : "2010-09-09",
"Description" : "Template to test Neutron resources",
"Resources" : {
"network_dhcp_agent": {
"Type": "OS::Neutron::NetDHCPAgent",
"Properties": {
"network_id": "66a426ef-8b77-4e25-8098-b3a7c0964b93",
"dhcp_agent_id": "9f0df05b-4846-4d3d-971e-a2e1a06b1622"
}
}
}
}
'''
neutron_external_gateway_template = '''
{
"AWSTemplateFormatVersion" : "2010-09-09",
@ -341,6 +328,8 @@ class NeutronNetTest(HeatTestCase):
'add_network_to_dhcp_agent')
self.m.StubOutWithMock(neutronclient.Client,
'remove_network_from_dhcp_agent')
self.m.StubOutWithMock(neutronclient.Client,
'list_dhcp_agent_hosting_networks')
self.m.StubOutWithMock(clients.OpenStackClients, 'keystone')
utils.setup_dummy_db()
@ -371,6 +360,15 @@ class NeutronNetTest(HeatTestCase):
"id": "fc68ea2c-b60b-4b4f-bd82-94ec81110766"
}})
neutronclient.Client.list_dhcp_agent_hosting_networks(
'fc68ea2c-b60b-4b4f-bd82-94ec81110766'
).AndReturn({"agents": []})
neutronclient.Client.add_network_to_dhcp_agent(
'28c25a04-3f73-45a7-a2b4-59e183943ddc',
{'network_id': u'fc68ea2c-b60b-4b4f-bd82-94ec81110766'}
).AndReturn(None)
neutronclient.Client.show_network(
'fc68ea2c-b60b-4b4f-bd82-94ec81110766'
).AndReturn({"network": {
@ -424,6 +422,41 @@ class NeutronNetTest(HeatTestCase):
}})
# Update script
neutronclient.Client.list_dhcp_agent_hosting_networks(
'fc68ea2c-b60b-4b4f-bd82-94ec81110766'
).AndReturn({
"agents": [{
"admin_state_up": True,
"agent_type": "DHCP agent",
"alive": True,
"binary": "neutron-dhcp-agent",
"configurations": {
"dhcp_driver": "DummyDriver",
"dhcp_lease_duration": 86400,
"networks": 0,
"ports": 0,
"subnets": 0,
"use_namespaces": True},
"created_at": "2014-03-20 05:12:34",
"description": None,
"heartbeat_timestamp": "2014-03-20 05:12:34",
"host": "hostname",
"id": "28c25a04-3f73-45a7-a2b4-59e183943ddc",
"started_at": "2014-03-20 05:12:34",
"topic": "dhcp_agent"
}]
})
neutronclient.Client.add_network_to_dhcp_agent(
'bb09cfcd-5277-473d-8336-d4ed8628ae68',
{'network_id': u'fc68ea2c-b60b-4b4f-bd82-94ec81110766'}
).AndReturn(None)
neutronclient.Client.remove_network_from_dhcp_agent(
'28c25a04-3f73-45a7-a2b4-59e183943ddc',
'fc68ea2c-b60b-4b4f-bd82-94ec81110766'
).AndReturn(None)
neutronclient.Client.update_network(
'fc68ea2c-b60b-4b4f-bd82-94ec81110766',
{'network': {
@ -472,134 +505,25 @@ class NeutronNetTest(HeatTestCase):
"Properties": {
"name": "mynet",
"shared": True,
"admin_state_up": True
"admin_state_up": True,
"dhcp_agent_ids": [
"bb09cfcd-5277-473d-8336-d4ed8628ae68"
]
}
}
rsrc.handle_update(update_snippet, {}, {})
prop_diff = {
"name": "mynet",
"dhcp_agent_ids": [
"bb09cfcd-5277-473d-8336-d4ed8628ae68"
]
}
rsrc.handle_update(update_snippet, {}, prop_diff)
scheduler.TaskRunner(rsrc.delete)()
rsrc.state_set(rsrc.CREATE, rsrc.COMPLETE, 'to delete again')
scheduler.TaskRunner(rsrc.delete)()
self.m.VerifyAll()
def test_net_dhcp_agent(self):
clients.OpenStackClients.keystone().AndReturn(
fakes.FakeKeystoneClient())
neutronclient.Client.add_network_to_dhcp_agent(
u'9f0df05b-4846-4d3d-971e-a2e1a06b1622',
{'network_id': u'66a426ef-8b77-4e25-8098-b3a7c0964b93'}
).AndReturn(None)
neutronclient.Client.remove_network_from_dhcp_agent(
u'9f0df05b-4846-4d3d-971e-a2e1a06b1622',
u'66a426ef-8b77-4e25-8098-b3a7c0964b93'
).AndReturn(None)
neutronclient.Client.remove_network_from_dhcp_agent(
u'9f0df05b-4846-4d3d-971e-a2e1a06b1622',
u'66a426ef-8b77-4e25-8098-b3a7c0964b93'
).AndRaise(qe.NeutronClientException(status_code=404))
self.m.ReplayAll()
t = template_format.parse(neutron_dhcp_agent_template)
stack = utils.parse_stack(t)
rsrc = net.NetDHCPAgent('test_net_dhcp_agent',
t['Resources']['network_dhcp_agent'], stack)
scheduler.TaskRunner(rsrc.create)()
self.assertEqual((rsrc.CREATE, rsrc.COMPLETE), rsrc.state)
self.assertIsNone(scheduler.TaskRunner(rsrc.delete)())
rsrc.state_set(rsrc.CREATE, rsrc.COMPLETE, 'to delete again')
self.assertIsNone(scheduler.TaskRunner(rsrc.delete)())
self.m.VerifyAll()
def test_net_dhcp_agent_create_happens_409(self):
clients.OpenStackClients.keystone().AndReturn(
fakes.FakeKeystoneClient())
neutronclient.Client.add_network_to_dhcp_agent(
u'9f0df05b-4846-4d3d-971e-a2e1a06b1622',
{'network_id': u'66a426ef-8b77-4e25-8098-b3a7c0964b93'}
).AndRaise(qe.NeutronClientException(status_code=409))
neutronclient.Client.remove_network_from_dhcp_agent(
u'9f0df05b-4846-4d3d-971e-a2e1a06b1622',
u'66a426ef-8b77-4e25-8098-b3a7c0964b93'
).AndReturn(None)
neutronclient.Client.remove_network_from_dhcp_agent(
u'9f0df05b-4846-4d3d-971e-a2e1a06b1622',
u'66a426ef-8b77-4e25-8098-b3a7c0964b93'
).AndRaise(qe.NeutronClientException(status_code=404))
self.m.ReplayAll()
t = template_format.parse(neutron_dhcp_agent_template)
stack = utils.parse_stack(t)
rsrc = net.NetDHCPAgent('test_net_dhcp_agent',
t['Resources']['network_dhcp_agent'], stack)
scheduler.TaskRunner(rsrc.create)()
self.assertEqual((rsrc.CREATE, rsrc.COMPLETE), rsrc.state)
self.assertIsNone(scheduler.TaskRunner(rsrc.delete)())
rsrc.state_set(rsrc.CREATE, rsrc.COMPLETE, 'to delete again')
self.assertIsNone(scheduler.TaskRunner(rsrc.delete)())
self.m.VerifyAll()
def test_net_dhcp_agent_create_failed(self):
clients.OpenStackClients.keystone().AndReturn(
fakes.FakeKeystoneClient())
neutronclient.Client.add_network_to_dhcp_agent(
u'9f0df05b-4846-4d3d-971e-a2e1a06b1622',
{'network_id': u'66a426ef-8b77-4e25-8098-b3a7c0964b93'}
).AndRaise(qe.NeutronClientException(status_code=500))
self.m.ReplayAll()
t = template_format.parse(neutron_dhcp_agent_template)
stack = utils.parse_stack(t)
rsrc = net.NetDHCPAgent('test_net_dhcp_agent',
t['Resources']['network_dhcp_agent'], stack)
error = self.assertRaises(exception.ResourceFailure,
scheduler.TaskRunner(rsrc.create))
self.assertEqual(
'NeutronClientException: An unknown exception occurred.',
str(error))
self.assertEqual((rsrc.CREATE, rsrc.FAILED), rsrc.state)
self.assertIsNone(scheduler.TaskRunner(rsrc.delete)())
self.m.VerifyAll()
def test_net_dhcp_agent_delete_failed(self):
clients.OpenStackClients.keystone().AndReturn(
fakes.FakeKeystoneClient())
neutronclient.Client.add_network_to_dhcp_agent(
u'9f0df05b-4846-4d3d-971e-a2e1a06b1622',
{'network_id': u'66a426ef-8b77-4e25-8098-b3a7c0964b93'}
).AndReturn(None)
neutronclient.Client.remove_network_from_dhcp_agent(
u'9f0df05b-4846-4d3d-971e-a2e1a06b1622',
u'66a426ef-8b77-4e25-8098-b3a7c0964b93'
).AndRaise(qe.NeutronClientException(status_code=500))
self.m.ReplayAll()
t = template_format.parse(neutron_dhcp_agent_template)
stack = utils.parse_stack(t)
rsrc = net.NetDHCPAgent('test_net_dhcp_agent',
t['Resources']['network_dhcp_agent'], stack)
scheduler.TaskRunner(rsrc.create)()
self.assertEqual((rsrc.CREATE, rsrc.COMPLETE), rsrc.state)
error = self.assertRaises(exception.ResourceFailure,
scheduler.TaskRunner(rsrc.delete))
self.assertEqual(
'NeutronClientException: An unknown exception occurred.',
str(error))
self.assertEqual((rsrc.DELETE, rsrc.FAILED), rsrc.state)
self.m.VerifyAll()
@skipIf(neutronclient is None, 'neutronclient unavailable')
class NeutronProviderNetTest(HeatTestCase):