Merge "Move logic from os-api-host into compute"
This commit is contained in:
commit
ec120d52b5
@ -22,9 +22,7 @@ from xml.parsers import expat
|
||||
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.compute import api as compute_api
|
||||
from nova import db
|
||||
from nova import compute
|
||||
from nova import exception
|
||||
from nova.openstack.common import log as logging
|
||||
|
||||
@ -94,140 +92,162 @@ class HostUpdateDeserializer(wsgi.XMLDeserializer):
|
||||
return dict(body=updates)
|
||||
|
||||
|
||||
def _list_hosts(req):
|
||||
"""Returns a summary list of hosts, optionally filtering
|
||||
by service type.
|
||||
"""
|
||||
context = req.environ['nova.context']
|
||||
services = db.service_get_all(context, False)
|
||||
services = availability_zones.set_availability_zones(context, services)
|
||||
zone = ''
|
||||
if 'zone' in req.GET:
|
||||
zone = req.GET['zone']
|
||||
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']})
|
||||
return hosts
|
||||
|
||||
|
||||
def check_host(fn):
|
||||
"""Makes sure that the host exists."""
|
||||
def wrapped(self, req, id, *args, **kwargs):
|
||||
listed_hosts = _list_hosts(req)
|
||||
hosts = [h["host_name"] for h in listed_hosts]
|
||||
if id in hosts:
|
||||
return fn(self, req, id, *args, **kwargs)
|
||||
else:
|
||||
message = _("Host '%s' could not be found.") % id
|
||||
raise webob.exc.HTTPNotFound(explanation=message)
|
||||
return wrapped
|
||||
|
||||
|
||||
class HostController(object):
|
||||
"""The Hosts API controller for the OpenStack API."""
|
||||
def __init__(self):
|
||||
self.api = compute_api.HostAPI()
|
||||
self.api = compute.HostAPI()
|
||||
super(HostController, self).__init__()
|
||||
|
||||
@wsgi.serializers(xml=HostIndexTemplate)
|
||||
def index(self, req):
|
||||
authorize(req.environ['nova.context'])
|
||||
return {'hosts': _list_hosts(req)}
|
||||
"""
|
||||
:returns: A dict in the format:
|
||||
|
||||
{'hosts': [{'host_name': 'some.host.name',
|
||||
'service': 'cells'},
|
||||
{'host_name': 'some.other.host.name',
|
||||
'service': 'cells'},
|
||||
{'host_name': 'some.celly.host.name',
|
||||
'service': 'cells'},
|
||||
{'host_name': 'console1.host.com',
|
||||
'service': 'consoleauth'},
|
||||
{'host_name': 'network1.host.com',
|
||||
'service': 'network'},
|
||||
{'host_name': 'netwwork2.host.com',
|
||||
'service': 'network'},
|
||||
{'host_name': 'sched1.host.com',
|
||||
'service': 'scheduler'},
|
||||
{'host_name': 'sched2.host.com',
|
||||
'service': 'scheduler'},
|
||||
{'host_name': 'vol1.host.com',
|
||||
'service': 'volume'}]}
|
||||
"""
|
||||
context = req.environ['nova.context']
|
||||
authorize(context)
|
||||
zone = req.GET.get('zone', None)
|
||||
data = self.api.list_hosts(context, zone)
|
||||
|
||||
return {'hosts': data}
|
||||
|
||||
@wsgi.serializers(xml=HostUpdateTemplate)
|
||||
@wsgi.deserializers(xml=HostUpdateDeserializer)
|
||||
@check_host
|
||||
def update(self, req, id, body):
|
||||
authorize(req.environ['nova.context'])
|
||||
update_values = {}
|
||||
for raw_key, raw_val in body.iteritems():
|
||||
key = raw_key.lower().strip()
|
||||
val = raw_val.lower().strip()
|
||||
if key == "status":
|
||||
if val in ("enable", "disable"):
|
||||
update_values['status'] = val.startswith("enable")
|
||||
else:
|
||||
explanation = _("Invalid status: '%s'") % raw_val
|
||||
raise webob.exc.HTTPBadRequest(explanation=explanation)
|
||||
elif key == "maintenance_mode":
|
||||
if val not in ['enable', 'disable']:
|
||||
explanation = _("Invalid mode: '%s'") % raw_val
|
||||
raise webob.exc.HTTPBadRequest(explanation=explanation)
|
||||
update_values['maintenance_mode'] = val == 'enable'
|
||||
"""
|
||||
:param body: example format {'status': 'enable',
|
||||
'maintenance_mode': 'enable'}
|
||||
:returns:
|
||||
"""
|
||||
def read_enabled(orig_val, msg):
|
||||
"""
|
||||
:param orig_val: A string with either 'enable' or 'disable'. May
|
||||
be surrounded by whitespace, and case doesn't
|
||||
matter
|
||||
:param msg: The message to be passed to HTTPBadRequest. A single
|
||||
%s will be replaced with orig_val.
|
||||
:returns: True for 'enabled' and False for 'disabled'
|
||||
"""
|
||||
val = orig_val.strip().lower()
|
||||
if val == "enable":
|
||||
return True
|
||||
elif val == "disable":
|
||||
return False
|
||||
else:
|
||||
explanation = _("Invalid update setting: '%s'") % raw_key
|
||||
raise webob.exc.HTTPBadRequest(explanation=explanation)
|
||||
|
||||
# this is for handling multiple settings at the same time:
|
||||
# the result dictionaries are merged in the first one.
|
||||
# Note: the 'host' key will always be the same so it's
|
||||
# okay that it gets overwritten.
|
||||
update_setters = {'status': self._set_enabled_status,
|
||||
'maintenance_mode': self._set_host_maintenance}
|
||||
result = {}
|
||||
for key, value in update_values.iteritems():
|
||||
result.update(update_setters[key](req, id, value))
|
||||
raise webob.exc.HTTPBadRequest(explanation=msg % orig_val)
|
||||
context = req.environ['nova.context']
|
||||
authorize(context)
|
||||
# See what the user wants to 'update'
|
||||
params = dict([(k.strip().lower(), v) for k, v in body.iteritems()])
|
||||
orig_status = status = params.pop('status', None)
|
||||
orig_maint_mode = maint_mode = params.pop('maintenance_mode', None)
|
||||
# Validate the request
|
||||
if len(params) > 0:
|
||||
# Some extra param was passed. Fail.
|
||||
explanation = _("Invalid update setting: '%s'") % params.keys()[0]
|
||||
raise webob.exc.HTTPBadRequest(explanation=explanation)
|
||||
if orig_status is not None:
|
||||
status = read_enabled(orig_status, _("Invalid status: '%s'"))
|
||||
if orig_maint_mode is not None:
|
||||
maint_mode = read_enabled(orig_maint_mode, _("Invalid mode: '%s'"))
|
||||
if status is None and maint_mode is None:
|
||||
explanation = _("'status' or 'maintenance_mode' needed for "
|
||||
"host update")
|
||||
raise webob.exc.HTTPBadRequest(explanation=explanation)
|
||||
# Make the calls and merge the results
|
||||
result = {'host': id}
|
||||
if status is not None:
|
||||
result['status'] = self._set_enabled_status(context, id, status)
|
||||
if maint_mode is not None:
|
||||
result['maintenance_mode'] = self._set_host_maintenance(context,
|
||||
id, maint_mode)
|
||||
return result
|
||||
|
||||
def _set_host_maintenance(self, req, host, mode=True):
|
||||
def _set_host_maintenance(self, context, host_name, mode=True):
|
||||
"""Start/Stop host maintenance window. On start, it triggers
|
||||
guest VMs evacuation."""
|
||||
context = req.environ['nova.context']
|
||||
LOG.audit(_("Putting host %(host)s in maintenance "
|
||||
LOG.audit(_("Putting host %(host_name)s in maintenance "
|
||||
"mode %(mode)s.") % locals())
|
||||
try:
|
||||
result = self.api.set_host_maintenance(context, host, mode)
|
||||
result = self.api.set_host_maintenance(context, host_name, mode)
|
||||
except NotImplementedError:
|
||||
msg = _("Virt driver does not implement host maintenance mode.")
|
||||
raise webob.exc.HTTPNotImplemented(explanation=msg)
|
||||
return {"host": host, "maintenance_mode": result}
|
||||
except exception.NotFound as e:
|
||||
raise webob.exc.HTTPNotFound(explanation=e.message)
|
||||
if result not in ("on_maintenance", "off_maintenance"):
|
||||
raise webob.exc.HTTPBadRequest(explanation=result)
|
||||
return result
|
||||
|
||||
def _set_enabled_status(self, req, host, enabled):
|
||||
"""Sets the specified host's ability to accept new instances."""
|
||||
context = req.environ['nova.context']
|
||||
state = "enabled" if enabled else "disabled"
|
||||
LOG.audit(_("Setting host %(host)s to %(state)s.") % locals())
|
||||
def _set_enabled_status(self, context, host_name, enabled):
|
||||
"""Sets the specified host's ability to accept new instances.
|
||||
:param enabled: a boolean - if False no new VMs will be able to start
|
||||
on the host"""
|
||||
if enabled:
|
||||
LOG.audit(_("Enabling host %s.") % host_name)
|
||||
else:
|
||||
LOG.audit(_("Disabling host %s.") % host_name)
|
||||
try:
|
||||
result = self.api.set_host_enabled(context, host=host,
|
||||
enabled=enabled)
|
||||
result = self.api.set_host_enabled(context, host_name=host_name,
|
||||
enabled=enabled)
|
||||
except NotImplementedError:
|
||||
msg = _("Virt driver does not implement host disabled status.")
|
||||
raise webob.exc.HTTPNotImplemented(explanation=msg)
|
||||
return {"host": host, "status": result}
|
||||
except exception.NotFound as e:
|
||||
raise webob.exc.HTTPNotFound(explanation=e.message)
|
||||
if result not in ("enabled", "disabled"):
|
||||
raise webob.exc.HTTPBadRequest(explanation=result)
|
||||
return result
|
||||
|
||||
def _host_power_action(self, req, host, action):
|
||||
def _host_power_action(self, req, host_name, action):
|
||||
"""Reboots, shuts down or powers up the host."""
|
||||
context = req.environ['nova.context']
|
||||
authorize(context)
|
||||
try:
|
||||
result = self.api.host_power_action(context, host=host,
|
||||
result = self.api.host_power_action(context, host_name=host_name,
|
||||
action=action)
|
||||
except NotImplementedError:
|
||||
msg = _("Virt driver does not implement host power management.")
|
||||
raise webob.exc.HTTPNotImplemented(explanation=msg)
|
||||
return {"host": host, "power_action": result}
|
||||
except exception.NotFound as e:
|
||||
raise webob.exc.HTTPNotFound(explanation=e.message)
|
||||
return {"host": host_name, "power_action": result}
|
||||
|
||||
@wsgi.serializers(xml=HostActionTemplate)
|
||||
def startup(self, req, id):
|
||||
return self._host_power_action(req, host=id, action="startup")
|
||||
return self._host_power_action(req, host_name=id, action="startup")
|
||||
|
||||
@wsgi.serializers(xml=HostActionTemplate)
|
||||
def shutdown(self, req, id):
|
||||
return self._host_power_action(req, host=id, action="shutdown")
|
||||
return self._host_power_action(req, host_name=id, action="shutdown")
|
||||
|
||||
@wsgi.serializers(xml=HostActionTemplate)
|
||||
def reboot(self, req, id):
|
||||
return self._host_power_action(req, host=id, action="reboot")
|
||||
return self._host_power_action(req, host_name=id, action="reboot")
|
||||
|
||||
@wsgi.serializers(xml=HostShowTemplate)
|
||||
def show(self, req, id):
|
||||
"""Shows the physical/usage resource given by hosts.
|
||||
|
||||
:param context: security context
|
||||
:param host: hostname
|
||||
:param id: hostname
|
||||
:returns: expected to use HostShowTemplate.
|
||||
ex.::
|
||||
|
||||
@ -235,66 +255,15 @@ class HostController(object):
|
||||
D: {'host': 'hostname','project': 'admin',
|
||||
'cpu': 1, 'memory_mb': 2048, 'disk_gb': 30}
|
||||
"""
|
||||
host = id
|
||||
context = req.environ['nova.context']
|
||||
if not context.is_admin:
|
||||
try:
|
||||
data = self.api.describe_host(context, id)
|
||||
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)
|
||||
|
||||
# Getting compute node info and related instances info
|
||||
try:
|
||||
compute_ref = db.service_get_all_compute_by_host(context, host)
|
||||
compute_ref = compute_ref[0]
|
||||
except exception.ComputeHostNotFound:
|
||||
raise webob.exc.HTTPNotFound(explanation=_("Host not found"))
|
||||
instance_refs = 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, 'project': '(total)',
|
||||
'cpu': compute_ref['vcpus'],
|
||||
'memory_mb': compute_ref['memory_mb'],
|
||||
'disk_gb': compute_ref['local_gb']}},
|
||||
{'resource': {'host': host, '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,
|
||||
'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,
|
||||
'project': project_id,
|
||||
'cpu': reduce(lambda x, y: x + y, vcpus),
|
||||
'memory_mb': reduce(lambda x, y: x + y, mem),
|
||||
'disk_gb': reduce(lambda x, y: x + y, disk)}})
|
||||
|
||||
return {'host': resources}
|
||||
return {'host': data}
|
||||
|
||||
|
||||
class Hosts(extensions.ExtensionDescriptor):
|
||||
|
@ -33,6 +33,17 @@ nova.openstack.common.cfg.CONF.register_opts(_compute_opts)
|
||||
|
||||
def API(*args, **kwargs):
|
||||
importutils = nova.openstack.common.importutils
|
||||
compute_api_class = nova.openstack.common.cfg.CONF.compute_api_class
|
||||
cls = importutils.import_class(compute_api_class)
|
||||
return cls(*args, **kwargs)
|
||||
class_name = nova.openstack.common.cfg.CONF.compute_api_class
|
||||
return importutils.import_object(class_name, *args, **kwargs)
|
||||
|
||||
|
||||
def HostAPI(*args, **kwargs):
|
||||
"""
|
||||
Returns the 'HostAPI' class from the same module as the configured compute
|
||||
api
|
||||
"""
|
||||
importutils = nova.openstack.common.importutils
|
||||
compute_api_class_name = nova.openstack.common.cfg.CONF.compute_api_class
|
||||
compute_api_class = importutils.import_class(compute_api_class_name)
|
||||
class_name = compute_api_class.__module__ + ".HostAPI"
|
||||
return importutils.import_object(class_name, *args, **kwargs)
|
||||
|
@ -29,6 +29,7 @@ import time
|
||||
import urllib
|
||||
import uuid
|
||||
|
||||
from nova import availability_zones
|
||||
from nova import block_device
|
||||
from nova.compute import instance_types
|
||||
from nova.compute import power_state
|
||||
@ -150,7 +151,7 @@ def policy_decorator(scope):
|
||||
|
||||
wrap_check_policy = policy_decorator(scope='compute')
|
||||
wrap_check_security_groups_policy = policy_decorator(
|
||||
scope='compute:security_groups')
|
||||
scope='compute:security_groups')
|
||||
|
||||
|
||||
def check_policy(context, action, target, scope='compute'):
|
||||
@ -844,10 +845,10 @@ class API(base.Base):
|
||||
def trigger_provider_fw_rules_refresh(self, context):
|
||||
"""Called when a rule is added/removed from a provider firewall."""
|
||||
|
||||
hosts = [x['host'] for (x, idx)
|
||||
in self.db.service_get_all_compute_sorted(context)]
|
||||
for host in hosts:
|
||||
self.compute_rpcapi.refresh_provider_fw_rules(context, host)
|
||||
host_names = [x['host'] for (x, idx)
|
||||
in self.db.service_get_all_compute_sorted(context)]
|
||||
for host_name in host_names:
|
||||
self.compute_rpcapi.refresh_provider_fw_rules(context, host_name)
|
||||
|
||||
@wrap_check_policy
|
||||
def update(self, context, instance, **kwargs):
|
||||
@ -944,13 +945,14 @@ class API(base.Base):
|
||||
host=src_host, cast=False,
|
||||
reservations=downsize_reservations)
|
||||
|
||||
is_up = False
|
||||
# NOTE(jogo): db allows for multiple compute services per host
|
||||
try:
|
||||
services = self.db.service_get_all_compute_by_host(
|
||||
context.elevated(), instance['host'])
|
||||
except exception.ComputeHostNotFound:
|
||||
services = []
|
||||
|
||||
is_up = False
|
||||
for service in services:
|
||||
if self.servicegroup_api.service_is_up(service):
|
||||
is_up = True
|
||||
@ -1865,9 +1867,9 @@ class API(base.Base):
|
||||
"""Retrieve diagnostics for the given instance."""
|
||||
return self.compute_rpcapi.get_diagnostics(context, instance=instance)
|
||||
|
||||
def get_backdoor_port(self, context, host):
|
||||
def get_backdoor_port(self, context, host_name):
|
||||
"""Retrieve backdoor port."""
|
||||
return self.compute_rpcapi.get_backdoor_port(context, host)
|
||||
return self.compute_rpcapi.get_backdoor_port(context, host_name)
|
||||
|
||||
@wrap_check_policy
|
||||
@check_instance_lock
|
||||
@ -2133,45 +2135,148 @@ class API(base.Base):
|
||||
|
||||
@check_instance_state(vm_state=[vm_states.ACTIVE])
|
||||
def live_migrate(self, context, instance, block_migration,
|
||||
disk_over_commit, host):
|
||||
disk_over_commit, host_name):
|
||||
"""Migrate a server lively to a new host."""
|
||||
LOG.debug(_("Going to try to live migrate instance to %s"),
|
||||
host, instance=instance)
|
||||
host_name, instance=instance)
|
||||
|
||||
instance = self.update(context, instance,
|
||||
task_state=task_states.MIGRATING,
|
||||
expected_task_state=None)
|
||||
|
||||
self.scheduler_rpcapi.live_migration(context, block_migration,
|
||||
disk_over_commit, instance, host)
|
||||
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()
|
||||
super(HostAPI, self).__init__()
|
||||
|
||||
"""Sub-set of the Compute Manager API for managing host operations."""
|
||||
def set_host_enabled(self, context, host, enabled):
|
||||
@check_host
|
||||
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,
|
||||
host=host)
|
||||
host=host_name)
|
||||
|
||||
def get_host_uptime(self, context, host):
|
||||
@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)
|
||||
return self.compute_rpcapi.get_host_uptime(context, host=host_name)
|
||||
|
||||
def host_power_action(self, context, host, action):
|
||||
@check_host
|
||||
def host_power_action(self, context, host_name, action):
|
||||
"""Reboots, shuts down or powers up the host."""
|
||||
# NOTE(comstud): No instance_uuid argument to this compute manager
|
||||
# call
|
||||
return self.compute_rpcapi.host_power_action(context, action=action,
|
||||
host=host)
|
||||
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.
|
||||
"""
|
||||
LOG.debug(_("Listing hosts"))
|
||||
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)
|
||||
|
||||
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_all_compute_by_host(context,
|
||||
host_name)
|
||||
compute_ref = compute_ref[0]
|
||||
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."""
|
||||
@ -2237,25 +2342,27 @@ class AggregateAPI(base.Base):
|
||||
reason='not empty')
|
||||
self.db.aggregate_delete(context, aggregate_id)
|
||||
|
||||
def add_host_to_aggregate(self, context, aggregate_id, host):
|
||||
def add_host_to_aggregate(self, context, aggregate_id, host_name):
|
||||
"""Adds the host to an aggregate."""
|
||||
# validates the host; ComputeHostNotFound is raised if invalid
|
||||
service = self.db.service_get_all_compute_by_host(context, host)[0]
|
||||
service = self.db.service_get_all_compute_by_host(
|
||||
context, host_name)[0]
|
||||
aggregate = self.db.aggregate_get(context, aggregate_id)
|
||||
self.db.aggregate_host_add(context, aggregate_id, host)
|
||||
self.db.aggregate_host_add(context, aggregate_id, host_name)
|
||||
#NOTE(jogo): Send message to host to support resource pools
|
||||
self.compute_rpcapi.add_aggregate_host(context,
|
||||
aggregate=aggregate, host_param=host, host=host)
|
||||
aggregate=aggregate, host_param=host_name, host=host_name)
|
||||
return self.get_aggregate(context, aggregate_id)
|
||||
|
||||
def remove_host_from_aggregate(self, context, aggregate_id, host):
|
||||
def remove_host_from_aggregate(self, context, aggregate_id, host_name):
|
||||
"""Removes host from the aggregate."""
|
||||
# validates the host; ComputeHostNotFound is raised if invalid
|
||||
service = self.db.service_get_all_compute_by_host(context, host)[0]
|
||||
service = self.db.service_get_all_compute_by_host(
|
||||
context, host_name)[0]
|
||||
aggregate = self.db.aggregate_get(context, aggregate_id)
|
||||
self.db.aggregate_host_delete(context, aggregate_id, host)
|
||||
self.db.aggregate_host_delete(context, aggregate_id, host_name)
|
||||
self.compute_rpcapi.remove_aggregate_host(context,
|
||||
aggregate=aggregate, host_param=host, host=host)
|
||||
aggregate=aggregate, host_param=host_name, host=host_name)
|
||||
return self.get_aggregate(context, aggregate_id)
|
||||
|
||||
def _get_aggregate_info(self, context, aggregate):
|
||||
|
@ -132,6 +132,15 @@ def service_get_all(context, disabled=None):
|
||||
return IMPL.service_get_all(context, disabled)
|
||||
|
||||
|
||||
def service_does_host_exist(context, host_name, include_disabled=False):
|
||||
"""Returns True if 'host_name' is found in the services table, False
|
||||
otherwise
|
||||
:param: host_name - the name of the host we want to check if it exists
|
||||
:param: include_disabled - Set to True to include hosts from disabled
|
||||
services"""
|
||||
return IMPL.service_does_host_exist(context, host_name, include_disabled)
|
||||
|
||||
|
||||
def service_get_all_by_topic(context, topic):
|
||||
"""Get all services for a given topic."""
|
||||
return IMPL.service_get_all_by_topic(context, topic)
|
||||
|
@ -336,6 +336,15 @@ def service_get_all(context, disabled=None):
|
||||
return query.all()
|
||||
|
||||
|
||||
@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").\
|
||||
|
@ -19,59 +19,68 @@ import webob.exc
|
||||
from nova.api.openstack.compute.contrib import hosts as os_hosts
|
||||
from nova.compute import power_state
|
||||
from nova.compute import vm_states
|
||||
from nova import context
|
||||
from nova import context as context_maker
|
||||
from nova import db
|
||||
from nova.openstack.common import log as logging
|
||||
from nova import test
|
||||
from nova.tests import fake_hosts
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
HOST_LIST = {"hosts": [
|
||||
{"host_name": "host_c1", "service": "compute", "zone": "nova"},
|
||||
{"host_name": "host_c2", "service": "compute", "zone": "nova"}]
|
||||
}
|
||||
HOST_LIST_NOVA_ZONE = [
|
||||
{"host_name": "host_c1", "service": "compute", "zone": "nova"},
|
||||
{"host_name": "host_c2", "service": "compute", "zone": "nova"}]
|
||||
SERVICES_LIST = [
|
||||
{"host": "host_c1", "topic": "compute"},
|
||||
{"host": "host_c2", "topic": "compute"}]
|
||||
|
||||
|
||||
def stub_service_get_all(self, req):
|
||||
return SERVICES_LIST
|
||||
def stub_service_get_all(context, disabled=None):
|
||||
return fake_hosts.SERVICES_LIST
|
||||
|
||||
|
||||
def stub_set_host_enabled(context, host, enabled):
|
||||
if host == "notimplemented":
|
||||
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_set_host_enabled(context, host_name, enabled):
|
||||
"""
|
||||
Simulates three possible behaviours for VM drivers or compute drivers when
|
||||
enabling or disabling a host.
|
||||
|
||||
'enabled' means new instances can go to this host
|
||||
'disabled' means they can't
|
||||
"""
|
||||
results = {True: "enabled", False: "disabled"}
|
||||
if host_name == "notimplemented":
|
||||
# The vm driver for this host doesn't support this feature
|
||||
raise NotImplementedError()
|
||||
elif host_name == "host_c2":
|
||||
# Simulate a failure
|
||||
return results[not enabled]
|
||||
else:
|
||||
# Do the right thing
|
||||
return results[enabled]
|
||||
|
||||
|
||||
def stub_set_host_maintenance(context, host_name, mode):
|
||||
# We'll simulate success and failure by assuming
|
||||
# that 'host_c1' always succeeds, and 'host_c2'
|
||||
# always fails
|
||||
fail = (host == "host_c2")
|
||||
status = "enabled" if (enabled != fail) else "disabled"
|
||||
return status
|
||||
|
||||
|
||||
def stub_set_host_maintenance(context, host, mode):
|
||||
if host == "notimplemented":
|
||||
results = {True: "on_maintenance", False: "off_maintenance"}
|
||||
if host_name == "notimplemented":
|
||||
# The vm driver for this host doesn't support this feature
|
||||
raise NotImplementedError()
|
||||
# We'll simulate success and failure by assuming
|
||||
# that 'host_c1' always succeeds, and 'host_c2'
|
||||
# always fails
|
||||
fail = (host == "host_c2")
|
||||
maintenance = "on_maintenance" if (mode != fail) else "off_maintenance"
|
||||
return maintenance
|
||||
elif host_name == "host_c2":
|
||||
# Simulate a failure
|
||||
return results[not mode]
|
||||
else:
|
||||
# Do the right thing
|
||||
return results[mode]
|
||||
|
||||
|
||||
def stub_host_power_action(context, host, action):
|
||||
if host == "notimplemented":
|
||||
def stub_host_power_action(context, host_name, action):
|
||||
if host_name == "notimplemented":
|
||||
raise NotImplementedError()
|
||||
return action
|
||||
|
||||
|
||||
def _create_instance(**kwargs):
|
||||
"""Create a test instance."""
|
||||
ctxt = context.get_admin_context()
|
||||
ctxt = context_maker.get_admin_context()
|
||||
return db.instance_create(ctxt, _create_instance_dict(**kwargs))
|
||||
|
||||
|
||||
@ -99,12 +108,12 @@ def _create_instance_dict(**kwargs):
|
||||
|
||||
|
||||
class FakeRequest(object):
|
||||
environ = {"nova.context": context.get_admin_context()}
|
||||
environ = {"nova.context": context_maker.get_admin_context()}
|
||||
GET = {}
|
||||
|
||||
|
||||
class FakeRequestWithNovaZone(object):
|
||||
environ = {"nova.context": context.get_admin_context()}
|
||||
environ = {"nova.context": context_maker.get_admin_context()}
|
||||
GET = {"zone": "nova"}
|
||||
|
||||
|
||||
@ -114,14 +123,22 @@ class HostTestCase(test.TestCase):
|
||||
def setUp(self):
|
||||
super(HostTestCase, self).setUp()
|
||||
self.controller = os_hosts.HostController()
|
||||
self.hosts_api = self.controller.api
|
||||
self.req = FakeRequest()
|
||||
|
||||
# Pretend we have fake_hosts.HOST_LIST in the DB
|
||||
self.stubs.Set(db, 'service_get_all',
|
||||
stub_service_get_all)
|
||||
self.stubs.Set(self.controller.api, 'set_host_enabled',
|
||||
# Only hosts in our fake DB exist
|
||||
self.stubs.Set(db, 'service_does_host_exist',
|
||||
stub_service_does_host_exist)
|
||||
# 'host_c1' always succeeds, and 'host_c2'
|
||||
self.stubs.Set(self.hosts_api, 'set_host_enabled',
|
||||
stub_set_host_enabled)
|
||||
self.stubs.Set(self.controller.api, 'set_host_maintenance',
|
||||
# 'host_c1' always succeeds, and 'host_c2'
|
||||
self.stubs.Set(self.hosts_api, 'set_host_maintenance',
|
||||
stub_set_host_maintenance)
|
||||
self.stubs.Set(self.controller.api, 'host_power_action',
|
||||
self.stubs.Set(self.hosts_api, 'host_power_action',
|
||||
stub_host_power_action)
|
||||
|
||||
def _test_host_update(self, host, key, val, expected_value):
|
||||
@ -130,14 +147,17 @@ class HostTestCase(test.TestCase):
|
||||
self.assertEqual(result[key], expected_value)
|
||||
|
||||
def test_list_hosts(self):
|
||||
# Verify that the compute hosts are returned.
|
||||
hosts = os_hosts._list_hosts(self.req)
|
||||
self.assertEqual(hosts, HOST_LIST['hosts'])
|
||||
"""Verify that the compute hosts are returned."""
|
||||
result = self.controller.index(self.req)
|
||||
self.assert_('hosts' in result)
|
||||
hosts = result['hosts']
|
||||
self.assertEqual(fake_hosts.HOST_LIST, hosts)
|
||||
|
||||
def test_list_hosts_with_zone(self):
|
||||
req = FakeRequestWithNovaZone()
|
||||
hosts = os_hosts._list_hosts(req)
|
||||
self.assertEqual(hosts, HOST_LIST_NOVA_ZONE)
|
||||
result = self.controller.index(FakeRequestWithNovaZone())
|
||||
self.assert_('hosts' in result)
|
||||
hosts = result['hosts']
|
||||
self.assertEqual(fake_hosts.HOST_LIST_NOVA_ZONE, hosts)
|
||||
|
||||
def test_disable_host(self):
|
||||
self._test_host_update('host_c1', 'status', 'disable', 'disabled')
|
||||
@ -222,10 +242,6 @@ class HostTestCase(test.TestCase):
|
||||
self.assertEqual(result["status"], "disabled")
|
||||
self.assertEqual(result["maintenance_mode"], "on_maintenance")
|
||||
|
||||
def test_bad_host(self):
|
||||
self.assertRaises(webob.exc.HTTPNotFound, self.controller.update,
|
||||
self.req, "bogus_host_name", {"status": "disable"})
|
||||
|
||||
def test_show_forbidden(self):
|
||||
self.req.environ["nova.context"].is_admin = False
|
||||
dest = 'dummydest'
|
||||
@ -244,7 +260,7 @@ class HostTestCase(test.TestCase):
|
||||
|
||||
def _create_compute_service(self):
|
||||
"""Create compute-manager(ComputeNode and Service record)."""
|
||||
ctxt = context.get_admin_context()
|
||||
ctxt = self.req.environ["nova.context"]
|
||||
dic = {'host': 'dummy', 'binary': 'nova-compute', 'topic': 'compute',
|
||||
'report_count': 0}
|
||||
s_ref = db.service_create(ctxt, dic)
|
||||
@ -259,8 +275,8 @@ class HostTestCase(test.TestCase):
|
||||
return db.service_get(ctxt, s_ref['id'])
|
||||
|
||||
def test_show_no_project(self):
|
||||
# No instance are running on the given host.
|
||||
ctxt = context.get_admin_context()
|
||||
"""No instances are running on the given host."""
|
||||
ctxt = context_maker.get_admin_context()
|
||||
s_ref = self._create_compute_service()
|
||||
|
||||
result = self.controller.show(self.req, s_ref['host'])
|
||||
@ -275,8 +291,8 @@ class HostTestCase(test.TestCase):
|
||||
db.service_destroy(ctxt, s_ref['id'])
|
||||
|
||||
def test_show_works_correctly(self):
|
||||
# show() works correctly as expected.
|
||||
ctxt = context.get_admin_context()
|
||||
"""show() works correctly as expected."""
|
||||
ctxt = context_maker.get_admin_context()
|
||||
s_ref = self._create_compute_service()
|
||||
i_ref1 = _create_instance(project_id='p-01', host=s_ref['host'])
|
||||
i_ref2 = _create_instance(project_id='p-02', vcpus=3,
|
||||
@ -303,17 +319,17 @@ class HostSerializerTest(test.TestCase):
|
||||
|
||||
def test_index_serializer(self):
|
||||
serializer = os_hosts.HostIndexTemplate()
|
||||
text = serializer.serialize(HOST_LIST)
|
||||
text = serializer.serialize(fake_hosts.OS_API_HOST_LIST)
|
||||
|
||||
tree = etree.fromstring(text)
|
||||
|
||||
self.assertEqual('hosts', tree.tag)
|
||||
self.assertEqual(len(HOST_LIST['hosts']), len(tree))
|
||||
for i in range(len(HOST_LIST)):
|
||||
self.assertEqual(len(fake_hosts.HOST_LIST), len(tree))
|
||||
for i in range(len(fake_hosts.HOST_LIST)):
|
||||
self.assertEqual('host', tree[i].tag)
|
||||
self.assertEqual(HOST_LIST['hosts'][i]['host_name'],
|
||||
self.assertEqual(fake_hosts.HOST_LIST[i]['host_name'],
|
||||
tree[i].get('host_name'))
|
||||
self.assertEqual(HOST_LIST['hosts'][i]['service'],
|
||||
self.assertEqual(fake_hosts.HOST_LIST[i]['service'],
|
||||
tree[i].get('service'))
|
||||
|
||||
def test_update_serializer_with_status(self):
|
||||
|
@ -5795,7 +5795,7 @@ class ComputeAPITestCase(BaseTestCase):
|
||||
self.compute_api.live_migrate(self.context, instance,
|
||||
block_migration=True,
|
||||
disk_over_commit=True,
|
||||
host='fake_dest_host')
|
||||
host_name='fake_dest_host')
|
||||
|
||||
instance = db.instance_get_by_uuid(self.context, instance_uuid)
|
||||
self.assertEqual(instance['task_state'], task_states.MIGRATING)
|
||||
@ -6091,7 +6091,7 @@ class ComputePolicyTestCase(BaseTestCase):
|
||||
|
||||
self.assertRaises(exception.PolicyNotAuthorized,
|
||||
self.compute_api.get_instance_faults,
|
||||
self.context, instances)
|
||||
context.get_admin_context(), instances)
|
||||
|
||||
def test_force_host_fail(self):
|
||||
rules = {"compute:create": [],
|
||||
@ -6123,11 +6123,19 @@ class ComputeHostAPITestCase(BaseTestCase):
|
||||
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.RequestContext('fake', 'fake')
|
||||
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')
|
||||
@ -6141,6 +6149,7 @@ class ComputeHostAPITestCase(BaseTestCase):
|
||||
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')
|
||||
@ -6150,9 +6159,10 @@ class ComputeHostAPITestCase(BaseTestCase):
|
||||
'version': compute_rpcapi.ComputeAPI.BASE_RPC_API_VERSION})
|
||||
|
||||
def test_host_power_action(self):
|
||||
ctxt = context.RequestContext('fake', 'fake')
|
||||
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')
|
||||
@ -6163,9 +6173,10 @@ class ComputeHostAPITestCase(BaseTestCase):
|
||||
compute_rpcapi.ComputeAPI.BASE_RPC_API_VERSION})
|
||||
|
||||
def test_set_host_maintenance(self):
|
||||
ctxt = context.RequestContext('fake', 'fake')
|
||||
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')
|
||||
|
105
nova/tests/compute/test_host_api.py
Normal file
105
nova/tests/compute/test_host_api.py
Normal file
@ -0,0 +1,105 @@
|
||||
# Copyright (c) 2012 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.
|
||||
|
||||
from nova.compute import api
|
||||
from nova import context
|
||||
from nova import db
|
||||
from nova import exception
|
||||
from nova import test
|
||||
from nova.tests import fake_hosts
|
||||
|
||||
|
||||
class HostApiTestCase(test.TestCase):
|
||||
"""
|
||||
Tests 'host' subset of the compute api
|
||||
"""
|
||||
|
||||
def setUp(self):
|
||||
super(HostApiTestCase, self).setUp()
|
||||
self.compute_rpcapi = api.compute_rpcapi
|
||||
self.api = api.HostAPI()
|
||||
|
||||
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
|
||||
"""
|
||||
self.assertRaises(exception.HostNotFound, self.api.set_host_enabled,
|
||||
context.get_admin_context(), "bogus_host_name", False)
|
||||
|
||||
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)
|
||||
self.mox.ReplayAll()
|
||||
compute_hosts = self.api.list_hosts(ctx, service="compute")
|
||||
self.mox.VerifyAll()
|
||||
expected = [host for host in fake_hosts.HOST_LIST
|
||||
if host["service"] == "compute"]
|
||||
self.assertEqual(expected, compute_hosts)
|
||||
|
||||
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_all_compute_by_host')
|
||||
host_name = 'host_c1'
|
||||
db.service_get_all_compute_by_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,
|
||||
}])
|
||||
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}}]
|
||||
)
|
||||
self.mox.VerifyAll()
|
32
nova/tests/fake_hosts.py
Normal file
32
nova/tests/fake_hosts.py
Normal file
@ -0,0 +1,32 @@
|
||||
# Copyright (c) 2012 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.
|
||||
|
||||
"""
|
||||
Provides some fake hosts to test host and service related functions
|
||||
"""
|
||||
|
||||
HOST_LIST = [
|
||||
{"host_name": "host_c1", "service": "compute", "zone": "nova"},
|
||||
{"host_name": "host_c2", "service": "compute", "zone": "nova"}]
|
||||
|
||||
OS_API_HOST_LIST = {"hosts": HOST_LIST}
|
||||
|
||||
HOST_LIST_NOVA_ZONE = [
|
||||
{"host_name": "host_c1", "service": "compute", "zone": "nova"},
|
||||
{"host_name": "host_c2", "service": "compute", "zone": "nova"}]
|
||||
|
||||
SERVICES_LIST = [
|
||||
{"host": "host_c1", "topic": "compute"},
|
||||
{"host": "host_c2", "topic": "compute"}]
|
Loading…
x
Reference in New Issue
Block a user