summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--doc/api_samples/all_extensions/extensions-get-resp.json12
-rw-r--r--doc/api_samples/all_extensions/extensions-get-resp.xml4
-rw-r--r--doc/api_samples/os-tenant-networks/networks-list-res.json (renamed from doc/api_samples/os-networks/networks-list-res.json)0
-rw-r--r--doc/api_samples/os-tenant-networks/networks-post-res.json (renamed from doc/api_samples/os-networks/networks-post-res.json)0
-rw-r--r--nova/api/openstack/compute/contrib/admin_networks.py170
-rw-r--r--nova/api/openstack/compute/contrib/hosts.py78
-rw-r--r--nova/api/openstack/compute/contrib/networks_associate.py2
-rw-r--r--nova/api/openstack/compute/contrib/os_networks.py261
-rw-r--r--nova/api/openstack/compute/contrib/os_tenant_networks.py214
-rw-r--r--nova/api/openstack/compute/contrib/services.py2
-rw-r--r--nova/api/openstack/compute/servers.py24
-rw-r--r--nova/compute/api.py177
-rw-r--r--nova/compute/cells_api.py46
-rw-r--r--nova/compute/manager.py23
-rw-r--r--nova/compute/rpcapi.py8
-rw-r--r--nova/db/sqlalchemy/api.py9
-rw-r--r--nova/tests/api/openstack/compute/contrib/test_hosts.py10
-rw-r--r--nova/tests/api/openstack/compute/contrib/test_networks.py4
-rw-r--r--nova/tests/api/openstack/compute/contrib/test_services.py18
-rw-r--r--nova/tests/api/openstack/compute/test_extensions.py1
-rw-r--r--nova/tests/compute/test_compute.py103
-rw-r--r--nova/tests/compute/test_host_api.py175
-rw-r--r--nova/tests/compute/test_rpcapi.py3
-rw-r--r--nova/tests/fake_policy.py6
-rw-r--r--nova/tests/integrated/api_samples/all_extensions/extensions-get-resp.json.tpl12
-rw-r--r--nova/tests/integrated/api_samples/all_extensions/extensions-get-resp.xml.tpl4
-rw-r--r--nova/tests/integrated/api_samples/os-tenant-networks/networks-list-res.json.tpl (renamed from nova/tests/integrated/api_samples/os-networks/networks-list-res.json.tpl)0
-rw-r--r--nova/tests/integrated/api_samples/os-tenant-networks/networks-post-req.json.tpl (renamed from nova/tests/integrated/api_samples/os-networks/networks-post-req.json.tpl)0
-rw-r--r--nova/tests/integrated/api_samples/os-tenant-networks/networks-post-res.json.tpl (renamed from nova/tests/integrated/api_samples/os-networks/networks-post-res.json.tpl)0
-rw-r--r--nova/tests/integrated/test_api_samples.py27
-rw-r--r--nova/tests/test_metadata.py10
31 files changed, 695 insertions, 708 deletions
diff --git a/doc/api_samples/all_extensions/extensions-get-resp.json b/doc/api_samples/all_extensions/extensions-get-resp.json
index 42e86eadd..25d077f27 100644
--- a/doc/api_samples/all_extensions/extensions-get-resp.json
+++ b/doc/api_samples/all_extensions/extensions-get-resp.json
@@ -297,19 +297,19 @@
"updated": "2012-08-07T00:00:00+00:00"
},
{
- "alias": "os-admin-networks",
+ "alias": "os-networks",
"description": "Admin-only Network Management Extension.",
"links": [],
- "name": "AdminNetworks",
- "namespace": "http://docs.openstack.org/compute/ext/os-admin-networks/api/v1.1",
+ "name": "Networks",
+ "namespace": "http://docs.openstack.org/compute/ext/os-networks/api/v1.1",
"updated": "2011-12-23T00:00:00+00:00"
},
{
- "alias": "os-networks",
+ "alias": "os-tenant-networks",
"description": "Tenant-based Network Management Extension.",
"links": [],
- "name": "OSNetworks",
- "namespace": "http://docs.openstack.org/compute/ext/os-networks/api/v1.1",
+ "name": "OSTenantNetworks",
+ "namespace": "http://docs.openstack.org/compute/ext/os-tenant-networks/api/v2",
"updated": "2011-12-23T00:00:00+00:00"
},
{
diff --git a/doc/api_samples/all_extensions/extensions-get-resp.xml b/doc/api_samples/all_extensions/extensions-get-resp.xml
index ea0b45a12..b66c3dbe7 100644
--- a/doc/api_samples/all_extensions/extensions-get-resp.xml
+++ b/doc/api_samples/all_extensions/extensions-get-resp.xml
@@ -125,13 +125,13 @@
<extension alias="os-multiple-create" updated="2012-08-07T00:00:00+00:00" namespace="http://docs.openstack.org/compute/ext/multiplecreate/api/v1.1" name="MultipleCreate">
<description>Allow multiple create in the Create Server v1.1 API.</description>
</extension>
- <extension alias="os-admin-networks" updated="2011-12-23T00:00:00+00:00" namespace="http://docs.openstack.org/compute/ext/os-admin-networks/api/v1.1" name="AdminNetworks">
+ <extension alias="os-networks" updated="2011-12-23T00:00:00+00:00" namespace="http://docs.openstack.org/compute/ext/os-networks/api/v1.1" name="Networks">
<description>Admin-only Network Management Extension.</description>
</extension>
<extension alias="os-networks-associate" updated="2012-11-19T00:00:00+00:00" namespace="http://docs.openstack.org/compute/ext/networks_associate/api/v2" name="NetworkAssociationSupport">
<description>Network association support.</description>
</extension>
- <extension alias="os-networks" updated="2011-12-23T00:00:00+00:00" namespace="http://docs.openstack.org/compute/ext/os-networks/api/v1.1" name="OSNetworks">
+ <extension alias="os-tenant-networks" updated="2011-12-23T00:00:00+00:00" namespace="http://docs.openstack.org/compute/ext/os-tenant-networks/api/v2" name="OSTenantNetworks">
<description>Tenant-based Network Management Extension.</description>
</extension>
<extension alias="os-quota-class-sets" updated="2012-03-12T00:00:00+00:00" namespace="http://docs.openstack.org/compute/ext/quota-classes-sets/api/v1.1" name="QuotaClasses">
diff --git a/doc/api_samples/os-networks/networks-list-res.json b/doc/api_samples/os-tenant-networks/networks-list-res.json
index b857e8112..b857e8112 100644
--- a/doc/api_samples/os-networks/networks-list-res.json
+++ b/doc/api_samples/os-tenant-networks/networks-list-res.json
diff --git a/doc/api_samples/os-networks/networks-post-res.json b/doc/api_samples/os-tenant-networks/networks-post-res.json
index 536a9a0a4..536a9a0a4 100644
--- a/doc/api_samples/os-networks/networks-post-res.json
+++ b/doc/api_samples/os-tenant-networks/networks-post-res.json
diff --git a/nova/api/openstack/compute/contrib/admin_networks.py b/nova/api/openstack/compute/contrib/admin_networks.py
deleted file mode 100644
index f5facd601..000000000
--- a/nova/api/openstack/compute/contrib/admin_networks.py
+++ /dev/null
@@ -1,170 +0,0 @@
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-
-# Copyright 2011 Grid Dynamics
-# Copyright 2011 OpenStack LLC.
-# All Rights Reserved.
-#
-# 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.
-
-import netaddr
-import webob
-from webob import exc
-
-from nova.api.openstack import extensions
-from nova.api.openstack import wsgi
-from nova import exception
-from nova import network
-from nova.openstack.common import log as logging
-
-LOG = logging.getLogger(__name__)
-authorize = extensions.extension_authorizer('compute', 'admin_networks')
-authorize_view = extensions.extension_authorizer('compute',
- 'admin_networks:view')
-
-
-def network_dict(context, network):
- fields = ('id', 'cidr', 'netmask', 'gateway', 'broadcast', 'dns1', 'dns2',
- 'cidr_v6', 'gateway_v6', 'label', 'netmask_v6')
- admin_fields = ('created_at', 'updated_at', 'deleted_at', 'deleted',
- 'injected', 'bridge', 'vlan', 'vpn_public_address',
- 'vpn_public_port', 'vpn_private_address', 'dhcp_start',
- 'project_id', 'host', 'bridge_interface', 'multi_host',
- 'priority', 'rxtx_base')
- if network:
- # NOTE(mnaser): We display a limited set of fields so users can know
- # what networks are available, extra system-only fields
- # are only visible if they are an admin.
- if context.is_admin:
- fields += admin_fields
- result = dict((field, network[field]) for field in fields)
- if 'uuid' in network:
- result['id'] = network['uuid']
- return result
- else:
- return {}
-
-
-class AdminNetworkController(wsgi.Controller):
-
- def __init__(self, network_api=None):
- self.network_api = network_api or network.API()
-
- def index(self, req):
- context = req.environ['nova.context']
- authorize_view(context)
- networks = self.network_api.get_all(context)
- result = [network_dict(context, net_ref) for net_ref in networks]
- return {'networks': result}
-
- @wsgi.action("disassociate")
- def _disassociate_host_and_project(self, req, id, body):
- context = req.environ['nova.context']
- authorize(context)
- LOG.debug(_("Disassociating network with id %s"), id)
-
- try:
- self.network_api.associate(context, id, host=None, project=None)
- except exception.NetworkNotFound:
- raise exc.HTTPNotFound(_("Network not found"))
- return exc.HTTPAccepted()
-
- def show(self, req, id):
- context = req.environ['nova.context']
- authorize_view(context)
- LOG.debug(_("Showing network with id %s") % id)
- try:
- network = self.network_api.get(context, id)
- except exception.NetworkNotFound:
- raise exc.HTTPNotFound(_("Network not found"))
- return {'network': network_dict(context, network)}
-
- def delete(self, req, id):
- context = req.environ['nova.context']
- authorize(context)
- LOG.info(_("Deleting network with id %s") % id)
- try:
- self.network_api.delete(context, id)
- except exception.NetworkNotFound:
- raise exc.HTTPNotFound(_("Network not found"))
- return exc.HTTPAccepted()
-
- def create(self, req, body):
- context = req.environ['nova.context']
- authorize(context)
-
- def bad(e):
- return exc.HTTPUnprocessableEntity(explanation=e)
-
- if not (body and body.get("network")):
- raise bad(_("Missing network in body"))
-
- params = body["network"]
- if not params.get("label"):
- raise bad(_("Network label is required"))
-
- cidr = params.get("cidr") or params.get("cidr_v6")
- if not cidr:
- raise bad(_("Network cidr or cidr_v6 is required"))
-
- LOG.debug(_("Creating network with label %s") % params["label"])
-
- params["num_networks"] = 1
- params["network_size"] = netaddr.IPNetwork(cidr).size
-
- network = self.network_api.create(context, **params)[0]
- return {"network": network_dict(context, network)}
-
- def add(self, req, body):
- context = req.environ['nova.context']
- authorize(context)
- if not body:
- raise exc.HTTPUnprocessableEntity()
-
- network_id = body.get('id', None)
- project_id = context.project_id
- LOG.debug(_("Associating network %(network)s"
- " with project %(project)s") %
- {"network": network_id or "",
- "project": project_id})
- try:
- self.network_api.add_network_to_project(
- context, project_id, network_id)
- except Exception as ex:
- msg = (_("Cannot associate network %(network)s"
- " with project %(project)s: %(message)s") %
- {"network": network_id or "",
- "project": project_id,
- "message": getattr(ex, "value", str(ex))})
- raise exc.HTTPBadRequest(explanation=msg)
-
- return webob.Response(status_int=202)
-
-
-class Admin_networks(extensions.ExtensionDescriptor):
- """Admin-only Network Management Extension."""
-
- name = "AdminNetworks"
- alias = "os-admin-networks"
- namespace = ("http://docs.openstack.org/compute/"
- "ext/os-admin-networks/api/v1.1")
- updated = "2011-12-23T00:00:00+00:00"
-
- def get_resources(self):
- member_actions = {'action': 'POST'}
- collection_actions = {'add': 'POST'}
- res = extensions.ResourceExtension(
- 'os-admin-networks',
- AdminNetworkController(),
- member_actions=member_actions,
- collection_actions=collection_actions)
- return [res]
diff --git a/nova/api/openstack/compute/contrib/hosts.py b/nova/api/openstack/compute/contrib/hosts.py
index 52487c305..d1b39d6db 100644
--- a/nova/api/openstack/compute/contrib/hosts.py
+++ b/nova/api/openstack/compute/contrib/hosts.py
@@ -124,10 +124,17 @@ class HostController(object):
"""
context = req.environ['nova.context']
authorize(context)
+ filters = {}
zone = req.GET.get('zone', None)
- data = self.api.list_hosts(context, zone)
-
- return {'hosts': data}
+ if zone:
+ filters['availability_zone'] = zone
+ services = self.api.service_get_all(context, filters=filters)
+ hosts = []
+ for service in services:
+ hosts.append({'host_name': service['host'],
+ 'service': service['topic'],
+ 'zone': service['availability_zone']})
+ return {'hosts': hosts}
@wsgi.serializers(xml=HostUpdateTemplate)
@wsgi.deserializers(xml=HostUpdateDeserializer)
@@ -243,6 +250,55 @@ class HostController(object):
def reboot(self, req, id):
return self._host_power_action(req, host_name=id, action="reboot")
+ @staticmethod
+ def _get_total_resources(host_name, compute_node):
+ return {'resource': {'host': host_name,
+ 'project': '(total)',
+ 'cpu': compute_node['vcpus'],
+ 'memory_mb': compute_node['memory_mb'],
+ 'disk_gb': compute_node['local_gb']}}
+
+ @staticmethod
+ def _get_used_now_resources(host_name, compute_node):
+ return {'resource': {'host': host_name,
+ 'project': '(used_now)',
+ 'cpu': compute_node['vcpus_used'],
+ 'memory_mb': compute_node['memory_mb_used'],
+ 'disk_gb': compute_node['local_gb_used']}}
+
+ @staticmethod
+ def _get_resource_totals_from_instances(host_name, instances):
+ cpu_sum = 0
+ mem_sum = 0
+ hdd_sum = 0
+ for instance in instances:
+ cpu_sum += instance['vcpus']
+ mem_sum += instance['memory_mb']
+ hdd_sum += instance['root_gb'] + instance['ephemeral_gb']
+
+ return {'resource': {'host': host_name,
+ 'project': '(used_max)',
+ 'cpu': cpu_sum,
+ 'memory_mb': mem_sum,
+ 'disk_gb': hdd_sum}}
+
+ @staticmethod
+ def _get_resources_by_project(host_name, instances):
+ # Getting usage resource per project
+ project_map = {}
+ for instance in instances:
+ resource = project_map.setdefault(instance['project_id'],
+ {'host': host_name,
+ 'project': instance['project_id'],
+ 'cpu': 0,
+ 'memory_mb': 0,
+ 'disk_gb': 0})
+ resource['cpu'] += instance['vcpus']
+ resource['memory_mb'] += instance['memory_mb']
+ resource['disk_gb'] += (instance['root_gb'] +
+ instance['ephemeral_gb'])
+ return project_map
+
@wsgi.serializers(xml=HostShowTemplate)
def show(self, req, id):
"""Shows the physical/usage resource given by hosts.
@@ -256,14 +312,26 @@ class HostController(object):
'cpu': 1, 'memory_mb': 2048, 'disk_gb': 30}
"""
context = req.environ['nova.context']
+ host_name = id
try:
- data = self.api.describe_host(context, id)
+ service = self.api.service_get_by_compute_host(context, host_name)
except exception.NotFound as e:
raise webob.exc.HTTPNotFound(explanation=e.message)
except exception.AdminRequired:
msg = _("Describe-resource is admin only functionality")
raise webob.exc.HTTPForbidden(explanation=msg)
- return {'host': data}
+ compute_node = service['compute_node'][0]
+ instances = self.api.instance_get_all_by_host(context, host_name)
+ resources = [self._get_total_resources(host_name, compute_node)]
+ resources.append(self._get_used_now_resources(host_name,
+ compute_node))
+ resources.append(self._get_resource_totals_from_instances(host_name,
+ instances))
+ by_proj_resources = self._get_resources_by_project(host_name,
+ instances)
+ for resource in by_proj_resources.itervalues():
+ resources.append({'resource': resource})
+ return {'host': resources}
class Hosts(extensions.ExtensionDescriptor):
diff --git a/nova/api/openstack/compute/contrib/networks_associate.py b/nova/api/openstack/compute/contrib/networks_associate.py
index 4990c1b5e..3cdda1d76 100644
--- a/nova/api/openstack/compute/contrib/networks_associate.py
+++ b/nova/api/openstack/compute/contrib/networks_associate.py
@@ -62,6 +62,6 @@ class Networks_associate(extensions.ExtensionDescriptor):
def get_controller_extensions(self):
extension = extensions.ControllerExtension(
- self, 'os-admin-networks', NetworkAssociateActionController())
+ self, 'os-networks', NetworkAssociateActionController())
return [extension]
diff --git a/nova/api/openstack/compute/contrib/os_networks.py b/nova/api/openstack/compute/contrib/os_networks.py
index 4be0bd100..d1d172686 100644
--- a/nova/api/openstack/compute/contrib/os_networks.py
+++ b/nova/api/openstack/compute/contrib/os_networks.py
@@ -1,6 +1,7 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
-# Copyright 2013 OpenStack LLC.
+# Copyright 2011 Grid Dynamics
+# Copyright 2011 OpenStack LLC.
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
@@ -15,199 +16,155 @@
# License for the specific language governing permissions and limitations
# under the License.
-
import netaddr
-import netaddr.core as netexc
+import webob
from webob import exc
from nova.api.openstack import extensions
-from nova import context as nova_context
+from nova.api.openstack import wsgi
from nova import exception
-import nova.network
-from nova.openstack.common import cfg
+from nova import network
from nova.openstack.common import log as logging
-from nova import quota
-
-
-CONF = cfg.CONF
-
-try:
- os_network_opts = [
- cfg.BoolOpt("enable_network_quota",
- default=False,
- help="Enables or disables quotaing of tenant networks"),
- cfg.StrOpt('use_quantum_default_nets',
- default="False",
- help=('Control for checking for default networks')),
- cfg.StrOpt('quantum_default_tenant_id',
- default="default",
- help=('Default tenant id when creating quantum '
- 'networks'))
- ]
- CONF.register_opts(os_network_opts)
-except cfg.DuplicateOptError:
- # NOTE(jkoelker) These options are verbatim elsewhere this is here
- # to make sure they are registered for our use.
- pass
-
-if CONF.enable_network_quota:
- opts = [
- cfg.IntOpt('quota_networks',
- default=3,
- help='number of private networks allowed per project'),
- ]
- CONF.register_opts(opts)
-
-QUOTAS = quota.QUOTAS
-LOG = logging.getLogger(__name__)
-authorize = extensions.extension_authorizer('compute', 'os-networks')
-
-
-def network_dict(network):
- return {"id": network.get("uuid") or network["id"],
- "cidr": network["cidr"],
- "label": network["label"]}
+LOG = logging.getLogger(__name__)
+authorize = extensions.extension_authorizer('compute', 'networks')
+authorize_view = extensions.extension_authorizer('compute',
+ 'networks:view')
+
+
+def network_dict(context, network):
+ fields = ('id', 'cidr', 'netmask', 'gateway', 'broadcast', 'dns1', 'dns2',
+ 'cidr_v6', 'gateway_v6', 'label', 'netmask_v6')
+ admin_fields = ('created_at', 'updated_at', 'deleted_at', 'deleted',
+ 'injected', 'bridge', 'vlan', 'vpn_public_address',
+ 'vpn_public_port', 'vpn_private_address', 'dhcp_start',
+ 'project_id', 'host', 'bridge_interface', 'multi_host',
+ 'priority', 'rxtx_base')
+ if network:
+ # NOTE(mnaser): We display a limited set of fields so users can know
+ # what networks are available, extra system-only fields
+ # are only visible if they are an admin.
+ if context.is_admin:
+ fields += admin_fields
+ result = dict((field, network[field]) for field in fields)
+ if 'uuid' in network:
+ result['id'] = network['uuid']
+ return result
+ else:
+ return {}
+
+
+class NetworkController(wsgi.Controller):
-class NetworkController(object):
def __init__(self, network_api=None):
- self.network_api = nova.network.API()
- self._default_networks = []
-
- def _refresh_default_networks(self):
- self._default_networks = []
- if CONF.use_quantum_default_nets == "True":
- try:
- self._default_networks = self._get_default_networks()
- except Exception:
- LOG.exception("Failed to get default networks")
-
- def _get_default_networks(self):
- project_id = CONF.quantum_default_tenant_id
- ctx = nova_context.RequestContext(user_id=None,
- project_id=project_id)
- networks = {}
- for n in self.network_api.get_all(ctx):
- networks[n['id']] = n['label']
- return [{'id': k, 'label': v} for k, v in networks.iteritems()]
+ self.network_api = network_api or network.API()
def index(self, req):
context = req.environ['nova.context']
- authorize(context)
+ authorize_view(context)
networks = self.network_api.get_all(context)
- if not self._default_networks:
- self._refresh_default_networks()
- networks.extend(self._default_networks)
- return {'networks': [network_dict(n) for n in networks]}
+ result = [network_dict(context, net_ref) for net_ref in networks]
+ return {'networks': result}
- def show(self, req, id):
+ @wsgi.action("disassociate")
+ def _disassociate_host_and_project(self, req, id, body):
context = req.environ['nova.context']
authorize(context)
+ LOG.debug(_("Disassociating network with id %s"), id)
+
+ try:
+ self.network_api.associate(context, id, host=None, project=None)
+ except exception.NetworkNotFound:
+ raise exc.HTTPNotFound(_("Network not found"))
+ return exc.HTTPAccepted()
+
+ def show(self, req, id):
+ context = req.environ['nova.context']
+ authorize_view(context)
LOG.debug(_("Showing network with id %s") % id)
try:
network = self.network_api.get(context, id)
except exception.NetworkNotFound:
raise exc.HTTPNotFound(_("Network not found"))
- return network_dict(network)
+ return {'network': network_dict(context, network)}
def delete(self, req, id):
context = req.environ['nova.context']
authorize(context)
- try:
- if CONF.enable_network_quota:
- reservation = QUOTAS.reserve(context, networks=-1)
- except Exception:
- reservation = None
- LOG.exception(_("Failed to update usages deallocating "
- "network."))
-
LOG.info(_("Deleting network with id %s") % id)
-
try:
self.network_api.delete(context, id)
- if CONF.enable_network_quota and reservation:
- QUOTAS.commit(context, reservation)
- response = exc.HTTPAccepted()
except exception.NetworkNotFound:
- response = exc.HTTPNotFound(_("Network not found"))
-
- return response
+ raise exc.HTTPNotFound(_("Network not found"))
+ return exc.HTTPAccepted()
def create(self, req, body):
- if not body:
- raise exc.HTTPUnprocessableEntity()
-
- context = req.environ["nova.context"]
+ context = req.environ['nova.context']
authorize(context)
- network = body["network"]
- keys = ["cidr", "cidr_v6", "ipam", "vlan_start", "network_size",
- "num_networks"]
- kwargs = dict((k, network.get(k)) for k in keys)
+ def bad(e):
+ return exc.HTTPUnprocessableEntity(explanation=e)
- label = network["label"]
+ if not (body and body.get("network")):
+ raise bad(_("Missing network in body"))
- if not (kwargs["cidr"] or kwargs["cidr_v6"]):
- msg = _("No CIDR requested")
- raise exc.HTTPBadRequest(explanation=msg)
- if kwargs["cidr"]:
- try:
- net = netaddr.IPNetwork(kwargs["cidr"])
- if net.size < 4:
- msg = _("Requested network does not contain "
- "enough (2+) usable hosts")
- raise exc.HTTPBadRequest(explanation=msg)
- except netexc.AddrFormatError:
- msg = _("CIDR is malformed.")
- raise exc.HTTPBadRequest(explanation=msg)
- except netexc.AddrConversionError:
- msg = _("Address could not be converted.")
- raise exc.HTTPBadRequest(explanation=msg)
-
- networks = []
+ params = body["network"]
+ if not params.get("label"):
+ raise bad(_("Network label is required"))
+
+ cidr = params.get("cidr") or params.get("cidr_v6")
+ if not cidr:
+ raise bad(_("Network cidr or cidr_v6 is required"))
+
+ LOG.debug(_("Creating network with label %s") % params["label"])
+
+ params["num_networks"] = 1
+ params["network_size"] = netaddr.IPNetwork(cidr).size
+
+ network = self.network_api.create(context, **params)[0]
+ return {"network": network_dict(context, network)}
+
+ def add(self, req, body):
+ context = req.environ['nova.context']
+ authorize(context)
+ if not body:
+ raise exc.HTTPUnprocessableEntity()
+
+ network_id = body.get('id', None)
+ project_id = context.project_id
+ LOG.debug(_("Associating network %(network)s"
+ " with project %(project)s") %
+ {"network": network_id or "",
+ "project": project_id})
try:
- if CONF.enable_network_quota:
- reservation = QUOTAS.reserve(context, networks=1)
- except exception.OverQuota:
- msg = _("Quota exceeded, too many networks.")
+ self.network_api.add_network_to_project(
+ context, project_id, network_id)
+ except Exception as ex:
+ msg = (_("Cannot associate network %(network)s"
+ " with project %(project)s: %(message)s") %
+ {"network": network_id or "",
+ "project": project_id,
+ "message": getattr(ex, "value", str(ex))})
raise exc.HTTPBadRequest(explanation=msg)
- try:
- networks = self.network_api.create(context,
- label=label, **kwargs)
- if CONF.enable_network_quota:
- QUOTAS.commit(context, reservation)
- except Exception:
- if CONF.enable_network_quota:
- QUOTAS.rollback(context, reservation)
- msg = _("Create networks failed")
- LOG.exception(msg, extra=network)
- raise exc.HTTPServiceUnavailable(explanation=msg)
- return {"network": network_dict(networks[0])}
+ return webob.Response(status_int=202)
class Os_networks(extensions.ExtensionDescriptor):
- """Tenant-based Network Management Extension."""
+ """Admin-only Network Management Extension."""
- name = "OSNetworks"
+ name = "Networks"
alias = "os-networks"
- namespace = "http://docs.openstack.org/compute/ext/os-networks/api/v1.1"
- updated = "2012-03-07T09:46:43-05:00"
+ namespace = ("http://docs.openstack.org/compute/"
+ "ext/os-networks/api/v1.1")
+ updated = "2011-12-23T00:00:00+00:00"
def get_resources(self):
- ext = extensions.ResourceExtension('os-networks',
- NetworkController())
- return [ext]
-
-
-def _sync_networks(context, project_id, session):
- ctx = nova_context.RequestContext(user_id=None, project_id=project_id)
- ctx = ctx.elevated()
- networks = nova.network.api.API().get_all(ctx)
- return dict(networks=len(networks))
-
-
-if CONF.enable_network_quota:
- QUOTAS.register_resource(quota.ReservableResource('networks',
- _sync_networks,
- 'quota_networks'))
+ member_actions = {'action': 'POST'}
+ collection_actions = {'add': 'POST'}
+ res = extensions.ResourceExtension(
+ 'os-networks',
+ NetworkController(),
+ member_actions=member_actions,
+ collection_actions=collection_actions)
+ return [res]
diff --git a/nova/api/openstack/compute/contrib/os_tenant_networks.py b/nova/api/openstack/compute/contrib/os_tenant_networks.py
new file mode 100644
index 000000000..03178ab65
--- /dev/null
+++ b/nova/api/openstack/compute/contrib/os_tenant_networks.py
@@ -0,0 +1,214 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2013 OpenStack LLC.
+# All Rights Reserved.
+#
+# 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.
+
+
+import netaddr
+import netaddr.core as netexc
+from webob import exc
+
+from nova.api.openstack import extensions
+from nova import context as nova_context
+from nova import exception
+import nova.network
+from nova.openstack.common import cfg
+from nova.openstack.common import log as logging
+from nova import quota
+
+
+CONF = cfg.CONF
+
+try:
+ os_network_opts = [
+ cfg.BoolOpt("enable_network_quota",
+ default=False,
+ help="Enables or disables quotaing of tenant networks"),
+ cfg.StrOpt('use_quantum_default_nets',
+ default="False",
+ help=('Control for checking for default networks')),
+ cfg.StrOpt('quantum_default_tenant_id',
+ default="default",
+ help=('Default tenant id when creating quantum '
+ 'networks'))
+ ]
+ CONF.register_opts(os_network_opts)
+except cfg.DuplicateOptError:
+ # NOTE(jkoelker) These options are verbatim elsewhere this is here
+ # to make sure they are registered for our use.
+ pass
+
+if CONF.enable_network_quota:
+ opts = [
+ cfg.IntOpt('quota_networks',
+ default=3,
+ help='number of private networks allowed per project'),
+ ]
+ CONF.register_opts(opts)
+
+QUOTAS = quota.QUOTAS
+LOG = logging.getLogger(__name__)
+authorize = extensions.extension_authorizer('compute', 'os-tenant-networks')
+
+
+def network_dict(network):
+ return {"id": network.get("uuid") or network["id"],
+ "cidr": network["cidr"],
+ "label": network["label"]}
+
+
+class NetworkController(object):
+ def __init__(self, network_api=None):
+ self.network_api = nova.network.API()
+ self._default_networks = []
+
+ def _refresh_default_networks(self):
+ self._default_networks = []
+ if CONF.use_quantum_default_nets == "True":
+ try:
+ self._default_networks = self._get_default_networks()
+ except Exception:
+ LOG.exception("Failed to get default networks")
+
+ def _get_default_networks(self):
+ project_id = CONF.quantum_default_tenant_id
+ ctx = nova_context.RequestContext(user_id=None,
+ project_id=project_id)
+ networks = {}
+ for n in self.network_api.get_all(ctx):
+ networks[n['id']] = n['label']
+ return [{'id': k, 'label': v} for k, v in networks.iteritems()]
+
+ def index(self, req):
+ context = req.environ['nova.context']
+ authorize(context)
+ networks = self.network_api.get_all(context)
+ if not self._default_networks:
+ self._refresh_default_networks()
+ networks.extend(self._default_networks)
+ return {'networks': [network_dict(n) for n in networks]}
+
+ def show(self, req, id):
+ context = req.environ['nova.context']
+ authorize(context)
+ LOG.debug(_("Showing network with id %s") % id)
+ try:
+ network = self.network_api.get(context, id)
+ except exception.NetworkNotFound:
+ raise exc.HTTPNotFound(_("Network not found"))
+ return network_dict(network)
+
+ def delete(self, req, id):
+ context = req.environ['nova.context']
+ authorize(context)
+ try:
+ if CONF.enable_network_quota:
+ reservation = QUOTAS.reserve(context, networks=-1)
+ except Exception:
+ reservation = None
+ LOG.exception(_("Failed to update usages deallocating "
+ "network."))
+
+ LOG.info(_("Deleting network with id %s") % id)
+
+ try:
+ self.network_api.delete(context, id)
+ if CONF.enable_network_quota and reservation:
+ QUOTAS.commit(context, reservation)
+ response = exc.HTTPAccepted()
+ except exception.NetworkNotFound:
+ response = exc.HTTPNotFound(_("Network not found"))
+
+ return response
+
+ def create(self, req, body):
+ if not body:
+ raise exc.HTTPUnprocessableEntity()
+
+ context = req.environ["nova.context"]
+ authorize(context)
+
+ network = body["network"]
+ keys = ["cidr", "cidr_v6", "ipam", "vlan_start", "network_size",
+ "num_networks"]
+ kwargs = dict((k, network.get(k)) for k in keys)
+
+ label = network["label"]
+
+ if not (kwargs["cidr"] or kwargs["cidr_v6"]):
+ msg = _("No CIDR requested")
+ raise exc.HTTPBadRequest(explanation=msg)
+ if kwargs["cidr"]:
+ try:
+ net = netaddr.IPNetwork(kwargs["cidr"])
+ if net.size < 4:
+ msg = _("Requested network does not contain "
+ "enough (2+) usable hosts")
+ raise exc.HTTPBadRequest(explanation=msg)
+ except netexc.AddrFormatError:
+ msg = _("CIDR is malformed.")
+ raise exc.HTTPBadRequest(explanation=msg)
+ except netexc.AddrConversionError:
+ msg = _("Address could not be converted.")
+ raise exc.HTTPBadRequest(explanation=msg)
+
+ networks = []
+ try:
+ if CONF.enable_network_quota:
+ reservation = QUOTAS.reserve(context, networks=1)
+ except exception.OverQuota:
+ msg = _("Quota exceeded, too many networks.")
+ raise exc.HTTPBadRequest(explanation=msg)
+
+ try:
+ networks = self.network_api.create(context,
+ label=label, **kwargs)
+ if CONF.enable_network_quota:
+ QUOTAS.commit(context, reservation)
+ except Exception:
+ if CONF.enable_network_quota:
+ QUOTAS.rollback(context, reservation)
+ msg = _("Create networks failed")
+ LOG.exception(msg, extra=network)
+ raise exc.HTTPServiceUnavailable(explanation=msg)
+ return {"network": network_dict(networks[0])}
+
+
+class Os_tenant_networks(extensions.ExtensionDescriptor):
+ """Tenant-based Network Management Extension."""
+
+ name = "OSTenantNetworks"
+ alias = "os-tenant-networks"
+ namespace = ("http://docs.openstack.org/compute/"
+ "ext/os-tenant-networks/api/v2")
+ updated = "2012-03-07T09:46:43-05:00"
+
+ def get_resources(self):
+ ext = extensions.ResourceExtension('os-tenant-networks',
+ NetworkController())
+ return [ext]
+
+
+def _sync_networks(context, project_id, session):
+ ctx = nova_context.RequestContext(user_id=None, project_id=project_id)
+ ctx = ctx.elevated()
+ networks = nova.network.api.API().get_all(ctx)
+ return dict(networks=len(networks))
+
+
+if CONF.enable_network_quota:
+ QUOTAS.register_resource(quota.ReservableResource('networks',
+ _sync_networks,
+ 'quota_networks'))
diff --git a/nova/api/openstack/compute/contrib/services.py b/nova/api/openstack/compute/contrib/services.py
index c792c72da..2786ad814 100644
--- a/nova/api/openstack/compute/contrib/services.py
+++ b/nova/api/openstack/compute/contrib/services.py
@@ -21,6 +21,7 @@ import webob.exc
from nova.api.openstack import extensions
from nova.api.openstack import wsgi
from nova.api.openstack import xmlutil
+from nova import availability_zones
from nova import db
from nova import exception
from nova.openstack.common import cfg
@@ -69,6 +70,7 @@ class ServiceController(object):
authorize(context)
now = timeutils.utcnow()
services = db.service_get_all(context)
+ services = availability_zones.set_availability_zones(context, services)
host = ''
if 'host' in req.GET:
diff --git a/nova/api/openstack/compute/servers.py b/nova/api/openstack/compute/servers.py
index d3a6fc8a9..f0fdb5a15 100644
--- a/nova/api/openstack/compute/servers.py
+++ b/nova/api/openstack/compute/servers.py
@@ -538,10 +538,10 @@ class Controller(wsgi.Controller):
marker=marker)
except exception.MarkerNotFound as e:
msg = _('marker [%s] not found') % marker
- raise webob.exc.HTTPBadRequest(explanation=msg)
+ raise exc.HTTPBadRequest(explanation=msg)
except exception.FlavorNotFound as e:
msg = _("Flavor could not be found")
- raise webob.exc.HTTPUnprocessableEntity(explanation=msg)
+ raise exc.HTTPUnprocessableEntity(explanation=msg)
if is_detail:
self._add_instance_faults(context, instance_list)
@@ -828,21 +828,24 @@ class Controller(wsgi.Controller):
try:
min_count = int(min_count)
except ValueError:
- raise webob.exc.HTTPBadRequest(_('min_count must be an '
- 'integer value'))
+ msg = _('min_count must be an integer value')
+ raise exc.HTTPBadRequest(explanation=msg)
if min_count < 1:
- raise webob.exc.HTTPBadRequest(_('min_count must be > 0'))
+ msg = _('min_count must be > 0')
+ raise exc.HTTPBadRequest(explanation=msg)
try:
max_count = int(max_count)
except ValueError:
- raise webob.exc.HTTPBadRequest(_('max_count must be an '
- 'integer value'))
+ msg = _('max_count must be an integer value')
+ raise exc.HTTPBadRequest(explanation=msg)
if max_count < 1:
- raise webob.exc.HTTPBadRequest(_('max_count must be > 0'))
+ msg = _('max_count must be > 0')
+ raise exc.HTTPBadRequest(explanation=msg)
if min_count > max_count:
- raise webob.exc.HTTPBadRequest(_('min_count must be <= max_count'))
+ msg = _('min_count must be <= max_count')
+ raise exc.HTTPBadRequest(explanation=msg)
auto_disk_config = False
if self.ext_mgr.is_loaded('OS-DCF'):
@@ -1202,7 +1205,8 @@ class Controller(wsgi.Controller):
try:
body = body['rebuild']
except (KeyError, TypeError):
- raise exc.HTTPBadRequest(_("Invalid request body"))
+ msg = _('Invalid request body')
+ raise exc.HTTPBadRequest(explanation=msg)
try:
image_href = body["imageRef"]
diff --git a/nova/compute/api.py b/nova/compute/api.py
index bddb83449..7770bc9e6 100644
--- a/nova/compute/api.py
+++ b/nova/compute/api.py
@@ -92,6 +92,7 @@ CONF = cfg.CONF
CONF.register_opts(compute_opts)
CONF.import_opt('compute_topic', 'nova.compute.rpcapi')
CONF.import_opt('consoleauth_topic', 'nova.consoleauth')
+CONF.import_opt('enable', 'nova.cells.opts', group='cells')
MAX_USERDATA_SIZE = 65535
QUOTAS = quota.QUOTAS
@@ -1547,12 +1548,9 @@ class API(base.Base):
elevated = context.elevated()
block_info = self._get_block_device_info(elevated,
instance['uuid'])
- network_info = self.network_api.get_instance_nw_info(elevated,
- instance)
self.compute_rpcapi.reboot_instance(context, instance=instance,
block_device_info=block_info,
- network_info=network_info,
reboot_type=reboot_type)
def _get_image(self, context, image_href):
@@ -1665,6 +1663,11 @@ class API(base.Base):
self.db.migration_update(elevated, migration_ref['id'],
{'status': 'reverting'})
+ # With cells, the best we can do right now is commit the reservations
+ # immediately...
+ if CONF.cells.enable and reservations:
+ QUOTAS.commit(context, reservations)
+ reservations = []
self.compute_rpcapi.revert_resize(context,
instance=instance, migration=migration_ref,
@@ -1689,6 +1692,11 @@ class API(base.Base):
self.db.migration_update(elevated, migration_ref['id'],
{'status': 'confirming'})
+ # With cells, the best we can do right now is commit the reservations
+ # immediately...
+ if CONF.cells.enable and reservations:
+ QUOTAS.commit(context, reservations)
+ reservations = []
self.compute_rpcapi.confirm_resize(context,
instance=instance, migration=migration_ref,
@@ -1851,6 +1859,12 @@ class API(base.Base):
if not CONF.allow_resize_to_same_host:
filter_properties['ignore_hosts'].append(instance['host'])
+ # With cells, the best we can do right now is commit the reservations
+ # immediately...
+ if CONF.cells.enable and reservations:
+ QUOTAS.commit(context, reservations)
+ reservations = []
+
args = {
"instance": instance,
"instance_type": new_instance_type,
@@ -2185,139 +2199,76 @@ class API(base.Base):
disk_over_commit, instance, host_name)
-def check_host(fn):
- """Decorator that makes sure that the host exists."""
- def wrapped(self, context, host_name, *args, **kwargs):
- if self.does_host_exist(context, host_name):
- return fn(self, context, host_name, *args, **kwargs)
- else:
- raise exception.HostNotFound(host=host_name)
- return wrapped
-
-
class HostAPI(base.Base):
"""Sub-set of the Compute Manager API for managing host operations."""
- def __init__(self):
- self.compute_rpcapi = compute_rpcapi.ComputeAPI()
+ def __init__(self, rpcapi=None):
+ self.rpcapi = rpcapi or compute_rpcapi.ComputeAPI()
super(HostAPI, self).__init__()
- @check_host
+ def _assert_host_exists(self, context, host_name):
+ """Raise HostNotFound if compute host doesn't exist."""
+ if not self.db.service_get_by_host_and_topic(context, host_name,
+ CONF.compute_topic):
+ raise exception.HostNotFound(host=host_name)
+
def set_host_enabled(self, context, host_name, enabled):
"""Sets the specified host's ability to accept new instances."""
# NOTE(comstud): No instance_uuid argument to this compute manager
# call
- return self.compute_rpcapi.set_host_enabled(context, enabled=enabled,
+ self._assert_host_exists(context, host_name)
+ return self.rpcapi.set_host_enabled(context, enabled=enabled,
host=host_name)
- @check_host
def get_host_uptime(self, context, host_name):
"""Returns the result of calling "uptime" on the target host."""
# NOTE(comstud): No instance_uuid argument to this compute manager
# call
- return self.compute_rpcapi.get_host_uptime(context, host=host_name)
+ self._assert_host_exists(context, host_name)
+ return self.rpcapi.get_host_uptime(context, host=host_name)
- @check_host
def host_power_action(self, context, host_name, action):
"""Reboots, shuts down or powers up the host."""
- return self.compute_rpcapi.host_power_action(context, action=action,
+ self._assert_host_exists(context, host_name)
+ return self.rpcapi.host_power_action(context, action=action,
host=host_name)
- def list_hosts(self, context, zone=None, service=None):
- """Returns a summary list of enabled hosts, optionally filtering
- by zone and/or service type.
+ def set_host_maintenance(self, context, host_name, mode):
+ """Start/Stop host maintenance window. On start, it triggers
+ guest VMs evacuation."""
+ self._assert_host_exists(context, host_name)
+ return self.rpcapi.host_maintenance_mode(context,
+ host_param=host_name, mode=mode, host=host_name)
+
+ def service_get_all(self, context, filters=None):
+ """Returns a list of services, optionally filtering the results.
+
+ If specified, 'filters' should be a dictionary containing services
+ attributes and matching values. Ie, to get a list of services for
+ the 'compute' topic, use filters={'topic': 'compute'}.
"""
- LOG.debug(_("Listing hosts"))
+ if filters is None:
+ filters = {}
services = self.db.service_get_all(context, False)
- services = availability_zones.set_availability_zones(context, services)
- if zone:
- services = [s for s in services if s['availability_zone'] == zone]
- hosts = []
- for host in services:
- hosts.append({'host_name': host['host'], 'service': host['topic'],
- 'zone': host['availability_zone']})
- if service:
- hosts = [host for host in hosts
- if host["service"] == service]
- return hosts
-
- def does_host_exist(self, context, host_name):
- """
- Returns True if the host with host_name exists, False otherwise
- """
- return self.db.service_does_host_exist(context, host_name)
+ services = availability_zones.set_availability_zones(context,
+ services)
+ ret_services = []
+ for service in services:
+ for key, val in filters.iteritems():
+ if service[key] != val:
+ break
+ else:
+ # All filters matched.
+ ret_services.append(service)
+ return ret_services
- def describe_host(self, context, host_name):
- """
- Returns information about a host in this kind of format:
- :returns:
- ex.::
- {'host': 'hostname',
- 'project': 'admin',
- 'cpu': 1,
- 'memory_mb': 2048,
- 'disk_gb': 30}
- """
- # Getting compute node info and related instances info
- try:
- compute_ref = self.db.service_get_by_compute_host(context,
- host_name)
- except exception.ComputeHostNotFound:
- raise exception.HostNotFound(host=host_name)
- instance_refs = self.db.instance_get_all_by_host(context,
- compute_ref['host'])
-
- # Getting total available/used resource
- compute_ref = compute_ref['compute_node'][0]
- resources = [{'resource': {'host': host_name, 'project': '(total)',
- 'cpu': compute_ref['vcpus'],
- 'memory_mb': compute_ref['memory_mb'],
- 'disk_gb': compute_ref['local_gb']}},
- {'resource': {'host': host_name, 'project': '(used_now)',
- 'cpu': compute_ref['vcpus_used'],
- 'memory_mb': compute_ref['memory_mb_used'],
- 'disk_gb': compute_ref['local_gb_used']}}]
-
- cpu_sum = 0
- mem_sum = 0
- hdd_sum = 0
- for i in instance_refs:
- cpu_sum += i['vcpus']
- mem_sum += i['memory_mb']
- hdd_sum += i['root_gb'] + i['ephemeral_gb']
-
- resources.append({'resource': {'host': host_name,
- 'project': '(used_max)',
- 'cpu': cpu_sum,
- 'memory_mb': mem_sum,
- 'disk_gb': hdd_sum}})
-
- # Getting usage resource per project
- project_ids = [i['project_id'] for i in instance_refs]
- project_ids = list(set(project_ids))
- for project_id in project_ids:
- vcpus = [i['vcpus'] for i in instance_refs
- if i['project_id'] == project_id]
-
- mem = [i['memory_mb'] for i in instance_refs
- if i['project_id'] == project_id]
-
- disk = [i['root_gb'] + i['ephemeral_gb'] for i in instance_refs
- if i['project_id'] == project_id]
-
- resources.append({'resource': {'host': host_name,
- 'project': project_id,
- 'cpu': sum(vcpus),
- 'memory_mb': sum(mem),
- 'disk_gb': sum(disk)}})
- return resources
-
- @check_host
- def set_host_maintenance(self, context, host, mode):
- """Start/Stop host maintenance window. On start, it triggers
- guest VMs evacuation."""
- return self.compute_rpcapi.host_maintenance_mode(context,
- host_param=host, mode=mode, host=host)
+ def service_get_by_compute_host(self, context, host_name):
+ """Get service entry for the given compute hostname."""
+ return self.db.service_get_by_compute_host(context, host_name)
+
+ def instance_get_all_by_host(self, context, host_name):
+ """Return all instances on the given host."""
+ return self.db.instance_get_all_by_host(context, host_name)
class AggregateAPI(base.Base):
diff --git a/nova/compute/cells_api.py b/nova/compute/cells_api.py
index 47d60aec4..d547c363a 100644
--- a/nova/compute/cells_api.py
+++ b/nova/compute/cells_api.py
@@ -18,7 +18,7 @@
from nova import block_device
from nova.cells import rpcapi as cells_rpcapi
from nova.compute import api as compute_api
-from nova.compute import task_states
+from nova.compute import instance_types
from nova.compute import vm_states
from nova import exception
from nova.openstack.common import excutils
@@ -254,22 +254,14 @@ class ComputeCellsAPI(compute_api.API):
@validate_cell
def revert_resize(self, context, instance):
"""Reverts a resize, deleting the 'new' instance in the process."""
- # NOTE(markwash): regular api manipulates the migration here, but we
- # don't have access to it. So to preserve the interface just update the
- # vm and task state.
- self.update(context, instance,
- task_state=task_states.RESIZE_REVERTING)
+ super(ComputeCellsAPI, self).revert_resize(context, instance)
self._cast_to_cells(context, instance, 'revert_resize')
@check_instance_state(vm_state=[vm_states.RESIZED])
@validate_cell
def confirm_resize(self, context, instance):
"""Confirms a migration/resize and deletes the 'old' instance."""
- # NOTE(markwash): regular api manipulates migration here, but we don't
- # have the migration in the api database. So to preserve the interface
- # just update the vm and task state without calling super()
- self.update(context, instance, task_state=None,
- vm_state=vm_states.ACTIVE)
+ super(ComputeCellsAPI, self).confirm_resize(context, instance)
self._cast_to_cells(context, instance, 'confirm_resize')
@check_instance_state(vm_state=[vm_states.ACTIVE, vm_states.STOPPED],
@@ -282,8 +274,36 @@ class ComputeCellsAPI(compute_api.API):
the original flavor_id. If flavor_id is not None, the instance should
be migrated to a new host and resized to the new flavor_id.
"""
- super(ComputeCellsAPI, self).resize(context, instance, *args,
- **kwargs)
+ super(ComputeCellsAPI, self).resize(context, instance, *args, **kwargs)
+
+ # NOTE(johannes): If we get to this point, then we know the
+ # specified flavor_id is valid and exists. We'll need to load
+ # it again, but that should be safe.
+
+ old_instance_type_id = instance['instance_type_id']
+ old_instance_type = instance_types.get_instance_type(
+ old_instance_type_id)
+
+ flavor_id = kwargs.get('flavor_id')
+
+ if not flavor_id:
+ new_instance_type = old_instance_type
+ else:
+ new_instance_type = instance_types.get_instance_type_by_flavor_id(
+ flavor_id)
+
+ # NOTE(johannes): Later, when the resize is confirmed or reverted,
+ # the superclass implementations of those methods will need access
+ # to a local migration record for quota reasons. We don't need
+ # source and/or destination information, just the old and new
+ # instance_types. Status is set to 'finished' since nothing else
+ # will update the status along the way.
+ self.db.migration_create(context.elevated(),
+ {'instance_uuid': instance['uuid'],
+ 'old_instance_type_id': old_instance_type['id'],
+ 'new_instance_type_id': new_instance_type['id'],
+ 'status': 'finished'})
+
# FIXME(comstud): pass new instance_type object down to a method
# that'll unfold it
self._cast_to_cells(context, instance, 'resize', *args, **kwargs)
diff --git a/nova/compute/manager.py b/nova/compute/manager.py
index a4f17ee3d..3bf8e61ef 100644
--- a/nova/compute/manager.py
+++ b/nova/compute/manager.py
@@ -293,7 +293,7 @@ class ComputeVirtAPI(virtapi.VirtAPI):
class ComputeManager(manager.SchedulerDependentManager):
"""Manages the running instances from creation to destruction."""
- RPC_API_VERSION = '2.22'
+ RPC_API_VERSION = '2.23'
def __init__(self, compute_driver=None, *args, **kwargs):
"""Load configuration options and connect to the hypervisor."""
@@ -1440,19 +1440,14 @@ class ComputeManager(manager.SchedulerDependentManager):
if block_device_info is None:
block_device_info = self._get_instance_volume_block_device_info(
context, instance)
- # NOTE(danms): remove this when RPC API < 2.5 compatibility
- # is no longer needed
- if network_info is None:
- network_info = self._get_instance_nw_info(context, instance)
- else:
- network_info = network_model.NetworkInfo.hydrate(network_info)
+ network_info = self._get_instance_nw_info(context, instance)
self._notify_about_instance_usage(context, instance, "reboot.start")
current_power_state = self._get_power_state(context, instance)
- self._instance_update(context, instance['uuid'],
- power_state=current_power_state,
- vm_state=vm_states.ACTIVE)
+ instance = self._instance_update(context, instance['uuid'],
+ power_state=current_power_state,
+ vm_state=vm_states.ACTIVE)
if instance['power_state'] != power_state.RUNNING:
state = instance['power_state']
@@ -1473,10 +1468,10 @@ class ComputeManager(manager.SchedulerDependentManager):
# Fall through and reset task_state to None
current_power_state = self._get_power_state(context, instance)
- self._instance_update(context, instance['uuid'],
- power_state=current_power_state,
- vm_state=vm_states.ACTIVE,
- task_state=None)
+ instance = self._instance_update(context, instance['uuid'],
+ power_state=current_power_state,
+ vm_state=vm_states.ACTIVE,
+ task_state=None)
self._notify_about_instance_usage(context, instance, "reboot.end")
diff --git a/nova/compute/rpcapi.py b/nova/compute/rpcapi.py
index 1c53b6084..3e7ed1cfd 100644
--- a/nova/compute/rpcapi.py
+++ b/nova/compute/rpcapi.py
@@ -157,6 +157,7 @@ class ComputeAPI(nova.openstack.common.rpc.proxy.RpcProxy):
2.21 - Add migrate_data dict param to pre_live_migration()
2.22 - Add recreate, on_shared_storage and host arguments to
rebuild_instance()
+ 2.23 - Remove network_info from reboot_instance
'''
#
@@ -383,16 +384,15 @@ class ComputeAPI(nova.openstack.common.rpc.proxy.RpcProxy):
_compute_topic(self.topic, ctxt, host, None),
version='2.20')
- def reboot_instance(self, ctxt, instance,
- block_device_info, network_info, reboot_type):
+ def reboot_instance(self, ctxt, instance, block_device_info,
+ reboot_type):
instance_p = jsonutils.to_primitive(instance)
self.cast(ctxt, self.make_msg('reboot_instance',
instance=instance_p,
block_device_info=block_device_info,
- network_info=network_info,
reboot_type=reboot_type),
topic=_compute_topic(self.topic, ctxt, None, instance),
- version='2.5')
+ version='2.23')
def rebuild_instance(self, ctxt, instance, new_pass, injected_files,
image_ref, orig_image_ref, orig_sys_metadata, bdms,
diff --git a/nova/db/sqlalchemy/api.py b/nova/db/sqlalchemy/api.py
index 52e3916ae..3fdfd53c8 100644
--- a/nova/db/sqlalchemy/api.py
+++ b/nova/db/sqlalchemy/api.py
@@ -337,15 +337,6 @@ def service_get_all(context, disabled=None):
@require_admin_context
-def service_does_host_exist(context, host_name, include_disabled):
- query = get_session().query(func.count(models.Service.host)).\
- filter_by(host=host_name)
- if not include_disabled:
- query = query.filter_by(disabled=False)
- return query.scalar() > 0
-
-
-@require_admin_context
def service_get_all_by_topic(context, topic):
return model_query(context, models.Service, read_deleted="no").\
filter_by(disabled=False).\
diff --git a/nova/tests/api/openstack/compute/contrib/test_hosts.py b/nova/tests/api/openstack/compute/contrib/test_hosts.py
index be4465cf9..e103b5b19 100644
--- a/nova/tests/api/openstack/compute/contrib/test_hosts.py
+++ b/nova/tests/api/openstack/compute/contrib/test_hosts.py
@@ -32,8 +32,10 @@ def stub_service_get_all(context, disabled=None):
return fake_hosts.SERVICES_LIST
-def stub_service_does_host_exist(context, host_name):
- return host_name in [row['host'] for row in stub_service_get_all(context)]
+def stub_service_get_by_host_and_topic(context, host_name, topic):
+ for service in stub_service_get_all(context):
+ if service['host'] == host_name and service['topic'] == topic:
+ return service
def stub_set_host_enabled(context, host_name, enabled):
@@ -130,8 +132,8 @@ class HostTestCase(test.TestCase):
self.stubs.Set(db, 'service_get_all',
stub_service_get_all)
# Only hosts in our fake DB exist
- self.stubs.Set(db, 'service_does_host_exist',
- stub_service_does_host_exist)
+ self.stubs.Set(db, 'service_get_by_host_and_topic',
+ stub_service_get_by_host_and_topic)
# 'host_c1' always succeeds, and 'host_c2'
self.stubs.Set(self.hosts_api, 'set_host_enabled',
stub_set_host_enabled)
diff --git a/nova/tests/api/openstack/compute/contrib/test_networks.py b/nova/tests/api/openstack/compute/contrib/test_networks.py
index ba65e8f6a..44d9e8af3 100644
--- a/nova/tests/api/openstack/compute/contrib/test_networks.py
+++ b/nova/tests/api/openstack/compute/contrib/test_networks.py
@@ -21,8 +21,8 @@ import uuid
import webob
-from nova.api.openstack.compute.contrib import admin_networks as networks
from nova.api.openstack.compute.contrib import networks_associate
+from nova.api.openstack.compute.contrib import os_networks as networks
from nova import exception
from nova.openstack.common import cfg
from nova import test
@@ -177,7 +177,7 @@ class NetworksTest(test.TestCase):
def setUp(self):
super(NetworksTest, self).setUp()
self.fake_network_api = FakeNetworkAPI()
- self.controller = networks.AdminNetworkController(
+ self.controller = networks.NetworkController(
self.fake_network_api)
self.associate_controller = networks_associate\
.NetworkAssociateActionController(self.fake_network_api)
diff --git a/nova/tests/api/openstack/compute/contrib/test_services.py b/nova/tests/api/openstack/compute/contrib/test_services.py
index 24f169d98..1bd47b67a 100644
--- a/nova/tests/api/openstack/compute/contrib/test_services.py
+++ b/nova/tests/api/openstack/compute/contrib/test_services.py
@@ -26,30 +26,30 @@ from nova.tests.api.openstack import fakes
fake_services_list = [{'binary': 'nova-scheduler',
'host': 'host1',
- 'availability_zone': 'nova',
'id': 1,
'disabled': True,
+ 'topic': 'scheduler',
'updated_at': datetime(2012, 10, 29, 13, 42, 2),
'created_at': datetime(2012, 9, 18, 2, 46, 27)},
{'binary': 'nova-compute',
'host': 'host1',
- 'availability_zone': 'nova',
'id': 2,
'disabled': True,
+ 'topic': 'compute',
'updated_at': datetime(2012, 10, 29, 13, 42, 5),
'created_at': datetime(2012, 9, 18, 2, 46, 27)},
{'binary': 'nova-scheduler',
'host': 'host2',
- 'availability_zone': 'nova',
'id': 3,
'disabled': False,
+ 'topic': 'scheduler',
'updated_at': datetime(2012, 9, 19, 6, 55, 34),
'created_at': datetime(2012, 9, 18, 2, 46, 28)},
{'binary': 'nova-compute',
'host': 'host2',
- 'availability_zone': 'nova',
'id': 4,
'disabled': True,
+ 'topic': 'compute',
'updated_at': datetime(2012, 9, 18, 8, 3, 38),
'created_at': datetime(2012, 9, 18, 2, 46, 28)},
]
@@ -75,7 +75,7 @@ class FakeRequestWithHostService(object):
GET = {"host": "host1", "service": "nova-compute"}
-def fake_servcie_get_all(context):
+def fake_service_get_all(context):
return fake_services_list
@@ -111,7 +111,7 @@ class ServicesTest(test.TestCase):
def setUp(self):
super(ServicesTest, self).setUp()
- self.stubs.Set(db, "service_get_all", fake_servcie_get_all)
+ self.stubs.Set(db, "service_get_all", fake_service_get_all)
self.stubs.Set(timeutils, "utcnow", fake_utcnow)
self.stubs.Set(db, "service_get_by_args",
fake_service_get_by_host_binary)
@@ -128,7 +128,7 @@ class ServicesTest(test.TestCase):
res_dict = self.controller.index(req)
response = {'services': [{'binary': 'nova-scheduler',
- 'host': 'host1', 'zone': 'nova',
+ 'host': 'host1', 'zone': 'internal',
'status': 'disabled', 'state': 'up',
'updated_at': datetime(2012, 10, 29, 13, 42, 2)},
{'binary': 'nova-compute',
@@ -136,7 +136,7 @@ class ServicesTest(test.TestCase):
'status': 'disabled', 'state': 'up',
'updated_at': datetime(2012, 10, 29, 13, 42, 5)},
{'binary': 'nova-scheduler', 'host': 'host2',
- 'zone': 'nova',
+ 'zone': 'internal',
'status': 'enabled', 'state': 'down',
'updated_at': datetime(2012, 9, 19, 6, 55, 34)},
{'binary': 'nova-compute', 'host': 'host2',
@@ -150,7 +150,7 @@ class ServicesTest(test.TestCase):
res_dict = self.controller.index(req)
response = {'services': [{'binary': 'nova-scheduler', 'host': 'host1',
- 'zone': 'nova',
+ 'zone': 'internal',
'status': 'disabled', 'state': 'up',
'updated_at': datetime(2012, 10, 29, 13, 42, 2)},
{'binary': 'nova-compute', 'host': 'host1',
diff --git a/nova/tests/api/openstack/compute/test_extensions.py b/nova/tests/api/openstack/compute/test_extensions.py
index e3810510b..485968209 100644
--- a/nova/tests/api/openstack/compute/test_extensions.py
+++ b/nova/tests/api/openstack/compute/test_extensions.py
@@ -185,7 +185,6 @@ class ExtensionControllerTest(ExtensionTestCase):
"Keypairs",
"Multinic",
"MultipleCreate",
- "OSNetworks",
"QuotaClasses",
"Quotas",
"Rescue",
diff --git a/nova/tests/compute/test_compute.py b/nova/tests/compute/test_compute.py
index 40bc8d148..0d9f67231 100644
--- a/nova/tests/compute/test_compute.py
+++ b/nova/tests/compute/test_compute.py
@@ -1000,8 +1000,7 @@ class ComputeTestCase(BaseTestCase):
# This is a true unit test, so we don't need the network stubs.
fake_network.unset_stub_network_methods(self.stubs)
- self.mox.StubOutWithMock(network_model.NetworkInfo,
- 'hydrate')
+ self.mox.StubOutWithMock(self.compute, '_get_instance_nw_info')
self.mox.StubOutWithMock(self.compute, '_notify_about_instance_usage')
self.mox.StubOutWithMock(self.compute, '_instance_update')
self.mox.StubOutWithMock(self.compute, '_get_power_state')
@@ -1010,8 +1009,11 @@ class ComputeTestCase(BaseTestCase):
instance = dict(uuid='fake-instance',
power_state='unknown')
+ updated_instance1 = dict(uuid='updated-instance1',
+ power_state='fake')
+ updated_instance2 = dict(uuid='updated-instance2',
+ power_state='fake')
- fake_nw_info = 'fake-network-info'
fake_nw_model = network_model.NetworkInfo()
self.mox.StubOutWithMock(fake_nw_model, 'legacy')
@@ -1031,8 +1033,9 @@ class ComputeTestCase(BaseTestCase):
self.mox.StubOutWithMock(self.context, 'elevated')
self.context.elevated().AndReturn(econtext)
- network_model.NetworkInfo.hydrate(fake_nw_info).AndReturn(
- fake_nw_model)
+ self.compute._get_instance_nw_info(econtext,
+ instance).AndReturn(
+ fake_nw_model)
self.compute._notify_about_instance_usage(econtext,
instance,
'reboot.start')
@@ -1040,7 +1043,7 @@ class ComputeTestCase(BaseTestCase):
instance).AndReturn(fake_power_state1)
self.compute._instance_update(econtext, instance['uuid'],
power_state=fake_power_state1,
- vm_state=vm_states.ACTIVE)
+ vm_state=vm_states.ACTIVE).AndReturn(updated_instance1)
# Reboot should check the driver to see if legacy nwinfo is
# needed. If it is, the model's legacy() method should be
@@ -1058,7 +1061,7 @@ class ComputeTestCase(BaseTestCase):
# this is called with the wrong args, so we have to hack
# around it.
reboot_call_info = {}
- expected_call_info = {'args': (instance, expected_nw_info,
+ expected_call_info = {'args': (updated_instance1, expected_nw_info,
reboot_type, fake_block_dev_info),
'kwargs': {}}
@@ -1070,19 +1073,18 @@ class ComputeTestCase(BaseTestCase):
# Power state should be updated again
self.compute._get_power_state(econtext,
- instance).AndReturn(fake_power_state2)
- self.compute._instance_update(econtext, instance['uuid'],
+ updated_instance1).AndReturn(fake_power_state2)
+ self.compute._instance_update(econtext, updated_instance1['uuid'],
power_state=fake_power_state2,
task_state=None,
- vm_state=vm_states.ACTIVE)
+ vm_state=vm_states.ACTIVE).AndReturn(updated_instance2)
self.compute._notify_about_instance_usage(econtext,
- instance,
+ updated_instance2,
'reboot.end')
self.mox.ReplayAll()
self.compute.reboot_instance(self.context, instance=instance,
block_device_info=fake_block_dev_info,
- network_info=fake_nw_info,
reboot_type=reboot_type)
self.assertEqual(expected_call_info, reboot_call_info)
@@ -4233,12 +4235,10 @@ class ComputeAPITestCase(BaseTestCase):
def _stub_out_reboot(self, device_name):
def fake_reboot_instance(rpcapi, context, instance,
block_device_info,
- network_info,
reboot_type):
self.assertEqual(
block_device_info['block_device_mapping'][0]['mount_device'],
device_name)
- self.assertEqual(network_info[0]['network']['bridge'], 'fake_br1')
self.stubs.Set(nova.compute.rpcapi.ComputeAPI, 'reboot_instance',
fake_reboot_instance)
@@ -6151,81 +6151,6 @@ class ComputePolicyTestCase(BaseTestCase):
availability_zone='1:1')
-class ComputeHostAPITestCase(BaseTestCase):
- def setUp(self):
- super(ComputeHostAPITestCase, self).setUp()
- self.host_api = compute_api.HostAPI()
-
- def _rpc_call_stub(self, call_info):
- def fake_rpc_call(context, topic, msg, timeout=None):
- call_info['context'] = context
- call_info['topic'] = topic
- call_info['msg'] = msg
- self.stubs.Set(rpc, 'call', fake_rpc_call)
-
- def _pretend_fake_host_exists(self, ctxt):
- """Sets it so that the host API always thinks that 'fake_host'
- exists"""
- self.mox.StubOutWithMock(self.host_api, 'does_host_exist')
- self.host_api.does_host_exist(ctxt, 'fake_host').AndReturn(True)
- self.mox.ReplayAll()
-
- def test_set_host_enabled(self):
- ctxt = context.get_admin_context()
- call_info = {}
- self._rpc_call_stub(call_info)
-
- self._pretend_fake_host_exists(ctxt)
- self.host_api.set_host_enabled(ctxt, 'fake_host', 'fake_enabled')
- self.assertEqual(call_info['context'], ctxt)
- self.assertEqual(call_info['topic'], 'compute.fake_host')
- self.assertEqual(call_info['msg'],
- {'method': 'set_host_enabled',
- 'args': {'enabled': 'fake_enabled'},
- 'version': compute_rpcapi.ComputeAPI.BASE_RPC_API_VERSION})
-
- def test_get_host_uptime(self):
- ctxt = context.RequestContext('fake', 'fake')
- call_info = {}
- self._rpc_call_stub(call_info)
-
- self._pretend_fake_host_exists(ctxt)
- self.host_api.get_host_uptime(ctxt, 'fake_host')
- self.assertEqual(call_info['context'], ctxt)
- self.assertEqual(call_info['topic'], 'compute.fake_host')
- self.assertEqual(call_info['msg'],
- {'method': 'get_host_uptime',
- 'args': {},
- 'version': compute_rpcapi.ComputeAPI.BASE_RPC_API_VERSION})
-
- def test_host_power_action(self):
- ctxt = context.get_admin_context()
- call_info = {}
- self._rpc_call_stub(call_info)
- self._pretend_fake_host_exists(ctxt)
- self.host_api.host_power_action(ctxt, 'fake_host', 'fake_action')
- self.assertEqual(call_info['context'], ctxt)
- self.assertEqual(call_info['topic'], 'compute.fake_host')
- self.assertEqual(call_info['msg'],
- {'method': 'host_power_action',
- 'args': {'action': 'fake_action'},
- 'version':
- compute_rpcapi.ComputeAPI.BASE_RPC_API_VERSION})
-
- def test_set_host_maintenance(self):
- ctxt = context.get_admin_context()
- call_info = {}
- self._rpc_call_stub(call_info)
- self._pretend_fake_host_exists(ctxt)
- self.host_api.set_host_maintenance(ctxt, 'fake_host', 'fake_mode')
- self.assertEqual(call_info['context'], ctxt)
- self.assertEqual(call_info['topic'], 'compute.fake_host')
- self.assertEqual(call_info['msg'],
- {'method': 'host_maintenance_mode',
- 'args': {'host': 'fake_host', 'mode': 'fake_mode'},
- 'version': compute_rpcapi.ComputeAPI.BASE_RPC_API_VERSION})
-
-
class KeypairAPITestCase(BaseTestCase):
def setUp(self):
super(KeypairAPITestCase, self).setUp()
diff --git a/nova/tests/compute/test_host_api.py b/nova/tests/compute/test_host_api.py
index 0af1d6766..95d3c4926 100644
--- a/nova/tests/compute/test_host_api.py
+++ b/nova/tests/compute/test_host_api.py
@@ -13,93 +13,114 @@
# License for the specific language governing permissions and limitations
# under the License.
-from nova.compute import api
+from nova import compute
+from nova.compute import rpcapi as compute_rpcapi
from nova import context
-from nova import db
-from nova import exception
+from nova.openstack.common import rpc
from nova import test
-from nova.tests import fake_hosts
-class HostApiTestCase(test.TestCase):
- """
- Tests 'host' subset of the compute api
- """
-
+class ComputeHostAPITestCase(test.TestCase):
def setUp(self):
- super(HostApiTestCase, self).setUp()
- self.compute_rpcapi = api.compute_rpcapi
- self.api = api.HostAPI()
+ super(ComputeHostAPITestCase, self).setUp()
+ self.host_api = compute.HostAPI()
+ self.ctxt = context.get_admin_context()
- def test_bad_host_set_enabled(self):
- """
- Tests that actions on single hosts that don't exist blow up without
- having to reach the host via rpc. Should raise HostNotFound if you
- try to update a host that is not in the DB
+ def _mock_rpc_call(self, expected_message, result=None):
+ if result is None:
+ result = 'fake-result'
+ self.mox.StubOutWithMock(rpc, 'call')
+ rpc.call(self.ctxt, 'compute.fake_host',
+ expected_message, None).AndReturn(result)
+
+ def _mock_assert_host_exists(self):
+ """Sets it so that the host API always thinks that 'fake_host'
+ exists.
"""
- self.assertRaises(exception.HostNotFound, self.api.set_host_enabled,
- context.get_admin_context(), "bogus_host_name", False)
+ self.mox.StubOutWithMock(self.host_api, '_assert_host_exists')
+ self.host_api._assert_host_exists(self.ctxt, 'fake_host')
+
+ def test_set_host_enabled(self):
+ self._mock_assert_host_exists()
+ self._mock_rpc_call(
+ {'method': 'set_host_enabled',
+ 'args': {'enabled': 'fake_enabled'},
+ 'version': compute_rpcapi.ComputeAPI.BASE_RPC_API_VERSION})
+
+ self.mox.ReplayAll()
+ result = self.host_api.set_host_enabled(self.ctxt, 'fake_host',
+ 'fake_enabled')
+ self.assertEqual('fake-result', result)
+
+ def test_get_host_uptime(self):
+ self._mock_assert_host_exists()
+ self._mock_rpc_call(
+ {'method': 'get_host_uptime',
+ 'args': {},
+ 'version': compute_rpcapi.ComputeAPI.BASE_RPC_API_VERSION})
+ self.mox.ReplayAll()
+ result = self.host_api.get_host_uptime(self.ctxt, 'fake_host')
+ self.assertEqual('fake-result', result)
+
+ def test_host_power_action(self):
+ self._mock_assert_host_exists()
+ self._mock_rpc_call(
+ {'method': 'host_power_action',
+ 'args': {'action': 'fake_action'},
+ 'version': compute_rpcapi.ComputeAPI.BASE_RPC_API_VERSION})
+ self.mox.ReplayAll()
+ result = self.host_api.host_power_action(self.ctxt, 'fake_host',
+ 'fake_action')
+ self.assertEqual('fake-result', result)
- def test_list_compute_hosts(self):
- ctx = context.get_admin_context()
- self.mox.StubOutWithMock(db, 'service_get_all')
- db.service_get_all(ctx, False).AndReturn(fake_hosts.SERVICES_LIST)
+ def test_set_host_maintenance(self):
+ self._mock_assert_host_exists()
+ self._mock_rpc_call(
+ {'method': 'host_maintenance_mode',
+ 'args': {'host': 'fake_host', 'mode': 'fake_mode'},
+ 'version': compute_rpcapi.ComputeAPI.BASE_RPC_API_VERSION})
self.mox.ReplayAll()
- compute_hosts = self.api.list_hosts(ctx, service="compute")
+ result = self.host_api.set_host_maintenance(self.ctxt, 'fake_host',
+ 'fake_mode')
+ self.assertEqual('fake-result', result)
+
+ def test_service_get_all(self):
+ services = [dict(id=1, key1='val1', key2='val2', topic='compute',
+ host='host1'),
+ dict(id=2, key1='val2', key3='val3', topic='compute',
+ host='host2')]
+ exp_services = []
+ for service in services:
+ exp_service = {}
+ exp_service.update(availability_zone='nova', **service)
+ exp_services.append(exp_service)
+
+ self.mox.StubOutWithMock(self.host_api.db,
+ 'service_get_all')
+
+ # Test no filters
+ self.host_api.db.service_get_all(self.ctxt, False).AndReturn(
+ services)
+ self.mox.ReplayAll()
+ result = self.host_api.service_get_all(self.ctxt)
self.mox.VerifyAll()
- expected = [host for host in fake_hosts.HOST_LIST
- if host["service"] == "compute"]
- self.assertEqual(expected, compute_hosts)
+ self.assertEqual(exp_services, result)
- def test_describe_host(self):
- """
- Makes sure that describe_host returns the correct information
- given our fake input.
- """
- ctx = context.get_admin_context()
- self.mox.StubOutWithMock(db, 'service_get_by_compute_host')
- host_name = 'host_c1'
- db.service_get_by_compute_host(ctx, host_name).AndReturn(
- {'host': 'fake_host',
- 'compute_node': [
- {'vcpus': 4,
- 'vcpus_used': 1,
- 'memory_mb': 8192,
- 'memory_mb_used': 2048,
- 'local_gb': 1024,
- 'local_gb_used': 648}
- ]
- })
- self.mox.StubOutWithMock(db, 'instance_get_all_by_host')
- db.instance_get_all_by_host(ctx, 'fake_host').AndReturn(
- [{'project_id': 42,
- 'vcpus': 1,
- 'memory_mb': 2048,
- 'root_gb': 648,
- 'ephemeral_gb': 0,
- }])
+ # Test no filters #2
+ self.mox.ResetAll()
+ self.host_api.db.service_get_all(self.ctxt, False).AndReturn(
+ services)
+ self.mox.ReplayAll()
+ result = self.host_api.service_get_all(self.ctxt, filters={})
+ self.mox.VerifyAll()
+ self.assertEqual(exp_services, result)
+
+ # Test w/ filter
+ self.mox.ResetAll()
+ self.host_api.db.service_get_all(self.ctxt, False).AndReturn(
+ services)
self.mox.ReplayAll()
- result = self.api.describe_host(ctx, host_name)
- self.assertEqual(result,
- [{'resource': {'cpu': 4,
- 'disk_gb': 1024,
- 'host': 'host_c1',
- 'memory_mb': 8192,
- 'project': '(total)'}},
- {'resource': {'cpu': 1,
- 'disk_gb': 648,
- 'host': 'host_c1',
- 'memory_mb': 2048,
- 'project': '(used_now)'}},
- {'resource': {'cpu': 1,
- 'disk_gb': 648,
- 'host': 'host_c1',
- 'memory_mb': 2048,
- 'project': '(used_max)'}},
- {'resource': {'cpu': 1,
- 'disk_gb': 648,
- 'host': 'host_c1',
- 'memory_mb': 2048,
- 'project': 42}}]
- )
+ result = self.host_api.service_get_all(self.ctxt,
+ filters=dict(key1='val2'))
self.mox.VerifyAll()
+ self.assertEqual([exp_services[1]], result)
diff --git a/nova/tests/compute/test_rpcapi.py b/nova/tests/compute/test_rpcapi.py
index a31d9a14b..00b90ea65 100644
--- a/nova/tests/compute/test_rpcapi.py
+++ b/nova/tests/compute/test_rpcapi.py
@@ -236,9 +236,8 @@ class ComputeRpcAPITestCase(test.TestCase):
self._test_compute_api('reboot_instance', 'cast',
instance=self.fake_instance,
block_device_info={},
- network_info={},
reboot_type='type',
- version='2.5')
+ version='2.23')
def test_rebuild_instance(self):
self._test_compute_api('rebuild_instance', 'cast',
diff --git a/nova/tests/fake_policy.py b/nova/tests/fake_policy.py
index c5d160209..51f3a3f85 100644
--- a/nova/tests/fake_policy.py
+++ b/nova/tests/fake_policy.py
@@ -136,10 +136,10 @@ policy_data = """
"compute_extension:instance_usage_audit_log": "",
"compute_extension:keypairs": "",
"compute_extension:multinic": "",
- "compute_extension:admin_networks": "",
- "compute_extension:admin_networks:view": "",
+ "compute_extension:networks": "",
+ "compute_extension:networks:view": "",
"compute_extension:networks_associate": "",
- "compute_extension:os-networks": "",
+ "compute_extension:os-tenant-networks": "",
"compute_extension:quotas:show": "",
"compute_extension:quotas:update": "",
"compute_extension:quota_classes": "",
diff --git a/nova/tests/integrated/api_samples/all_extensions/extensions-get-resp.json.tpl b/nova/tests/integrated/api_samples/all_extensions/extensions-get-resp.json.tpl
index 0dd777fe2..3d69fad45 100644
--- a/nova/tests/integrated/api_samples/all_extensions/extensions-get-resp.json.tpl
+++ b/nova/tests/integrated/api_samples/all_extensions/extensions-get-resp.json.tpl
@@ -305,19 +305,19 @@
"updated": "%(timestamp)s"
},
{
- "alias": "os-admin-networks",
+ "alias": "os-networks",
"description": "%(text)s",
"links": [],
- "name": "AdminNetworks",
- "namespace": "http://docs.openstack.org/compute/ext/os-admin-networks/api/v1.1",
+ "name": "Networks",
+ "namespace": "http://docs.openstack.org/compute/ext/os-networks/api/v1.1",
"updated": "%(timestamp)s"
},
{
- "alias": "os-networks",
+ "alias": "os-tenant-networks",
"description": "%(text)s",
"links": [],
- "name": "OSNetworks",
- "namespace": "http://docs.openstack.org/compute/ext/os-networks/api/v1.1",
+ "name": "OSTenantNetworks",
+ "namespace": "http://docs.openstack.org/compute/ext/os-tenant-networks/api/v2",
"updated": "%(timestamp)s"
},
{
diff --git a/nova/tests/integrated/api_samples/all_extensions/extensions-get-resp.xml.tpl b/nova/tests/integrated/api_samples/all_extensions/extensions-get-resp.xml.tpl
index fe34f369b..5953ba704 100644
--- a/nova/tests/integrated/api_samples/all_extensions/extensions-get-resp.xml.tpl
+++ b/nova/tests/integrated/api_samples/all_extensions/extensions-get-resp.xml.tpl
@@ -114,10 +114,10 @@
<extension alias="os-multiple-create" updated="%(timestamp)s" namespace="http://docs.openstack.org/compute/ext/multiplecreate/api/v1.1" name="MultipleCreate">
<description>%(text)s</description>
</extension>
- <extension alias="os-admin-networks" updated="%(timestamp)s" namespace="http://docs.openstack.org/compute/ext/os-admin-networks/api/v1.1" name="AdminNetworks">
+ <extension alias="os-networks" updated="%(timestamp)s" namespace="http://docs.openstack.org/compute/ext/os-networks/api/v1.1" name="Networks">
<description>%(text)s</description>
</extension>
- <extension alias="os-networks" updated="%(timestamp)s" namespace="http://docs.openstack.org/compute/ext/os-networks/api/v1.1" name="OSNetworks">
+ <extension alias="os-tenant-networks" updated="%(timestamp)s" namespace="http://docs.openstack.org/compute/ext/os-tenant-networks/api/v2" name="OSTenantNetworks">
<description>%(text)s</description>
</extension>
<extension alias="os-networks-associate" updated="%(timestamp)s" namespace="http://docs.openstack.org/compute/ext/networks_associate/api/v2" name="NetworkAssociationSupport">
diff --git a/nova/tests/integrated/api_samples/os-networks/networks-list-res.json.tpl b/nova/tests/integrated/api_samples/os-tenant-networks/networks-list-res.json.tpl
index 757084d2f..757084d2f 100644
--- a/nova/tests/integrated/api_samples/os-networks/networks-list-res.json.tpl
+++ b/nova/tests/integrated/api_samples/os-tenant-networks/networks-list-res.json.tpl
diff --git a/nova/tests/integrated/api_samples/os-networks/networks-post-req.json.tpl b/nova/tests/integrated/api_samples/os-tenant-networks/networks-post-req.json.tpl
index fb1c2d3d0..fb1c2d3d0 100644
--- a/nova/tests/integrated/api_samples/os-networks/networks-post-req.json.tpl
+++ b/nova/tests/integrated/api_samples/os-tenant-networks/networks-post-req.json.tpl
diff --git a/nova/tests/integrated/api_samples/os-networks/networks-post-res.json.tpl b/nova/tests/integrated/api_samples/os-tenant-networks/networks-post-res.json.tpl
index ff9e2273d..ff9e2273d 100644
--- a/nova/tests/integrated/api_samples/os-networks/networks-post-res.json.tpl
+++ b/nova/tests/integrated/api_samples/os-tenant-networks/networks-post-res.json.tpl
diff --git a/nova/tests/integrated/test_api_samples.py b/nova/tests/integrated/test_api_samples.py
index 0fb0e9107..98ac6a230 100644
--- a/nova/tests/integrated/test_api_samples.py
+++ b/nova/tests/integrated/test_api_samples.py
@@ -371,7 +371,7 @@ class ApiSamplesTrap(ApiSampleTestBase):
do_not_approve_additions.append('os-fping')
do_not_approve_additions.append('os-hypervisors')
do_not_approve_additions.append('os-instance_usage_audit_log')
- do_not_approve_additions.append('os-admin-networks')
+ do_not_approve_additions.append('os-networks')
do_not_approve_additions.append('os-services')
do_not_approve_additions.append('os-volumes')
@@ -2359,8 +2359,8 @@ class DiskConfigXmlTest(DiskConfigJsonTest):
class OsNetworksJsonTests(ApiSampleTestBase):
- extension_name = ("nova.api.openstack.compute.contrib.os_networks"
- ".Os_networks")
+ extension_name = ("nova.api.openstack.compute.contrib.os_tenant_networks"
+ ".Os_tenant_networks")
def setUp(self):
super(OsNetworksJsonTests, self).setUp()
@@ -2377,21 +2377,22 @@ class OsNetworksJsonTests(ApiSampleTestBase):
self.stubs.Set(nova.quota.QuotaEngine, "rollback", fake)
def test_list_networks(self):
- response = self._do_get('os-networks')
+ response = self._do_get('os-tenant-networks')
self.assertEqual(response.status, 200)
subs = self._get_regexes()
return self._verify_response('networks-list-res', subs, response)
def test_create_network(self):
- response = self._do_post('os-networks', "networks-post-req", {})
+ response = self._do_post('os-tenant-networks', "networks-post-req", {})
self.assertEqual(response.status, 200)
subs = self._get_regexes()
self._verify_response('networks-post-res', subs, response)
- def test_delete_networK(self):
- response = self._do_post('os-networks', "networks-post-req", {})
+ def test_delete_network(self):
+ response = self._do_post('os-tenant-networks', "networks-post-req", {})
net = json.loads(response.read())
- response = self._do_delete('os-networks/%s' % net["network"]["id"])
+ response = self._do_delete('os-tenant-networks/%s' %
+ net["network"]["id"])
self.assertEqual(response.status, 202)
@@ -2406,7 +2407,7 @@ class NetworksAssociateJsonTests(ApiSampleTestBase):
f['osapi_compute_extension'] = CONF.osapi_compute_extension[:]
# Networks_associate requires Networks to be update
f['osapi_compute_extension'].append(
- 'nova.api.openstack.compute.contrib.admin_networks.Admin_networks')
+ 'nova.api.openstack.compute.contrib.os_networks.Os_networks')
return f
def setUp(self):
@@ -2420,25 +2421,25 @@ class NetworksAssociateJsonTests(ApiSampleTestBase):
self.stubs.Set(network_api.API, "associate", fake_associate)
def test_disassociate(self):
- response = self._do_post('os-admin-networks/1/action',
+ response = self._do_post('os-networks/1/action',
'network-disassociate-req',
{})
self.assertEqual(response.status, 202)
def test_disassociate_host(self):
- response = self._do_post('os-admin-networks/1/action',
+ response = self._do_post('os-networks/1/action',
'network-disassociate-host-req',
{})
self.assertEqual(response.status, 202)
def test_disassociate_project(self):
- response = self._do_post('os-admin-networks/1/action',
+ response = self._do_post('os-networks/1/action',
'network-disassociate-project-req',
{})
self.assertEqual(response.status, 202)
def test_associate_host(self):
- response = self._do_post('os-admin-networks/1/action',
+ response = self._do_post('os-networks/1/action',
'network-associate-host-req',
{"host": "testHost"})
self.assertEqual(response.status, 202)
diff --git a/nova/tests/test_metadata.py b/nova/tests/test_metadata.py
index 29e63aba7..f15d71633 100644
--- a/nova/tests/test_metadata.py
+++ b/nova/tests/test_metadata.py
@@ -342,7 +342,7 @@ class OpenStackMetadataTestCase(test.TestCase):
mdinst = fake_InstanceMetadata(self.stubs, inst)
# since this instance had no user-data it should not be there.
- self.assertFalse('user-data' in mdinst.lookup("/openstack/2012-08-10"))
+ self.assertFalse('user_data' in mdinst.lookup("/openstack/2012-08-10"))
self.assertRaises(base.InvalidMetadataPath,
mdinst.lookup, "/openstack/2012-08-10/user_data")
@@ -362,6 +362,14 @@ class OpenStackMetadataTestCase(test.TestCase):
mdjson = mdinst.lookup("/openstack/2012-08-10/meta_data.json")
self.assertFalse("random_seed" in json.loads(mdjson))
+ def test_no_dashes_in_metadata(self):
+ # top level entries in meta_data should not contain '-' in their name
+ inst = copy(self.instance)
+ mdinst = fake_InstanceMetadata(self.stubs, inst)
+ mdjson = json.loads(mdinst.lookup("/openstack/latest/meta_data.json"))
+
+ self.assertEqual([], [k for k in mdjson.keys() if k.find("-") != -1])
+
class MetadataHandlerTestCase(test.TestCase):
"""Test that metadata is returning proper values."""