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):
|
class Net(neutron.NeutronResource):
|
||||||
PROPERTIES = (
|
PROPERTIES = (
|
||||||
NAME, VALUE_SPECS, ADMIN_STATE_UP, TENANT_ID, SHARED,
|
NAME, VALUE_SPECS, ADMIN_STATE_UP, TENANT_ID, SHARED,
|
||||||
|
DHCP_AGENT_IDS,
|
||||||
) = (
|
) = (
|
||||||
'name', 'value_specs', 'admin_state_up', 'tenant_id', 'shared',
|
'name', 'value_specs', 'admin_state_up', 'tenant_id', 'shared',
|
||||||
|
'dhcp_agent_ids',
|
||||||
)
|
)
|
||||||
|
|
||||||
properties_schema = {
|
properties_schema = {
|
||||||
|
@ -67,6 +69,13 @@ class Net(neutron.NeutronResource):
|
||||||
default=False,
|
default=False,
|
||||||
update_allowed=True
|
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 = {
|
attributes_schema = {
|
||||||
|
@ -84,9 +93,15 @@ class Net(neutron.NeutronResource):
|
||||||
props = self.prepare_properties(
|
props = self.prepare_properties(
|
||||||
self.properties,
|
self.properties,
|
||||||
self.physical_resource_name())
|
self.physical_resource_name())
|
||||||
|
|
||||||
|
dhcp_agent_ids = props.pop(self.DHCP_AGENT_IDS, None)
|
||||||
|
|
||||||
net = self.neutron().create_network({'network': props})['network']
|
net = self.neutron().create_network({'network': props})['network']
|
||||||
self.resource_id_set(net['id'])
|
self.resource_id_set(net['id'])
|
||||||
|
|
||||||
|
if dhcp_agent_ids:
|
||||||
|
self._replace_dhcp_agents(dhcp_agent_ids)
|
||||||
|
|
||||||
def _show_resource(self):
|
def _show_resource(self):
|
||||||
return self.neutron().show_network(
|
return self.neutron().show_network(
|
||||||
self.resource_id)['network']
|
self.resource_id)['network']
|
||||||
|
@ -107,7 +122,16 @@ class Net(neutron.NeutronResource):
|
||||||
def handle_update(self, json_snippet, tmpl_diff, prop_diff):
|
def handle_update(self, json_snippet, tmpl_diff, prop_diff):
|
||||||
props = self.prepare_update_properties(json_snippet)
|
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):
|
def check_update_complete(self, *args):
|
||||||
attributes = self._show_resource()
|
attributes = self._show_resource()
|
||||||
|
@ -119,53 +143,25 @@ class Net(neutron.NeutronResource):
|
||||||
isinstance(ex, neutron_exp.NetworkNotFoundClient)):
|
isinstance(ex, neutron_exp.NetworkNotFoundClient)):
|
||||||
raise ex
|
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):
|
for dhcp_agent_id in new - old:
|
||||||
PROPERTIES = (
|
|
||||||
NETWORK_ID, DHCP_AGENT_ID,
|
|
||||||
) = (
|
|
||||||
'network_id', 'dhcp_agent_id',
|
|
||||||
)
|
|
||||||
|
|
||||||
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:
|
try:
|
||||||
self.neutron().add_network_to_dhcp_agent(
|
self.neutron().add_network_to_dhcp_agent(
|
||||||
dhcp_agent_id, {'network_id': network_id})
|
dhcp_agent_id, {'network_id': self.resource_id})
|
||||||
except neutron_exp.NeutronClientException as ex:
|
except neutron_exp.NeutronClientException as ex:
|
||||||
# if 409 is happened, the agent is already associated.
|
# if 409 is happened, the agent is already associated.
|
||||||
if ex.status_code != 409:
|
if ex.status_code != 409:
|
||||||
raise ex
|
raise ex
|
||||||
self.resource_id_set('%(net)s:%(agt)s' %
|
|
||||||
{'net': network_id, 'agt': dhcp_agent_id})
|
|
||||||
|
|
||||||
def handle_delete(self):
|
for dhcp_agent_id in old - new:
|
||||||
if not self.resource_id:
|
|
||||||
return
|
|
||||||
client = self.neutron()
|
|
||||||
network_id, dhcp_agent_id = self.resource_id.split(':')
|
|
||||||
try:
|
try:
|
||||||
client.remove_network_from_dhcp_agent(
|
self.neutron().remove_network_from_dhcp_agent(
|
||||||
dhcp_agent_id, network_id)
|
dhcp_agent_id, self.resource_id)
|
||||||
except neutron_exp.NeutronClientException as ex:
|
except neutron_exp.NeutronClientException as ex:
|
||||||
# assume 2 patterns about status_code following:
|
# assume 2 patterns about status_code following:
|
||||||
# 404: the network or agent is already gone
|
# 404: the network or agent is already gone
|
||||||
|
@ -199,5 +195,4 @@ def resource_mapping():
|
||||||
|
|
||||||
return {
|
return {
|
||||||
'OS::Neutron::Net': Net,
|
'OS::Neutron::Net': Net,
|
||||||
'OS::Neutron::NetDHCPAgent': NetDHCPAgent,
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,7 +46,10 @@ neutron_template = '''
|
||||||
"Properties": {
|
"Properties": {
|
||||||
"name": "the_network",
|
"name": "the_network",
|
||||||
"tenant_id": "c1210485b2424d48804aad5d39c61b8f",
|
"tenant_id": "c1210485b2424d48804aad5d39c61b8f",
|
||||||
"shared": true
|
"shared": true,
|
||||||
|
"dhcp_agent_ids": [
|
||||||
|
"28c25a04-3f73-45a7-a2b4-59e183943ddc"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"unnamed_network": {
|
"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 = '''
|
neutron_external_gateway_template = '''
|
||||||
{
|
{
|
||||||
"AWSTemplateFormatVersion" : "2010-09-09",
|
"AWSTemplateFormatVersion" : "2010-09-09",
|
||||||
|
@ -341,6 +328,8 @@ class NeutronNetTest(HeatTestCase):
|
||||||
'add_network_to_dhcp_agent')
|
'add_network_to_dhcp_agent')
|
||||||
self.m.StubOutWithMock(neutronclient.Client,
|
self.m.StubOutWithMock(neutronclient.Client,
|
||||||
'remove_network_from_dhcp_agent')
|
'remove_network_from_dhcp_agent')
|
||||||
|
self.m.StubOutWithMock(neutronclient.Client,
|
||||||
|
'list_dhcp_agent_hosting_networks')
|
||||||
self.m.StubOutWithMock(clients.OpenStackClients, 'keystone')
|
self.m.StubOutWithMock(clients.OpenStackClients, 'keystone')
|
||||||
utils.setup_dummy_db()
|
utils.setup_dummy_db()
|
||||||
|
|
||||||
|
@ -371,6 +360,15 @@ class NeutronNetTest(HeatTestCase):
|
||||||
"id": "fc68ea2c-b60b-4b4f-bd82-94ec81110766"
|
"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(
|
neutronclient.Client.show_network(
|
||||||
'fc68ea2c-b60b-4b4f-bd82-94ec81110766'
|
'fc68ea2c-b60b-4b4f-bd82-94ec81110766'
|
||||||
).AndReturn({"network": {
|
).AndReturn({"network": {
|
||||||
|
@ -424,6 +422,41 @@ class NeutronNetTest(HeatTestCase):
|
||||||
}})
|
}})
|
||||||
|
|
||||||
# Update script
|
# 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(
|
neutronclient.Client.update_network(
|
||||||
'fc68ea2c-b60b-4b4f-bd82-94ec81110766',
|
'fc68ea2c-b60b-4b4f-bd82-94ec81110766',
|
||||||
{'network': {
|
{'network': {
|
||||||
|
@ -472,134 +505,25 @@ class NeutronNetTest(HeatTestCase):
|
||||||
"Properties": {
|
"Properties": {
|
||||||
"name": "mynet",
|
"name": "mynet",
|
||||||
"shared": True,
|
"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)()
|
scheduler.TaskRunner(rsrc.delete)()
|
||||||
rsrc.state_set(rsrc.CREATE, rsrc.COMPLETE, 'to delete again')
|
rsrc.state_set(rsrc.CREATE, rsrc.COMPLETE, 'to delete again')
|
||||||
scheduler.TaskRunner(rsrc.delete)()
|
scheduler.TaskRunner(rsrc.delete)()
|
||||||
self.m.VerifyAll()
|
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')
|
@skipIf(neutronclient is None, 'neutronclient unavailable')
|
||||||
class NeutronProviderNetTest(HeatTestCase):
|
class NeutronProviderNetTest(HeatTestCase):
|
||||||
|
|
Loading…
Reference in New Issue