summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--etc/nova/nova.conf.sample8
-rw-r--r--nova/cells/opts.py9
-rw-r--r--nova/cells/state.py4
-rw-r--r--nova/cells/weights/mute_child.py6
-rw-r--r--nova/db/sqlalchemy/api.py12
-rw-r--r--nova/exception.py4
-rw-r--r--nova/network/quantumv2/__init__.py59
-rw-r--r--nova/network/quantumv2/api.py4
-rw-r--r--nova/objects/base.py2
-rw-r--r--nova/openstack/common/strutils.py90
-rw-r--r--nova/scheduler/filters/compute_capabilities_filter.py2
-rw-r--r--nova/tests/db/test_db_api.py497
-rw-r--r--nova/tests/network/test_quantumv2.py15
-rw-r--r--nova/tests/scheduler/test_host_filters.py13
-rw-r--r--nova/tests/test_utils.py35
-rw-r--r--nova/tests/virt/vmwareapi/db_fakes.py2
-rw-r--r--nova/tests/virt/vmwareapi/test_vmwareapi.py65
-rw-r--r--nova/utils.py28
-rw-r--r--nova/virt/baremetal/virtual_power_driver.py2
-rwxr-xr-xnova/virt/images.py5
-rwxr-xr-xnova/virt/libvirt/driver.py6
-rw-r--r--nova/virt/vmwareapi/fake.py56
-rw-r--r--nova/wsgi.py3
-rw-r--r--requirements.txt2
-rwxr-xr-xtools/xenserver/rotate_xen_guest_logs.sh62
25 files changed, 600 insertions, 391 deletions
diff --git a/etc/nova/nova.conf.sample b/etc/nova/nova.conf.sample
index 7524a7e5e..9e095cb29 100644
--- a/etc/nova/nova.conf.sample
+++ b/etc/nova/nova.conf.sample
@@ -515,8 +515,8 @@
# (string value)
#vpn_image_id=0
-# Instance type for vpn instances (string value)
-#vpn_instance_type=m1.tiny
+# Flavor for vpn instances (string value)
+#vpn_flavor=m1.tiny
# Template for cloudpipe instance boot script (string value)
#boot_script_template=$pybasedir/nova/cloudpipe/bootscript.template
@@ -641,8 +641,8 @@
# Options defined in nova.compute.flavors
#
-# default instance type to use, testing only (string value)
-#default_instance_type=m1.small
+# default flavor to use, testing only (string value)
+#default_flavor=m1.small
#
diff --git a/nova/cells/opts.py b/nova/cells/opts.py
index 4e3d75de4..5ab16f377 100644
--- a/nova/cells/opts.py
+++ b/nova/cells/opts.py
@@ -44,8 +44,13 @@ cells_opts = [
help='Percentage of cell capacity to hold in reserve. '
'Affects both memory and disk utilization'),
cfg.StrOpt('cell_type',
- default=None,
- help='Type of cell: api or compute'),
+ default=None,
+ help='Type of cell: api or compute'),
+ cfg.IntOpt("mute_child_interval",
+ default=300,
+ help='Number of seconds after which a lack of capability and '
+ 'capacity updates signals the child cell is to be '
+ 'treated as a mute.'),
]
cfg.CONF.register_opts(cells_opts, group='cells')
diff --git a/nova/cells/state.py b/nova/cells/state.py
index 37813d581..14fa97507 100644
--- a/nova/cells/state.py
+++ b/nova/cells/state.py
@@ -42,6 +42,7 @@ LOG = logging.getLogger(__name__)
CONF = cfg.CONF
CONF.import_opt('name', 'nova.cells.opts', group='cells')
CONF.import_opt('reserve_percent', 'nova.cells.opts', group='cells')
+CONF.import_opt('mute_child_interval', 'nova.cells.opts', group='cells')
#CONF.import_opt('capabilities', 'nova.cells.opts', group='cells')
CONF.register_opts(cell_state_manager_opts, group='cells')
@@ -340,6 +341,9 @@ class CellStateManager(base.Base):
capabs = copy.deepcopy(self.my_cell_state.capabilities)
if include_children:
for cell in self.child_cells.values():
+ if timeutils.is_older_than(cell.last_seen,
+ CONF.cells.mute_child_interval):
+ continue
for capab_name, values in cell.capabilities.items():
if capab_name not in capabs:
capabs[capab_name] = set([])
diff --git a/nova/cells/weights/mute_child.py b/nova/cells/weights/mute_child.py
index 0f6fb0bbb..82139d4f3 100644
--- a/nova/cells/weights/mute_child.py
+++ b/nova/cells/weights/mute_child.py
@@ -35,14 +35,10 @@ mute_weigher_opts = [
default=1000.0,
help='Weight value assigned to mute children. (The value '
'should be positive.)'),
- cfg.IntOpt("mute_child_interval",
- default=300,
- help='Number of seconds after which a lack of capability and '
- 'capacity updates signals the child cell is to be '
- 'treated as a mute.')
]
CONF = cfg.CONF
+CONF.import_opt('mute_child_interval', 'nova.cells.opts', group='cells')
CONF.register_opts(mute_weigher_opts, group='cells')
diff --git a/nova/db/sqlalchemy/api.py b/nova/db/sqlalchemy/api.py
index 25108b062..69157a86a 100644
--- a/nova/db/sqlalchemy/api.py
+++ b/nova/db/sqlalchemy/api.py
@@ -603,18 +603,6 @@ def compute_node_statistics(context):
@require_admin_context
-def certificate_get(context, certificate_id):
- result = model_query(context, models.Certificate).\
- filter_by(id=certificate_id).\
- first()
-
- if not result:
- raise exception.CertificateNotFound(certificate_id=certificate_id)
-
- return result
-
-
-@require_admin_context
def certificate_create(context, values):
certificate_ref = models.Certificate()
for (key, value) in values.iteritems():
diff --git a/nova/exception.py b/nova/exception.py
index 893c0df75..c774b56cc 100644
--- a/nova/exception.py
+++ b/nova/exception.py
@@ -673,10 +673,6 @@ class KeypairNotFound(NotFound):
message = _("Keypair %(name)s not found for user %(user_id)s")
-class CertificateNotFound(NotFound):
- message = _("Certificate %(certificate_id)s not found.")
-
-
class ServiceNotFound(NotFound):
message = _("Service %(service_id)s could not be found.")
diff --git a/nova/network/quantumv2/__init__.py b/nova/network/quantumv2/__init__.py
index 89c08311f..6d6e7c7bc 100644
--- a/nova/network/quantumv2/__init__.py
+++ b/nova/network/quantumv2/__init__.py
@@ -16,7 +16,9 @@
# under the License.
from oslo.config import cfg
-from quantumclient.v2_0 import client
+from quantumclient import client
+from quantumclient.common import exceptions
+from quantumclient.v2_0 import client as clientv20
from nova.openstack.common import excutils
from nova.openstack.common import log as logging
@@ -25,24 +27,27 @@ CONF = cfg.CONF
LOG = logging.getLogger(__name__)
-cached_admin_client = None
-
-
-def _fill_admin_details(params):
- params['username'] = CONF.quantum_admin_username
- params['tenant_name'] = CONF.quantum_admin_tenant_name
- params['region_name'] = CONF.quantum_region_name
- params['password'] = CONF.quantum_admin_password
- params['auth_url'] = CONF.quantum_admin_auth_url
- params['timeout'] = CONF.quantum_url_timeout
- params['auth_strategy'] = CONF.quantum_auth_strategy
- params['insecure'] = CONF.quantum_api_insecure
+def _get_auth_token():
+ try:
+ httpclient = client.HTTPClient(
+ username=CONF.quantum_admin_username,
+ tenant_name=CONF.quantum_admin_tenant_name,
+ region_name=CONF.quantum_region_name,
+ password=CONF.quantum_admin_password,
+ auth_url=CONF.quantum_admin_auth_url,
+ timeout=CONF.quantum_url_timeout,
+ auth_strategy=CONF.quantum_auth_strategy,
+ insecure=CONF.quantum_api_insecure)
+ httpclient.authenticate()
+ return httpclient.auth_token
+ except exceptions.QuantumClientException as e:
+ with excutils.save_and_reraise_exception():
+ LOG.error(_('Quantum client authentication failed: %s'), e)
def _get_client(token=None):
- global cached_admin_client
-
- should_cache = False
+ if not token and CONF.quantum_auth_strategy:
+ token = _get_auth_token()
params = {
'endpoint_url': CONF.quantum_url,
'timeout': CONF.quantum_url_timeout,
@@ -51,30 +56,12 @@ def _get_client(token=None):
if token:
params['token'] = token
else:
- if CONF.quantum_auth_strategy:
- should_cache = True
- _fill_admin_details(params)
- else:
- params['auth_strategy'] = None
-
- new_client = client.Client(**params)
- if should_cache:
- # in this case, we don't have the token yet
- try:
- new_client.httpclient.authenticate()
- except Exception:
- with excutils.save_and_reraise_exception():
- LOG.exception(_("quantum authentication failed"))
-
- cached_admin_client = new_client
- return new_client
+ params['auth_strategy'] = None
+ return clientv20.Client(**params)
def get_client(context, admin=False):
if admin:
- if cached_admin_client is not None:
- return cached_admin_client
-
token = None
else:
token = context.auth_token
diff --git a/nova/network/quantumv2/api.py b/nova/network/quantumv2/api.py
index 61995a344..e155f694a 100644
--- a/nova/network/quantumv2/api.py
+++ b/nova/network/quantumv2/api.py
@@ -33,8 +33,6 @@ from nova.openstack.common import excutils
from nova.openstack.common import log as logging
from nova.openstack.common import uuidutils
-import quantumclient.common.exceptions
-
quantum_opts = [
cfg.StrOpt('quantum_url',
default='http://127.0.0.1:9696',
@@ -723,7 +721,7 @@ class API(base.Base):
port_id=port)
# If a quantum plugin does not implement the L3 API a 404 from
# list_floatingips will be raised.
- except quantumclient.common.exceptions.QuantumClientException as e:
+ except quantumv2.exceptions.QuantumClientException as e:
if e.status_code == 404:
return []
raise
diff --git a/nova/objects/base.py b/nova/objects/base.py
index 008ea667c..f5fc37e03 100644
--- a/nova/objects/base.py
+++ b/nova/objects/base.py
@@ -39,7 +39,7 @@ def make_class_properties(cls):
cls.fields.update(NovaObject.fields)
for name, typefn in cls.fields.iteritems():
- def getter(self, name=name, typefn=typefn):
+ def getter(self, name=name):
attrname = get_attrname(name)
if not hasattr(self, attrname):
self.obj_load_attr(name)
diff --git a/nova/openstack/common/strutils.py b/nova/openstack/common/strutils.py
index cdf70cb20..62e547e60 100644
--- a/nova/openstack/common/strutils.py
+++ b/nova/openstack/common/strutils.py
@@ -19,18 +19,33 @@
System-level utilities and helper functions.
"""
+import re
import sys
+import unicodedata
from nova.openstack.common.gettextutils import _
+# Used for looking up extensions of text
+# to their 'multiplied' byte amount
+BYTE_MULTIPLIERS = {
+ '': 1,
+ 't': 1024 ** 4,
+ 'g': 1024 ** 3,
+ 'm': 1024 ** 2,
+ 'k': 1024,
+}
+BYTE_REGEX = re.compile(r'(^-?\d+)(\D*)')
+
TRUE_STRINGS = ('1', 't', 'true', 'on', 'y', 'yes')
FALSE_STRINGS = ('0', 'f', 'false', 'off', 'n', 'no')
+SLUGIFY_STRIP_RE = re.compile(r"[^\w\s-]")
+SLUGIFY_HYPHENATE_RE = re.compile(r"[-\s]+")
+
def int_from_bool_as_string(subject):
- """
- Interpret a string as a boolean and return either 1 or 0.
+ """Interpret a string as a boolean and return either 1 or 0.
Any string value in:
@@ -44,8 +59,7 @@ def int_from_bool_as_string(subject):
def bool_from_string(subject, strict=False):
- """
- Interpret a string as a boolean.
+ """Interpret a string as a boolean.
A case-insensitive match is performed such that strings matching 't',
'true', 'on', 'y', 'yes', or '1' are considered True and, when
@@ -78,9 +92,7 @@ def bool_from_string(subject, strict=False):
def safe_decode(text, incoming=None, errors='strict'):
- """
- Decodes incoming str using `incoming` if they're
- not already unicode.
+ """Decodes incoming str using `incoming` if they're not already unicode.
:param incoming: Text's current encoding
:param errors: Errors handling policy. See here for valid
@@ -119,11 +131,10 @@ def safe_decode(text, incoming=None, errors='strict'):
def safe_encode(text, incoming=None,
encoding='utf-8', errors='strict'):
- """
- Encodes incoming str/unicode using `encoding`. If
- incoming is not specified, text is expected to
- be encoded with current python's default encoding.
- (`sys.getdefaultencoding`)
+ """Encodes incoming str/unicode using `encoding`.
+
+ If incoming is not specified, text is expected to be encoded with
+ current python's default encoding. (`sys.getdefaultencoding`)
:param incoming: Text's current encoding
:param encoding: Expected encoding for text (Default UTF-8)
@@ -148,3 +159,58 @@ def safe_encode(text, incoming=None,
return text.encode(encoding, errors)
return text
+
+
+def to_bytes(text, default=0):
+ """Converts a string into an integer of bytes.
+
+ Looks at the last characters of the text to determine
+ what conversion is needed to turn the input text into a byte number.
+ Supports "B, K(B), M(B), G(B), and T(B)". (case insensitive)
+
+ :param text: String input for bytes size conversion.
+ :param default: Default return value when text is blank.
+
+ """
+ match = BYTE_REGEX.search(text)
+ if match:
+ magnitude = int(match.group(1))
+ mult_key_org = match.group(2)
+ if not mult_key_org:
+ return magnitude
+ elif text:
+ msg = _('Invalid string format: %s') % text
+ raise TypeError(msg)
+ else:
+ return default
+ mult_key = mult_key_org.lower().replace('b', '', 1)
+ multiplier = BYTE_MULTIPLIERS.get(mult_key)
+ if multiplier is None:
+ msg = _('Unknown byte multiplier: %s') % mult_key_org
+ raise TypeError(msg)
+ return magnitude * multiplier
+
+
+def to_slug(value, incoming=None, errors="strict"):
+ """Normalize string.
+
+ Convert to lowercase, remove non-word characters, and convert spaces
+ to hyphens.
+
+ Inspired by Django's `slugify` filter.
+
+ :param value: Text to slugify
+ :param incoming: Text's current encoding
+ :param errors: Errors handling policy. See here for valid
+ values http://docs.python.org/2/library/codecs.html
+ :returns: slugified unicode representation of `value`
+ :raises TypeError: If text is not an instance of basestring
+ """
+ value = safe_decode(value, incoming, errors)
+ # NOTE(aababilov): no need to use safe_(encode|decode) here:
+ # encodings are always "ascii", error handling is always "ignore"
+ # and types are always known (first: unicode; second: str)
+ value = unicodedata.normalize("NFKD", value).encode(
+ "ascii", "ignore").decode("ascii")
+ value = SLUGIFY_STRIP_RE.sub("", value).strip().lower()
+ return SLUGIFY_HYPHENATE_RE.sub("-", value)
diff --git a/nova/scheduler/filters/compute_capabilities_filter.py b/nova/scheduler/filters/compute_capabilities_filter.py
index 7fb5725b6..36629435c 100644
--- a/nova/scheduler/filters/compute_capabilities_filter.py
+++ b/nova/scheduler/filters/compute_capabilities_filter.py
@@ -46,7 +46,7 @@ class ComputeCapabilitiesFilter(filters.BaseHostFilter):
return False
if cap is None:
return False
- if not extra_specs_ops.match(cap, req):
+ if not extra_specs_ops.match(str(cap), req):
return False
return True
diff --git a/nova/tests/db/test_db_api.py b/nova/tests/db/test_db_api.py
index 9f05bc55b..81b15b4d5 100644
--- a/nova/tests/db/test_db_api.py
+++ b/nova/tests/db/test_db_api.py
@@ -1313,6 +1313,54 @@ class ModelsObjectComparatorMixin(object):
self.assertIn(primitive, primitives1)
+class InstanceSystemMetadataTestCase(test.TestCase):
+
+ """Tests for db.api.instance_system_metadata_* methods."""
+
+ def setUp(self):
+ super(InstanceSystemMetadataTestCase, self).setUp()
+ values = {'host': 'h1', 'project_id': 'p1',
+ 'system_metadata': {'key': 'value'}}
+ self.ctxt = context.get_admin_context()
+ self.instance = db.instance_create(self.ctxt, values)
+
+ def test_instance_system_metadata_get(self):
+ metadata = db.instance_system_metadata_get(self.ctxt,
+ self.instance['uuid'])
+ self.assertEqual(metadata, {'key': 'value'})
+
+ def test_instance_system_metadata_update_new_pair(self):
+ db.instance_system_metadata_update(
+ self.ctxt, self.instance['uuid'],
+ {'new_key': 'new_value'}, False)
+ metadata = db.instance_system_metadata_get(self.ctxt,
+ self.instance['uuid'])
+ self.assertEqual(metadata, {'key': 'value', 'new_key': 'new_value'})
+
+ def test_instance_system_metadata_update_existent_pair(self):
+ db.instance_system_metadata_update(
+ self.ctxt, self.instance['uuid'],
+ {'key': 'new_value'}, True)
+ metadata = db.instance_system_metadata_get(self.ctxt,
+ self.instance['uuid'])
+ self.assertEqual(metadata, {'key': 'new_value'})
+
+ def test_instance_system_metadata_update_delete_true(self):
+ db.instance_system_metadata_update(
+ self.ctxt, self.instance['uuid'],
+ {'new_key': 'new_value'}, True)
+ metadata = db.instance_system_metadata_get(self.ctxt,
+ self.instance['uuid'])
+ self.assertEqual(metadata, {'new_key': 'new_value'})
+
+ @test.testtools.skip("bug 1189462")
+ def test_instance_system_metadata_update_nonexistent(self):
+ self.assertRaises(exception.InstanceNotFound,
+ db.instance_system_metadata_update,
+ self.ctxt, 'nonexistent-uuid',
+ {'key': 'value'}, True)
+
+
class ReservationTestCase(test.TestCase, ModelsObjectComparatorMixin):
"""Tests for db.api.reservation_* methods."""
@@ -1967,292 +2015,264 @@ class BaseInstanceTypeTestCase(test.TestCase, ModelsObjectComparatorMixin):
class InstanceActionTestCase(test.TestCase, ModelsObjectComparatorMixin):
+ IGNORED_FIELDS = [
+ 'id',
+ 'created_at',
+ 'updated_at',
+ 'deleted_at',
+ 'deleted'
+ ]
+
+ def setUp(self):
+ super(InstanceActionTestCase, self).setUp()
+ self.ctxt = context.get_admin_context()
+
+ def _create_action_values(self, uuid, action='run_instance', ctxt=None):
+ if ctxt is None:
+ ctxt = self.ctxt
+ return {
+ 'action': action,
+ 'instance_uuid': uuid,
+ 'request_id': ctxt.request_id,
+ 'user_id': ctxt.user_id,
+ 'project_id': ctxt.project_id,
+ 'start_time': timeutils.utcnow(),
+ 'message': 'action-message'
+ }
+
+ def _create_event_values(self, uuid, event='schedule',
+ ctxt=None, extra=None):
+ if ctxt is None:
+ ctxt = self.ctxt
+ values = {
+ 'event': event,
+ 'instance_uuid': uuid,
+ 'request_id': ctxt.request_id,
+ 'start_time': timeutils.utcnow()
+ }
+ if extra is not None:
+ values.update(extra)
+ return values
+
+ def _assertActionSaved(self, action, uuid):
+ """Retrieve the action to ensure it was successfully added."""
+ actions = db.actions_get(self.ctxt, uuid)
+ self.assertEqual(1, len(actions))
+ self._assertEqualObjects(action, actions[0])
+
+ def _assertActionEventSaved(self, event, action_id):
+ # Retrieve the event to ensure it was successfully added
+ events = db.action_events_get(self.ctxt, action_id)
+ self.assertEqual(1, len(events))
+ self._assertEqualObjects(event, events[0],
+ ['instance_uuid', 'request_id'])
+
def test_instance_action_start(self):
"""Create an instance action."""
- ctxt = context.get_admin_context()
uuid = str(stdlib_uuid.uuid4())
- start_time = timeutils.utcnow()
- action_values = {'action': 'run_instance',
- 'instance_uuid': uuid,
- 'request_id': ctxt.request_id,
- 'user_id': ctxt.user_id,
- 'project_id': ctxt.project_id,
- 'start_time': start_time}
- db.action_start(ctxt, action_values)
+ action_values = self._create_action_values(uuid)
+ action = db.action_start(self.ctxt, action_values)
- # Retrieve the action to ensure it was successfully added
- actions = db.actions_get(ctxt, uuid)
- self.assertEqual(1, len(actions))
- self.assertEqual('run_instance', actions[0]['action'])
- self.assertEqual(start_time, actions[0]['start_time'])
- self.assertEqual(ctxt.request_id, actions[0]['request_id'])
- self.assertEqual(ctxt.user_id, actions[0]['user_id'])
- self.assertEqual(ctxt.project_id, actions[0]['project_id'])
+ ignored_keys = self.IGNORED_FIELDS + ['finish_time']
+ self._assertEqualObjects(action_values, action, ignored_keys)
+
+ self._assertActionSaved(action, uuid)
def test_instance_action_finish(self):
"""Create an instance action."""
- ctxt = context.get_admin_context()
uuid = str(stdlib_uuid.uuid4())
- start_time = timeutils.utcnow()
- action_start_values = {'action': 'run_instance',
- 'instance_uuid': uuid,
- 'request_id': ctxt.request_id,
- 'user_id': ctxt.user_id,
- 'project_id': ctxt.project_id,
- 'start_time': start_time}
- db.action_start(ctxt, action_start_values)
-
- finish_time = timeutils.utcnow() + datetime.timedelta(seconds=5)
- action_finish_values = {'instance_uuid': uuid,
- 'request_id': ctxt.request_id,
- 'finish_time': finish_time}
- db.action_finish(ctxt, action_finish_values)
+ action_values = self._create_action_values(uuid)
+ db.action_start(self.ctxt, action_values)
- # Retrieve the action to ensure it was successfully added
- actions = db.actions_get(ctxt, uuid)
- self.assertEqual(1, len(actions))
- self.assertEqual('run_instance', actions[0]['action'])
- self.assertEqual(start_time, actions[0]['start_time'])
- self.assertEqual(finish_time, actions[0]['finish_time'])
- self.assertEqual(ctxt.request_id, actions[0]['request_id'])
- self.assertEqual(ctxt.user_id, actions[0]['user_id'])
- self.assertEqual(ctxt.project_id, actions[0]['project_id'])
+ action_values['finish_time'] = timeutils.utcnow()
+ action = db.action_finish(self.ctxt, action_values)
+ self._assertEqualObjects(action_values, action, self.IGNORED_FIELDS)
+
+ self._assertActionSaved(action, uuid)
+
+ def test_instance_action_finish_without_started_event(self):
+ """Create an instance finish action."""
+ uuid = str(stdlib_uuid.uuid4())
+
+ action_values = self._create_action_values(uuid)
+ action_values['finish_time'] = timeutils.utcnow()
+ self.assertRaises(exception.InstanceActionNotFound, db.action_finish,
+ self.ctxt, action_values)
def test_instance_actions_get_by_instance(self):
"""Ensure we can get actions by UUID."""
- ctxt1 = context.get_admin_context()
- ctxt2 = context.get_admin_context()
uuid1 = str(stdlib_uuid.uuid4())
- uuid2 = str(stdlib_uuid.uuid4())
- action_values = {'action': 'run_instance',
- 'instance_uuid': uuid1,
- 'request_id': ctxt1.request_id,
- 'user_id': ctxt1.user_id,
- 'project_id': ctxt1.project_id,
- 'start_time': timeutils.utcnow()}
- db.action_start(ctxt1, action_values)
+ expected = []
+
+ action_values = self._create_action_values(uuid1)
+ action = db.action_start(self.ctxt, action_values)
+ expected.append(action)
+
action_values['action'] = 'resize'
- db.action_start(ctxt1, action_values)
-
- action_values = {'action': 'reboot',
- 'instance_uuid': uuid2,
- 'request_id': ctxt2.request_id,
- 'user_id': ctxt2.user_id,
- 'project_id': ctxt2.project_id,
- 'start_time': timeutils.utcnow()}
+ action = db.action_start(self.ctxt, action_values)
+ expected.append(action)
+
+ # Create some extra actions
+ uuid2 = str(stdlib_uuid.uuid4())
+ ctxt2 = context.get_admin_context()
+ action_values = self._create_action_values(uuid2, 'reboot', ctxt2)
db.action_start(ctxt2, action_values)
db.action_start(ctxt2, action_values)
# Retrieve the action to ensure it was successfully added
- actions = db.actions_get(ctxt1, uuid1)
- self.assertEqual(2, len(actions))
- self.assertEqual('resize', actions[0]['action'])
- self.assertEqual('run_instance', actions[1]['action'])
+ actions = db.actions_get(self.ctxt, uuid1)
+ self._assertEqualListsOfObjects(expected, actions)
def test_instance_action_get_by_instance_and_action(self):
"""Ensure we can get an action by instance UUID and action id."""
- ctxt1 = context.get_admin_context()
ctxt2 = context.get_admin_context()
uuid1 = str(stdlib_uuid.uuid4())
uuid2 = str(stdlib_uuid.uuid4())
- action_values = {'action': 'run_instance',
- 'instance_uuid': uuid1,
- 'request_id': ctxt1.request_id,
- 'user_id': ctxt1.user_id,
- 'project_id': ctxt1.project_id,
- 'start_time': timeutils.utcnow()}
- db.action_start(ctxt1, action_values)
+ action_values = self._create_action_values(uuid1)
+ db.action_start(self.ctxt, action_values)
action_values['action'] = 'resize'
- db.action_start(ctxt1, action_values)
-
- action_values = {'action': 'reboot',
- 'instance_uuid': uuid2,
- 'request_id': ctxt2.request_id,
- 'user_id': ctxt2.user_id,
- 'project_id': ctxt2.project_id,
- 'start_time': timeutils.utcnow()}
+ db.action_start(self.ctxt, action_values)
+
+ action_values = self._create_action_values(uuid2, 'reboot', ctxt2)
db.action_start(ctxt2, action_values)
db.action_start(ctxt2, action_values)
- actions = db.actions_get(ctxt1, uuid1)
+ actions = db.actions_get(self.ctxt, uuid1)
request_id = actions[0]['request_id']
- action = db.action_get_by_request_id(ctxt1, uuid1, request_id)
+ action = db.action_get_by_request_id(self.ctxt, uuid1, request_id)
self.assertEqual('run_instance', action['action'])
- self.assertEqual(ctxt1.request_id, action['request_id'])
+ self.assertEqual(self.ctxt.request_id, action['request_id'])
def test_instance_action_event_start(self):
"""Create an instance action event."""
- ctxt = context.get_admin_context()
uuid = str(stdlib_uuid.uuid4())
- start_time = timeutils.utcnow()
- action_values = {'action': 'run_instance',
- 'instance_uuid': uuid,
- 'request_id': ctxt.request_id,
- 'user_id': ctxt.user_id,
- 'project_id': ctxt.project_id,
- 'start_time': start_time}
- action = db.action_start(ctxt, action_values)
-
- event_values = {'event': 'schedule',
- 'instance_uuid': uuid,
- 'request_id': ctxt.request_id,
- 'start_time': start_time}
- db.action_event_start(ctxt, event_values)
+ action_values = self._create_action_values(uuid)
+ action = db.action_start(self.ctxt, action_values)
- # Retrieve the event to ensure it was successfully added
- events = db.action_events_get(ctxt, action['id'])
- self.assertEqual(1, len(events))
- self.assertEqual('schedule', events[0]['event'])
- self.assertEqual(start_time, events[0]['start_time'])
+ event_values = self._create_event_values(uuid)
+ event = db.action_event_start(self.ctxt, event_values)
+ # self.fail(self._dict_from_object(event, None))
+ event_values['action_id'] = action['id']
+ ignored = self.IGNORED_FIELDS + ['finish_time', 'traceback', 'result']
+ self._assertEqualObjects(event_values, event, ignored)
+
+ self._assertActionEventSaved(event, action['id'])
+
+ def test_instance_action_event_start_without_action(self):
+ """Create an instance action event."""
+ uuid = str(stdlib_uuid.uuid4())
+
+ event_values = self._create_event_values(uuid)
+ self.assertRaises(exception.InstanceActionNotFound,
+ db.action_event_start, self.ctxt, event_values)
+
+ def test_instance_action_event_finish_without_started_event(self):
+ """Finish an instance action event."""
+ uuid = str(stdlib_uuid.uuid4())
+
+ db.action_start(self.ctxt, self._create_action_values(uuid))
+
+ event_values = {
+ 'finish_time': timeutils.utcnow() + datetime.timedelta(seconds=5),
+ 'result': 'Success'
+ }
+ event_values = self._create_event_values(uuid, extra=event_values)
+ self.assertRaises(exception.InstanceActionEventNotFound,
+ db.action_event_finish, self.ctxt, event_values)
+
+ def test_instance_action_event_finish_without_action(self):
+ """Finish an instance action event."""
+ uuid = str(stdlib_uuid.uuid4())
+
+ event_values = {
+ 'finish_time': timeutils.utcnow() + datetime.timedelta(seconds=5),
+ 'result': 'Success'
+ }
+ event_values = self._create_event_values(uuid, extra=event_values)
+ self.assertRaises(exception.InstanceActionNotFound,
+ db.action_event_finish, self.ctxt, event_values)
def test_instance_action_event_finish_success(self):
"""Finish an instance action event."""
- ctxt = context.get_admin_context()
uuid = str(stdlib_uuid.uuid4())
- start_time = timeutils.utcnow()
- action_values = {'action': 'run_instance',
- 'instance_uuid': uuid,
- 'request_id': ctxt.request_id,
- 'user_id': ctxt.user_id,
- 'project_id': ctxt.project_id,
- 'start_time': start_time}
- action = db.action_start(ctxt, action_values)
-
- event_values = {'event': 'schedule',
- 'request_id': ctxt.request_id,
- 'instance_uuid': uuid,
- 'start_time': start_time}
- db.action_event_start(ctxt, event_values)
-
- finish_time = timeutils.utcnow() + datetime.timedelta(seconds=5)
- event_finish_values = {'event': 'schedule',
- 'request_id': ctxt.request_id,
- 'instance_uuid': uuid,
- 'finish_time': finish_time,
- 'result': 'Success'}
- db.action_event_finish(ctxt, event_finish_values)
+ action = db.action_start(self.ctxt, self._create_action_values(uuid))
- # Retrieve the event to ensure it was successfully added
- events = db.action_events_get(ctxt, action['id'])
- action = db.action_get_by_request_id(ctxt, uuid, ctxt.request_id)
- self.assertEqual(1, len(events))
- self.assertEqual('schedule', events[0]['event'])
- self.assertEqual(start_time, events[0]['start_time'])
- self.assertEqual(finish_time, events[0]['finish_time'])
- self.assertNotEqual(action['message'], 'Error')
+ db.action_event_start(self.ctxt, self._create_event_values(uuid))
+
+ event_values = {
+ 'finish_time': timeutils.utcnow() + datetime.timedelta(seconds=5),
+ 'result': 'Success'
+ }
+ event_values = self._create_event_values(uuid, extra=event_values)
+ event = db.action_event_finish(self.ctxt, event_values)
+
+ self._assertActionEventSaved(event, action['id'])
+ action = db.action_get_by_request_id(self.ctxt, uuid,
+ self.ctxt.request_id)
+ self.assertNotEqual('Error', action['message'])
def test_instance_action_event_finish_error(self):
"""Finish an instance action event with an error."""
- ctxt = context.get_admin_context()
uuid = str(stdlib_uuid.uuid4())
- start_time = timeutils.utcnow()
- action_values = {'action': 'run_instance',
- 'instance_uuid': uuid,
- 'request_id': ctxt.request_id,
- 'user_id': ctxt.user_id,
- 'project_id': ctxt.project_id,
- 'start_time': start_time}
- action = db.action_start(ctxt, action_values)
-
- event_values = {'event': 'schedule',
- 'request_id': ctxt.request_id,
- 'instance_uuid': uuid,
- 'start_time': start_time}
- db.action_event_start(ctxt, event_values)
-
- finish_time = timeutils.utcnow() + datetime.timedelta(seconds=5)
- event_finish_values = {'event': 'schedule',
- 'request_id': ctxt.request_id,
- 'instance_uuid': uuid,
- 'finish_time': finish_time,
- 'result': 'Error'}
- db.action_event_finish(ctxt, event_finish_values)
+ action = db.action_start(self.ctxt, self._create_action_values(uuid))
- # Retrieve the event to ensure it was successfully added
- events = db.action_events_get(ctxt, action['id'])
- action = db.action_get_by_request_id(ctxt, uuid, ctxt.request_id)
- self.assertEqual(1, len(events))
- self.assertEqual('schedule', events[0]['event'])
- self.assertEqual(start_time, events[0]['start_time'])
- self.assertEqual(finish_time, events[0]['finish_time'])
- self.assertEqual(action['message'], 'Error')
+ db.action_event_start(self.ctxt, self._create_event_values(uuid))
+
+ event_values = {
+ 'finish_time': timeutils.utcnow() + datetime.timedelta(seconds=5),
+ 'result': 'Error'
+ }
+ event_values = self._create_event_values(uuid, extra=event_values)
+ event = db.action_event_finish(self.ctxt, event_values)
+
+ self._assertActionEventSaved(event, action['id'])
+ action = db.action_get_by_request_id(self.ctxt, uuid,
+ self.ctxt.request_id)
+ self.assertEqual('Error', action['message'])
def test_instance_action_and_event_start_string_time(self):
"""Create an instance action and event with a string start_time."""
- ctxt = context.get_admin_context()
uuid = str(stdlib_uuid.uuid4())
- start_time = timeutils.utcnow()
- start_time_str = timeutils.strtime(start_time)
- action_values = {'action': 'run_instance',
- 'instance_uuid': uuid,
- 'request_id': ctxt.request_id,
- 'user_id': ctxt.user_id,
- 'project_id': ctxt.project_id,
- 'start_time': start_time_str}
- action = db.action_start(ctxt, action_values)
-
- event_values = {'event': 'schedule',
- 'instance_uuid': uuid,
- 'request_id': ctxt.request_id,
- 'start_time': start_time_str}
- db.action_event_start(ctxt, event_values)
+ action = db.action_start(self.ctxt, self._create_action_values(uuid))
- # Retrieve the event to ensure it was successfully added
- events = db.action_events_get(ctxt, action['id'])
- self.assertEqual(1, len(events))
- self.assertEqual('schedule', events[0]['event'])
- # db api still returns models with datetime, not str, values
- self.assertEqual(start_time, events[0]['start_time'])
+ event_values = {'start_time': timeutils.strtime(timeutils.utcnow())}
+ event_values = self._create_event_values(uuid, extra=event_values)
+ event = db.action_event_start(self.ctxt, event_values)
+
+ self._assertActionEventSaved(event, action['id'])
def test_instance_action_event_get_by_id(self):
"""Get a specific instance action event."""
- ctxt1 = context.get_admin_context()
ctxt2 = context.get_admin_context()
uuid1 = str(stdlib_uuid.uuid4())
uuid2 = str(stdlib_uuid.uuid4())
- action_values = {'action': 'run_instance',
- 'instance_uuid': uuid1,
- 'request_id': ctxt1.request_id,
- 'user_id': ctxt1.user_id,
- 'project_id': ctxt1.project_id,
- 'start_time': timeutils.utcnow()}
- added_action = db.action_start(ctxt1, action_values)
-
- action_values = {'action': 'reboot',
- 'instance_uuid': uuid2,
- 'request_id': ctxt2.request_id,
- 'user_id': ctxt2.user_id,
- 'project_id': ctxt2.project_id,
- 'start_time': timeutils.utcnow()}
- db.action_start(ctxt2, action_values)
+ action = db.action_start(self.ctxt,
+ self._create_action_values(uuid1))
+
+ db.action_start(ctxt2,
+ self._create_action_values(uuid2, 'reboot', ctxt2))
- start_time = timeutils.utcnow()
- event_values = {'event': 'schedule',
- 'instance_uuid': uuid1,
- 'request_id': ctxt1.request_id,
- 'start_time': start_time}
- added_event = db.action_event_start(ctxt1, event_values)
-
- event_values = {'event': 'reboot',
- 'instance_uuid': uuid2,
- 'request_id': ctxt2.request_id,
- 'start_time': timeutils.utcnow()}
+ event = db.action_event_start(self.ctxt,
+ self._create_event_values(uuid1))
+
+ event_values = self._create_event_values(uuid2, 'reboot', ctxt2)
db.action_event_start(ctxt2, event_values)
# Retrieve the event to ensure it was successfully added
- event = db.action_event_get_by_id(ctxt1, added_action['id'],
- added_event['id'])
- self.assertEqual('schedule', event['event'])
- self.assertEqual(start_time, event['start_time'])
+ saved_event = db.action_event_get_by_id(self.ctxt,
+ action['id'],
+ event['id'])
+ self._assertEqualObjects(event, saved_event,
+ ['instance_uuid', 'request_id'])
class InstanceFaultTestCase(test.TestCase, ModelsObjectComparatorMixin):
@@ -4979,6 +4999,49 @@ class ProviderFwRuleTestCase(test.TestCase, ModelsObjectComparatorMixin):
self.assertEqual([], db.provider_fw_rule_get_all(self.ctxt))
+class CertificateTestCase(test.TestCase, ModelsObjectComparatorMixin):
+
+ def setUp(self):
+ super(CertificateTestCase, self).setUp()
+ self.ctxt = context.get_admin_context()
+ self.created = self._certificates_create()
+
+ def _get_certs_values(self):
+ base_values = {
+ 'user_id': 'user',
+ 'project_id': 'project',
+ 'file_name': 'filename'
+ }
+ return [dict((k, v + str(x)) for k, v in base_values.iteritems())
+ for x in xrange(1, 4)]
+
+ def _certificates_create(self):
+ return [db.certificate_create(self.ctxt, cert)
+ for cert in self._get_certs_values()]
+
+ def test_certificate_create(self):
+ ignored_keys = ['id', 'deleted', 'deleted_at', 'created_at',
+ 'updated_at']
+ for i, cert in enumerate(self._get_certs_values()):
+ self._assertEqualObjects(self.created[i], cert,
+ ignored_keys=ignored_keys)
+
+ def test_certificate_get_all_by_project(self):
+ cert = db.certificate_get_all_by_project(self.ctxt,
+ self.created[1].project_id)
+ self._assertEqualObjects(self.created[1], cert[0])
+
+ def test_certificate_get_all_by_user(self):
+ cert = db.certificate_get_all_by_user(self.ctxt,
+ self.created[1].user_id)
+ self._assertEqualObjects(self.created[1], cert[0])
+
+ def test_certificate_get_all_by_user_and_project(self):
+ cert = db.certificate_get_all_by_user_and_project(self.ctxt,
+ self.created[1].user_id, self.created[1].project_id)
+ self._assertEqualObjects(self.created[1], cert[0])
+
+
class CellTestCase(test.TestCase, ModelsObjectComparatorMixin):
_ignored_keys = ['id', 'deleted', 'deleted_at', 'created_at', 'updated_at']
diff --git a/nova/tests/network/test_quantumv2.py b/nova/tests/network/test_quantumv2.py
index 0b6f184ae..7f21a2aa9 100644
--- a/nova/tests/network/test_quantumv2.py
+++ b/nova/tests/network/test_quantumv2.py
@@ -19,8 +19,6 @@ import uuid
import mox
from oslo.config import cfg
-from quantumclient import client as quantum_client
-from quantumclient.common import exceptions as quantum_exceptions
from quantumclient.v2_0 import client
from nova.compute import flavors
@@ -104,17 +102,6 @@ class TestQuantumClient(test.TestCase):
self.mox.ReplayAll()
quantumv2.get_client(my_context)
- def test_cached_admin_client(self):
- self.mox.StubOutWithMock(quantum_client.HTTPClient, "authenticate")
-
- # should be called one time only
- quantum_client.HTTPClient.authenticate()
- self.mox.ReplayAll()
-
- admin1 = quantumv2.get_client(None, admin=True)
- admin2 = quantumv2.get_client(None, admin=True)
- self.assertIs(admin1, admin2)
-
def test_withouttoken_keystone_connection_error(self):
self.flags(quantum_auth_strategy='keystone')
self.flags(quantum_url='http://anyhost/')
@@ -1236,7 +1223,7 @@ class TestQuantumv2(test.TestCase):
def test_list_floating_ips_without_l3_support(self):
api = quantumapi.API()
- QuantumNotFound = quantum_exceptions.QuantumClientException(
+ QuantumNotFound = quantumv2.exceptions.QuantumClientException(
status_code=404)
self.moxed_client.list_floatingips(
fixed_ip_address='1.1.1.1', port_id=1).AndRaise(QuantumNotFound)
diff --git a/nova/tests/scheduler/test_host_filters.py b/nova/tests/scheduler/test_host_filters.py
index b09e23f1d..9306615ed 100644
--- a/nova/tests/scheduler/test_host_filters.py
+++ b/nova/tests/scheduler/test_host_filters.py
@@ -708,6 +708,9 @@ class HostFiltersTestCase(test.NoDBTestCase):
self.assertFalse(filt_cls.host_passes(host, filter_properties))
def _do_test_compute_filter_extra_specs(self, ecaps, especs, passes):
+ """In real Openstack runtime environment,compute capabilities
+ value may be number, so we should use number to do unit test.
+ """
self._stub_service_is_up(True)
filt_cls = self.class_map['ComputeCapabilitiesFilter']()
capabilities = {'enabled': True}
@@ -723,33 +726,33 @@ class HostFiltersTestCase(test.NoDBTestCase):
def test_compute_filter_passes_extra_specs_simple(self):
self._do_test_compute_filter_extra_specs(
- ecaps={'opt1': '1', 'opt2': '2'},
+ ecaps={'opt1': 1, 'opt2': 2},
especs={'opt1': '1', 'opt2': '2', 'trust:trusted_host': 'true'},
passes=True)
def test_compute_filter_fails_extra_specs_simple(self):
self._do_test_compute_filter_extra_specs(
- ecaps={'opt1': '1', 'opt2': '2'},
+ ecaps={'opt1': 1, 'opt2': 2},
especs={'opt1': '1', 'opt2': '222', 'trust:trusted_host': 'true'},
passes=False)
def test_compute_filter_pass_extra_specs_simple_with_scope(self):
self._do_test_compute_filter_extra_specs(
- ecaps={'opt1': '1', 'opt2': '2'},
+ ecaps={'opt1': 1, 'opt2': 2},
especs={'capabilities:opt1': '1',
'trust:trusted_host': 'true'},
passes=True)
def test_compute_filter_extra_specs_simple_with_wrong_scope(self):
self._do_test_compute_filter_extra_specs(
- ecaps={'opt1': '1', 'opt2': '2'},
+ ecaps={'opt1': 1, 'opt2': 2},
especs={'wrong_scope:opt1': '1',
'trust:trusted_host': 'true'},
passes=True)
def test_compute_filter_extra_specs_pass_multi_level_with_scope(self):
self._do_test_compute_filter_extra_specs(
- ecaps={'opt1': {'a': '1', 'b': {'aa': '2'}}, 'opt2': '2'},
+ ecaps={'opt1': {'a': 1, 'b': {'aa': 2}}, 'opt2': 2},
especs={'opt1:a': '1', 'capabilities:opt1:b:aa': '2',
'trust:trusted_host': 'true'},
passes=True)
diff --git a/nova/tests/test_utils.py b/nova/tests/test_utils.py
index f400bb899..609280261 100644
--- a/nova/tests/test_utils.py
+++ b/nova/tests/test_utils.py
@@ -38,41 +38,6 @@ from nova import utils
CONF = cfg.CONF
-class ByteConversionTest(test.TestCase):
- def test_string_conversions(self):
- working_examples = {
- '1024KB': 1048576,
- '1024TB': 1125899906842624,
- '1024K': 1048576,
- '1024T': 1125899906842624,
- '1TB': 1099511627776,
- '1T': 1099511627776,
- '1KB': 1024,
- '1K': 1024,
- '1B': 1,
- '1B': 1,
- '1': 1,
- '1MB': 1048576,
- '7MB': 7340032,
- '0MB': 0,
- '0KB': 0,
- '0TB': 0,
- '': 0,
- }
- for (in_value, expected_value) in working_examples.items():
- b_value = utils.to_bytes(in_value)
- self.assertEquals(expected_value, b_value)
- if len(in_value):
- in_value = "-" + in_value
- b_value = utils.to_bytes(in_value)
- self.assertEquals(expected_value * -1, b_value)
- breaking_examples = [
- 'junk1KB', '1023BBBB',
- ]
- for v in breaking_examples:
- self.assertRaises(TypeError, utils.to_bytes, v)
-
-
class GetFromPathTestCase(test.TestCase):
def test_tolerates_nones(self):
f = utils.get_from_path
diff --git a/nova/tests/virt/vmwareapi/db_fakes.py b/nova/tests/virt/vmwareapi/db_fakes.py
index 93fcf6e13..87c3dde67 100644
--- a/nova/tests/virt/vmwareapi/db_fakes.py
+++ b/nova/tests/virt/vmwareapi/db_fakes.py
@@ -1,5 +1,6 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
+# Copyright (c) 2013 Hewlett-Packard Development Company, L.P.
# Copyright (c) 2011 Citrix Systems, Inc.
# Copyright 2011 OpenStack Foundation
#
@@ -74,6 +75,7 @@ def stub_out_db_instance_api(stubs):
'vcpus': type_data['vcpus'],
'mac_addresses': [{'address': values['mac_address']}],
'root_gb': type_data['root_gb'],
+ 'node': values['node'],
}
return FakeModel(base_options)
diff --git a/nova/tests/virt/vmwareapi/test_vmwareapi.py b/nova/tests/virt/vmwareapi/test_vmwareapi.py
index 69a9ffab8..5ba2f98af 100644
--- a/nova/tests/virt/vmwareapi/test_vmwareapi.py
+++ b/nova/tests/virt/vmwareapi/test_vmwareapi.py
@@ -1,5 +1,6 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
+# Copyright (c) 2013 Hewlett-Packard Development Company, L.P.
# Copyright (c) 2012 VMware, Inc.
# Copyright (c) 2011 Citrix Systems, Inc.
# Copyright 2011 OpenStack Foundation
@@ -111,6 +112,7 @@ class VMwareAPIVMTestCase(test.TestCase):
use_linked_clone=False)
self.user_id = 'fake'
self.project_id = 'fake'
+ self.node_name = 'test_url'
self.context = context.RequestContext(self.user_id, self.project_id)
vmwareapi_fake.reset()
db_fakes.stub_out_db_instance_api(self.stubs)
@@ -143,6 +145,7 @@ class VMwareAPIVMTestCase(test.TestCase):
'ramdisk_id': "1",
'mac_address': "de:ad:be:ef:be:ef",
'instance_type': 'm1.large',
+ 'node': self.node_name,
}
self.instance = db.instance_create(None, values)
@@ -500,6 +503,41 @@ class VMwareAPIVMTestCase(test.TestCase):
def test_finish_revert_migration_power_off(self):
self._test_finish_revert_migration(power_on=False)
+ def test_diagnostics_non_existent_vm(self):
+ self._create_instance_in_the_db()
+ self.assertRaises(exception.InstanceNotFound,
+ self.conn.get_diagnostics,
+ self.instance)
+
+ def test_get_console_pool_info(self):
+ info = self.conn.get_console_pool_info("console_type")
+ self.assertEquals(info['address'], 'test_url')
+ self.assertEquals(info['username'], 'test_username')
+ self.assertEquals(info['password'], 'test_pass')
+
+ def test_get_vnc_console_non_existent(self):
+ self._create_instance_in_the_db()
+ self.assertRaises(exception.InstanceNotFound,
+ self.conn.get_vnc_console,
+ self.instance)
+
+ def test_get_vnc_console(self):
+ self._create_instance_in_the_db()
+ self._create_vm()
+ vnc_dict = self.conn.get_vnc_console(self.instance)
+ self.assertEquals(vnc_dict['host'], "test_url")
+ self.assertEquals(vnc_dict['port'], 5910)
+
+ def test_host_ip_addr(self):
+ self.assertEquals(self.conn.get_host_ip_addr(), "test_url")
+
+ def test_get_volume_connector(self):
+ self._create_instance_in_the_db()
+ connector_dict = self.conn.get_volume_connector(self.instance)
+ self.assertEquals(connector_dict['ip'], "test_url")
+ self.assertEquals(connector_dict['initiator'], "iscsi-name")
+ self.assertEquals(connector_dict['host'], "test_url")
+
class VMwareAPIHostTestCase(test.TestCase):
"""Unit tests for Vmware API host calls."""
@@ -547,3 +585,30 @@ class VMwareAPIHostTestCase(test.TestCase):
def test_host_maintenance_off(self):
self._test_host_action(self.conn.host_maintenance_mode, False)
+
+
+class VMwareAPIVCDriverTestCase(VMwareAPIVMTestCase):
+
+ def setUp(self):
+ super(VMwareAPIVCDriverTestCase, self).setUp()
+ self.flags(
+ vmwareapi_cluster_name='test_cluster',
+ vmwareapi_task_poll_interval=10,
+ vnc_enabled=False
+ )
+ self.conn = driver.VMwareVCDriver(None, False)
+
+ def tearDown(self):
+ super(VMwareAPIVCDriverTestCase, self).tearDown()
+ vmwareapi_fake.cleanup()
+
+ def test_get_available_resource(self):
+ stats = self.conn.get_available_resource(self.node_name)
+ self.assertEquals(stats['vcpus'], 16)
+ self.assertEquals(stats['local_gb'], 1024)
+ self.assertEquals(stats['local_gb_used'], 1024 - 500)
+ self.assertEquals(stats['memory_mb'], 1024)
+ self.assertEquals(stats['memory_mb_used'], 1024 - 524)
+ self.assertEquals(stats['hypervisor_type'], 'VMware ESXi')
+ self.assertEquals(stats['hypervisor_version'], '5.0.0')
+ self.assertEquals(stats['hypervisor_hostname'], 'test_url')
diff --git a/nova/utils.py b/nova/utils.py
index fe360cac6..5e968bd35 100644
--- a/nova/utils.py
+++ b/nova/utils.py
@@ -411,34 +411,6 @@ def utf8(value):
return value
-def to_bytes(text, default=0):
- """Try to turn a string into a number of bytes. Looks at the last
- characters of the text to determine what conversion is needed to
- turn the input text into a byte number.
-
- Supports: B/b, K/k, M/m, G/g, T/t (or the same with b/B on the end)
-
- """
- # Take off everything not number 'like' (which should leave
- # only the byte 'identifier' left)
- mult_key_org = text.lstrip('-1234567890')
- mult_key = mult_key_org.lower()
- mult_key_len = len(mult_key)
- if mult_key.endswith("b"):
- mult_key = mult_key[0:-1]
- try:
- multiplier = BYTE_MULTIPLIERS[mult_key]
- if mult_key_len:
- # Empty cases shouldn't cause text[0:-0]
- text = text[0:-mult_key_len]
- return int(text) * multiplier
- except KeyError:
- msg = _('Unknown byte multiplier: %s') % mult_key_org
- raise TypeError(msg)
- except ValueError:
- return default
-
-
def get_from_path(items, path):
"""Returns a list of items matching the specified path.
diff --git a/nova/virt/baremetal/virtual_power_driver.py b/nova/virt/baremetal/virtual_power_driver.py
index e110bf436..303e5a009 100644
--- a/nova/virt/baremetal/virtual_power_driver.py
+++ b/nova/virt/baremetal/virtual_power_driver.py
@@ -59,7 +59,6 @@ CONF.register_group(baremetal_vp)
CONF.register_opts(opts, baremetal_vp)
_conn = None
-_virtual_power_settings = None
_vp_cmd = None
_cmds = None
@@ -84,7 +83,6 @@ class VirtualPowerManager(base.PowerManager):
"""
def __init__(self, **kwargs):
global _conn
- global _virtual_power_settings
global _cmds
if _cmds is None:
diff --git a/nova/virt/images.py b/nova/virt/images.py
index b752b7a64..e1b42eafc 100755
--- a/nova/virt/images.py
+++ b/nova/virt/images.py
@@ -30,6 +30,7 @@ from nova import exception
from nova.image import glance
from nova.openstack.common import fileutils
from nova.openstack.common import log as logging
+from nova.openstack.common import strutils
from nova import utils
LOG = logging.getLogger(__name__)
@@ -90,8 +91,8 @@ class QemuImgInfo(object):
if real_size:
details = real_size.group(1)
try:
- details = utils.to_bytes(details)
- except (TypeError, ValueError):
+ details = strutils.to_bytes(details)
+ except TypeError:
pass
return details
diff --git a/nova/virt/libvirt/driver.py b/nova/virt/libvirt/driver.py
index 6cfa2c7c7..6f1da242a 100755
--- a/nova/virt/libvirt/driver.py
+++ b/nova/virt/libvirt/driver.py
@@ -557,9 +557,6 @@ class LibvirtDriver(driver.ComputeDriver):
dispatch_thread = eventlet.spawn(self._dispatch_thread)
def init_host(self, host):
- libvirt.registerErrorHandler(libvirt_error_handler, None)
- libvirt.virEventRegisterDefaultImpl()
-
if not self.has_min_version(MIN_LIBVIRT_VERSION):
major = MIN_LIBVIRT_VERSION[0]
minor = MIN_LIBVIRT_VERSION[1]
@@ -568,6 +565,9 @@ class LibvirtDriver(driver.ComputeDriver):
'%(major)i.%(minor)i.%(micro)i or greater.') %
locals())
+ libvirt.registerErrorHandler(libvirt_error_handler, None)
+ libvirt.virEventRegisterDefaultImpl()
+
self._init_events()
def _get_connection(self):
diff --git a/nova/virt/vmwareapi/fake.py b/nova/virt/vmwareapi/fake.py
index 83c53e5cb..cd8302115 100644
--- a/nova/virt/vmwareapi/fake.py
+++ b/nova/virt/vmwareapi/fake.py
@@ -30,7 +30,7 @@ from nova.virt.vmwareapi import error_util
_CLASSES = ['Datacenter', 'Datastore', 'ResourcePool', 'VirtualMachine',
'Network', 'HostSystem', 'HostNetworkSystem', 'Task', 'session',
- 'files']
+ 'files', 'ClusterComputeResource']
_FAKE_FILE_SIZE = 1024
@@ -61,6 +61,7 @@ def reset():
create_datacenter()
create_datastore()
create_res_pool()
+ create_cluster()
def cleanup():
@@ -90,14 +91,20 @@ class Prop(object):
self.val = None
+class Obj(object):
+ def __init__(self, name, value):
+ self.value = value
+ self._type = name
+
+
class ManagedObject(object):
"""Managed Data Object base class."""
- def __init__(self, name="ManagedObject", obj_ref=None):
+ def __init__(self, name="ManagedObject", obj_ref=None, value=None):
"""Sets the obj property which acts as a reference to the object."""
super(ManagedObject, self).__setattr__('objName', name)
if obj_ref is None:
- obj_ref = str(uuid.uuid4())
+ obj_ref = Obj(name, value)
object.__setattr__(self, 'obj', obj_ref)
object.__setattr__(self, 'propSet', [])
@@ -141,6 +148,10 @@ class DataObject(object):
self.obj_name = obj_name
+class HostInternetScsiHba():
+ pass
+
+
class VirtualDisk(DataObject):
"""
Virtual Disk class.
@@ -186,7 +197,7 @@ class VirtualMachine(ManagedObject):
"""Virtual Machine class."""
def __init__(self, **kwargs):
- super(VirtualMachine, self).__init__("VirtualMachine")
+ super(VirtualMachine, self).__init__("VirtualMachine", value='vm-10')
self.set("name", kwargs.get("name"))
self.set("runtime.connectionState",
kwargs.get("conn_state", "connected"))
@@ -250,6 +261,25 @@ class ResourcePool(ManagedObject):
self.set("name", "ResPool")
+class ClusterComputeResource(ManagedObject):
+ """Cluster class."""
+ def __init__(self, **kwargs):
+ super(ClusterComputeResource, self).__init__("ClusterComputeResource",
+ value="domain-test")
+ r_pool = DataObject()
+ r_pool.ManagedObjectReference = [_get_objects("ResourcePool")[0].obj]
+ self.set("resourcePool", r_pool)
+
+ host_sys = DataObject()
+ host_sys.ManagedObjectReference = [_get_objects("HostSystem")[0].obj]
+ self.set("host", host_sys)
+ self.set("name", "test_cluster")
+
+ datastore = DataObject()
+ datastore.ManagedObjectReference = [_get_objects("Datastore")[0].obj]
+ self.set("datastore", datastore)
+
+
class Datastore(ManagedObject):
"""Datastore class."""
@@ -347,6 +377,17 @@ class HostSystem(ManagedObject):
host_pg.HostPortGroup = [host_pg_do]
self.set("config.network.portgroup", host_pg)
+ config = DataObject()
+ storageDevice = DataObject()
+
+ hostBusAdapter = HostInternetScsiHba()
+ hostBusAdapter.HostHostBusAdapter = [hostBusAdapter]
+ hostBusAdapter.iScsiName = "iscsi-name"
+ storageDevice.hostBusAdapter = hostBusAdapter
+ config.storageDevice = storageDevice
+ self.set("config.storageDevice.hostBusAdapter",
+ config.storageDevice.hostBusAdapter)
+
def _add_port_group(self, spec):
"""Adds a port group to the host system object in the db."""
pg_name = spec.name
@@ -429,6 +470,11 @@ def create_network():
_create_object('Network', network)
+def create_cluster():
+ cluster = ClusterComputeResource()
+ _create_object('ClusterComputeResource', cluster)
+
+
def create_task(task_name, state="running"):
task = Task(task_name, state)
_create_object("Task", task)
@@ -682,6 +728,8 @@ class FakeVim(object):
spec_set = kwargs.get("specSet")[0]
type = spec_set.propSet[0].type
properties = spec_set.propSet[0].pathSet
+ if not isinstance(properties, list):
+ properties = properties.split()
objs = spec_set.objectSet
lst_ret_objs = []
for obj in objs:
diff --git a/nova/wsgi.py b/nova/wsgi.py
index 72e464919..2e3f66f0d 100644
--- a/nova/wsgi.py
+++ b/nova/wsgi.py
@@ -37,6 +37,9 @@ from nova import exception
from nova.openstack.common import excutils
from nova.openstack.common import log as logging
+# Raise the default from 8192 to accommodate large tokens
+eventlet.wsgi.MAX_HEADER_LINE = 16384
+
wsgi_opts = [
cfg.StrOpt('api_paste_config',
default="api-paste.ini",
diff --git a/requirements.txt b/requirements.txt
index 7db3a2a0b..c10862581 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -28,6 +28,6 @@ python-quantumclient>=2.2.0,<3.0.0
python-glanceclient>=0.5.0,<2
python-keystoneclient>=0.2.0
six
-stevedore>=0.7
+stevedore>=0.9
websockify<0.4
oslo.config>=1.1.0
diff --git a/tools/xenserver/rotate_xen_guest_logs.sh b/tools/xenserver/rotate_xen_guest_logs.sh
new file mode 100755
index 000000000..0e6c7d6ea
--- /dev/null
+++ b/tools/xenserver/rotate_xen_guest_logs.sh
@@ -0,0 +1,62 @@
+#!/bin/bash
+set -eux
+
+# Script to rotate console logs
+#
+# Should be run on Dom0, with cron, every minute:
+# * * * * * /root/rotate_xen_guest_logs.sh
+#
+# Should clear out the guest logs on every boot
+# because the domain ids may get re-used for a
+# different tenant after the reboot
+#
+# /var/log/xen/guest should be mounted into a
+# small loopback device to stop any guest being
+# able to fill dom0 file system
+
+log_dir="/var/log/xen/guest"
+kb=1024
+max_size_bytes=$(($kb*$kb))
+truncated_size_bytes=$((5*$kb))
+list_domains=/opt/xensource/bin/list_domains
+
+log_file_base="${log_dir}/console."
+tmp_file_base="${log_dir}/tmp.console."
+
+# Ensure logging is setup correctly for all domains
+xenstore-write /local/logconsole/@ "${log_file_base}%d"
+
+# Move logs we want to keep
+domains=$($list_domains | sed '/^id*/d' | sed 's/|.*|.*$//g' | xargs)
+for i in $domains; do
+ log="${log_file_base}$i"
+ tmp="${tmp_file_base}$i"
+ mv $log $tmp || true
+done
+
+# Delete all console logs,
+# mostly to remove logs from recently killed domains
+rm -f ${log_dir}/console.*
+
+# Reload domain list, in case it changed
+# (note we may have just deleted a new console log)
+domains=$($list_domains | sed '/^id*/d' | sed 's/|.*|.*$//g' | xargs)
+for i in $domains; do
+ log="${log_file_base}$i"
+ tmp="${tmp_file_base}$i"
+ size=$(stat -c%s "$tmp")
+
+ # Trim the log if required
+ if [ "$size" -gt "$max_size_bytes" ]; then
+ tail -c $truncated_size_bytes $tmp > $log || true
+ else
+ mv $tmp $log || true
+ fi
+
+ # Notify xen that it needs to reload the file
+ xenstore-write /local/logconsole/$i $log
+ xenstore-rm /local/logconsole/$i
+done
+
+# Delete all the tmp files
+rm -f ${tmp_file_base}* || true