Merge "Reimplement DHCPAgent as net's property"
This commit is contained in:
commit
0d19394458
|
@ -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,
|
||||
}
|
||||
|
|
|
@ -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):
|
||||
|
|
Loading…
Reference in New Issue