summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJenkins <jenkins@review.openstack.org>2012-08-15 16:50:45 +0000
committerGerrit Code Review <review@openstack.org>2012-08-15 16:50:45 +0000
commit6f924bbeb0dd66f3c5ba2465099f23069d2cacf2 (patch)
tree0d103f3066904d97e9f6c307c10bfc2bfbcc38f9
parent35c12feb8c9467b9b4a7eac7a3f3d63bd620a35b (diff)
parent51ad3d4ee9f28184510a2802867535284c0f1b8b (diff)
Merge "Adding port attribute in network parameter of boot."
-rw-r--r--nova/api/openstack/compute/servers.py49
-rw-r--r--nova/exception.py12
-rw-r--r--nova/network/quantumv2/api.py67
-rw-r--r--nova/tests/network/test_quantumv2.py71
4 files changed, 161 insertions, 38 deletions
diff --git a/nova/api/openstack/compute/servers.py b/nova/api/openstack/compute/servers.py
index 99d48d8a6..0c5a2e530 100644
--- a/nova/api/openstack/compute/servers.py
+++ b/nova/api/openstack/compute/servers.py
@@ -197,6 +197,8 @@ class CommonDeserializer(wsgi.MetadataXMLDeserializer):
item["uuid"] = network_node.getAttribute("uuid")
if network_node.hasAttribute("fixed_ip"):
item["fixed_ip"] = network_node.getAttribute("fixed_ip")
+ if network_node.hasAttribute("port"):
+ item["port"] = network_node.getAttribute("port")
networks.append(item)
return networks
else:
@@ -498,14 +500,31 @@ class Controller(wsgi.Controller):
injected_files.append((path, contents))
return injected_files
+ def _is_quantum_v2(self):
+ return FLAGS.network_api_class ==\
+ "nova.network.quantumv2.api.API"
+
def _get_requested_networks(self, requested_networks):
"""Create a list of requested networks from the networks attribute."""
networks = []
for network in requested_networks:
try:
- network_uuid = network['uuid']
+ port_id = network.get('port', None)
+ if port_id:
+ network_uuid = None
+ if not self._is_quantum_v2():
+ # port parameter is only for qunatum v2.0
+ msg = _("Unknown argment : port")
+ raise exc.HTTPBadRequest(explanation=msg)
+ if not utils.is_uuid_like(port_id):
+ msg = _("Bad port format: port uuid is "
+ "not in proper format "
+ "(%s)") % port_id
+ raise exc.HTTPBadRequest(explanation=msg)
+ else:
+ network_uuid = network['uuid']
- if not utils.is_uuid_like(network_uuid):
+ if not port_id and not utils.is_uuid_like(network_uuid):
br_uuid = network_uuid.split('-', 1)[-1]
if not utils.is_uuid_like(br_uuid):
msg = _("Bad networks format: network uuid is "
@@ -520,16 +539,22 @@ class Controller(wsgi.Controller):
if address is not None and not utils.is_valid_ipv4(address):
msg = _("Invalid fixed IP address (%s)") % address
raise exc.HTTPBadRequest(explanation=msg)
- # check if the network id is already present in the list,
- # we don't want duplicate networks to be passed
- # at the boot time
- for id, ip in networks:
- if id == network_uuid:
- expl = (_("Duplicate networks (%s) are not allowed") %
- network_uuid)
- raise exc.HTTPBadRequest(explanation=expl)
-
- networks.append((network_uuid, address))
+
+ # For quantumv2, requestd_networks
+ # should be tuple of (network_uuid, fixed_ip, port_id)
+ if self._is_quantum_v2():
+ networks.append((network_uuid, address, port_id))
+ else:
+ # check if the network id is already present in the list,
+ # we don't want duplicate networks to be passed
+ # at the boot time
+ for id, ip in networks:
+ if id == network_uuid:
+ expl = (_("Duplicate networks"
+ " (%s) are not allowed") %
+ network_uuid)
+ raise exc.HTTPBadRequest(explanation=expl)
+ networks.append((network_uuid, address))
except KeyError as key:
expl = _('Bad network format: missing %s') % key
raise exc.HTTPBadRequest(explanation=expl)
diff --git a/nova/exception.py b/nova/exception.py
index 9beadd2df..86d3a59b2 100644
--- a/nova/exception.py
+++ b/nova/exception.py
@@ -588,10 +588,22 @@ class NetworkBusy(NovaException):
message = _("Network %(network)s has active ports, cannot delete.")
+class NetworkIsDuplicated(NovaException):
+ message = _("Network %(network)s is duplicated.")
+
+
class DatastoreNotFound(NotFound):
message = _("Could not find the datastore reference(s) which the VM uses.")
+class PortInUse(NovaException):
+ message = _("Port %(port_id)s is still in use.")
+
+
+class PortNotFound(NotFound):
+ message = _("Port %(port_id)s could not be found.")
+
+
class FixedIpNotFound(NotFound):
message = _("No fixed IP associated with id %(id)s.")
diff --git a/nova/network/quantumv2/api.py b/nova/network/quantumv2/api.py
index ca5b44e25..be288f46e 100644
--- a/nova/network/quantumv2/api.py
+++ b/nova/network/quantumv2/api.py
@@ -62,6 +62,7 @@ class API(base.Base):
def allocate_for_instance(self, context, instance, **kwargs):
"""Allocate all network resources for the instance."""
+ quantum = quantumv2.get_client(context)
LOG.debug(_('allocate_for_instance() for %s'),
instance['display_name'])
search_opts = {}
@@ -76,28 +77,55 @@ class API(base.Base):
# networks, add them to **search_opts
# Tenant-only network only allowed so far
requested_networks = kwargs.get('requested_networks')
+ ports = {}
+ fixed_ips = {}
if requested_networks:
- net_ids = [net_id for (net_id, _i) in requested_networks]
+ net_ids = []
+ for network_id, fixed_ip, port_id in requested_networks:
+ if port_id:
+ port = quantum.show_port(port_id).get('port')
+ network_id = port['network_id']
+ ports[network_id] = port
+ elif fixed_ip:
+ fixed_ips[network_id] = fixed_ip
+ net_ids.append(network_id)
search_opts['id'] = net_ids
- data = quantumv2.get_client(context).list_networks(**search_opts)
+ data = quantum.list_networks(**search_opts)
nets = data.get('networks', [])
+
+ touched_port_ids = []
created_port_ids = []
for network in nets:
- port_req_body = {'port': {'network_id': network['id'],
- 'admin_state_up': True,
- 'device_id': instance['uuid'],
- 'tenant_id': instance['project_id']},
- }
+ network_id = network['id']
+ zone = 'compute:%s' % FLAGS.node_availability_zone
+ port_req_body = {'port': {'device_id': instance['uuid'],
+ 'device_owner': zone}}
try:
- created_port_ids.append(
- quantumv2.get_client(context).create_port(
- port_req_body)['port']['id'])
+ port = ports.get(network_id)
+ if port:
+ quantum.update_port(port['id'], port_req_body)
+ touched_port_ids.append(port['id'])
+ else:
+ if fixed_ips.get(network_id):
+ port_req_body['port']['fixed_ip'] = fixed_ip
+ port_req_body['port']['network_id'] = network_id
+ port_req_body['port']['admin_state_up'] = True
+ port_req_body['port']['tenant_id'] = instance['project_id']
+ created_port_ids.append(
+ quantum.create_port(port_req_body)['port']['id'])
except Exception:
with excutils.save_and_reraise_exception():
+ for port_id in touched_port_ids:
+ port_in_server = quantum.show_port(port_id).get('port')
+ if not port_in_server:
+ raise Exception('Port have already lost')
+ port_req_body = {'port': {'device_id': None}}
+ quantum.update_port(port_id, port_req_body)
+
for port_id in created_port_ids:
try:
- quantumv2.get_client(context).delete_port(port_id)
+ quantum.delete_port(port_id)
except Exception as ex:
msg = _("Fail to delete port %(portid)s with"
" failure: %(exception)s")
@@ -147,7 +175,22 @@ class API(base.Base):
if not requested_networks:
return
search_opts = {"tenant_id": context.project_id}
- net_ids = [net_id for (net_id, _i) in requested_networks]
+ net_ids = []
+
+ for (net_id, _i, port_id) in requested_networks:
+ if not port_id:
+ net_ids.append(net_id)
+ continue
+ port = quantumv2.get_client(context).show_port(port_id).get('port')
+ if not port:
+ raise exception.PortNotFound(port_id=port_id)
+ if port.get('device_id', None):
+ raise exception.PortInUse(port_id=port_id)
+ net_id = port['network_id']
+ if net_id in net_ids:
+ raise exception.NetworkDuplicated(network_id=net_id)
+ net_ids.append(net_id)
+
search_opts['id'] = net_ids
data = quantumv2.get_client(context).list_networks(**search_opts)
nets = data.get('networks', [])
diff --git a/nova/tests/network/test_quantumv2.py b/nova/tests/network/test_quantumv2.py
index 1f4d72462..7ee814b6b 100644
--- a/nova/tests/network/test_quantumv2.py
+++ b/nova/tests/network/test_quantumv2.py
@@ -159,6 +159,7 @@ class TestQuantumv2(test.TestCase):
self.port_data1 = [{'network_id': 'my_netid1',
'device_id': 'device_id1',
+ 'device_owner': 'compute:nova',
'id': 'my_portid1',
'fixed_ips': [{'ip_address': '10.0.1.2',
'subnet_id': 'my_subid1'}],
@@ -167,6 +168,7 @@ class TestQuantumv2(test.TestCase):
self.port_data2.append(self.port_data1[0])
self.port_data2.append({'network_id': 'my_netid2',
'device_id': 'device_id2',
+ 'device_owner': 'compute:nova',
'id': 'my_portid2',
'fixed_ips': [{'ip_address': '10.0.2.2',
'subnet_id': 'my_subid2'}],
@@ -262,8 +264,22 @@ class TestQuantumv2(test.TestCase):
networks=nets).AndReturn(None)
mox_list_network_params = dict(tenant_id=self.instance['project_id'])
+ ports = {}
+ fixed_ips = {}
if 'requested_networks' in kwargs:
- req_net_ids = [id for (id, _i) in kwargs['requested_networks']]
+ req_net_ids = []
+ for id, fixed_ip, port_id in kwargs['requested_networks']:
+ if port_id:
+ self.moxed_client.show_port(port_id).AndReturn(
+ {'port': {'id': 'my_portid1',
+ 'network_id': 'my_netid1'}})
+ req_net_ids.append('my_netid1')
+ ports['my_netid1'] = self.port_data1[0]
+ id = 'my_netid1'
+ else:
+ fixed_ips[id] = fixed_ip
+ req_net_ids.append(id)
+
mox_list_network_params['id'] = [net['id'] for net in nets
if net['id'] in req_net_ids]
self.moxed_client.list_networks(
@@ -272,15 +288,28 @@ class TestQuantumv2(test.TestCase):
for network in nets:
port_req_body = {
'port': {
- 'network_id': network['id'],
- 'admin_state_up': True,
'device_id': self.instance['uuid'],
- 'tenant_id': self.instance['project_id'],
+ 'device_owner': 'compute:nova',
},
}
- port = {'id': 'portid_' + network['id']}
- self.moxed_client.create_port(
- MyComparator(port_req_body)).AndReturn({'port': port})
+ port = ports.get(network['id'], None)
+ if port:
+ port_id = port['id']
+ self.moxed_client.update_port(port_id,
+ MyComparator(port_req_body)
+ ).AndReturn(
+ {'port': port})
+ else:
+ fixed_ip = fixed_ips.get(network['id'])
+ if fixed_ip:
+ port_req_body['port']['fixed_ip'] = fixed_ip
+ port_req_body['port']['network_id'] = network['id']
+ port_req_body['port']['admin_state_up'] = True
+ port_req_body['port']['tenant_id'] = \
+ self.instance['project_id']
+ res_port = {'port': {'id': 'fake'}}
+ self.moxed_client.create_port(
+ MyComparator(port_req_body)).AndReturn(res_port)
self.mox.ReplayAll()
api.allocate_for_instance(self.context, self.instance, **kwargs)
@@ -294,12 +323,23 @@ class TestQuantumv2(test.TestCase):
def test_allocate_for_instance_with_requested_networks(self):
# specify only first and last network
- requested_networks = [(net['id'], object())
+ requested_networks = [(net['id'], None, None)
for net in (self.nets3[0], self.nets3[-1])]
-
self._allocate_for_instance(net_idx=3,
requested_networks=requested_networks)
+ def test_allocate_for_instance_with_requested_networks_with_fixedip(self):
+ # specify only first and last network
+ requested_networks = [(self.nets1[0]['id'], '10.0.1.0/24', None)]
+ self._allocate_for_instance(net_idx=1,
+ requested_networks=requested_networks)
+
+ def test_allocate_for_instance_with_requested_networks_with_port(self):
+ # specify only first and last network
+ requested_networks = [(None, None, 'myportid1')]
+ self._allocate_for_instance(net_idx=1,
+ requested_networks=requested_networks)
+
def test_allocate_for_instance_ex1(self):
"""verify we will delete created ports
if we fail to allocate all net resources.
@@ -318,6 +358,7 @@ class TestQuantumv2(test.TestCase):
'network_id': network['id'],
'admin_state_up': True,
'device_id': self.instance['uuid'],
+ 'device_owner': 'compute:nova',
'tenant_id': self.instance['project_id'],
},
}
@@ -381,7 +422,8 @@ class TestQuantumv2(test.TestCase):
self._deallocate_for_instance(2)
def test_validate_networks(self):
- requested_networks = [('my_netid1', 'test'), ('my_netid2', 'test2')]
+ requested_networks = [('my_netid1', 'test', None),
+ ('my_netid2', 'test2', None)]
self.moxed_client.list_networks(
id=mox.SameElementsAs(['my_netid1', 'my_netid2']),
tenant_id=self.context.project_id).AndReturn(
@@ -391,7 +433,8 @@ class TestQuantumv2(test.TestCase):
api.validate_networks(self.context, requested_networks)
def test_validate_networks_ex_1(self):
- requested_networks = [('my_netid1', 'test'), ('my_netid2', 'test2')]
+ requested_networks = [('my_netid1', 'test', None),
+ ('my_netid2', 'test2', None)]
self.moxed_client.list_networks(
id=mox.SameElementsAs(['my_netid1', 'my_netid2']),
tenant_id=self.context.project_id).AndReturn(
@@ -404,9 +447,9 @@ class TestQuantumv2(test.TestCase):
self.assertTrue("my_netid2" in str(ex))
def test_validate_networks_ex_2(self):
- requested_networks = [('my_netid1', 'test'),
- ('my_netid2', 'test2'),
- ('my_netid3', 'test3')]
+ requested_networks = [('my_netid1', 'test', None),
+ ('my_netid2', 'test2', None),
+ ('my_netid3', 'test3', None)]
self.moxed_client.list_networks(
id=mox.SameElementsAs(['my_netid1', 'my_netid2', 'my_netid3']),
tenant_id=self.context.project_id).AndReturn(