diff options
| author | Tushar Patil <tushar.vitthal.patil@gmail.com> | 2011-08-23 02:05:35 +0000 |
|---|---|---|
| committer | Tarmac <> | 2011-08-23 02:05:35 +0000 |
| commit | c2fb9485f956482a5e6d628bb80e86d3e8d90d3a (patch) | |
| tree | 28a12d89b20beee54fb6378da562306d7441563f /nova/api | |
| parent | 4e987a070ad3d50d2b47a894029f981168bacd1f (diff) | |
| parent | 4ded14d0d8fb4ec1bbc14255e90cbaae0626997f (diff) | |
Our goal is to add optional parameter to the Create server OS 1.0 and 1.1 API to achieve following objectives:-
1) Specify number and order of networks to the create server API.
In the current implementation every instance you launch for a project having 3 networks assigned to it will always have 3 vnics. In this case it is not possible to have one instance with 2 vnics ,another with 1 vnic and so on. This is not flexible enough and the network resources are not used effectively.
2) Specify fixed IP address to the vnic at the boot time. When you launch a server, you can specify the fixed IP address you want to be assigned to the vnic from a particular network. If this fixed IP address is already in use, it will give exception.
Example of Server Create API request XML:
<?xml version="1.0" encoding="UTF-8"?>
<server xmlns="http://docs.nttpflab.com/servers/api/v1.0"
name="new-server-test" imageId="1" flavorId="1">
<metadata>
<meta key="My Server Name">Apache1</meta>
</metadata>
<personality>
<file path="/etc/banner.txt">
ICAgICAgDQoiQSBjbG91ZCBkb2VzIG5vdCBrbm93IHdoeSBp
</file>
</personality>
<networks>
<network uuid="6622436e-5289-460f-8479-e4dcc63f16c5" fixed_ip="10.0.0.3">
<network uuid="d97efefc-e071-4174-b6dd-b33af0a37706" fixed_ip="10.0.1.3">
</networks>
</server>
3) Networks is an optional parameter, so if you don't provide any networks to the server Create API, it will behave exactly the same as of today.
This feature is supported to all of the network models.
Diffstat (limited to 'nova/api')
| -rw-r--r-- | nova/api/openstack/contrib/createserverext.py | 66 | ||||
| -rw-r--r-- | nova/api/openstack/create_instance_helper.py | 73 |
2 files changed, 138 insertions, 1 deletions
diff --git a/nova/api/openstack/contrib/createserverext.py b/nova/api/openstack/contrib/createserverext.py new file mode 100644 index 000000000..ba72fdb0b --- /dev/null +++ b/nova/api/openstack/contrib/createserverext.py @@ -0,0 +1,66 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright 2011 OpenStack LLC. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License + +from nova.api.openstack import create_instance_helper as helper +from nova.api.openstack import extensions +from nova.api.openstack import servers +from nova.api.openstack import wsgi + + +class Createserverext(extensions.ExtensionDescriptor): + """The servers create ext + + Exposes addFixedIp and removeFixedIp actions on servers. + + """ + def get_name(self): + return "Createserverext" + + def get_alias(self): + return "os-create-server-ext" + + def get_description(self): + return "Extended support to the Create Server v1.1 API" + + def get_namespace(self): + return "http://docs.openstack.org/ext/createserverext/api/v1.1" + + def get_updated(self): + return "2011-07-19T00:00:00+00:00" + + def get_resources(self): + resources = [] + + headers_serializer = servers.HeadersSerializer() + body_serializers = { + 'application/xml': servers.ServerXMLSerializer(), + } + + body_deserializers = { + 'application/xml': helper.ServerXMLDeserializerV11(), + } + + serializer = wsgi.ResponseSerializer(body_serializers, + headers_serializer) + deserializer = wsgi.RequestDeserializer(body_deserializers) + + res = extensions.ResourceExtension('os-create-server-ext', + controller=servers.ControllerV11(), + deserializer=deserializer, + serializer=serializer) + resources.append(res) + + return resources diff --git a/nova/api/openstack/create_instance_helper.py b/nova/api/openstack/create_instance_helper.py index 339f260b9..4b4a1b0c3 100644 --- a/nova/api/openstack/create_instance_helper.py +++ b/nova/api/openstack/create_instance_helper.py @@ -29,7 +29,7 @@ from nova import utils from nova.compute import instance_types from nova.api.openstack import common from nova.api.openstack import wsgi - +from nova.rpc.common import RemoteError LOG = logging.getLogger('nova.api.openstack.create_instance_helper') FLAGS = flags.FLAGS @@ -120,6 +120,11 @@ class CreateInstanceHelper(object): sg_names = list(set(sg_names)) + requested_networks = server_dict.get('networks') + if requested_networks is not None: + requested_networks = self._get_requested_networks( + requested_networks) + try: flavor_id = self.controller._flavor_id_from_req_data(body) except ValueError as error: @@ -175,6 +180,7 @@ class CreateInstanceHelper(object): reservation_id=reservation_id, min_count=min_count, max_count=max_count, + requested_networks=requested_networks, security_group=sg_names, user_data=user_data, availability_zone=availability_zone)) @@ -188,6 +194,10 @@ class CreateInstanceHelper(object): raise exc.HTTPBadRequest(explanation=msg) except exception.SecurityGroupNotFound as error: raise exc.HTTPBadRequest(explanation=unicode(error)) + except RemoteError as err: + msg = "%(err_type)s: %(err_msg)s" % \ + {'err_type': err.exc_type, 'err_msg': err.value} + raise exc.HTTPBadRequest(explanation=msg) # Let the caller deal with unhandled exceptions. def _handle_quota_error(self, error): @@ -316,6 +326,46 @@ class CreateInstanceHelper(object): raise exc.HTTPBadRequest(explanation=msg) return password + 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'] + + if not utils.is_uuid_like(network_uuid): + msg = _("Bad networks format: network uuid is not in" + " proper format (%s)") % network_uuid + raise exc.HTTPBadRequest(explanation=msg) + + #fixed IP address is optional + #if the fixed IP address is not provided then + #it will use one of the available IP address from the network + address = network.get('fixed_ip', None) + 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)) + except KeyError as key: + expl = _('Bad network format: missing %s') % key + raise exc.HTTPBadRequest(explanation=expl) + except TypeError: + expl = _('Bad networks format') + raise exc.HTTPBadRequest(explanation=expl) + + return networks + class ServerXMLDeserializer(wsgi.XMLDeserializer): """ @@ -480,6 +530,10 @@ class ServerXMLDeserializerV11(wsgi.MetadataXMLDeserializer): if personality is not None: server["personality"] = personality + networks = self._extract_networks(server_node) + if networks is not None: + server["networks"] = networks + security_groups = self._extract_security_groups(server_node) if security_groups is not None: server["security_groups"] = security_groups @@ -501,6 +555,23 @@ class ServerXMLDeserializerV11(wsgi.MetadataXMLDeserializer): else: return None + def _extract_networks(self, server_node): + """Marshal the networks attribute of a parsed request""" + node = self.find_first_child_named(server_node, "networks") + if node is not None: + networks = [] + for network_node in self.find_children_named(node, + "network"): + item = {} + if network_node.hasAttribute("uuid"): + item["uuid"] = network_node.getAttribute("uuid") + if network_node.hasAttribute("fixed_ip"): + item["fixed_ip"] = network_node.getAttribute("fixed_ip") + networks.append(item) + return networks + else: + return None + def _extract_security_groups(self, server_node): """Marshal the security_groups attribute of a parsed request""" node = self.find_first_child_named(server_node, "security_groups") |
