summaryrefslogtreecommitdiffstats
path: root/nova/tests
diff options
context:
space:
mode:
Diffstat (limited to 'nova/tests')
-rw-r--r--nova/tests/README.rst78
-rw-r--r--nova/tests/api/openstack/compute/contrib/test_admin_actions.py57
-rw-r--r--nova/tests/api/openstack/compute/contrib/test_console_output.py16
-rw-r--r--nova/tests/api/openstack/compute/contrib/test_extended_availability_zone.py30
-rw-r--r--nova/tests/api/openstack/compute/contrib/test_extended_ips.py168
-rw-r--r--nova/tests/api/openstack/compute/contrib/test_instance_actions.py231
-rw-r--r--nova/tests/api/openstack/compute/contrib/test_quotas.py39
-rw-r--r--nova/tests/api/openstack/compute/contrib/test_security_groups.py38
-rw-r--r--nova/tests/api/openstack/compute/contrib/test_server_start_stop.py21
-rw-r--r--nova/tests/api/openstack/compute/test_extensions.py2
-rw-r--r--nova/tests/compute/test_compute.py59
-rw-r--r--nova/tests/conductor/test_conductor.py83
-rw-r--r--nova/tests/fake_instance_actions.py58
-rw-r--r--nova/tests/fake_network.py4
-rw-r--r--nova/tests/fake_policy.py3
-rw-r--r--nova/tests/hyperv/fake.py52
-rw-r--r--nova/tests/integrated/api_samples/OS-EXT-AZ/server-get-resp.json.tpl3
-rw-r--r--nova/tests/integrated/api_samples/OS-EXT-AZ/server-get-resp.xml.tpl2
-rw-r--r--nova/tests/integrated/api_samples/OS-EXT-AZ/servers-detail-resp.json.tpl3
-rw-r--r--nova/tests/integrated/api_samples/OS-EXT-AZ/servers-detail-resp.xml.tpl2
-rw-r--r--nova/tests/integrated/api_samples/OS-EXT-IPS/server-get-resp.json.tpl55
-rw-r--r--nova/tests/integrated/api_samples/OS-EXT-IPS/server-get-resp.xml.tpl19
-rw-r--r--nova/tests/integrated/api_samples/OS-EXT-IPS/server-post-req.json.tpl16
-rw-r--r--nova/tests/integrated/api_samples/OS-EXT-IPS/server-post-req.xml.tpl19
-rw-r--r--nova/tests/integrated/api_samples/OS-EXT-IPS/server-post-resp.json.tpl16
-rw-r--r--nova/tests/integrated/api_samples/OS-EXT-IPS/server-post-resp.xml.tpl6
-rw-r--r--nova/tests/integrated/api_samples/OS-EXT-IPS/servers-detail-resp.json.tpl56
-rw-r--r--nova/tests/integrated/api_samples/OS-EXT-IPS/servers-detail-resp.xml.tpl21
-rw-r--r--nova/tests/integrated/api_samples/OS-EXT-SRV-ATTR/server-get-resp.json.tpl (renamed from nova/tests/integrated/api_samples/OS-EXT-SRV-ATTR/extended-server-attrs-get.json.tpl)0
-rw-r--r--nova/tests/integrated/api_samples/OS-EXT-SRV-ATTR/server-get-resp.xml.tpl (renamed from nova/tests/integrated/api_samples/OS-EXT-SRV-ATTR/extended-server-attrs-get.xml.tpl)0
-rw-r--r--nova/tests/integrated/api_samples/OS-EXT-SRV-ATTR/servers-detail-resp.json.tpl (renamed from nova/tests/integrated/api_samples/OS-EXT-SRV-ATTR/extended-server-attrs-list.json.tpl)0
-rw-r--r--nova/tests/integrated/api_samples/OS-EXT-SRV-ATTR/servers-detail-resp.xml.tpl (renamed from nova/tests/integrated/api_samples/OS-EXT-SRV-ATTR/extended-server-attrs-list.xml.tpl)0
-rw-r--r--nova/tests/integrated/api_samples/OS-EXT-STS/server-get-resp.json.tpl57
-rw-r--r--nova/tests/integrated/api_samples/OS-EXT-STS/server-get-resp.xml.tpl19
-rw-r--r--nova/tests/integrated/api_samples/OS-EXT-STS/servers-list-resp.json.tpl18
-rw-r--r--nova/tests/integrated/api_samples/OS-EXT-STS/servers-list-resp.xml.tpl7
-rw-r--r--nova/tests/integrated/api_samples/all_extensions/extensions-get-resp.json.tpl16
-rw-r--r--nova/tests/integrated/api_samples/all_extensions/extensions-get-resp.xml.tpl6
-rw-r--r--nova/tests/integrated/api_samples/all_extensions/server-get-resp.json.tpl4
-rw-r--r--nova/tests/integrated/api_samples/all_extensions/server-get-resp.xml.tpl4
-rw-r--r--nova/tests/integrated/api_samples/all_extensions/servers-details-resp.json.tpl4
-rw-r--r--nova/tests/integrated/api_samples/all_extensions/servers-details-resp.xml.tpl6
-rw-r--r--nova/tests/integrated/api_samples/os-config-drive/server-config-drive-get-resp.json.tpl55
-rw-r--r--nova/tests/integrated/api_samples/os-config-drive/server-config-drive-get-resp.xml.tpl19
-rw-r--r--nova/tests/integrated/api_samples/os-config-drive/server-post-req.json.tpl16
-rw-r--r--nova/tests/integrated/api_samples/os-config-drive/server-post-req.xml.tpl19
-rw-r--r--nova/tests/integrated/api_samples/os-config-drive/server-post-resp.json.tpl16
-rw-r--r--nova/tests/integrated/api_samples/os-config-drive/server-post-resp.xml.tpl6
-rw-r--r--nova/tests/integrated/api_samples/os-config-drive/servers-config-drive-details-resp.json.tpl57
-rw-r--r--nova/tests/integrated/api_samples/os-config-drive/servers-config-drive-details-resp.xml.tpl21
-rw-r--r--nova/tests/integrated/api_samples/os-floating-ip-dns/floating-ip-dns-create-or-update-entry-req.json.tpl7
-rw-r--r--nova/tests/integrated/api_samples/os-floating-ip-dns/floating-ip-dns-create-or-update-entry-req.xml.tpl5
-rw-r--r--nova/tests/integrated/api_samples/os-floating-ip-dns/floating-ip-dns-create-or-update-entry-resp.json.tpl9
-rw-r--r--nova/tests/integrated/api_samples/os-floating-ip-dns/floating-ip-dns-create-or-update-entry-resp.xml.tpl2
-rw-r--r--nova/tests/integrated/api_samples/os-floating-ip-dns/floating-ip-dns-create-or-update-req.json.tpl8
-rw-r--r--nova/tests/integrated/api_samples/os-floating-ip-dns/floating-ip-dns-create-or-update-req.xml.tpl6
-rw-r--r--nova/tests/integrated/api_samples/os-floating-ip-dns/floating-ip-dns-create-or-update-resp.json.tpl8
-rw-r--r--nova/tests/integrated/api_samples/os-floating-ip-dns/floating-ip-dns-create-or-update-resp.xml.tpl2
-rw-r--r--nova/tests/integrated/api_samples/os-floating-ip-dns/floating-ip-dns-entry-get-resp.json.tpl9
-rw-r--r--nova/tests/integrated/api_samples/os-floating-ip-dns/floating-ip-dns-entry-get-resp.xml.tpl2
-rw-r--r--nova/tests/integrated/api_samples/os-floating-ip-dns/floating-ip-dns-entry-list-resp.json.tpl11
-rw-r--r--nova/tests/integrated/api_samples/os-floating-ip-dns/floating-ip-dns-entry-list-resp.xml.tpl4
-rw-r--r--nova/tests/integrated/api_samples/os-floating-ip-dns/floating-ip-dns-list-resp.json.tpl10
-rw-r--r--nova/tests/integrated/api_samples/os-floating-ip-dns/floating-ip-dns-list-resp.xml.tpl4
-rw-r--r--nova/tests/integrated/api_samples/os-instance-actions/instance-action-get-resp.json.tpl27
-rw-r--r--nova/tests/integrated/api_samples/os-instance-actions/instance-action-get-resp.xml.tpl5
-rw-r--r--nova/tests/integrated/api_samples/os-instance-actions/instance-actions-list-resp.json.tpl22
-rw-r--r--nova/tests/integrated/api_samples/os-instance-actions/instance-actions-list-resp.xml.tpl5
-rw-r--r--nova/tests/integrated/api_samples/os-services/service-disable-put-req.json.tpl4
-rw-r--r--nova/tests/integrated/api_samples/os-services/service-disable-put-resp.json.tpl5
-rw-r--r--nova/tests/integrated/api_samples/os-services/service-enable-put-req.json.tpl4
-rw-r--r--nova/tests/integrated/api_samples/os-services/service-enable-put-resp.json.tpl5
-rw-r--r--nova/tests/integrated/api_samples/os-services/services-list-get-resp.json.tpl36
-rw-r--r--nova/tests/integrated/test_api_samples.py296
-rw-r--r--nova/tests/network/test_linux_net.py67
-rw-r--r--nova/tests/network/test_quantumv2.py12
-rw-r--r--nova/tests/scheduler/test_filter_scheduler.py176
-rw-r--r--nova/tests/scheduler/test_host_filters.py14
-rw-r--r--nova/tests/scheduler/test_scheduler.py56
-rw-r--r--nova/tests/servicegroup/test_zk_driver.py65
-rw-r--r--nova/tests/test_api.py7
-rw-r--r--nova/tests/test_crypto.py28
-rw-r--r--nova/tests/test_db_api.py6
-rw-r--r--nova/tests/test_hypervapi.py290
-rw-r--r--nova/tests/test_imagebackend.py8
-rw-r--r--nova/tests/test_instance_types.py11
-rw-r--r--nova/tests/test_libvirt_blockinfo.py2
-rw-r--r--nova/tests/test_libvirt_vif.py44
-rw-r--r--nova/tests/test_libvirt_volume.py56
-rw-r--r--nova/tests/test_metadata.py14
-rw-r--r--nova/tests/test_migration_utils.py126
-rw-r--r--nova/tests/test_migrations.py76
-rw-r--r--nova/tests/test_utils.py39
-rw-r--r--nova/tests/test_versions.py36
-rw-r--r--nova/tests/test_vmwareapi.py20
-rw-r--r--nova/tests/test_vmwareapi_vmops.py62
-rw-r--r--nova/tests/test_xenapi.py7
-rw-r--r--nova/tests/utils.py85
-rw-r--r--nova/tests/virt/xenapi/test_volumeops.py32
99 files changed, 3069 insertions, 273 deletions
diff --git a/nova/tests/README.rst b/nova/tests/README.rst
new file mode 100644
index 000000000..76b92258a
--- /dev/null
+++ b/nova/tests/README.rst
@@ -0,0 +1,78 @@
+=====================================
+OpenStack Nova Testing Infrastructure
+=====================================
+
+This README file attempts to provide current and prospective contributors with
+everything they need to know in order to start creating unit tests for nova.
+
+Note: the content for the rest of this file will be added as the work items in
+the following blueprint are completed:
+ https://blueprints.launchpad.net/nova/+spec/consolidate-testing-infrastructure
+
+
+Test Types: Unit vs. Functional vs. Integration
+-----------------------------------------------
+
+TBD
+
+Writing Unit Tests
+------------------
+
+TBD
+
+Using Fakes
+~~~~~~~~~~~
+
+TBD
+
+test.TestCase
+-------------
+The TestCase class from nova.test (generally imported as test) will
+automatically manage self.stubs using the stubout module and self.mox
+using the mox module during the setUp step. They will automatically
+verify and clean up during the tearDown step.
+
+If using test.TestCase, calling the super class setUp is required and
+calling the super class tearDown is required to be last if tearDown
+is overriden.
+
+Writing Functional Tests
+------------------------
+
+TBD
+
+Writing Integration Tests
+-------------------------
+
+TBD
+
+Tests and Exceptions
+--------------------
+A properly written test asserts that particular behavior occurs. This can
+be a success condition or a failure condition, including an exception.
+When asserting that a particular exception is raised, the most specific
+exception possible should be used.
+
+In particular, testing for Exception being raised is almost always a
+mistake since it will match (almost) every exception, even those
+unrelated to the exception intended to be tested.
+
+This applies to catching exceptions manually with a try/except block,
+or using assertRaises().
+
+Example::
+
+ self.assertRaises(exception.InstanceNotFound, db.instance_get_by_uuid,
+ elevated, instance_uuid)
+
+If a stubbed function/method needs a generic exception for testing
+purposes, test.TestingException is available.
+
+Example::
+
+ def stubbed_method(self):
+ raise test.TestingException()
+ self.stubs.Set(cls, 'inner_method', stubbed_method)
+
+ obj = cls()
+ self.assertRaises(test.TestingException, obj.outer_method)
diff --git a/nova/tests/api/openstack/compute/contrib/test_admin_actions.py b/nova/tests/api/openstack/compute/contrib/test_admin_actions.py
index dfb687cf4..76351e489 100644
--- a/nova/tests/api/openstack/compute/contrib/test_admin_actions.py
+++ b/nova/tests/api/openstack/compute/contrib/test_admin_actions.py
@@ -64,13 +64,6 @@ def fake_compute_api_get(self, context, instance_id):
'task_state': None}
-def fake_scheduler_api_live_migration(self, context, dest,
- block_migration=False,
- disk_over_commit=False, instance=None,
- instance_id=None, topic=None):
- return None
-
-
class AdminActionsTest(test.TestCase):
_actions = ('pause', 'unpause', 'suspend', 'resume', 'migrate',
@@ -93,9 +86,6 @@ class AdminActionsTest(test.TestCase):
self.UUID = uuid.uuid4()
for _method in self._methods:
self.stubs.Set(compute_api.API, _method, fake_compute_api)
- self.stubs.Set(scheduler_rpcapi.SchedulerAPI,
- 'live_migration',
- fake_scheduler_api_live_migration)
self.flags(
osapi_compute_extension=[
'nova.api.openstack.compute.contrib.select_extensions'],
@@ -150,7 +140,16 @@ class AdminActionsTest(test.TestCase):
task_state, expected_task_state):
return None
+ def fake_scheduler_api_live_migration(self, context, dest,
+ block_migration=False,
+ disk_over_commit=False, instance=None,
+ instance_id=None, topic=None):
+ return None
+
self.stubs.Set(compute_api.API, 'update', fake_update)
+ self.stubs.Set(scheduler_rpcapi.SchedulerAPI,
+ 'live_migration',
+ fake_scheduler_api_live_migration)
res = req.get_response(app)
self.assertEqual(res.status_int, 202)
@@ -174,6 +173,44 @@ class AdminActionsTest(test.TestCase):
res = req.get_response(app)
self.assertEqual(res.status_int, 400)
+ def test_migrate_live_compute_service_unavailable(self):
+ ctxt = context.get_admin_context()
+ ctxt.user_id = 'fake'
+ ctxt.project_id = 'fake'
+ ctxt.is_admin = True
+ app = fakes.wsgi_app(fake_auth_context=ctxt, init_only=('servers',))
+ req = webob.Request.blank('/v2/fake/servers/%s/action' % self.UUID)
+ req.method = 'POST'
+ req.body = jsonutils.dumps({
+ 'os-migrateLive': {
+ 'host': 'hostname',
+ 'block_migration': False,
+ 'disk_over_commit': False,
+ }
+ })
+ req.content_type = 'application/json'
+
+ def fake_update(inst, context, instance,
+ task_state, expected_task_state):
+ return None
+
+ def fake_scheduler_api_live_migration(context, dest,
+ block_migration=False,
+ disk_over_commit=False, instance=None,
+ instance_id=None, topic=None):
+ raise exception.ComputeServiceUnavailable(host='host')
+
+ self.stubs.Set(compute_api.API, 'update', fake_update)
+ self.stubs.Set(scheduler_rpcapi.SchedulerAPI,
+ 'live_migration',
+ fake_scheduler_api_live_migration)
+
+ res = req.get_response(app)
+ self.assertEqual(res.status_int, 400)
+ self.assertIn(
+ unicode(exception.ComputeServiceUnavailable(host='host')),
+ res.body)
+
class CreateBackupTests(test.TestCase):
diff --git a/nova/tests/api/openstack/compute/contrib/test_console_output.py b/nova/tests/api/openstack/compute/contrib/test_console_output.py
index d3f80b655..14b61abb7 100644
--- a/nova/tests/api/openstack/compute/contrib/test_console_output.py
+++ b/nova/tests/api/openstack/compute/contrib/test_console_output.py
@@ -35,6 +35,10 @@ def fake_get_console_output(self, _context, _instance, tail_length):
return '\n'.join(fixture)
+def fake_get_console_output_not_ready(self, _context, _instance, tail_length):
+ raise exception.InstanceNotReady(instance_id=_instance["uuid"])
+
+
def fake_get(self, context, instance_uuid):
return {'uuid': instance_uuid}
@@ -133,3 +137,15 @@ class ConsoleOutputExtensionTest(test.TestCase):
res = req.get_response(self.app)
self.assertEqual(res.status_int, 400)
+
+ def test_get_console_output_not_ready(self):
+ self.stubs.Set(compute_api.API, 'get_console_output',
+ fake_get_console_output_not_ready)
+ body = {'os-getConsoleOutput': {'length': 3}}
+ req = webob.Request.blank('/v2/fake/servers/1/action')
+ req.method = "POST"
+ req.body = jsonutils.dumps(body)
+ req.headers["content-type"] = "application/json"
+
+ res = req.get_response(self.app)
+ self.assertEqual(res.status_int, 409)
diff --git a/nova/tests/api/openstack/compute/contrib/test_extended_availability_zone.py b/nova/tests/api/openstack/compute/contrib/test_extended_availability_zone.py
index 8ebd810ac..d847e54f9 100644
--- a/nova/tests/api/openstack/compute/contrib/test_extended_availability_zone.py
+++ b/nova/tests/api/openstack/compute/contrib/test_extended_availability_zone.py
@@ -17,6 +17,7 @@ from lxml import etree
import webob
from nova.api.openstack.compute.contrib import extended_availability_zone
+from nova import availability_zones
from nova import compute
from nova import exception
from nova.openstack.common import jsonutils
@@ -29,19 +30,20 @@ UUID3 = '00000000-0000-0000-0000-000000000003'
def fake_compute_get(*args, **kwargs):
- inst = fakes.stub_instance(1, uuid=UUID3, host="host-fake")
- inst['availability_zone'] = 'az-i'
+ inst = fakes.stub_instance(1, uuid=UUID3, host="get-host")
return inst
def fake_compute_get_all(*args, **kwargs):
- inst1 = fakes.stub_instance(1, uuid=UUID1, host="host-1")
- inst2 = fakes.stub_instance(2, uuid=UUID2, host="host-2")
- inst1['availability_zone'] = 'az-i'
- inst2['availability_zone'] = 'az-i'
+ inst1 = fakes.stub_instance(1, uuid=UUID1, host="all-host")
+ inst2 = fakes.stub_instance(2, uuid=UUID2, host="all-host")
return [inst1, inst2]
+def fake_get_host_availability_zone(context, host):
+ return host
+
+
class ExtendedServerAttributesTest(test.TestCase):
content_type = 'application/json'
prefix = 'OS-EXT-AZ:'
@@ -51,6 +53,8 @@ class ExtendedServerAttributesTest(test.TestCase):
fakes.stub_out_nw_api(self.stubs)
self.stubs.Set(compute.api.API, 'get', fake_compute_get)
self.stubs.Set(compute.api.API, 'get_all', fake_compute_get_all)
+ self.stubs.Set(availability_zones, 'get_host_availability_zone',
+ fake_get_host_availability_zone)
self.flags(
osapi_compute_extension=[
@@ -69,20 +73,16 @@ class ExtendedServerAttributesTest(test.TestCase):
def _get_servers(self, body):
return jsonutils.loads(body).get('servers')
- def assertServerAttributes(self, server, az_instance, az_host):
+ def assertServerAttributes(self, server, az):
self.assertEqual(server.get('%savailability_zone' % self.prefix),
- az_instance)
- self.assertEqual(server.get('%shost_availability_zone' % self.prefix),
- az_host)
+ az)
def test_show(self):
url = '/v2/fake/servers/%s' % UUID3
res = self._make_request(url)
self.assertEqual(res.status_int, 200)
- self.assertServerAttributes(self._get_server(res.body),
- az_instance='az-i',
- az_host='nova')
+ self.assertServerAttributes(self._get_server(res.body), 'get-host')
def test_detail(self):
url = '/v2/fake/servers/detail'
@@ -90,9 +90,7 @@ class ExtendedServerAttributesTest(test.TestCase):
self.assertEqual(res.status_int, 200)
for i, server in enumerate(self._get_servers(res.body)):
- self.assertServerAttributes(server,
- az_instance='az-i',
- az_host='nova')
+ self.assertServerAttributes(server, 'all-host')
def test_no_instance_passthrough_404(self):
diff --git a/nova/tests/api/openstack/compute/contrib/test_extended_ips.py b/nova/tests/api/openstack/compute/contrib/test_extended_ips.py
new file mode 100644
index 000000000..9fd646b91
--- /dev/null
+++ b/nova/tests/api/openstack/compute/contrib/test_extended_ips.py
@@ -0,0 +1,168 @@
+# Copyright 2013 Nebula, Inc.
+# 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 lxml import etree
+import webob
+
+from nova.api.openstack.compute.contrib import extended_ips
+from nova.api.openstack import xmlutil
+from nova import compute
+from nova.openstack.common import jsonutils
+from nova import test
+from nova.tests.api.openstack import fakes
+
+UUID1 = '00000000-0000-0000-0000-000000000001'
+UUID2 = '00000000-0000-0000-0000-000000000002'
+UUID3 = '00000000-0000-0000-0000-000000000003'
+NW_CACHE = [
+ {
+ 'address': 'aa:aa:aa:aa:aa:aa',
+ 'id': 1,
+ 'network': {
+ 'bridge': 'br0',
+ 'id': 1,
+ 'label': 'private',
+ 'subnets': [
+ {
+ 'cidr': '192.168.1.0/24',
+ 'ips': [
+ {
+ 'address': '192.168.1.100',
+ 'type': 'fixed',
+ 'floating_ips': [
+ {'address': '5.0.0.1', 'type': 'floating'},
+ ],
+ },
+ ],
+ },
+ ]
+ }
+ },
+ {
+ 'address': 'bb:bb:bb:bb:bb:bb',
+ 'id': 2,
+ 'network': {
+ 'bridge': 'br1',
+ 'id': 2,
+ 'label': 'public',
+ 'subnets': [
+ {
+ 'cidr': '10.0.0.0/24',
+ 'ips': [
+ {
+ 'address': '10.0.0.100',
+ 'type': 'fixed',
+ 'floating_ips': [
+ {'address': '5.0.0.2', 'type': 'floating'},
+ ],
+ }
+ ],
+ },
+ ]
+ }
+ }
+]
+ALL_IPS = []
+for cache in NW_CACHE:
+ for subnet in cache['network']['subnets']:
+ for fixed in subnet['ips']:
+ sanitized = dict(fixed)
+ sanitized.pop('floating_ips')
+ ALL_IPS.append(sanitized)
+ for floating in fixed['floating_ips']:
+ ALL_IPS.append(floating)
+ALL_IPS.sort()
+
+
+def fake_compute_get(*args, **kwargs):
+ return fakes.stub_instance(1, uuid=UUID3, nw_cache=NW_CACHE)
+
+
+def fake_compute_get_all(*args, **kwargs):
+ return [
+ fakes.stub_instance(1, uuid=UUID1, nw_cache=NW_CACHE),
+ fakes.stub_instance(2, uuid=UUID2, nw_cache=NW_CACHE),
+ ]
+
+
+class ExtendedIpsTest(test.TestCase):
+ content_type = 'application/json'
+ prefix = 'OS-EXT-IPS:'
+
+ def setUp(self):
+ super(ExtendedIpsTest, self).setUp()
+ fakes.stub_out_nw_api(self.stubs)
+ self.stubs.Set(compute.api.API, 'get', fake_compute_get)
+ self.stubs.Set(compute.api.API, 'get_all', fake_compute_get_all)
+ self.flags(
+ osapi_compute_extension=[
+ 'nova.api.openstack.compute.contrib.select_extensions'],
+ osapi_compute_ext_list=['Extended_ips'])
+
+ def _make_request(self, url):
+ req = webob.Request.blank(url)
+ req.headers['Accept'] = self.content_type
+ res = req.get_response(fakes.wsgi_app(init_only=('servers',)))
+ return res
+
+ def _get_server(self, body):
+ return jsonutils.loads(body).get('server')
+
+ def _get_servers(self, body):
+ return jsonutils.loads(body).get('servers')
+
+ def _get_ips(self, server):
+ for network in server['addresses'].itervalues():
+ for ip in network:
+ yield ip
+
+ def assertServerStates(self, server):
+ results = []
+ for ip in self._get_ips(server):
+ results.append({'address': ip.get('addr'),
+ 'type': ip.get('%stype' % self.prefix)})
+
+ self.assertEqual(ALL_IPS, sorted(results))
+
+ def test_show(self):
+ url = '/v2/fake/servers/%s' % UUID3
+ res = self._make_request(url)
+
+ self.assertEqual(res.status_int, 200)
+ self.assertServerStates(self._get_server(res.body))
+
+ def test_detail(self):
+ url = '/v2/fake/servers/detail'
+ res = self._make_request(url)
+
+ self.assertEqual(res.status_int, 200)
+ for i, server in enumerate(self._get_servers(res.body)):
+ self.assertServerStates(server)
+
+
+class ExtendedIpsXmlTest(ExtendedIpsTest):
+ content_type = 'application/xml'
+ prefix = '{%s}' % extended_ips.Extended_ips.namespace
+
+ def _get_server(self, body):
+ return etree.XML(body)
+
+ def _get_servers(self, body):
+ return etree.XML(body).getchildren()
+
+ def _get_ips(self, server):
+ for network in server.find('{%s}addresses' % xmlutil.XMLNS_V11):
+ for ip in network:
+ yield ip
diff --git a/nova/tests/api/openstack/compute/contrib/test_instance_actions.py b/nova/tests/api/openstack/compute/contrib/test_instance_actions.py
new file mode 100644
index 000000000..b4db5daba
--- /dev/null
+++ b/nova/tests/api/openstack/compute/contrib/test_instance_actions.py
@@ -0,0 +1,231 @@
+# Copyright 2013 Rackspace Hosting
+# All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+import copy
+import uuid
+
+from lxml import etree
+from webob import exc
+
+from nova.api.openstack.compute.contrib import instance_actions
+from nova import db
+from nova import exception
+from nova.openstack.common import policy
+from nova import test
+from nova.tests.api.openstack import fakes
+from nova.tests import fake_instance_actions
+
+FAKE_UUID = fake_instance_actions.FAKE_UUID
+FAKE_REQUEST_ID = fake_instance_actions.FAKE_REQUEST_ID1
+
+
+def format_action(action):
+ '''Remove keys that aren't serialized.'''
+ if 'id' in action:
+ del(action['id'])
+ if 'finish_time' in action:
+ del(action['finish_time'])
+ return action
+
+
+def format_event(event):
+ '''Remove keys that aren't serialized.'''
+ if 'id' in event:
+ del(event['id'])
+ return event
+
+
+class InstanceActionsPolicyTest(test.TestCase):
+ def setUp(self):
+ super(InstanceActionsPolicyTest, self).setUp()
+ self.controller = instance_actions.InstanceActionsController()
+
+ def test_list_actions_restricted_by_project(self):
+ rules = policy.Rules({'compute:get': policy.parse_rule(''),
+ 'compute_extension:instance_actions':
+ policy.parse_rule('project_id:%(project_id)s')})
+ policy.set_rules(rules)
+
+ def fake_instance_get_by_uuid(context, instance_id):
+ return {'name': 'fake', 'project_id': '%s_unequal' %
+ context.project_id}
+
+ self.stubs.Set(db, 'instance_get_by_uuid', fake_instance_get_by_uuid)
+ req = fakes.HTTPRequest.blank('/v2/123/servers/12/os-instance-actions')
+ self.assertRaises(exception.NotAuthorized, self.controller.index, req,
+ str(uuid.uuid4()))
+
+ def test_get_action_restricted_by_project(self):
+ rules = policy.Rules({'compute:get': policy.parse_rule(''),
+ 'compute_extension:instance_actions':
+ policy.parse_rule('project_id:%(project_id)s')})
+ policy.set_rules(rules)
+
+ def fake_instance_get_by_uuid(context, instance_id):
+ return {'name': 'fake', 'project_id': '%s_unequal' %
+ context.project_id}
+
+ self.stubs.Set(db, 'instance_get_by_uuid', fake_instance_get_by_uuid)
+ req = fakes.HTTPRequest.blank(
+ '/v2/123/servers/12/os-instance-actions/1')
+ self.assertRaises(exception.NotAuthorized, self.controller.show, req,
+ str(uuid.uuid4()), '1')
+
+
+class InstanceActionsTest(test.TestCase):
+ def setUp(self):
+ super(InstanceActionsTest, self).setUp()
+ self.controller = instance_actions.InstanceActionsController()
+ self.fake_actions = copy.deepcopy(fake_instance_actions.FAKE_ACTIONS)
+ self.fake_events = copy.deepcopy(fake_instance_actions.FAKE_EVENTS)
+
+ def fake_instance_get_by_uuid(context, instance_id):
+ return {'name': 'fake', 'project_id': context.project_id}
+
+ self.stubs.Set(db, 'instance_get_by_uuid', fake_instance_get_by_uuid)
+
+ def test_list_actions(self):
+ def fake_get_actions(context, uuid):
+ return self.fake_actions[uuid].values()
+
+ self.stubs.Set(db, 'actions_get', fake_get_actions)
+ req = fakes.HTTPRequest.blank('/v2/123/servers/12/os-instance-actions')
+ res_dict = self.controller.index(req, FAKE_UUID)
+ for res in res_dict['instanceActions']:
+ fake_action = self.fake_actions[FAKE_UUID][res['request_id']]
+ fake_action = format_action(fake_action)
+ self.assertEqual(fake_action, res)
+
+ def test_get_action_with_events_allowed(self):
+ def fake_get_action(context, uuid, request_id):
+ return self.fake_actions[uuid][request_id]
+
+ def fake_get_events(context, action_id):
+ return self.fake_events[action_id]
+
+ self.stubs.Set(db, 'action_get_by_request_id', fake_get_action)
+ self.stubs.Set(db, 'action_events_get', fake_get_events)
+ req = fakes.HTTPRequest.blank(
+ '/v2/123/servers/12/os-instance-actions/1',
+ use_admin_context=True)
+ res_dict = self.controller.show(req, FAKE_UUID, FAKE_REQUEST_ID)
+ fake_action = self.fake_actions[FAKE_UUID][FAKE_REQUEST_ID]
+ fake_events = self.fake_events[fake_action['id']]
+ fake_events = [format_event(event) for event in fake_events]
+ fake_action = format_action(fake_action)
+ fake_action['events'] = fake_events
+ self.assertEqual(fake_action, res_dict['instanceAction'])
+
+ def test_get_action_with_events_not_allowed(self):
+ def fake_get_action(context, uuid, request_id):
+ return self.fake_actions[uuid][request_id]
+
+ def fake_get_events(context, action_id):
+ return self.fake_events[action_id]
+
+ self.stubs.Set(db, 'action_get_by_request_id', fake_get_action)
+ self.stubs.Set(db, 'action_events_get', fake_get_events)
+ rules = policy.Rules({'compute:get': policy.parse_rule(''),
+ 'compute_extension:instance_actions':
+ policy.parse_rule(''),
+ 'compute_extension:instance_actions:events':
+ policy.parse_rule('is_admin:True')})
+ policy.set_rules(rules)
+ req = fakes.HTTPRequest.blank(
+ '/v2/123/servers/12/os-instance-actions/1')
+ res_dict = self.controller.show(req, FAKE_UUID, FAKE_REQUEST_ID)
+ fake_action = self.fake_actions[FAKE_UUID][FAKE_REQUEST_ID]
+ fake_action = format_action(fake_action)
+ self.assertEqual(fake_action, res_dict['instanceAction'])
+
+ def test_action_not_found(self):
+ def fake_no_action(context, uuid, action_id):
+ return None
+
+ self.stubs.Set(db, 'action_get_by_request_id', fake_no_action)
+ req = fakes.HTTPRequest.blank(
+ '/v2/123/servers/12/os-instance-actions/1')
+ self.assertRaises(exc.HTTPNotFound, self.controller.show, req,
+ FAKE_UUID, FAKE_REQUEST_ID)
+
+
+class InstanceActionsSerializerTest(test.TestCase):
+ def setUp(self):
+ super(InstanceActionsSerializerTest, self).setUp()
+ self.fake_actions = copy.deepcopy(fake_instance_actions.FAKE_ACTIONS)
+ self.fake_events = copy.deepcopy(fake_instance_actions.FAKE_EVENTS)
+
+ def _verify_instance_action_attachment(self, attach, tree):
+ for key in attach.keys():
+ if key != 'events':
+ self.assertEqual(attach[key], tree.get(key),
+ '%s did not match' % key)
+
+ def _verify_instance_action_event_attachment(self, attach, tree):
+ for key in attach.keys():
+ self.assertEqual(attach[key], tree.get(key),
+ '%s did not match' % key)
+
+ def test_instance_action_serializer(self):
+ serializer = instance_actions.InstanceActionTemplate()
+ action = self.fake_actions[FAKE_UUID][FAKE_REQUEST_ID]
+ text = serializer.serialize({'instanceAction': action})
+ tree = etree.fromstring(text)
+
+ action = format_action(action)
+ self.assertEqual('instanceAction', tree.tag)
+ self._verify_instance_action_attachment(action, tree)
+ found_events = False
+ for child in tree:
+ if child.tag == 'events':
+ found_events = True
+ self.assertFalse(found_events)
+
+ def test_instance_action_events_serializer(self):
+ serializer = instance_actions.InstanceActionTemplate()
+ action = self.fake_actions[FAKE_UUID][FAKE_REQUEST_ID]
+ event = self.fake_events[action['id']][0]
+ action['events'] = [event, event]
+ text = serializer.serialize({'instanceAction': action})
+ tree = etree.fromstring(text)
+
+ action = format_action(action)
+ self.assertEqual('instanceAction', tree.tag)
+ self._verify_instance_action_attachment(action, tree)
+
+ event = format_event(event)
+ found_events = False
+ for child in tree:
+ if child.tag == 'events':
+ found_events = True
+ for key in event:
+ self.assertEqual(event[key], child.get(key))
+ self.assertTrue(found_events)
+
+ def test_instance_actions_serializer(self):
+ serializer = instance_actions.InstanceActionsTemplate()
+ action_list = self.fake_actions[FAKE_UUID].values()
+ text = serializer.serialize({'instanceActions': action_list})
+ tree = etree.fromstring(text)
+
+ action_list = [format_action(action) for action in action_list]
+ self.assertEqual('instanceActions', tree.tag)
+ self.assertEqual(len(action_list), len(tree))
+ for idx, child in enumerate(tree):
+ self.assertEqual('instanceAction', child.tag)
+ request_id = child.get('request_id')
+ self._verify_instance_action_attachment(
+ self.fake_actions[FAKE_UUID][request_id],
+ child)
diff --git a/nova/tests/api/openstack/compute/contrib/test_quotas.py b/nova/tests/api/openstack/compute/contrib/test_quotas.py
index 8d518b815..6636824fd 100644
--- a/nova/tests/api/openstack/compute/contrib/test_quotas.py
+++ b/nova/tests/api/openstack/compute/contrib/test_quotas.py
@@ -143,6 +143,45 @@ class QuotaSetsTest(test.TestCase):
self.assertRaises(webob.exc.HTTPBadRequest, self.controller.update,
req, 'update_me', body)
+ def test_quotas_update_invalid_value(self):
+ expected_resp = {'quota_set': {
+ 'instances': 50, 'cores': 50,
+ 'ram': 51200, 'floating_ips': 10,
+ 'metadata_items': 128, 'injected_files': 5,
+ 'injected_file_content_bytes': 10240,
+ 'injected_file_path_bytes': 255,
+ 'security_groups': 10,
+ 'security_group_rules': 20,
+ 'key_pairs': 100}}
+
+ # when PUT JSON format with empty string for quota
+ body = {'quota_set': {'instances': 50, 'cores': 50,
+ 'ram': '', 'floating_ips': 10,
+ 'metadata_items': 128, 'injected_files': 5,
+ 'injected_file_content_bytes': 10240,
+ 'injected_file_path_bytes': 255,
+ 'security_groups': 10,
+ 'security_group_rules': 20,
+ 'key_pairs': 100}}
+ req = fakes.HTTPRequest.blank('/v2/fake4/os-quota-sets/update_me',
+ use_admin_context=True)
+ res_dict = self.controller.update(req, 'update_me', body)
+ self.assertEqual(res_dict, expected_resp)
+
+ # when PUT XML format with empty string for quota
+ body = {'quota_set': {'instances': 50, 'cores': 50,
+ 'ram': {}, 'floating_ips': 10,
+ 'metadata_items': 128, 'injected_files': 5,
+ 'injected_file_content_bytes': 10240,
+ 'injected_file_path_bytes': 255,
+ 'security_groups': 10,
+ 'security_group_rules': 20,
+ 'key_pairs': 100}}
+ req = fakes.HTTPRequest.blank('/v2/fake4/os-quota-sets/update_me',
+ use_admin_context=True)
+ res_dict = self.controller.update(req, 'update_me', body)
+ self.assertEqual(res_dict, expected_resp)
+
class QuotaXMLSerializerTest(test.TestCase):
def setUp(self):
diff --git a/nova/tests/api/openstack/compute/contrib/test_security_groups.py b/nova/tests/api/openstack/compute/contrib/test_security_groups.py
index 231923e6d..2823c3e8f 100644
--- a/nova/tests/api/openstack/compute/contrib/test_security_groups.py
+++ b/nova/tests/api/openstack/compute/contrib/test_security_groups.py
@@ -448,6 +448,9 @@ class TestSecurityGroups(test.TestCase):
req, '1')
def test_associate_by_non_existing_security_group_name(self):
+ self.stubs.Set(nova.db, 'instance_get', return_server)
+ self.assertEquals(return_server(None, '1'),
+ nova.db.instance_get(None, '1'))
body = dict(addSecurityGroup=dict(name='non-existing'))
req = fakes.HTTPRequest.blank('/v2/fake/servers/1/action')
@@ -537,6 +540,9 @@ class TestSecurityGroups(test.TestCase):
self.manager._addSecurityGroup(req, '1', body)
def test_disassociate_by_non_existing_security_group_name(self):
+ self.stubs.Set(nova.db, 'instance_get', return_server)
+ self.assertEquals(return_server(None, '1'),
+ nova.db.instance_get(None, '1'))
body = dict(removeSecurityGroup=dict(name='non-existing'))
req = fakes.HTTPRequest.blank('/v2/fake/servers/1/action')
@@ -1011,6 +1017,38 @@ class TestSecurityGroupRules(test.TestCase):
self.controller.create,
req, {'security_group_rule': rule})
+ def test_create_rule_cidr_allow_all(self):
+ rule = security_group_rule_template(cidr='0.0.0.0/0')
+
+ req = fakes.HTTPRequest.blank('/v2/fake/os-security-group-rules')
+ res_dict = self.controller.create(req, {'security_group_rule': rule})
+
+ security_group_rule = res_dict['security_group_rule']
+ self.assertNotEquals(security_group_rule['id'], 0)
+ self.assertEquals(security_group_rule['parent_group_id'],
+ self.parent_security_group['id'])
+ self.assertEquals(security_group_rule['ip_range']['cidr'],
+ "0.0.0.0/0")
+
+ def test_create_rule_cidr_allow_some(self):
+ rule = security_group_rule_template(cidr='15.0.0.0/8')
+
+ req = fakes.HTTPRequest.blank('/v2/fake/os-security-group-rules')
+ res_dict = self.controller.create(req, {'security_group_rule': rule})
+
+ security_group_rule = res_dict['security_group_rule']
+ self.assertNotEquals(security_group_rule['id'], 0)
+ self.assertEquals(security_group_rule['parent_group_id'],
+ self.parent_security_group['id'])
+ self.assertEquals(security_group_rule['ip_range']['cidr'],
+ "15.0.0.0/8")
+
+ def test_create_rule_cidr_bad_netmask(self):
+ rule = security_group_rule_template(cidr='15.0.0.0/0')
+ req = fakes.HTTPRequest.blank('/v2/fake/os-security-group-rules')
+ self.assertRaises(webob.exc.HTTPBadRequest, self.controller.create,
+ req, {'security_group_rule': rule})
+
class TestSecurityGroupRulesXMLDeserializer(test.TestCase):
diff --git a/nova/tests/api/openstack/compute/contrib/test_server_start_stop.py b/nova/tests/api/openstack/compute/contrib/test_server_start_stop.py
index 554379e74..eb708a574 100644
--- a/nova/tests/api/openstack/compute/contrib/test_server_start_stop.py
+++ b/nova/tests/api/openstack/compute/contrib/test_server_start_stop.py
@@ -17,6 +17,7 @@ import webob
from nova.api.openstack.compute.contrib import server_start_stop
from nova.compute import api as compute_api
+from nova import exception
from nova import test
from nova.tests.api.openstack import fakes
@@ -25,6 +26,10 @@ def fake_compute_api_get(self, context, instance_id):
return {'id': 1, 'uuid': instance_id}
+def fake_start_stop_not_ready(self, context, instance):
+ raise exception.InstanceNotReady(instance_id=instance["uuid"])
+
+
class ServerStartStopTest(test.TestCase):
def setUp(self):
@@ -41,6 +46,14 @@ class ServerStartStopTest(test.TestCase):
body = dict(start="")
self.controller._start_server(req, 'test_inst', body)
+ def test_start_not_ready(self):
+ self.stubs.Set(compute_api.API, 'get', fake_compute_api_get)
+ self.stubs.Set(compute_api.API, 'start', fake_start_stop_not_ready)
+ req = fakes.HTTPRequest.blank('/v2/fake/servers/test_inst/action')
+ body = dict(start="")
+ self.assertRaises(webob.exc.HTTPConflict,
+ self.controller._start_server, req, 'test_inst', body)
+
def test_stop(self):
self.stubs.Set(compute_api.API, 'get', fake_compute_api_get)
self.mox.StubOutWithMock(compute_api.API, 'stop')
@@ -51,6 +64,14 @@ class ServerStartStopTest(test.TestCase):
body = dict(stop="")
self.controller._stop_server(req, 'test_inst', body)
+ def test_stop_not_ready(self):
+ self.stubs.Set(compute_api.API, 'get', fake_compute_api_get)
+ self.stubs.Set(compute_api.API, 'stop', fake_start_stop_not_ready)
+ req = fakes.HTTPRequest.blank('/v2/fake/servers/test_inst/action')
+ body = dict(start="")
+ self.assertRaises(webob.exc.HTTPConflict,
+ self.controller._stop_server, req, 'test_inst', body)
+
def test_start_with_bogus_id(self):
req = fakes.HTTPRequest.blank('/v2/fake/servers/test_inst/action')
body = dict(start="")
diff --git a/nova/tests/api/openstack/compute/test_extensions.py b/nova/tests/api/openstack/compute/test_extensions.py
index a52b0e0fc..9c45edc08 100644
--- a/nova/tests/api/openstack/compute/test_extensions.py
+++ b/nova/tests/api/openstack/compute/test_extensions.py
@@ -167,6 +167,7 @@ class ExtensionControllerTest(ExtensionTestCase):
"DeferredDelete",
"DiskConfig",
"ExtendedAvailabilityZone",
+ "ExtendedIps",
"Evacuate",
"ExtendedStatus",
"ExtendedServerAttributes",
@@ -184,6 +185,7 @@ class ExtensionControllerTest(ExtensionTestCase):
"FloatingIpsBulk",
"Fox In Socks",
"Hosts",
+ "InstanceActions",
"Keypairs",
"Multinic",
"MultipleCreate",
diff --git a/nova/tests/compute/test_compute.py b/nova/tests/compute/test_compute.py
index a75ba00cc..5afaa8e3c 100644
--- a/nova/tests/compute/test_compute.py
+++ b/nova/tests/compute/test_compute.py
@@ -2640,10 +2640,11 @@ class ComputeTestCase(BaseTestCase):
# creating mocks
self.mox.StubOutWithMock(self.compute.driver, 'unfilter_instance')
self.compute.driver.unfilter_instance(inst_ref, [])
- self.mox.StubOutWithMock(self.compute.network_api,
- 'migrate_instance_start')
+ self.mox.StubOutWithMock(self.compute.conductor_api,
+ 'network_migrate_instance_start')
migration = {'source_compute': srchost, 'dest_compute': dest, }
- self.compute.network_api.migrate_instance_start(c, inst_ref, migration)
+ self.compute.conductor_api.network_migrate_instance_start(c, inst_ref,
+ migration)
self.mox.StubOutWithMock(rpc, 'call')
rpc.call(c, rpc.queue_get_for(c, CONF.compute_topic, dest),
{"method": "post_live_migration_at_destination",
@@ -2684,11 +2685,12 @@ class ComputeTestCase(BaseTestCase):
# creating mocks
self.mox.StubOutWithMock(self.compute.driver, 'unfilter_instance')
self.compute.driver.unfilter_instance(inst_ref, [])
- self.mox.StubOutWithMock(self.compute.network_api,
- 'migrate_instance_start')
+ self.mox.StubOutWithMock(self.compute.conductor_api,
+ 'network_migrate_instance_start')
migration = {'source_compute': srchost,
'dest_compute': dest, }
- self.compute.network_api.migrate_instance_start(c, inst_ref, migration)
+ self.compute.conductor_api.network_migrate_instance_start(c, inst_ref,
+ migration)
self.mox.StubOutWithMock(rpc, 'call')
rpc.call(c, rpc.queue_get_for(c, CONF.compute_topic, dest),
{"method": "post_live_migration_at_destination",
@@ -2710,8 +2712,8 @@ class ComputeTestCase(BaseTestCase):
def test_post_live_migration_at_destination(self):
self.mox.StubOutWithMock(self.compute.network_api,
'setup_networks_on_host')
- self.mox.StubOutWithMock(self.compute.network_api,
- 'migrate_instance_finish')
+ self.mox.StubOutWithMock(self.compute.conductor_api,
+ 'network_migrate_instance_finish')
self.mox.StubOutWithMock(self.compute, '_get_power_state')
self.mox.StubOutWithMock(self.compute, '_instance_update')
@@ -2726,8 +2728,8 @@ class ComputeTestCase(BaseTestCase):
self.compute.host)
migration = {'source_compute': instance['host'],
'dest_compute': self.compute.host, }
- self.compute.network_api.migrate_instance_finish(admin_ctxt,
- instance, migration)
+ self.compute.conductor_api.network_migrate_instance_finish(admin_ctxt,
+ instance, migration)
fake_net_info = []
fake_block_dev_info = {'foo': 'bar'}
self.compute.driver.post_live_migration_at_destination(admin_ctxt,
@@ -3804,6 +3806,15 @@ class ComputeAPITestCase(BaseTestCase):
db.instance_destroy(self.context, instance['uuid'])
+ def test_start_no_host(self):
+ instance = self._create_fake_instance(params={'host': ''})
+
+ self.assertRaises(exception.InstanceNotReady,
+ self.compute_api.start,
+ self.context, instance)
+
+ db.instance_destroy(self.context, instance['uuid'])
+
def test_stop(self):
instance = jsonutils.to_primitive(self._create_fake_instance())
instance_uuid = instance['uuid']
@@ -3819,6 +3830,15 @@ class ComputeAPITestCase(BaseTestCase):
db.instance_destroy(self.context, instance['uuid'])
+ def test_stop_no_host(self):
+ instance = self._create_fake_instance(params={'host': ''})
+
+ self.assertRaises(exception.InstanceNotReady,
+ self.compute_api.stop,
+ self.context, instance)
+
+ db.instance_destroy(self.context, instance['uuid'])
+
def test_start_shutdown(self):
def check_state(instance_uuid, power_state_, vm_state_, task_state_):
instance = db.instance_get_by_uuid(self.context, instance_uuid)
@@ -5657,6 +5677,15 @@ class ComputeAPITestCase(BaseTestCase):
fake_instance, tail_length=fake_tail_length)
self.assertEqual(output, fake_console_output)
+ def test_console_output_no_host(self):
+ instance = self._create_fake_instance(params={'host': ''})
+
+ self.assertRaises(exception.InstanceNotReady,
+ self.compute_api.get_console_output,
+ self.context, instance)
+
+ db.instance_destroy(self.context, instance['uuid'])
+
def test_attach_volume(self):
# Ensure instance can be soft rebooted.
@@ -6161,6 +6190,16 @@ class ComputeAPIAggrTestCase(BaseTestCase):
self.stubs.Set(rpc, 'call', fake_rpc_method)
self.stubs.Set(rpc, 'cast', fake_rpc_method)
+ def test_aggregate_no_zone(self):
+ # Ensure we can create an aggregate without an availability zone
+ aggr = self.api.create_aggregate(self.context, 'fake_aggregate',
+ None)
+ self.api.delete_aggregate(self.context, aggr['id'])
+ db.aggregate_get(self.context.elevated(read_deleted='yes'),
+ aggr['id'])
+ self.assertRaises(exception.AggregateNotFound,
+ self.api.delete_aggregate, self.context, aggr['id'])
+
def test_update_aggregate_metadata(self):
# Ensure metadata can be updated.
aggr = self.api.create_aggregate(self.context, 'fake_aggregate',
diff --git a/nova/tests/conductor/test_conductor.py b/nova/tests/conductor/test_conductor.py
index bd73328e8..ed733599b 100644
--- a/nova/tests/conductor/test_conductor.py
+++ b/nova/tests/conductor/test_conductor.py
@@ -16,6 +16,7 @@
import mox
+from nova.api.ec2 import ec2utils
from nova.compute import instance_types
from nova.compute import utils as compute_utils
from nova.compute import vm_states
@@ -31,6 +32,7 @@ from nova import notifications
from nova.openstack.common import jsonutils
from nova.openstack.common.rpc import common as rpc_common
from nova.openstack.common import timeutils
+from nova import quota
from nova import test
@@ -240,6 +242,15 @@ class _BaseTestCase(object):
aggregate,
'fake')
+ def test_aggregate_metadata_get_by_host(self):
+ self.mox.StubOutWithMock(db, 'aggregate_metadata_get_by_host')
+ db.aggregate_metadata_get_by_host(self.context, 'host',
+ 'key').AndReturn('result')
+ self.mox.ReplayAll()
+ result = self.conductor.aggregate_metadata_get_by_host(self.context,
+ 'host', 'key')
+ self.assertEqual(result, 'result')
+
def test_bw_usage_update(self):
self.mox.StubOutWithMock(db, 'bw_usage_update')
self.mox.StubOutWithMock(db, 'bw_usage_get')
@@ -503,6 +514,78 @@ class _BaseTestCase(object):
self.conductor.security_groups_trigger_members_refresh(self.context,
[1, 2, 3])
+ def test_network_migrate_instance_start(self):
+ self.mox.StubOutWithMock(self.conductor_manager.network_api,
+ 'migrate_instance_start')
+ self.conductor_manager.network_api.migrate_instance_start(self.context,
+ 'instance',
+ 'migration')
+ self.mox.ReplayAll()
+ self.conductor.network_migrate_instance_start(self.context,
+ 'instance',
+ 'migration')
+
+ def test_network_migrate_instance_finish(self):
+ self.mox.StubOutWithMock(self.conductor_manager.network_api,
+ 'migrate_instance_finish')
+ self.conductor_manager.network_api.migrate_instance_finish(
+ self.context, 'instance', 'migration')
+ self.mox.ReplayAll()
+ self.conductor.network_migrate_instance_finish(self.context,
+ 'instance',
+ 'migration')
+
+ def test_quota_commit(self):
+ self.mox.StubOutWithMock(quota.QUOTAS, 'commit')
+ quota.QUOTAS.commit(self.context, 'reservations')
+ self.mox.ReplayAll()
+ self.conductor.quota_commit(self.context, 'reservations')
+
+ def test_quota_commit(self):
+ self.mox.StubOutWithMock(quota.QUOTAS, 'rollback')
+ quota.QUOTAS.rollback(self.context, 'reservations')
+ self.mox.ReplayAll()
+ self.conductor.quota_rollback(self.context, 'reservations')
+
+ def test_get_ec2_ids(self):
+ expected = {
+ 'instance-id': 'ec2-inst-id',
+ 'ami-id': 'ec2-ami-id',
+ 'kernel-id': 'ami-kernel-ec2-kernelid',
+ 'ramdisk-id': 'ami-ramdisk-ec2-ramdiskid',
+ }
+ inst = {
+ 'uuid': 'fake-uuid',
+ 'kernel_id': 'ec2-kernelid',
+ 'ramdisk_id': 'ec2-ramdiskid',
+ 'image_ref': 'fake-image',
+ }
+ self.mox.StubOutWithMock(ec2utils, 'id_to_ec2_inst_id')
+ self.mox.StubOutWithMock(ec2utils, 'glance_id_to_ec2_id')
+ self.mox.StubOutWithMock(ec2utils, 'image_type')
+
+ ec2utils.id_to_ec2_inst_id(inst['uuid']).AndReturn(
+ expected['instance-id'])
+ ec2utils.glance_id_to_ec2_id(self.context,
+ inst['image_ref']).AndReturn(
+ expected['ami-id'])
+ for image_type in ['kernel', 'ramdisk']:
+ image_id = inst['%s_id' % image_type]
+ ec2utils.image_type(image_type).AndReturn('ami-' + image_type)
+ ec2utils.glance_id_to_ec2_id(self.context, image_id,
+ 'ami-' + image_type).AndReturn(
+ 'ami-%s-ec2-%sid' % (image_type, image_type))
+
+ self.mox.ReplayAll()
+ result = self.conductor.get_ec2_ids(self.context, inst)
+ self.assertEqual(result, expected)
+
+ def test_compute_stop(self):
+ self.mox.StubOutWithMock(self.conductor_manager.compute_api, 'stop')
+ self.conductor_manager.compute_api.stop(self.context, 'instance', True)
+ self.mox.ReplayAll()
+ self.conductor.compute_stop(self.context, 'instance')
+
class ConductorTestCase(_BaseTestCase, test.TestCase):
"""Conductor Manager Tests."""
diff --git a/nova/tests/fake_instance_actions.py b/nova/tests/fake_instance_actions.py
index 1667ac62d..f34d9b213 100644
--- a/nova/tests/fake_instance_actions.py
+++ b/nova/tests/fake_instance_actions.py
@@ -17,6 +17,64 @@
from nova import db
+FAKE_UUID = 'b48316c5-71e8-45e4-9884-6c78055b9b13'
+FAKE_REQUEST_ID1 = 'req-3293a3f1-b44c-4609-b8d2-d81b105636b8'
+FAKE_REQUEST_ID2 = 'req-25517360-b757-47d3-be45-0e8d2a01b36a'
+FAKE_ACTION_ID1 = 'f811a359-0c98-4daa-87a4-2948d4c21b78'
+FAKE_ACTION_ID2 = '4e9594b5-4ac5-421c-ac60-2d802b11c798'
+
+FAKE_ACTIONS = {
+ FAKE_UUID: {
+ FAKE_REQUEST_ID1: {'id': FAKE_ACTION_ID1,
+ 'action': 'reboot',
+ 'instance_uuid': FAKE_UUID,
+ 'request_id': FAKE_REQUEST_ID1,
+ 'project_id': '147',
+ 'user_id': '789',
+ 'start_time': '2012-12-05 00:00:00.000000',
+ 'finish_time': '',
+ 'message': '',
+ },
+ FAKE_REQUEST_ID2: {'id': FAKE_ACTION_ID2,
+ 'action': 'resize',
+ 'instance_uuid': FAKE_UUID,
+ 'request_id': FAKE_REQUEST_ID2,
+ 'user_id': '789',
+ 'project_id': '842',
+ 'start_time': '2012-12-05 01:00:00.000000',
+ 'finish_time': '',
+ 'message': '',
+ }
+ }
+}
+
+FAKE_EVENTS = {
+ FAKE_ACTION_ID1: [{'id': '1',
+ 'event': 'schedule',
+ 'start_time': '2012-12-05 01:00:02.000000',
+ 'finish_time': '2012-12-05 01:02:00.000000',
+ 'result': 'Success',
+ 'traceback': '',
+ },
+ {'id': '2',
+ 'event': 'compute_create',
+ 'start_time': '2012-12-05 01:03:00.000000',
+ 'finish_time': '2012-12-05 01:04:00.000000',
+ 'result': 'Success',
+ 'traceback': '',
+ }
+ ],
+ FAKE_ACTION_ID2: [{'id': '3',
+ 'event': 'schedule',
+ 'start_time': '2012-12-05 03:00:00.000000',
+ 'finish_time': '2012-12-05 03:02:00.000000',
+ 'result': 'Error',
+ 'traceback': ''
+ }
+ ]
+}
+
+
def fake_action_event_start(*args):
pass
diff --git a/nova/tests/fake_network.py b/nova/tests/fake_network.py
index 883466cd6..12d263584 100644
--- a/nova/tests/fake_network.py
+++ b/nova/tests/fake_network.py
@@ -53,7 +53,7 @@ class FakeVIFDriver(object):
def setattr(self, key, val):
self.__setattr__(key, val)
- def get_config(self, instance, network, mapping):
+ def get_config(self, instance, network, mapping, image_meta):
conf = libvirt_config.LibvirtConfigGuestInterface()
for attr, val in conf.__dict__.iteritems():
@@ -372,7 +372,7 @@ def stub_out_nw_api_get_instance_nw_info(stubs, func=None,
floating_ips_per_fixed_ip=0,
spectacular=False):
- def get_instance_nw_info(self, context, instance):
+ def get_instance_nw_info(self, context, instance, conductor_api=None):
return fake_get_instance_nw_info(stubs, num_networks=num_networks,
ips_per_vif=ips_per_vif,
floating_ips_per_fixed_ip=floating_ips_per_fixed_ip,
diff --git a/nova/tests/fake_policy.py b/nova/tests/fake_policy.py
index 92ce0815a..3878df531 100644
--- a/nova/tests/fake_policy.py
+++ b/nova/tests/fake_policy.py
@@ -121,6 +121,7 @@ policy_data = """
"compute_extension:extended_server_attributes": "",
"compute_extension:extended_status": "",
"compute_extension:extended_availability_zone": "",
+ "compute_extension:extended_ips": "",
"compute_extension:fixed_ips": "",
"compute_extension:flavor_access": "",
"compute_extension:flavor_disabled": "",
@@ -142,6 +143,8 @@ policy_data = """
"compute_extension:hide_server_addresses": "",
"compute_extension:hosts": "",
"compute_extension:hypervisors": "",
+ "compute_extension:instance_actions": "",
+ "compute_extension:instance_actions:events": "is_admin:True",
"compute_extension:instance_usage_audit_log": "",
"compute_extension:keypairs": "",
"compute_extension:multinic": "",
diff --git a/nova/tests/hyperv/fake.py b/nova/tests/hyperv/fake.py
index 9890a5462..e0e5a6bbe 100644
--- a/nova/tests/hyperv/fake.py
+++ b/nova/tests/hyperv/fake.py
@@ -23,24 +23,50 @@ class PathUtils(object):
def open(self, path, mode):
return io.BytesIO(b'fake content')
- def get_instances_path(self):
- return 'C:\\FakePath\\'
+ def exists(self, path):
+ return False
+
+ def makedirs(self, path):
+ pass
+
+ def remove(self, path):
+ pass
+
+ def rename(self, src, dest):
+ pass
+
+ def copyfile(self, src, dest):
+ pass
+
+ def copy(self, src, dest):
+ pass
+
+ def rmtree(self, path):
+ pass
+
+ def get_instances_dir(self, remote_server=None):
+ return 'C:\\FakeInstancesPath\\'
+
+ def get_instance_migr_revert_dir(self, instance_name, create_dir=False,
+ remove_dir=False):
+ return os.path.join(self.get_instances_dir(), instance_name, '_revert')
- def get_instance_path(self, instance_name):
- return os.path.join(self.get_instances_path(), instance_name)
+ def get_instance_dir(self, instance_name, remote_server=None,
+ create_dir=True, remove_dir=False):
+ return os.path.join(self.get_instances_dir(remote_server),
+ instance_name)
def get_vhd_path(self, instance_name):
- instance_path = self.get_instance_path(instance_name)
- return os.path.join(instance_path, instance_name + ".vhd")
+ instance_path = self.get_instance_dir(instance_name)
+ return os.path.join(instance_path, 'root.vhd')
- def get_base_vhd_path(self, image_name):
- base_dir = os.path.join(self.get_instances_path(), '_base')
- return os.path.join(base_dir, image_name + ".vhd")
+ def get_base_vhd_dir(self):
+ return os.path.join(self.get_instances_dir(), '_base')
- def make_export_path(self, instance_name):
- export_folder = os.path.join(self.get_instances_path(), "export",
- instance_name)
- return export_folder
+ def get_export_dir(self, instance_name):
+ export_dir = os.path.join(self.get_instances_dir(), 'export',
+ instance_name)
+ return export_dir
def vhd_exists(self, path):
return False
diff --git a/nova/tests/integrated/api_samples/OS-EXT-AZ/server-get-resp.json.tpl b/nova/tests/integrated/api_samples/OS-EXT-AZ/server-get-resp.json.tpl
index 25915610d..413f3ce95 100644
--- a/nova/tests/integrated/api_samples/OS-EXT-AZ/server-get-resp.json.tpl
+++ b/nova/tests/integrated/api_samples/OS-EXT-AZ/server-get-resp.json.tpl
@@ -2,8 +2,7 @@
"server": {
"updated": "%(timestamp)s",
"created": "%(timestamp)s",
- "OS-EXT-AZ:availability_zone": null,
- "OS-EXT-AZ:host_availability_zone": "nova",
+ "OS-EXT-AZ:availability_zone": "nova",
"accessIPv4": "",
"accessIPv6": "",
"addresses": {
diff --git a/nova/tests/integrated/api_samples/OS-EXT-AZ/server-get-resp.xml.tpl b/nova/tests/integrated/api_samples/OS-EXT-AZ/server-get-resp.xml.tpl
index 1cdbd2012..849b9b750 100644
--- a/nova/tests/integrated/api_samples/OS-EXT-AZ/server-get-resp.xml.tpl
+++ b/nova/tests/integrated/api_samples/OS-EXT-AZ/server-get-resp.xml.tpl
@@ -1,5 +1,5 @@
<?xml version='1.0' encoding='UTF-8'?>
-<server xmlns:OS-EXT-AZ="http://docs.openstack.org/compute/ext/extended_availability_zone/api/v2" xmlns:atom="http://www.w3.org/2005/Atom" xmlns="http://docs.openstack.org/compute/api/v1.1" status="ACTIVE" updated="%(timestamp)s" hostId="%(hostid)s" name="new-server-test" created="%(timestamp)s" userId="fake" tenantId="openstack" accessIPv4="" accessIPv6="" progress="0" id="%(uuid)s" OS-EXT-AZ:availability_zone="None" OS-EXT-AZ:host_availability_zone="nova">
+<server xmlns:OS-EXT-AZ="http://docs.openstack.org/compute/ext/extended_availability_zone/api/v2" xmlns:atom="http://www.w3.org/2005/Atom" xmlns="http://docs.openstack.org/compute/api/v1.1" status="ACTIVE" updated="%(timestamp)s" hostId="%(hostid)s" name="new-server-test" created="%(timestamp)s" userId="fake" tenantId="openstack" accessIPv4="" accessIPv6="" progress="0" id="%(uuid)s" OS-EXT-AZ:availability_zone="nova">
<image id="%(uuid)s">
<atom:link href="%(host)s/openstack/images/%(uuid)s" rel="bookmark"/>
</image>
diff --git a/nova/tests/integrated/api_samples/OS-EXT-AZ/servers-detail-resp.json.tpl b/nova/tests/integrated/api_samples/OS-EXT-AZ/servers-detail-resp.json.tpl
index 895f0a514..362c85085 100644
--- a/nova/tests/integrated/api_samples/OS-EXT-AZ/servers-detail-resp.json.tpl
+++ b/nova/tests/integrated/api_samples/OS-EXT-AZ/servers-detail-resp.json.tpl
@@ -3,8 +3,7 @@
{
"updated": "%(timestamp)s",
"created": "%(timestamp)s",
- "OS-EXT-AZ:availability_zone": null,
- "OS-EXT-AZ:host_availability_zone": "nova",
+ "OS-EXT-AZ:availability_zone": "nova",
"accessIPv4": "",
"accessIPv6": "",
"addresses": {
diff --git a/nova/tests/integrated/api_samples/OS-EXT-AZ/servers-detail-resp.xml.tpl b/nova/tests/integrated/api_samples/OS-EXT-AZ/servers-detail-resp.xml.tpl
index 15cd9b1e1..9cd820cd0 100644
--- a/nova/tests/integrated/api_samples/OS-EXT-AZ/servers-detail-resp.xml.tpl
+++ b/nova/tests/integrated/api_samples/OS-EXT-AZ/servers-detail-resp.xml.tpl
@@ -1,5 +1,5 @@
<?xml version='1.0' encoding='UTF-8'?>
-<servers xmlns:OS-EXT-AZ="http://docs.openstack.org/compute/ext/extended_availability_zone/api/v2" xmlns:atom="http://www.w3.org/2005/Atom" xmlns="http://docs.openstack.org/compute/api/v1.1"> <server status="ACTIVE" updated="%(timestamp)s" hostId="%(hostid)s" name="new-server-test" created="%(timestamp)s" userId="fake" tenantId="openstack" accessIPv4="" accessIPv6="" progress="0" id="%(id)s" OS-EXT-AZ:availability_zone="None" OS-EXT-AZ:host_availability_zone="nova">
+<servers xmlns:OS-EXT-AZ="http://docs.openstack.org/compute/ext/extended_availability_zone/api/v2" xmlns:atom="http://www.w3.org/2005/Atom" xmlns="http://docs.openstack.org/compute/api/v1.1"> <server status="ACTIVE" updated="%(timestamp)s" hostId="%(hostid)s" name="new-server-test" created="%(timestamp)s" userId="fake" tenantId="openstack" accessIPv4="" accessIPv6="" progress="0" id="%(id)s" OS-EXT-AZ:availability_zone="nova">
<image id="%(uuid)s">
<atom:link href="%(host)s/openstack/images/%(uuid)s" rel="bookmark"/>
</image>
diff --git a/nova/tests/integrated/api_samples/OS-EXT-IPS/server-get-resp.json.tpl b/nova/tests/integrated/api_samples/OS-EXT-IPS/server-get-resp.json.tpl
new file mode 100644
index 000000000..bea96d4f6
--- /dev/null
+++ b/nova/tests/integrated/api_samples/OS-EXT-IPS/server-get-resp.json.tpl
@@ -0,0 +1,55 @@
+{
+ "server": {
+ "accessIPv4": "",
+ "accessIPv6": "",
+ "addresses": {
+ "private": [
+ {
+ "OS-EXT-IPS:type": "fixed",
+ "addr": "%(ip)s",
+ "version": 4
+ }
+ ]
+ },
+ "created": "%(timestamp)s",
+ "flavor": {
+ "id": "1",
+ "links": [
+ {
+ "href": "%(host)s/openstack/flavors/1",
+ "rel": "bookmark"
+ }
+ ]
+ },
+ "hostId": "%(hostid)s",
+ "id": "%(id)s",
+ "image": {
+ "id": "%(uuid)s",
+ "links": [
+ {
+ "href": "%(host)s/openstack/images/%(uuid)s",
+ "rel": "bookmark"
+ }
+ ]
+ },
+ "links": [
+ {
+ "href": "%(host)s/v2/openstack/servers/%(id)s",
+ "rel": "self"
+ },
+ {
+ "href": "%(host)s/openstack/servers/%(id)s",
+ "rel": "bookmark"
+ }
+ ],
+ "metadata": {
+ "My Server Name": "Apache1"
+ },
+ "name": "new-server-test",
+ "progress": 0,
+ "status": "ACTIVE",
+ "tenant_id": "openstack",
+ "updated": "%(timestamp)s",
+ "user_id": "fake"
+ }
+}
diff --git a/nova/tests/integrated/api_samples/OS-EXT-IPS/server-get-resp.xml.tpl b/nova/tests/integrated/api_samples/OS-EXT-IPS/server-get-resp.xml.tpl
new file mode 100644
index 000000000..d3f14f6ed
--- /dev/null
+++ b/nova/tests/integrated/api_samples/OS-EXT-IPS/server-get-resp.xml.tpl
@@ -0,0 +1,19 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<server xmlns:OS-EXT-IPS="http://docs.openstack.org/compute/ext/extended_ips/api/v1.1" xmlns:atom="http://www.w3.org/2005/Atom" xmlns="http://docs.openstack.org/compute/api/v1.1" status="ACTIVE" updated="%(timestamp)s" hostId="%(hostid)s" name="new-server-test" created="%(timestamp)s" userId="fake" tenantId="openstack" accessIPv4="" accessIPv6="" progress="0" id="%(id)s">
+ <image id="%(uuid)s">
+ <atom:link href="%(host)s/openstack/images/%(uuid)s" rel="bookmark"/>
+ </image>
+ <flavor id="1">
+ <atom:link href="%(host)s/openstack/flavors/1" rel="bookmark"/>
+ </flavor>
+ <metadata>
+ <meta key="My Server Name">Apache1</meta>
+ </metadata>
+ <addresses>
+ <network id="private">
+ <ip OS-EXT-IPS:type="fixed" version="4" addr="%(ip)s"/>
+ </network>
+ </addresses>
+ <atom:link href="%(host)s/v2/openstack/servers/%(id)s" rel="self"/>
+ <atom:link href="%(host)s/openstack/servers/%(id)s" rel="bookmark"/>
+</server>
diff --git a/nova/tests/integrated/api_samples/OS-EXT-IPS/server-post-req.json.tpl b/nova/tests/integrated/api_samples/OS-EXT-IPS/server-post-req.json.tpl
new file mode 100644
index 000000000..d3916d1aa
--- /dev/null
+++ b/nova/tests/integrated/api_samples/OS-EXT-IPS/server-post-req.json.tpl
@@ -0,0 +1,16 @@
+{
+ "server" : {
+ "name" : "new-server-test",
+ "imageRef" : "%(host)s/openstack/images/%(image_id)s",
+ "flavorRef" : "%(host)s/openstack/flavors/1",
+ "metadata" : {
+ "My Server Name" : "Apache1"
+ },
+ "personality" : [
+ {
+ "path" : "/etc/banner.txt",
+ "contents" : "ICAgICAgDQoiQSBjbG91ZCBkb2VzIG5vdCBrbm93IHdoeSBpdCBtb3ZlcyBpbiBqdXN0IHN1Y2ggYSBkaXJlY3Rpb24gYW5kIGF0IHN1Y2ggYSBzcGVlZC4uLkl0IGZlZWxzIGFuIGltcHVsc2lvbi4uLnRoaXMgaXMgdGhlIHBsYWNlIHRvIGdvIG5vdy4gQnV0IHRoZSBza3kga25vd3MgdGhlIHJlYXNvbnMgYW5kIHRoZSBwYXR0ZXJucyBiZWhpbmQgYWxsIGNsb3VkcywgYW5kIHlvdSB3aWxsIGtub3csIHRvbywgd2hlbiB5b3UgbGlmdCB5b3Vyc2VsZiBoaWdoIGVub3VnaCB0byBzZWUgYmV5b25kIGhvcml6b25zLiINCg0KLVJpY2hhcmQgQmFjaA=="
+ }
+ ]
+ }
+}
diff --git a/nova/tests/integrated/api_samples/OS-EXT-IPS/server-post-req.xml.tpl b/nova/tests/integrated/api_samples/OS-EXT-IPS/server-post-req.xml.tpl
new file mode 100644
index 000000000..f92614984
--- /dev/null
+++ b/nova/tests/integrated/api_samples/OS-EXT-IPS/server-post-req.xml.tpl
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<server xmlns="http://docs.openstack.org/compute/api/v1.1" imageRef="%(host)s/openstack/images/%(image_id)s" flavorRef="%(host)s/openstack/flavors/1" name="new-server-test">
+ <metadata>
+ <meta key="My Server Name">Apache1</meta>
+ </metadata>
+ <personality>
+ <file path="/etc/banner.txt">
+ ICAgICAgDQoiQSBjbG91ZCBkb2VzIG5vdCBrbm93IHdoeSBp
+ dCBtb3ZlcyBpbiBqdXN0IHN1Y2ggYSBkaXJlY3Rpb24gYW5k
+ IGF0IHN1Y2ggYSBzcGVlZC4uLkl0IGZlZWxzIGFuIGltcHVs
+ c2lvbi4uLnRoaXMgaXMgdGhlIHBsYWNlIHRvIGdvIG5vdy4g
+ QnV0IHRoZSBza3kga25vd3MgdGhlIHJlYXNvbnMgYW5kIHRo
+ ZSBwYXR0ZXJucyBiZWhpbmQgYWxsIGNsb3VkcywgYW5kIHlv
+ dSB3aWxsIGtub3csIHRvbywgd2hlbiB5b3UgbGlmdCB5b3Vy
+ c2VsZiBoaWdoIGVub3VnaCB0byBzZWUgYmV5b25kIGhvcml6
+ b25zLiINCg0KLVJpY2hhcmQgQmFjaA==
+ </file>
+ </personality>
+</server>
diff --git a/nova/tests/integrated/api_samples/OS-EXT-IPS/server-post-resp.json.tpl b/nova/tests/integrated/api_samples/OS-EXT-IPS/server-post-resp.json.tpl
new file mode 100644
index 000000000..d5f030c87
--- /dev/null
+++ b/nova/tests/integrated/api_samples/OS-EXT-IPS/server-post-resp.json.tpl
@@ -0,0 +1,16 @@
+{
+ "server": {
+ "adminPass": "%(password)s",
+ "id": "%(id)s",
+ "links": [
+ {
+ "href": "%(host)s/v2/openstack/servers/%(uuid)s",
+ "rel": "self"
+ },
+ {
+ "href": "%(host)s/openstack/servers/%(uuid)s",
+ "rel": "bookmark"
+ }
+ ]
+ }
+}
diff --git a/nova/tests/integrated/api_samples/OS-EXT-IPS/server-post-resp.xml.tpl b/nova/tests/integrated/api_samples/OS-EXT-IPS/server-post-resp.xml.tpl
new file mode 100644
index 000000000..3bb13e69b
--- /dev/null
+++ b/nova/tests/integrated/api_samples/OS-EXT-IPS/server-post-resp.xml.tpl
@@ -0,0 +1,6 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<server xmlns:atom="http://www.w3.org/2005/Atom" xmlns="http://docs.openstack.org/compute/api/v1.1" id="%(id)s" adminPass="%(password)s">
+ <metadata/>
+ <atom:link href="%(host)s/v2/openstack/servers/%(uuid)s" rel="self"/>
+ <atom:link href="%(host)s/openstack/servers/%(uuid)s" rel="bookmark"/>
+</server>
diff --git a/nova/tests/integrated/api_samples/OS-EXT-IPS/servers-detail-resp.json.tpl b/nova/tests/integrated/api_samples/OS-EXT-IPS/servers-detail-resp.json.tpl
new file mode 100644
index 000000000..37487e49f
--- /dev/null
+++ b/nova/tests/integrated/api_samples/OS-EXT-IPS/servers-detail-resp.json.tpl
@@ -0,0 +1,56 @@
+{
+ "servers": [
+ {
+ "status": "ACTIVE",
+ "updated": "%(timestamp)s",
+ "user_id": "fake",
+ "addresses": {
+ "private": [
+ {
+ "OS-EXT-IPS:type": "fixed",
+ "addr": "%(ip)s",
+ "version": 4
+ }
+ ]
+ },
+ "links": [
+ {
+ "href": "%(host)s/v2/openstack/servers/%(id)s",
+ "rel": "self"
+ },
+ {
+ "href": "%(host)s/openstack/servers/%(id)s",
+ "rel": "bookmark"
+ }
+ ],
+ "created": "%(timestamp)s",
+ "name": "new-server-test",
+ "image": {
+ "id": "%(uuid)s",
+ "links": [
+ {
+ "href": "%(host)s/openstack/images/%(uuid)s",
+ "rel": "bookmark"
+ }
+ ]
+ },
+ "id": "%(uuid)s",
+ "accessIPv4": "",
+ "accessIPv6": "",
+ "tenant_id": "openstack",
+ "progress": 0,
+ "flavor": {
+ "id": "1",
+ "links": [
+ {
+ "href": "%(host)s/openstack/flavors/1",
+ "rel": "bookmark"
+ }
+ ]
+ },
+ "hostId": "%(hostid)s",
+ "metadata": {
+ "My Server Name": "Apache1"
+ }
+ }]
+}
diff --git a/nova/tests/integrated/api_samples/OS-EXT-IPS/servers-detail-resp.xml.tpl b/nova/tests/integrated/api_samples/OS-EXT-IPS/servers-detail-resp.xml.tpl
new file mode 100644
index 000000000..5fc5c1f93
--- /dev/null
+++ b/nova/tests/integrated/api_samples/OS-EXT-IPS/servers-detail-resp.xml.tpl
@@ -0,0 +1,21 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<servers xmlns:OS-EXT-IPS="http://docs.openstack.org/compute/ext/extended_ips/api/v1.1" xmlns:atom="http://www.w3.org/2005/Atom" xmlns="http://docs.openstack.org/compute/api/v1.1">
+ <server xmlns:OS-EXT-IPS="http://docs.openstack.org/compute/ext/extended_ips/api/v1.1" xmlns:atom="http://www.w3.org/2005/Atom" xmlns="http://docs.openstack.org/compute/api/v1.1" status="ACTIVE" updated="%(timestamp)s" hostId="%(hostid)s" name="new-server-test" created="%(timestamp)s" userId="fake" tenantId="openstack" accessIPv4="" accessIPv6="" progress="0" id="%(id)s">
+ <image id="%(uuid)s">
+ <atom:link href="%(host)s/openstack/images/%(uuid)s" rel="bookmark"/>
+ </image>
+ <flavor id="1">
+ <atom:link href="%(host)s/openstack/flavors/1" rel="bookmark"/>
+ </flavor>
+ <metadata>
+ <meta key="My Server Name">Apache1</meta>
+ </metadata>
+ <addresses>
+ <network id="private">
+ <ip OS-EXT-IPS:type="fixed" version="4" addr="%(ip)s"/>
+ </network>
+ </addresses>
+ <atom:link href="%(host)s/v2/openstack/servers/%(id)s" rel="self"/>
+ <atom:link href="%(host)s/openstack/servers/%(id)s" rel="bookmark"/>
+ </server>
+</servers>
diff --git a/nova/tests/integrated/api_samples/OS-EXT-SRV-ATTR/extended-server-attrs-get.json.tpl b/nova/tests/integrated/api_samples/OS-EXT-SRV-ATTR/server-get-resp.json.tpl
index c70192949..c70192949 100644
--- a/nova/tests/integrated/api_samples/OS-EXT-SRV-ATTR/extended-server-attrs-get.json.tpl
+++ b/nova/tests/integrated/api_samples/OS-EXT-SRV-ATTR/server-get-resp.json.tpl
diff --git a/nova/tests/integrated/api_samples/OS-EXT-SRV-ATTR/extended-server-attrs-get.xml.tpl b/nova/tests/integrated/api_samples/OS-EXT-SRV-ATTR/server-get-resp.xml.tpl
index beec3a12a..beec3a12a 100644
--- a/nova/tests/integrated/api_samples/OS-EXT-SRV-ATTR/extended-server-attrs-get.xml.tpl
+++ b/nova/tests/integrated/api_samples/OS-EXT-SRV-ATTR/server-get-resp.xml.tpl
diff --git a/nova/tests/integrated/api_samples/OS-EXT-SRV-ATTR/extended-server-attrs-list.json.tpl b/nova/tests/integrated/api_samples/OS-EXT-SRV-ATTR/servers-detail-resp.json.tpl
index 1fb8e1a47..1fb8e1a47 100644
--- a/nova/tests/integrated/api_samples/OS-EXT-SRV-ATTR/extended-server-attrs-list.json.tpl
+++ b/nova/tests/integrated/api_samples/OS-EXT-SRV-ATTR/servers-detail-resp.json.tpl
diff --git a/nova/tests/integrated/api_samples/OS-EXT-SRV-ATTR/extended-server-attrs-list.xml.tpl b/nova/tests/integrated/api_samples/OS-EXT-SRV-ATTR/servers-detail-resp.xml.tpl
index 1811882a2..1811882a2 100644
--- a/nova/tests/integrated/api_samples/OS-EXT-SRV-ATTR/extended-server-attrs-list.xml.tpl
+++ b/nova/tests/integrated/api_samples/OS-EXT-SRV-ATTR/servers-detail-resp.xml.tpl
diff --git a/nova/tests/integrated/api_samples/OS-EXT-STS/server-get-resp.json.tpl b/nova/tests/integrated/api_samples/OS-EXT-STS/server-get-resp.json.tpl
new file mode 100644
index 000000000..7ac35024b
--- /dev/null
+++ b/nova/tests/integrated/api_samples/OS-EXT-STS/server-get-resp.json.tpl
@@ -0,0 +1,57 @@
+{
+ "server": {
+ "OS-EXT-STS:task_state": null,
+ "OS-EXT-STS:vm_state": "active",
+ "OS-EXT-STS:power_state": 1,
+ "accessIPv4": "",
+ "accessIPv6": "",
+ "addresses": {
+ "private": [
+ {
+ "addr": "%(ip)s",
+ "version": 4
+ }
+ ]
+ },
+ "created": "%(timestamp)s",
+ "flavor": {
+ "id": "1",
+ "links": [
+ {
+ "href": "%(host)s/openstack/flavors/1",
+ "rel": "bookmark"
+ }
+ ]
+ },
+ "hostId": "%(hostid)s",
+ "id": "%(id)s",
+ "image": {
+ "id": "%(uuid)s",
+ "links": [
+ {
+ "href": "%(host)s/openstack/images/%(uuid)s",
+ "rel": "bookmark"
+ }
+ ]
+ },
+ "links": [
+ {
+ "href": "%(host)s/v2/openstack/servers/%(id)s",
+ "rel": "self"
+ },
+ {
+ "href": "%(host)s/openstack/servers/%(id)s",
+ "rel": "bookmark"
+ }
+ ],
+ "metadata": {
+ "My Server Name": "Apache1"
+ },
+ "name": "new-server-test",
+ "progress": 0,
+ "status": "ACTIVE",
+ "tenant_id": "openstack",
+ "updated": "%(timestamp)s",
+ "user_id": "fake"
+ }
+}
diff --git a/nova/tests/integrated/api_samples/OS-EXT-STS/server-get-resp.xml.tpl b/nova/tests/integrated/api_samples/OS-EXT-STS/server-get-resp.xml.tpl
new file mode 100644
index 000000000..f594be120
--- /dev/null
+++ b/nova/tests/integrated/api_samples/OS-EXT-STS/server-get-resp.xml.tpl
@@ -0,0 +1,19 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<server xmlns:OS-EXT-STS="http://docs.openstack.org/compute/ext/extended_status/api/v1.1" xmlns:atom="http://www.w3.org/2005/Atom" xmlns="http://docs.openstack.org/compute/api/v1.1" status="ACTIVE" updated="%(timestamp)s" hostId="%(hostid)s" name="new-server-test" created="%(timestamp)s" userId="fake" tenantId="openstack" accessIPv4="" accessIPv6="" progress="0" id="%(id)s" OS-EXT-STS:vm_state="active" OS-EXT-STS:task_state="None" OS-EXT-STS:power_state="1">
+ <image id="%(uuid)s">
+ <atom:link href="%(host)s/openstack/images/%(uuid)s" rel="bookmark"/>
+ </image>
+ <flavor id="1">
+ <atom:link href="%(host)s/openstack/flavors/1" rel="bookmark"/>
+ </flavor>
+ <metadata>
+ <meta key="My Server Name">Apache1</meta>
+ </metadata>
+ <addresses>
+ <network id="private">
+ <ip version="4" addr="%(ip)s"/>
+ </network>
+ </addresses>
+ <atom:link href="%(host)s/v2/openstack/servers/%(id)s" rel="self"/>
+ <atom:link href="%(host)s/openstack/servers/%(id)s" rel="bookmark"/>
+</server>
diff --git a/nova/tests/integrated/api_samples/OS-EXT-STS/servers-list-resp.json.tpl b/nova/tests/integrated/api_samples/OS-EXT-STS/servers-list-resp.json.tpl
deleted file mode 100644
index 8b97dc28d..000000000
--- a/nova/tests/integrated/api_samples/OS-EXT-STS/servers-list-resp.json.tpl
+++ /dev/null
@@ -1,18 +0,0 @@
-{
- "servers": [
- {
- "id": "%(id)s",
- "links": [
- {
- "href": "%(host)s/v2/openstack/servers/%(id)s",
- "rel": "self"
- },
- {
- "href": "%(host)s/openstack/servers/%(id)s",
- "rel": "bookmark"
- }
- ],
- "name": "new-server-test"
- }
- ]
-}
diff --git a/nova/tests/integrated/api_samples/OS-EXT-STS/servers-list-resp.xml.tpl b/nova/tests/integrated/api_samples/OS-EXT-STS/servers-list-resp.xml.tpl
deleted file mode 100644
index 03bee03a6..000000000
--- a/nova/tests/integrated/api_samples/OS-EXT-STS/servers-list-resp.xml.tpl
+++ /dev/null
@@ -1,7 +0,0 @@
-<?xml version='1.0' encoding='UTF-8'?>
-<servers xmlns:atom="http://www.w3.org/2005/Atom" xmlns="http://docs.openstack.org/compute/api/v1.1">
- <server name="new-server-test" id="%(id)s">
- <atom:link href="%(host)s/v2/openstack/servers/%(id)s" rel="self"/>
- <atom:link href="%(host)s/openstack/servers/%(id)s" rel="bookmark"/>
- </server>
-</servers>
diff --git a/nova/tests/integrated/api_samples/all_extensions/extensions-get-resp.json.tpl b/nova/tests/integrated/api_samples/all_extensions/extensions-get-resp.json.tpl
index 35d50d025..17914de42 100644
--- a/nova/tests/integrated/api_samples/all_extensions/extensions-get-resp.json.tpl
+++ b/nova/tests/integrated/api_samples/all_extensions/extensions-get-resp.json.tpl
@@ -25,6 +25,14 @@
"updated": "%(timestamp)s"
},
{
+ "alias": "OS-EXT-IPS",
+ "description": "%(text)s",
+ "links": [],
+ "name": "ExtendedIps",
+ "namespace": "http://docs.openstack.org/compute/ext/extended_ips/api/v1.1",
+ "updated": "%(timestamp)s"
+ },
+ {
"alias": "OS-EXT-SRV-ATTR",
"description": "%(text)s",
"links": [],
@@ -455,6 +463,14 @@
"name": "Volumes",
"namespace": "http://docs.openstack.org/compute/ext/volumes/api/v1.1",
"updated": "%(timestamp)s"
+ },
+ {
+ "alias": "os-instance-actions",
+ "description": "%(text)s",
+ "links": [],
+ "name": "InstanceActions",
+ "namespace": "http://docs.openstack.org/compute/ext/instance-actions/api/v1.1",
+ "updated": "%(timestamp)s"
}
]
}
diff --git a/nova/tests/integrated/api_samples/all_extensions/extensions-get-resp.xml.tpl b/nova/tests/integrated/api_samples/all_extensions/extensions-get-resp.xml.tpl
index 2adc5988c..4492ed3aa 100644
--- a/nova/tests/integrated/api_samples/all_extensions/extensions-get-resp.xml.tpl
+++ b/nova/tests/integrated/api_samples/all_extensions/extensions-get-resp.xml.tpl
@@ -9,6 +9,9 @@
<extension alias="OS-EXT-AZ" updated="%(timestamp)s" namespace="http://docs.openstack.org/compute/ext/extended_availability_zone/api/v2" name="ExtendedAvailabilityZone">
<description>%(text)s</description>
</extension>
+ <extension alias="OS-EXT-IPS" updated="%(timestamp)s" namespace="http://docs.openstack.org/compute/ext/extended_ips/api/v1.1" name="ExtendedIps">
+ <description>%(text)s</description>
+ </extension>
<extension alias="OS-EXT-SRV-ATTR" updated="%(timestamp)s" namespace="http://docs.openstack.org/compute/ext/extended_status/api/v1.1" name="ExtendedServerAttributes">
<description>%(text)s</description>
</extension>
@@ -171,4 +174,7 @@
<extension alias="os-volumes" updated="%(timestamp)s" namespace="http://docs.openstack.org/compute/ext/volumes/api/v1.1" name="Volumes">
<description>%(text)s</description>
</extension>
+ <extension alias="os-instance-actions" updated="%(timestamp)s" namespace="http://docs.openstack.org/compute/ext/instance-actions/api/v1.1" name="InstanceActions">
+ <description>%(text)s</description>
+ </extension>
</extensions>
diff --git a/nova/tests/integrated/api_samples/all_extensions/server-get-resp.json.tpl b/nova/tests/integrated/api_samples/all_extensions/server-get-resp.json.tpl
index 85fc6f605..ccefc2dc7 100644
--- a/nova/tests/integrated/api_samples/all_extensions/server-get-resp.json.tpl
+++ b/nova/tests/integrated/api_samples/all_extensions/server-get-resp.json.tpl
@@ -1,8 +1,7 @@
{
"server": {
"OS-DCF:diskConfig": "AUTO",
- "OS-EXT-AZ:availability_zone": null,
- "OS-EXT-AZ:host_availability_zone": "nova",
+ "OS-EXT-AZ:availability_zone": "nova",
"OS-EXT-SRV-ATTR:host": "%(compute_host)s",
"OS-EXT-SRV-ATTR:hypervisor_hostname": "%(hypervisor_hostname)s",
"OS-EXT-SRV-ATTR:instance_name": "instance-00000001",
@@ -14,6 +13,7 @@
"addresses": {
"private": [
{
+ "OS-EXT-IPS:type": "fixed",
"addr": "%(ip)s",
"version": 4
}
diff --git a/nova/tests/integrated/api_samples/all_extensions/server-get-resp.xml.tpl b/nova/tests/integrated/api_samples/all_extensions/server-get-resp.xml.tpl
index bd73accda..973305854 100644
--- a/nova/tests/integrated/api_samples/all_extensions/server-get-resp.xml.tpl
+++ b/nova/tests/integrated/api_samples/all_extensions/server-get-resp.xml.tpl
@@ -1,5 +1,5 @@
<?xml version='1.0' encoding='UTF-8'?>
-<server xmlns:OS-DCF="http://docs.openstack.org/compute/ext/disk_config/api/v1.1" xmlns:OS-EXT-AZ="http://docs.openstack.org/compute/ext/extended_availability_zone/api/v2" xmlns:OS-EXT-SRV-ATTR="http://docs.openstack.org/compute/ext/extended_status/api/v1.1" xmlns:OS-EXT-STS="http://docs.openstack.org/compute/ext/extended_status/api/v1.1" xmlns:atom="http://www.w3.org/2005/Atom" xmlns="http://docs.openstack.org/compute/api/v1.1" status="ACTIVE" updated="%(timestamp)s" hostId="%(hostid)s" name="new-server-test" created="%(timestamp)s" userId="fake" tenantId="openstack" accessIPv4="" accessIPv6="" progress="0" id="%(id)s" key_name="None" config_drive="" OS-EXT-SRV-ATTR:vm_state="active" OS-EXT-SRV-ATTR:task_state="None" OS-EXT-SRV-ATTR:power_state="1" OS-EXT-SRV-ATTR:instance_name="instance-00000001" OS-EXT-SRV-ATTR:host="%(compute_host)s" OS-EXT-SRV-ATTR:hypervisor_hostname="%(hypervisor_hostname)s" OS-EXT-AZ:availability_zone="None" OS-EXT-AZ:host_availability_zone="nova" OS-DCF:diskConfig="AUTO">
+<server xmlns:OS-DCF="http://docs.openstack.org/compute/ext/disk_config/api/v1.1" xmlns:OS-EXT-AZ="http://docs.openstack.org/compute/ext/extended_availability_zone/api/v2" xmlns:OS-EXT-SRV-ATTR="http://docs.openstack.org/compute/ext/extended_status/api/v1.1" xmlns:OS-EXT-IPS="http://docs.openstack.org/compute/ext/extended_ips/api/v1.1" xmlns:OS-EXT-STS="http://docs.openstack.org/compute/ext/extended_status/api/v1.1" xmlns:atom="http://www.w3.org/2005/Atom" xmlns="http://docs.openstack.org/compute/api/v1.1" status="ACTIVE" updated="%(timestamp)s" hostId="%(hostid)s" name="new-server-test" created="%(timestamp)s" userId="fake" tenantId="openstack" accessIPv4="" accessIPv6="" progress="0" id="%(id)s" key_name="None" config_drive="" OS-EXT-SRV-ATTR:vm_state="active" OS-EXT-SRV-ATTR:task_state="None" OS-EXT-SRV-ATTR:power_state="1" OS-EXT-SRV-ATTR:instance_name="instance-00000001" OS-EXT-SRV-ATTR:host="%(compute_host)s" OS-EXT-SRV-ATTR:hypervisor_hostname="%(hypervisor_hostname)s" OS-EXT-AZ:availability_zone="nova" OS-DCF:diskConfig="AUTO">
<image id="%(uuid)s">
<atom:link href="%(host)s/openstack/images/%(uuid)s" rel="bookmark"/>
</image>
@@ -11,7 +11,7 @@
</metadata>
<addresses>
<network id="private">
- <ip version="4" addr="%(ip)s"/>
+ <ip OS-EXT-IPS:type="fixed" version="4" addr="%(ip)s"/>
</network>
</addresses>
<atom:link href="%(host)s/v2/openstack/servers/%(id)s" rel="self"/>
diff --git a/nova/tests/integrated/api_samples/all_extensions/servers-details-resp.json.tpl b/nova/tests/integrated/api_samples/all_extensions/servers-details-resp.json.tpl
index a4918203b..d50088837 100644
--- a/nova/tests/integrated/api_samples/all_extensions/servers-details-resp.json.tpl
+++ b/nova/tests/integrated/api_samples/all_extensions/servers-details-resp.json.tpl
@@ -2,8 +2,7 @@
"servers": [
{
"OS-DCF:diskConfig": "AUTO",
- "OS-EXT-AZ:availability_zone": null,
- "OS-EXT-AZ:host_availability_zone": "nova",
+ "OS-EXT-AZ:availability_zone": "nova",
"OS-EXT-SRV-ATTR:host": "%(compute_host)s",
"OS-EXT-SRV-ATTR:hypervisor_hostname": "%(hypervisor_hostname)s",
"OS-EXT-SRV-ATTR:instance_name": "instance-00000001",
@@ -15,6 +14,7 @@
"addresses": {
"private": [
{
+ "OS-EXT-IPS:type": "fixed",
"addr": "%(ip)s",
"version": 4
}
diff --git a/nova/tests/integrated/api_samples/all_extensions/servers-details-resp.xml.tpl b/nova/tests/integrated/api_samples/all_extensions/servers-details-resp.xml.tpl
index d26eb38ef..e2166c2ff 100644
--- a/nova/tests/integrated/api_samples/all_extensions/servers-details-resp.xml.tpl
+++ b/nova/tests/integrated/api_samples/all_extensions/servers-details-resp.xml.tpl
@@ -1,6 +1,6 @@
<?xml version='1.0' encoding='UTF-8'?>
-<servers xmlns:OS-DCF="http://docs.openstack.org/compute/ext/disk_config/api/v1.1" xmlns:OS-EXT-AZ="http://docs.openstack.org/compute/ext/extended_availability_zone/api/v2" xmlns:OS-EXT-SRV-ATTR="http://docs.openstack.org/compute/ext/extended_status/api/v1.1" xmlns:OS-EXT-STS="http://docs.openstack.org/compute/ext/extended_status/api/v1.1" xmlns:atom="http://www.w3.org/2005/Atom" xmlns="http://docs.openstack.org/compute/api/v1.1">
- <server xmlns:OS-DCF="http://docs.openstack.org/compute/ext/disk_config/api/v1.1" xmlns:OS-EXT-AZ="http://docs.openstack.org/compute/ext/extended_availability_zone/api/v2" xmlns:OS-EXT-SRV-ATTR="http://docs.openstack.org/compute/ext/extended_status/api/v1.1" xmlns:OS-EXT-STS="http://docs.openstack.org/compute/ext/extended_status/api/v1.1" xmlns:atom="http://www.w3.org/2005/Atom" xmlns="http://docs.openstack.org/compute/api/v1.1" status="ACTIVE" updated="%(timestamp)s" hostId="%(hostid)s" name="new-server-test" created="%(timestamp)s" userId="fake" tenantId="openstack" accessIPv4="" accessIPv6="" progress="0" id="%(id)s" key_name="None" config_drive="" OS-EXT-SRV-ATTR:vm_state="active" OS-EXT-SRV-ATTR:task_state="None" OS-EXT-SRV-ATTR:power_state="1" OS-EXT-SRV-ATTR:instance_name="instance-00000001" OS-EXT-SRV-ATTR:host="%(compute_host)s" OS-EXT-SRV-ATTR:hypervisor_hostname="%(hypervisor_hostname)s" OS-EXT-AZ:availability_zone="None" OS-EXT-AZ:host_availability_zone="nova" OS-DCF:diskConfig="AUTO">
+<servers xmlns:OS-DCF="http://docs.openstack.org/compute/ext/disk_config/api/v1.1" xmlns:OS-EXT-AZ="http://docs.openstack.org/compute/ext/extended_availability_zone/api/v2" xmlns:OS-EXT-SRV-ATTR="http://docs.openstack.org/compute/ext/extended_status/api/v1.1" xmlns:OS-EXT-IPS="http://docs.openstack.org/compute/ext/extended_ips/api/v1.1" xmlns:OS-EXT-STS="http://docs.openstack.org/compute/ext/extended_status/api/v1.1" xmlns:atom="http://www.w3.org/2005/Atom" xmlns="http://docs.openstack.org/compute/api/v1.1">
+ <server xmlns:OS-DCF="http://docs.openstack.org/compute/ext/disk_config/api/v1.1" xmlns:OS-EXT-AZ="http://docs.openstack.org/compute/ext/extended_availability_zone/api/v2" xmlns:OS-EXT-SRV-ATTR="http://docs.openstack.org/compute/ext/extended_status/api/v1.1" xmlns:OS-EXT-IPS="http://docs.openstack.org/compute/ext/extended_ips/api/v1.1" xmlns:OS-EXT-STS="http://docs.openstack.org/compute/ext/extended_status/api/v1.1" xmlns:atom="http://www.w3.org/2005/Atom" xmlns="http://docs.openstack.org/compute/api/v1.1" status="ACTIVE" updated="%(timestamp)s" hostId="%(hostid)s" name="new-server-test" created="%(timestamp)s" userId="fake" tenantId="openstack" accessIPv4="" accessIPv6="" progress="0" id="%(id)s" key_name="None" config_drive="" OS-EXT-SRV-ATTR:vm_state="active" OS-EXT-SRV-ATTR:task_state="None" OS-EXT-SRV-ATTR:power_state="1" OS-EXT-SRV-ATTR:instance_name="instance-00000001" OS-EXT-SRV-ATTR:host="%(compute_host)s" OS-EXT-SRV-ATTR:hypervisor_hostname="%(hypervisor_hostname)s" OS-EXT-AZ:availability_zone="nova" OS-DCF:diskConfig="AUTO">
<image id="%(uuid)s">
<atom:link href="%(host)s/openstack/images/%(uuid)s" rel="bookmark"/>
</image>
@@ -12,7 +12,7 @@
</metadata>
<addresses>
<network id="private">
- <ip version="4" addr="%(ip)s"/>
+ <ip OS-EXT-IPS:type="fixed" version="4" addr="%(ip)s"/>
</network>
</addresses>
<atom:link href="%(host)s/v2/openstack/servers/%(id)s" rel="self"/>
diff --git a/nova/tests/integrated/api_samples/os-config-drive/server-config-drive-get-resp.json.tpl b/nova/tests/integrated/api_samples/os-config-drive/server-config-drive-get-resp.json.tpl
new file mode 100644
index 000000000..ea47da06c
--- /dev/null
+++ b/nova/tests/integrated/api_samples/os-config-drive/server-config-drive-get-resp.json.tpl
@@ -0,0 +1,55 @@
+{
+ "server": {
+ "accessIPv4": "",
+ "accessIPv6": "",
+ "addresses": {
+ "private": [
+ {
+ "addr": "%(ip)s",
+ "version": 4
+ }
+ ]
+ },
+ "config_drive": "%(cdrive)s",
+ "created": "%(timestamp)s",
+ "flavor": {
+ "id": "1",
+ "links": [
+ {
+ "href": "%(host)s/openstack/flavors/1",
+ "rel": "bookmark"
+ }
+ ]
+ },
+ "hostId": "%(hostid)s",
+ "id": "%(id)s",
+ "image": {
+ "id": "%(uuid)s",
+ "links": [
+ {
+ "href": "%(host)s/openstack/images/%(uuid)s",
+ "rel": "bookmark"
+ }
+ ]
+ },
+ "links": [
+ {
+ "href": "%(host)s/v2/openstack/servers/%(id)s",
+ "rel": "self"
+ },
+ {
+ "href": "%(host)s/openstack/servers/%(id)s",
+ "rel": "bookmark"
+ }
+ ],
+ "metadata": {
+ "My Server Name": "Apache1"
+ },
+ "name": "new-server-test",
+ "progress": 0,
+ "status": "ACTIVE",
+ "tenant_id": "openstack",
+ "updated": "%(timestamp)s",
+ "user_id": "fake"
+ }
+}
diff --git a/nova/tests/integrated/api_samples/os-config-drive/server-config-drive-get-resp.xml.tpl b/nova/tests/integrated/api_samples/os-config-drive/server-config-drive-get-resp.xml.tpl
new file mode 100644
index 000000000..c6fb338c7
--- /dev/null
+++ b/nova/tests/integrated/api_samples/os-config-drive/server-config-drive-get-resp.xml.tpl
@@ -0,0 +1,19 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<server xmlns:atom="http://www.w3.org/2005/Atom" xmlns="http://docs.openstack.org/compute/api/v1.1" status="ACTIVE" updated="%(timestamp)s" hostId="%(hostid)s" name="new-server-test" created="%(timestamp)s" userId="fake" tenantId="openstack" accessIPv4="" accessIPv6="" progress="0" id="%(id)s" config_drive="%(cdrive)s">
+ <image id="%(uuid)s">
+ <atom:link href="%(host)s/openstack/images/%(uuid)s" rel="bookmark"/>
+ </image>
+ <flavor id="1">
+ <atom:link href="%(host)s/openstack/flavors/1" rel="bookmark"/>
+ </flavor>
+ <metadata>
+ <meta key="My Server Name">Apache1</meta>
+ </metadata>
+ <addresses>
+ <network id="private">
+ <ip version="4" addr="%(ip)s"/>
+ </network>
+ </addresses>
+ <atom:link href="%(host)s/v2/openstack/servers/%(id)s" rel="self"/>
+ <atom:link href="%(host)s/openstack/servers/%(id)s" rel="bookmark"/>
+</server>
diff --git a/nova/tests/integrated/api_samples/os-config-drive/server-post-req.json.tpl b/nova/tests/integrated/api_samples/os-config-drive/server-post-req.json.tpl
new file mode 100644
index 000000000..d3916d1aa
--- /dev/null
+++ b/nova/tests/integrated/api_samples/os-config-drive/server-post-req.json.tpl
@@ -0,0 +1,16 @@
+{
+ "server" : {
+ "name" : "new-server-test",
+ "imageRef" : "%(host)s/openstack/images/%(image_id)s",
+ "flavorRef" : "%(host)s/openstack/flavors/1",
+ "metadata" : {
+ "My Server Name" : "Apache1"
+ },
+ "personality" : [
+ {
+ "path" : "/etc/banner.txt",
+ "contents" : "ICAgICAgDQoiQSBjbG91ZCBkb2VzIG5vdCBrbm93IHdoeSBpdCBtb3ZlcyBpbiBqdXN0IHN1Y2ggYSBkaXJlY3Rpb24gYW5kIGF0IHN1Y2ggYSBzcGVlZC4uLkl0IGZlZWxzIGFuIGltcHVsc2lvbi4uLnRoaXMgaXMgdGhlIHBsYWNlIHRvIGdvIG5vdy4gQnV0IHRoZSBza3kga25vd3MgdGhlIHJlYXNvbnMgYW5kIHRoZSBwYXR0ZXJucyBiZWhpbmQgYWxsIGNsb3VkcywgYW5kIHlvdSB3aWxsIGtub3csIHRvbywgd2hlbiB5b3UgbGlmdCB5b3Vyc2VsZiBoaWdoIGVub3VnaCB0byBzZWUgYmV5b25kIGhvcml6b25zLiINCg0KLVJpY2hhcmQgQmFjaA=="
+ }
+ ]
+ }
+}
diff --git a/nova/tests/integrated/api_samples/os-config-drive/server-post-req.xml.tpl b/nova/tests/integrated/api_samples/os-config-drive/server-post-req.xml.tpl
new file mode 100644
index 000000000..f92614984
--- /dev/null
+++ b/nova/tests/integrated/api_samples/os-config-drive/server-post-req.xml.tpl
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<server xmlns="http://docs.openstack.org/compute/api/v1.1" imageRef="%(host)s/openstack/images/%(image_id)s" flavorRef="%(host)s/openstack/flavors/1" name="new-server-test">
+ <metadata>
+ <meta key="My Server Name">Apache1</meta>
+ </metadata>
+ <personality>
+ <file path="/etc/banner.txt">
+ ICAgICAgDQoiQSBjbG91ZCBkb2VzIG5vdCBrbm93IHdoeSBp
+ dCBtb3ZlcyBpbiBqdXN0IHN1Y2ggYSBkaXJlY3Rpb24gYW5k
+ IGF0IHN1Y2ggYSBzcGVlZC4uLkl0IGZlZWxzIGFuIGltcHVs
+ c2lvbi4uLnRoaXMgaXMgdGhlIHBsYWNlIHRvIGdvIG5vdy4g
+ QnV0IHRoZSBza3kga25vd3MgdGhlIHJlYXNvbnMgYW5kIHRo
+ ZSBwYXR0ZXJucyBiZWhpbmQgYWxsIGNsb3VkcywgYW5kIHlv
+ dSB3aWxsIGtub3csIHRvbywgd2hlbiB5b3UgbGlmdCB5b3Vy
+ c2VsZiBoaWdoIGVub3VnaCB0byBzZWUgYmV5b25kIGhvcml6
+ b25zLiINCg0KLVJpY2hhcmQgQmFjaA==
+ </file>
+ </personality>
+</server>
diff --git a/nova/tests/integrated/api_samples/os-config-drive/server-post-resp.json.tpl b/nova/tests/integrated/api_samples/os-config-drive/server-post-resp.json.tpl
new file mode 100644
index 000000000..d5f030c87
--- /dev/null
+++ b/nova/tests/integrated/api_samples/os-config-drive/server-post-resp.json.tpl
@@ -0,0 +1,16 @@
+{
+ "server": {
+ "adminPass": "%(password)s",
+ "id": "%(id)s",
+ "links": [
+ {
+ "href": "%(host)s/v2/openstack/servers/%(uuid)s",
+ "rel": "self"
+ },
+ {
+ "href": "%(host)s/openstack/servers/%(uuid)s",
+ "rel": "bookmark"
+ }
+ ]
+ }
+}
diff --git a/nova/tests/integrated/api_samples/os-config-drive/server-post-resp.xml.tpl b/nova/tests/integrated/api_samples/os-config-drive/server-post-resp.xml.tpl
new file mode 100644
index 000000000..3bb13e69b
--- /dev/null
+++ b/nova/tests/integrated/api_samples/os-config-drive/server-post-resp.xml.tpl
@@ -0,0 +1,6 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<server xmlns:atom="http://www.w3.org/2005/Atom" xmlns="http://docs.openstack.org/compute/api/v1.1" id="%(id)s" adminPass="%(password)s">
+ <metadata/>
+ <atom:link href="%(host)s/v2/openstack/servers/%(uuid)s" rel="self"/>
+ <atom:link href="%(host)s/openstack/servers/%(uuid)s" rel="bookmark"/>
+</server>
diff --git a/nova/tests/integrated/api_samples/os-config-drive/servers-config-drive-details-resp.json.tpl b/nova/tests/integrated/api_samples/os-config-drive/servers-config-drive-details-resp.json.tpl
new file mode 100644
index 000000000..535d00410
--- /dev/null
+++ b/nova/tests/integrated/api_samples/os-config-drive/servers-config-drive-details-resp.json.tpl
@@ -0,0 +1,57 @@
+{
+ "servers": [
+ {
+ "accessIPv4": "",
+ "accessIPv6": "",
+ "addresses": {
+ "private": [
+ {
+ "addr": "%(ip)s",
+ "version": 4
+ }
+ ]
+ },
+ "config_drive": "%(cdrive)s",
+ "created": "%(timestamp)s",
+ "flavor": {
+ "id": "1",
+ "links": [
+ {
+ "href": "%(host)s/openstack/flavors/1",
+ "rel": "bookmark"
+ }
+ ]
+ },
+ "hostId": "%(hostid)s",
+ "id": "%(id)s",
+ "image": {
+ "id": "%(uuid)s",
+ "links": [
+ {
+ "href": "%(host)s/openstack/images/%(uuid)s",
+ "rel": "bookmark"
+ }
+ ]
+ },
+ "links": [
+ {
+ "href": "%(host)s/v2/openstack/servers/%(id)s",
+ "rel": "self"
+ },
+ {
+ "href": "%(host)s/openstack/servers/%(id)s",
+ "rel": "bookmark"
+ }
+ ],
+ "metadata": {
+ "My Server Name": "Apache1"
+ },
+ "name": "new-server-test",
+ "progress": 0,
+ "status": "ACTIVE",
+ "tenant_id": "openstack",
+ "updated": "%(timestamp)s",
+ "user_id": "fake"
+ }
+ ]
+}
diff --git a/nova/tests/integrated/api_samples/os-config-drive/servers-config-drive-details-resp.xml.tpl b/nova/tests/integrated/api_samples/os-config-drive/servers-config-drive-details-resp.xml.tpl
new file mode 100644
index 000000000..c2b2fa3ba
--- /dev/null
+++ b/nova/tests/integrated/api_samples/os-config-drive/servers-config-drive-details-resp.xml.tpl
@@ -0,0 +1,21 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<servers xmlns:atom="http://www.w3.org/2005/Atom" xmlns="http://docs.openstack.org/compute/api/v1.1">
+ <server status="ACTIVE" updated="%(timestamp)s" hostId="%(hostid)s" name="new-server-test" created="%(timestamp)s" userId="fake" tenantId="openstack" accessIPv4="" accessIPv6="" progress="0" id="%(id)s" config_drive="%(cdrive)s">
+ <image id="%(uuid)s">
+ <atom:link href="%(host)s/openstack/images/%(uuid)s" rel="bookmark"/>
+ </image>
+ <flavor id="1">
+ <atom:link href="%(host)s/openstack/flavors/1" rel="bookmark"/>
+ </flavor>
+ <metadata>
+ <meta key="My Server Name">Apache1</meta>
+ </metadata>
+ <addresses>
+ <network id="private">
+ <ip version="4" addr="%(ip)s"/>
+ </network>
+ </addresses>
+ <atom:link href="%(host)s/v2/openstack/servers/%(id)s" rel="self"/>
+ <atom:link href="%(host)s/openstack/servers/%(id)s" rel="bookmark"/>
+ </server>
+</servers>
diff --git a/nova/tests/integrated/api_samples/os-floating-ip-dns/floating-ip-dns-create-or-update-entry-req.json.tpl b/nova/tests/integrated/api_samples/os-floating-ip-dns/floating-ip-dns-create-or-update-entry-req.json.tpl
new file mode 100644
index 000000000..7dc33ddb1
--- /dev/null
+++ b/nova/tests/integrated/api_samples/os-floating-ip-dns/floating-ip-dns-create-or-update-entry-req.json.tpl
@@ -0,0 +1,7 @@
+{
+ "dns_entry" :
+ {
+ "ip": "%(ip)s",
+ "dns_type": "%(dns_type)s"
+ }
+}
diff --git a/nova/tests/integrated/api_samples/os-floating-ip-dns/floating-ip-dns-create-or-update-entry-req.xml.tpl b/nova/tests/integrated/api_samples/os-floating-ip-dns/floating-ip-dns-create-or-update-entry-req.xml.tpl
new file mode 100644
index 000000000..bd62d3418
--- /dev/null
+++ b/nova/tests/integrated/api_samples/os-floating-ip-dns/floating-ip-dns-create-or-update-entry-req.xml.tpl
@@ -0,0 +1,5 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<dns_entry>
+ <ip>%(ip)s</ip>
+ <dns_type>%(dns_type)s</dns_type>
+</dns_entry>
diff --git a/nova/tests/integrated/api_samples/os-floating-ip-dns/floating-ip-dns-create-or-update-entry-resp.json.tpl b/nova/tests/integrated/api_samples/os-floating-ip-dns/floating-ip-dns-create-or-update-entry-resp.json.tpl
new file mode 100644
index 000000000..3ec0743ba
--- /dev/null
+++ b/nova/tests/integrated/api_samples/os-floating-ip-dns/floating-ip-dns-create-or-update-entry-resp.json.tpl
@@ -0,0 +1,9 @@
+{
+ "dns_entry": {
+ "domain": "%(domain)s",
+ "id": null,
+ "ip": "%(ip)s",
+ "name": "%(name)s",
+ "type": "%(dns_type)s"
+ }
+}
diff --git a/nova/tests/integrated/api_samples/os-floating-ip-dns/floating-ip-dns-create-or-update-entry-resp.xml.tpl b/nova/tests/integrated/api_samples/os-floating-ip-dns/floating-ip-dns-create-or-update-entry-resp.xml.tpl
new file mode 100644
index 000000000..38a659b78
--- /dev/null
+++ b/nova/tests/integrated/api_samples/os-floating-ip-dns/floating-ip-dns-create-or-update-entry-resp.xml.tpl
@@ -0,0 +1,2 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<dns_entry ip="%(ip)s" domain="%(domain)s" type="%(dns_type)s" id="None" name="%(name)s"/>
diff --git a/nova/tests/integrated/api_samples/os-floating-ip-dns/floating-ip-dns-create-or-update-req.json.tpl b/nova/tests/integrated/api_samples/os-floating-ip-dns/floating-ip-dns-create-or-update-req.json.tpl
new file mode 100644
index 000000000..db73be14a
--- /dev/null
+++ b/nova/tests/integrated/api_samples/os-floating-ip-dns/floating-ip-dns-create-or-update-req.json.tpl
@@ -0,0 +1,8 @@
+{
+ "domain_entry" :
+ {
+ "domain": "%(domain)s",
+ "scope": "%(scope)s",
+ "project": "%(project)s"
+ }
+}
diff --git a/nova/tests/integrated/api_samples/os-floating-ip-dns/floating-ip-dns-create-or-update-req.xml.tpl b/nova/tests/integrated/api_samples/os-floating-ip-dns/floating-ip-dns-create-or-update-req.xml.tpl
new file mode 100644
index 000000000..40866a537
--- /dev/null
+++ b/nova/tests/integrated/api_samples/os-floating-ip-dns/floating-ip-dns-create-or-update-req.xml.tpl
@@ -0,0 +1,6 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<domain_entry>
+ <domain>%(domain)s</domain>
+ <scope>%(scope)s</scope>
+ <project>%(project)s</project>
+</domain_entry>
diff --git a/nova/tests/integrated/api_samples/os-floating-ip-dns/floating-ip-dns-create-or-update-resp.json.tpl b/nova/tests/integrated/api_samples/os-floating-ip-dns/floating-ip-dns-create-or-update-resp.json.tpl
new file mode 100644
index 000000000..a14d395d2
--- /dev/null
+++ b/nova/tests/integrated/api_samples/os-floating-ip-dns/floating-ip-dns-create-or-update-resp.json.tpl
@@ -0,0 +1,8 @@
+{
+ "domain_entry": {
+ "availability_zone": null,
+ "domain": "%(domain)s",
+ "project": "%(project)s",
+ "scope": "%(scope)s"
+ }
+}
diff --git a/nova/tests/integrated/api_samples/os-floating-ip-dns/floating-ip-dns-create-or-update-resp.xml.tpl b/nova/tests/integrated/api_samples/os-floating-ip-dns/floating-ip-dns-create-or-update-resp.xml.tpl
new file mode 100644
index 000000000..1759c403a
--- /dev/null
+++ b/nova/tests/integrated/api_samples/os-floating-ip-dns/floating-ip-dns-create-or-update-resp.xml.tpl
@@ -0,0 +1,2 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<domain_entry project="%(project)s" scope="%(scope)s" domain="%(domain)s" availability_zone="None"/>
diff --git a/nova/tests/integrated/api_samples/os-floating-ip-dns/floating-ip-dns-entry-get-resp.json.tpl b/nova/tests/integrated/api_samples/os-floating-ip-dns/floating-ip-dns-entry-get-resp.json.tpl
new file mode 100644
index 000000000..8edd0603f
--- /dev/null
+++ b/nova/tests/integrated/api_samples/os-floating-ip-dns/floating-ip-dns-entry-get-resp.json.tpl
@@ -0,0 +1,9 @@
+{
+ "dns_entry": {
+ "domain": "%(domain)s",
+ "id": null,
+ "ip": "%(ip)s",
+ "name": "%(name)s",
+ "type": null
+ }
+}
diff --git a/nova/tests/integrated/api_samples/os-floating-ip-dns/floating-ip-dns-entry-get-resp.xml.tpl b/nova/tests/integrated/api_samples/os-floating-ip-dns/floating-ip-dns-entry-get-resp.xml.tpl
new file mode 100644
index 000000000..a889ef6e2
--- /dev/null
+++ b/nova/tests/integrated/api_samples/os-floating-ip-dns/floating-ip-dns-entry-get-resp.xml.tpl
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<dns_entry ip="%(ip)s" domain="%(domain)s" type="None" id="None" name="%(name)s"/>
diff --git a/nova/tests/integrated/api_samples/os-floating-ip-dns/floating-ip-dns-entry-list-resp.json.tpl b/nova/tests/integrated/api_samples/os-floating-ip-dns/floating-ip-dns-entry-list-resp.json.tpl
new file mode 100644
index 000000000..831cda7b5
--- /dev/null
+++ b/nova/tests/integrated/api_samples/os-floating-ip-dns/floating-ip-dns-entry-list-resp.json.tpl
@@ -0,0 +1,11 @@
+{
+ "dns_entries": [
+ {
+ "domain": "%(domain)s",
+ "id": null,
+ "ip": "%(ip)s",
+ "name": "%(name)s",
+ "type": null
+ }
+ ]
+}
diff --git a/nova/tests/integrated/api_samples/os-floating-ip-dns/floating-ip-dns-entry-list-resp.xml.tpl b/nova/tests/integrated/api_samples/os-floating-ip-dns/floating-ip-dns-entry-list-resp.xml.tpl
new file mode 100644
index 000000000..bf7788f94
--- /dev/null
+++ b/nova/tests/integrated/api_samples/os-floating-ip-dns/floating-ip-dns-entry-list-resp.xml.tpl
@@ -0,0 +1,4 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<dns_entries>
+ <dns_entry ip="%(ip)s" domain="%(domain)s" type="None" id="None" name="%(name)s"/>
+</dns_entries>
diff --git a/nova/tests/integrated/api_samples/os-floating-ip-dns/floating-ip-dns-list-resp.json.tpl b/nova/tests/integrated/api_samples/os-floating-ip-dns/floating-ip-dns-list-resp.json.tpl
new file mode 100644
index 000000000..a6055cfec
--- /dev/null
+++ b/nova/tests/integrated/api_samples/os-floating-ip-dns/floating-ip-dns-list-resp.json.tpl
@@ -0,0 +1,10 @@
+{
+ "domain_entries": [
+ {
+ "availability_zone": null,
+ "domain": "%(domain)s",
+ "project": "%(project)s",
+ "scope": "%(scope)s"
+ }
+ ]
+}
diff --git a/nova/tests/integrated/api_samples/os-floating-ip-dns/floating-ip-dns-list-resp.xml.tpl b/nova/tests/integrated/api_samples/os-floating-ip-dns/floating-ip-dns-list-resp.xml.tpl
new file mode 100644
index 000000000..e57c290cb
--- /dev/null
+++ b/nova/tests/integrated/api_samples/os-floating-ip-dns/floating-ip-dns-list-resp.xml.tpl
@@ -0,0 +1,4 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<domain_entries>
+ <domain_entry project="%(project)s" scope="%(scope)s" domain="%(domain)s" availability_zone="None"/>
+</domain_entries>
diff --git a/nova/tests/integrated/api_samples/os-instance-actions/instance-action-get-resp.json.tpl b/nova/tests/integrated/api_samples/os-instance-actions/instance-action-get-resp.json.tpl
new file mode 100644
index 000000000..6ba99d264
--- /dev/null
+++ b/nova/tests/integrated/api_samples/os-instance-actions/instance-action-get-resp.json.tpl
@@ -0,0 +1,27 @@
+{
+ "instanceAction": {
+ "action": "%(action)s",
+ "instance_uuid": "%(instance_uuid)s",
+ "request_id": "%(request_id)s",
+ "user_id": "%(integer_id)s",
+ "project_id": "%(integer_id)s",
+ "start_time": "%(start_time)s",
+ "message": "",
+ "events": [
+ {
+ "event": "%(event)s",
+ "start_time": "%(timestamp)s",
+ "finish_time": "%(timestamp)s",
+ "result": "%(result)s",
+ "traceback": ""
+ },
+ {
+ "event": "%(event)s",
+ "start_time": "%(timestamp)s",
+ "finish_time": "%(timestamp)s",
+ "result": "%(result)s",
+ "traceback": ""
+ }
+ ]
+ }
+}
diff --git a/nova/tests/integrated/api_samples/os-instance-actions/instance-action-get-resp.xml.tpl b/nova/tests/integrated/api_samples/os-instance-actions/instance-action-get-resp.xml.tpl
new file mode 100644
index 000000000..ef4b7b003
--- /dev/null
+++ b/nova/tests/integrated/api_samples/os-instance-actions/instance-action-get-resp.xml.tpl
@@ -0,0 +1,5 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<instanceAction action="%(action)s" instance_uuid="%(instance_uuid)s" request_id="%(request_id)s" user_id="%(integer_id)s" project_id="%(integer_id)s" start_time="%(start_time)s" message="">
+ <events event="%(event)s" start_time="%(timestamp)s" finish_time="%(timestamp)s" result="%(result)s" traceback=""/>
+ <events event="%(event)s" start_time="%(timestamp)s" finish_time="%(timestamp)s" result="%(result)s" traceback=""/>
+</instanceAction>
diff --git a/nova/tests/integrated/api_samples/os-instance-actions/instance-actions-list-resp.json.tpl b/nova/tests/integrated/api_samples/os-instance-actions/instance-actions-list-resp.json.tpl
new file mode 100644
index 000000000..9f64a1b29
--- /dev/null
+++ b/nova/tests/integrated/api_samples/os-instance-actions/instance-actions-list-resp.json.tpl
@@ -0,0 +1,22 @@
+{
+ "instanceActions": [
+ {
+ "action": "%(action)s",
+ "instance_uuid": "%(uuid)s",
+ "request_id": "%(request_id)s",
+ "user_id": "%(integer_id)s",
+ "project_id": "%(integer_id)s",
+ "start_time": "%(timestamp)s",
+ "message": ""
+ },
+ {
+ "action": "%(action)s",
+ "instance_uuid": "%(uuid)s",
+ "request_id": "%(request_id)s",
+ "user_id": "%(integer_id)s",
+ "project_id": "%(integer_id)s",
+ "start_time": "%(timestamp)s",
+ "message": ""
+ }
+ ]
+}
diff --git a/nova/tests/integrated/api_samples/os-instance-actions/instance-actions-list-resp.xml.tpl b/nova/tests/integrated/api_samples/os-instance-actions/instance-actions-list-resp.xml.tpl
new file mode 100644
index 000000000..943b1ba74
--- /dev/null
+++ b/nova/tests/integrated/api_samples/os-instance-actions/instance-actions-list-resp.xml.tpl
@@ -0,0 +1,5 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<instanceActions>
+ <instanceAction action="%(action)s" instance_uuid="%(uuid)s" request_id="%(request_id)s" user_id="%(integer_id)s" project_id="%(integer_id)s" start_time="%(timestamp)s" message=""/>
+ <instanceAction action="%(action)s" instance_uuid="%(uuid)s" request_id="%(request_id)s" user_id="%(integer_id)s" project_id="%(integer_id)s" start_time="%(timestamp)s" message=""/>
+</instanceActions>
diff --git a/nova/tests/integrated/api_samples/os-services/service-disable-put-req.json.tpl b/nova/tests/integrated/api_samples/os-services/service-disable-put-req.json.tpl
new file mode 100644
index 000000000..4d48af1b8
--- /dev/null
+++ b/nova/tests/integrated/api_samples/os-services/service-disable-put-req.json.tpl
@@ -0,0 +1,4 @@
+{
+ "host": "%(host)s",
+ "service": "%(service)s"
+}
diff --git a/nova/tests/integrated/api_samples/os-services/service-disable-put-resp.json.tpl b/nova/tests/integrated/api_samples/os-services/service-disable-put-resp.json.tpl
new file mode 100644
index 000000000..8219a43f6
--- /dev/null
+++ b/nova/tests/integrated/api_samples/os-services/service-disable-put-resp.json.tpl
@@ -0,0 +1,5 @@
+{
+ "disabled": true,
+ "host": "%(host)s",
+ "service": "%(service)s"
+}
diff --git a/nova/tests/integrated/api_samples/os-services/service-enable-put-req.json.tpl b/nova/tests/integrated/api_samples/os-services/service-enable-put-req.json.tpl
new file mode 100644
index 000000000..4d48af1b8
--- /dev/null
+++ b/nova/tests/integrated/api_samples/os-services/service-enable-put-req.json.tpl
@@ -0,0 +1,4 @@
+{
+ "host": "%(host)s",
+ "service": "%(service)s"
+}
diff --git a/nova/tests/integrated/api_samples/os-services/service-enable-put-resp.json.tpl b/nova/tests/integrated/api_samples/os-services/service-enable-put-resp.json.tpl
new file mode 100644
index 000000000..079b9c76e
--- /dev/null
+++ b/nova/tests/integrated/api_samples/os-services/service-enable-put-resp.json.tpl
@@ -0,0 +1,5 @@
+{
+ "disabled": false,
+ "host": "%(host)s",
+ "service": "%(service)s"
+}
diff --git a/nova/tests/integrated/api_samples/os-services/services-list-get-resp.json.tpl b/nova/tests/integrated/api_samples/os-services/services-list-get-resp.json.tpl
new file mode 100644
index 000000000..cc6101338
--- /dev/null
+++ b/nova/tests/integrated/api_samples/os-services/services-list-get-resp.json.tpl
@@ -0,0 +1,36 @@
+{
+ "services": [
+ {
+ "binary": "nova-scheduler",
+ "host": "host1",
+ "state": "up",
+ "status": "disabled",
+ "updated_at": "%(timestamp)s",
+ "zone": "internal"
+ },
+ {
+ "binary": "nova-compute",
+ "host": "host1",
+ "state": "up",
+ "status": "disabled",
+ "updated_at": "%(timestamp)s",
+ "zone": "nova"
+ },
+ {
+ "binary": "nova-scheduler",
+ "host": "host2",
+ "state": "down",
+ "status": "enabled",
+ "updated_at": "%(timestamp)s",
+ "zone": "internal"
+ },
+ {
+ "binary": "nova-compute",
+ "host": "host2",
+ "state": "down",
+ "status": "disabled",
+ "updated_at": "%(timestamp)s",
+ "zone": "nova"
+ }
+ ]
+}
diff --git a/nova/tests/integrated/test_api_samples.py b/nova/tests/integrated/test_api_samples.py
index f37b3ac5d..97e38fa0c 100644
--- a/nova/tests/integrated/test_api_samples.py
+++ b/nova/tests/integrated/test_api_samples.py
@@ -14,6 +14,7 @@
# under the License.
import base64
+import copy
import datetime
import inspect
import json
@@ -46,10 +47,14 @@ from nova.servicegroup import api as service_group_api
from nova import test
from nova.tests.api.openstack.compute.contrib import test_fping
from nova.tests.api.openstack.compute.contrib import test_networks
+from nova.tests.api.openstack.compute.contrib import test_services
+from nova.tests.api.openstack import fakes
from nova.tests.baremetal.db import base as bm_db_base
+from nova.tests import fake_instance_actions
from nova.tests import fake_network
from nova.tests.image import fake
from nova.tests.integrated import integrated_helpers
+from nova.tests import utils as test_utils
from nova import utils
CONF = cfg.CONF
@@ -377,12 +382,9 @@ class ApiSamplesTrap(ApiSampleTestBase):
# NOT be allowed to grow, and should shrink to zero (and be
# removed) soon.
do_not_approve_additions = []
- do_not_approve_additions.append('os-config-drive')
do_not_approve_additions.append('os-create-server-ext')
do_not_approve_additions.append('os-flavor-access')
- do_not_approve_additions.append('os-floating-ip-dns')
do_not_approve_additions.append('os-hypervisors')
- do_not_approve_additions.append('os-services')
do_not_approve_additions.append('os-volumes')
tests = self._get_extensions_tested()
@@ -1175,7 +1177,7 @@ class ExtendedServerAttributesJsonTest(ServersSampleBase):
".extended_server_attributes" + \
".Extended_server_attributes"
- def test_extended_server_attrs_get(self):
+ def test_show(self):
uuid = self._post_server()
response = self._do_get('servers/%s' % uuid)
@@ -1184,10 +1186,10 @@ class ExtendedServerAttributesJsonTest(ServersSampleBase):
subs['id'] = uuid
subs['instance_name'] = 'instance-\d{8}'
subs['hypervisor_hostname'] = r'[\w\.\-]+'
- return self._verify_response('extended-server-attrs-get',
+ return self._verify_response('server-get-resp',
subs, response)
- def test_extended_server_attrs_list(self):
+ def test_detail(self):
uuid = self._post_server()
response = self._do_get('servers/detail')
@@ -1196,7 +1198,7 @@ class ExtendedServerAttributesJsonTest(ServersSampleBase):
subs['id'] = uuid
subs['instance_name'] = 'instance-\d{8}'
subs['hypervisor_hostname'] = r'[\w\.\-]+'
- return self._verify_response('extended-server-attrs-list',
+ return self._verify_response('servers-detail-resp',
subs, response)
@@ -1909,6 +1911,61 @@ class MultipleCreateXmlTest(MultipleCreateJsonTest):
ctype = 'xml'
+class ServicesJsonTest(ApiSampleTestBase):
+ extension_name = "nova.api.openstack.compute.contrib.services.Services"
+
+ def setUp(self):
+ super(ServicesJsonTest, self).setUp()
+ self.stubs.Set(db, "service_get_all",
+ test_services.fake_service_get_all)
+ self.stubs.Set(timeutils, "utcnow", test_services.fake_utcnow)
+ self.stubs.Set(db, "service_get_by_args",
+ test_services.fake_service_get_by_host_binary)
+ self.stubs.Set(db, "service_update",
+ test_services.fake_service_update)
+
+ def tearDown(self):
+ super(ServicesJsonTest, self).tearDown()
+ timeutils.clear_time_override()
+
+ def test_services_list(self):
+ """Return a list of all agent builds."""
+ response = self._do_get('os-services')
+ self.assertEqual(response.status, 200)
+ subs = {'binary': 'nova-compute',
+ 'host': 'host1',
+ 'zone': 'nova',
+ 'status': 'disabled',
+ 'state': 'up'}
+ subs.update(self._get_regexes())
+ return self._verify_response('services-list-get-resp',
+ subs, response)
+
+ def test_service_enable(self):
+ """Enable an existing agent build."""
+ subs = {"host": "host1",
+ 'service': 'nova-compute'}
+ response = self._do_put('/os-services/enable',
+ 'service-enable-put-req', subs)
+ self.assertEqual(response.status, 200)
+ subs = {"host": "host1",
+ "service": "nova-compute"}
+ return self._verify_response('service-enable-put-resp',
+ subs, response)
+
+ def test_service_disable(self):
+ """Disable an existing agent build."""
+ subs = {"host": "host1",
+ 'service': 'nova-compute'}
+ response = self._do_put('/os-services/disable',
+ 'service-disable-put-req', subs)
+ self.assertEqual(response.status, 200)
+ subs = {"host": "host1",
+ "service": "nova-compute"}
+ return self._verify_response('service-disable-put-resp',
+ subs, response)
+
+
class SimpleTenantUsageSampleJsonTest(ServersSampleBase):
extension_name = ("nova.api.openstack.compute.contrib.simple_tenant_usage."
"Simple_tenant_usage")
@@ -2218,17 +2275,45 @@ class QuotasSampleXmlTests(QuotasSampleJsonTests):
ctype = "xml"
-class ExtendedStatusSampleJsonTests(ServersSampleBase):
+class ExtendedIpsSampleJsonTests(ServersSampleBase):
extension_name = ("nova.api.openstack.compute.contrib"
- ".extended_status.Extended_status")
+ ".extended_ips.Extended_ips")
def test_show(self):
uuid = self._post_server()
- response = self._do_get('servers')
+ response = self._do_get('servers/%s' % uuid)
self.assertEqual(response.status, 200)
subs = self._get_regexes()
+ subs['hostid'] = '[a-f0-9]+'
subs['id'] = uuid
- return self._verify_response('servers-list-resp', subs, response)
+ subs['hypervisor_hostname'] = r'[\w\.\-]+'
+ return self._verify_response('server-get-resp', subs, response)
+
+ def test_detail(self):
+ uuid = self._post_server()
+ response = self._do_get('servers/detail')
+ self.assertEqual(response.status, 200)
+ subs = self._get_regexes()
+ subs['id'] = uuid
+ subs['hostid'] = '[a-f0-9]+'
+ return self._verify_response('servers-detail-resp', subs, response)
+
+
+class ExtendedIpsSampleXmlTests(ExtendedIpsSampleJsonTests):
+ ctype = 'xml'
+
+
+class ExtendedStatusSampleJsonTests(ServersSampleBase):
+ extension_name = ("nova.api.openstack.compute.contrib"
+ ".extended_status.Extended_status")
+
+ def test_show(self):
+ uuid = self._post_server()
+ response = self._do_get('servers/%s' % uuid)
+ self.assertEqual(response.status, 200)
+ subs = self._get_regexes()
+ subs['hostid'] = '[a-f0-9]+'
+ return self._verify_response('server-get-resp', subs, response)
def test_detail(self):
uuid = self._post_server()
@@ -2886,7 +2971,7 @@ class ExtendedAvailabilityZoneJsonTests(ServersSampleBase):
".extended_availability_zone"
".Extended_availability_zone")
- def test_get(self):
+ def test_show(self):
uuid = self._post_server()
response = self._do_get('servers/%s' % uuid)
self.assertEqual(response.status, 200)
@@ -2938,3 +3023,190 @@ class EvacuateJsonTest(ServersSampleBase):
class EvacuateXmlTest(EvacuateJsonTest):
ctype = 'xml'
+
+
+class FloatingIpDNSJsonTest(ApiSampleTestBase):
+ extension_name = ("nova.api.openstack.compute.contrib.floating_ip_dns."
+ "Floating_ip_dns")
+
+ domain = 'domain1.example.org'
+ name = 'instance1'
+ scope = 'public'
+ project = 'project1'
+ dns_type = 'A'
+ ip = '192.168.1.1'
+
+ def _create_or_update(self):
+ subs = {'domain': self.domain,
+ 'project': self.project,
+ 'scope': self.scope}
+ response = self._do_put('os-floating-ip-dns/%s' % self.domain,
+ 'floating-ip-dns-create-or-update-req', subs)
+ self.assertEqual(response.status, 200)
+ self._verify_response('floating-ip-dns-create-or-update-resp', subs,
+ response)
+
+ def _create_or_update_entry(self):
+ subs = {'ip': self.ip, 'dns_type': self.dns_type}
+ response = self._do_put('os-floating-ip-dns/%s/entries/%s'
+ % (self.domain, self.name),
+ 'floating-ip-dns-create-or-update-entry-req',
+ subs)
+ self.assertEqual(response.status, 200)
+ subs.update({'name': self.name, 'domain': self.domain})
+ self._verify_response('floating-ip-dns-create-or-update-entry-resp',
+ subs, response)
+
+ def test_floating_ip_dns_list(self):
+ self._create_or_update()
+ response = self._do_get('os-floating-ip-dns')
+ self.assertEqual(response.status, 200)
+ subs = {'domain': self.domain,
+ 'project': self.project,
+ 'scope': self.scope}
+ return self._verify_response('floating-ip-dns-list-resp', subs,
+ response)
+
+ def test_floating_ip_dns_create_or_update(self):
+ self._create_or_update()
+
+ def test_floating_ip_dns_delete(self):
+ self._create_or_update()
+ response = self._do_delete('os-floating-ip-dns/%s' % self.domain)
+ self.assertEqual(response.status, 202)
+
+ def test_floating_ip_dns_create_or_update_entry(self):
+ self._create_or_update_entry()
+
+ def test_floating_ip_dns_entry_get(self):
+ self._create_or_update_entry()
+ response = self._do_get('os-floating-ip-dns/%s/entries/%s'
+ % (self.domain, self.name))
+ self.assertEqual(response.status, 200)
+ subs = {'domain': self.domain,
+ 'ip': self.ip,
+ 'name': self.name}
+ return self._verify_response('floating-ip-dns-entry-get-resp', subs,
+ response)
+
+ def test_floating_ip_dns_entry_delete(self):
+ self._create_or_update_entry()
+ response = self._do_delete('os-floating-ip-dns/%s/entries/%s'
+ % (self.domain, self.name))
+ self.assertEqual(response.status, 202)
+
+ def test_floating_ip_dns_entry_list(self):
+ self._create_or_update_entry()
+ response = self._do_get('os-floating-ip-dns/%s/entries/%s'
+ % (self.domain, self.ip))
+ self.assertEqual(response.status, 200)
+ subs = {'domain': self.domain,
+ 'ip': self.ip,
+ 'name': self.name}
+ return self._verify_response('floating-ip-dns-entry-list-resp', subs,
+ response)
+
+
+class FloatingIpDNSXmlTest(FloatingIpDNSJsonTest):
+ ctype = 'xml'
+
+
+class InstanceActionsSampleJsonTest(ApiSampleTestBase):
+ extension_name = ('nova.api.openstack.compute.contrib.instance_actions.'
+ 'Instance_actions')
+
+ def setUp(self):
+ super(InstanceActionsSampleJsonTest, self).setUp()
+ self.actions = fake_instance_actions.FAKE_ACTIONS
+ self.events = fake_instance_actions.FAKE_EVENTS
+ self.instance = test_utils.get_test_instance()
+
+ def fake_instance_action_get_by_request_id(context, uuid, request_id):
+ return copy.deepcopy(self.actions[uuid][request_id])
+
+ def fake_instance_actions_get(context, uuid):
+ return [copy.deepcopy(value) for value in
+ self.actions[uuid].itervalues()]
+
+ def fake_instance_action_events_get(context, action_id):
+ return copy.deepcopy(self.events[action_id])
+
+ def fake_instance_get_by_uuid(context, instance_id):
+ return self.instance
+
+ self.stubs.Set(db, 'action_get_by_request_id',
+ fake_instance_action_get_by_request_id)
+ self.stubs.Set(db, 'actions_get', fake_instance_actions_get)
+ self.stubs.Set(db, 'action_events_get',
+ fake_instance_action_events_get)
+ self.stubs.Set(db, 'instance_get_by_uuid', fake_instance_get_by_uuid)
+
+ def test_instance_action_get(self):
+ fake_uuid = fake_instance_actions.FAKE_UUID
+ fake_request_id = fake_instance_actions.FAKE_REQUEST_ID1
+ fake_action = self.actions[fake_uuid][fake_request_id]
+
+ response = self._do_get('servers/%s/os-instance-actions/%s' %
+ (fake_uuid, fake_request_id))
+ subs = self._get_regexes()
+ subs['action'] = '(reboot)|(resize)'
+ subs['instance_uuid'] = fake_uuid
+ subs['integer_id'] = '[0-9]+'
+ subs['request_id'] = fake_action['request_id']
+ subs['start_time'] = fake_action['start_time']
+ subs['result'] = '(Success)|(Error)'
+ subs['event'] = '(schedule)|(compute_create)'
+ return self._verify_response('instance-action-get-resp', subs,
+ response)
+
+ def test_instance_actions_list(self):
+ fake_uuid = fake_instance_actions.FAKE_UUID
+ response = self._do_get('servers/%s/os-instance-actions' % (fake_uuid))
+ subs = self._get_regexes()
+ subs['action'] = '(reboot)|(resize)'
+ subs['integer_id'] = '[0-9]+'
+ subs['request_id'] = ('req-[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}'
+ '-[0-9a-f]{4}-[0-9a-f]{12}')
+ return self._verify_response('instance-actions-list-resp', subs,
+ response)
+
+
+class InstanceActionsSampleXmlTest(InstanceActionsSampleJsonTest):
+ ctype = 'xml'
+
+
+class ConfigDriveSampleJsonTest(ServersSampleBase):
+ extension_name = ("nova.api.openstack.compute.contrib.config_drive."
+ "Config_drive")
+
+ def setUp(self):
+ super(ConfigDriveSampleJsonTest, self).setUp()
+ fakes.stub_out_networking(self.stubs)
+ fakes.stub_out_rate_limiting(self.stubs)
+ fake.stub_out_image_service(self.stubs)
+
+ def test_config_drive_show(self):
+ uuid = self._post_server()
+ response = self._do_get('servers/%s' % uuid)
+ self.assertEqual(response.status, 200)
+ subs = self._get_regexes()
+ subs['hostid'] = '[a-f0-9]+'
+ # config drive can be an uuid or empty value
+ subs['cdrive'] = '(%s)?' % subs['uuid']
+ return self._verify_response('server-config-drive-get-resp', subs,
+ response)
+
+ def test_config_drive_detail(self):
+ uuid = self._post_server()
+ response = self._do_get('servers/detail')
+ self.assertEqual(response.status, 200)
+ subs = self._get_regexes()
+ subs['hostid'] = '[a-f0-9]+'
+ # config drive can be an uuid or empty value
+ subs['cdrive'] = '(%s)?' % subs['uuid']
+ return self._verify_response('servers-config-drive-details-resp',
+ subs, response)
+
+
+class ConfigDriveSampleXmlTest(ConfigDriveSampleJsonTest):
+ ctype = 'xml'
diff --git a/nova/tests/network/test_linux_net.py b/nova/tests/network/test_linux_net.py
index bc21b80ad..50c98e78c 100644
--- a/nova/tests/network/test_linux_net.py
+++ b/nova/tests/network/test_linux_net.py
@@ -24,6 +24,7 @@ from nova import context
from nova import db
from nova.network import driver
from nova.network import linux_net
+from nova.openstack.common import cfg
from nova.openstack.common import fileutils
from nova.openstack.common import log as logging
from nova.openstack.common import timeutils
@@ -31,6 +32,7 @@ from nova import test
from nova import utils
LOG = logging.getLogger(__name__)
+CONF = cfg.CONF
HOST = "testhost"
@@ -472,6 +474,71 @@ class LinuxNetworkTestCase(test.TestCase):
driver.plug(network, "fakemac")
self.assertEqual(info['passed_interface'], "override_interface")
+ def _test_dnsmasq_execute(self, extra_expected=None):
+ network_ref = {'id': 'fake',
+ 'label': 'fake',
+ 'multi_host': False,
+ 'cidr': '10.0.0.0/24',
+ 'dns1': '8.8.4.4',
+ 'dhcp_start': '1.0.0.2',
+ 'dhcp_server': '10.0.0.1'}
+ executes = []
+
+ def fake_execute(*args, **kwargs):
+ executes.append(args)
+ return "", ""
+
+ self.stubs.Set(linux_net, '_execute', fake_execute)
+
+ self.stubs.Set(os, 'chmod', lambda *a, **kw: None)
+ self.stubs.Set(linux_net, 'write_to_file', lambda *a, **kw: None)
+ self.stubs.Set(linux_net, '_dnsmasq_pid_for', lambda *a, **kw: None)
+ dev = 'br100'
+ linux_net.restart_dhcp(self.context, dev, network_ref)
+ expected = ['env',
+ 'CONFIG_FILE=%s' % CONF.dhcpbridge_flagfile,
+ 'NETWORK_ID=fake',
+ 'dnsmasq',
+ '--strict-order',
+ '--bind-interfaces',
+ '--conf-file=%s' % CONF.dnsmasq_config_file,
+ '--domain=%s' % CONF.dhcp_domain,
+ '--pid-file=%s' % linux_net._dhcp_file(dev, 'pid'),
+ '--listen-address=%s' % network_ref['dhcp_server'],
+ '--except-interface=lo',
+ "--dhcp-range=set:'%s',%s,static,%ss" % (network_ref['label'],
+ network_ref['dhcp_start'],
+ CONF.dhcp_lease_time),
+ '--dhcp-lease-max=256',
+ '--dhcp-hostsfile=%s' % linux_net._dhcp_file(dev, 'conf'),
+ '--dhcp-script=%s' % CONF.dhcpbridge,
+ '--leasefile-ro']
+ if extra_expected:
+ expected += extra_expected
+ self.assertEqual([tuple(expected)], executes)
+
+ def test_dnsmasq_execute(self):
+ self._test_dnsmasq_execute()
+
+ def test_dnsmasq_execute_dns_servers(self):
+ self.flags(dns_server=['1.1.1.1', '2.2.2.2'])
+ expected = [
+ '--no-hosts',
+ '--no-resolv',
+ '--server=1.1.1.1',
+ '--server=2.2.2.2',
+ ]
+ self._test_dnsmasq_execute(expected)
+
+ def test_dnsmasq_execute_use_network_dns_servers(self):
+ self.flags(use_network_dns_servers=True)
+ expected = [
+ '--no-hosts',
+ '--no-resolv',
+ '--server=8.8.4.4',
+ ]
+ self._test_dnsmasq_execute(expected)
+
def test_isolated_host(self):
self.flags(fake_network=False,
share_dhcp_address=True)
diff --git a/nova/tests/network/test_quantumv2.py b/nova/tests/network/test_quantumv2.py
index 1805044a1..f3f306694 100644
--- a/nova/tests/network/test_quantumv2.py
+++ b/nova/tests/network/test_quantumv2.py
@@ -189,6 +189,16 @@ class TestQuantumv2(test.TestCase):
'gateway_ip': '10.0.1.1',
'dns_nameservers': ['8.8.1.1', '8.8.1.2']}]
self.subnet_data2 = []
+ self.subnet_data_n = [{'id': 'my_subid1',
+ 'cidr': '10.0.1.0/24',
+ 'network_id': 'my_netid1',
+ 'gateway_ip': '10.0.1.1',
+ 'dns_nameservers': ['8.8.1.1', '8.8.1.2']},
+ {'id': 'my_subid2',
+ 'cidr': '20.0.1.0/24',
+ 'network_id': 'my_netid2',
+ 'gateway_ip': '20.0.1.1',
+ 'dns_nameservers': ['8.8.1.1', '8.8.1.2']}]
self.subnet_data2.append({'id': 'my_subid2',
'cidr': '10.0.2.0/24',
'network_id': 'my_netid2',
@@ -1010,7 +1020,7 @@ class TestQuantumv2(test.TestCase):
network_id = 'my_netid1'
search_opts = {'network_id': network_id}
self.moxed_client.list_subnets(
- **search_opts).AndReturn({'subnets': self.subnet_data1})
+ **search_opts).AndReturn({'subnets': self.subnet_data_n})
zone = 'compute:%s' % self.instance['availability_zone']
search_opts = {'device_id': self.instance['uuid'],
diff --git a/nova/tests/scheduler/test_filter_scheduler.py b/nova/tests/scheduler/test_filter_scheduler.py
index b4d73ec0c..4b07581fb 100644
--- a/nova/tests/scheduler/test_filter_scheduler.py
+++ b/nova/tests/scheduler/test_filter_scheduler.py
@@ -40,6 +40,16 @@ def fake_get_filtered_hosts(hosts, filter_properties):
return list(hosts)
+def fake_get_group_filtered_hosts(hosts, filter_properties):
+ group_hosts = filter_properties.get('group_hosts') or []
+ if group_hosts:
+ hosts = list(hosts)
+ hosts.pop(0)
+ return hosts
+ else:
+ return list(hosts)
+
+
class FilterSchedulerTestCase(test_scheduler.SchedulerTestCase):
"""Test case for Filter Scheduler."""
@@ -480,3 +490,169 @@ class FilterSchedulerTestCase(test_scheduler.SchedulerTestCase):
self.assertRaises(exception.MigrationError,
self.driver._assert_compute_node_has_enough_memory,
self.context, instance, dest)
+
+ def test_basic_schedule_run_instances_anti_affinity(self):
+ filter_properties = {'scheduler_hints':
+ {'group': 'cats'}}
+ # Request spec 1
+ instance_opts1 = {'project_id': 1, 'os_type': 'Linux',
+ 'memory_mb': 512, 'root_gb': 512,
+ 'ephemeral_gb': 0, 'vcpus': 1,
+ 'system_metadata': {'system': 'metadata'}}
+ request_spec1 = {'instance_uuids': ['fake-uuid1-1', 'fake-uuid1-2'],
+ 'instance_properties': instance_opts1,
+ 'instance_type': {'memory_mb': 512, 'root_gb': 512,
+ 'ephemeral_gb': 0, 'vcpus': 1}}
+ self.next_weight = 1.0
+
+ def _fake_weigh_objects(_self, functions, hosts, options):
+ self.next_weight += 2.0
+ host_state = hosts[0]
+ return [weights.WeighedHost(host_state, self.next_weight)]
+
+ sched = fakes.FakeFilterScheduler()
+
+ fake_context = context.RequestContext('user', 'project',
+ is_admin=True)
+
+ self.stubs.Set(sched.host_manager, 'get_filtered_hosts',
+ fake_get_group_filtered_hosts)
+ self.stubs.Set(weights.HostWeightHandler,
+ 'get_weighed_objects', _fake_weigh_objects)
+ fakes.mox_host_manager_db_calls(self.mox, fake_context)
+
+ self.mox.StubOutWithMock(driver, 'instance_update_db')
+ self.mox.StubOutWithMock(compute_rpcapi.ComputeAPI, 'run_instance')
+ self.mox.StubOutWithMock(sched, 'group_hosts')
+
+ instance1_1 = {'uuid': 'fake-uuid1-1'}
+ instance1_2 = {'uuid': 'fake-uuid1-2'}
+
+ sched.group_hosts(mox.IgnoreArg(), 'cats').AndReturn([])
+
+ def inc_launch_index1(*args, **kwargs):
+ request_spec1['instance_properties']['launch_index'] = (
+ request_spec1['instance_properties']['launch_index'] + 1)
+
+ expected_metadata = {'system_metadata':
+ {'system': 'metadata', 'group': 'cats'}}
+ driver.instance_update_db(fake_context, instance1_1['uuid'],
+ extra_values=expected_metadata).WithSideEffects(
+ inc_launch_index1).AndReturn(instance1_1)
+ compute_rpcapi.ComputeAPI.run_instance(fake_context, host='host3',
+ instance=instance1_1, requested_networks=None,
+ injected_files=None, admin_password=None, is_first_time=None,
+ request_spec=request_spec1, filter_properties=mox.IgnoreArg(),
+ node='node3')
+
+ driver.instance_update_db(fake_context, instance1_2['uuid'],
+ extra_values=expected_metadata).WithSideEffects(
+ inc_launch_index1).AndReturn(instance1_2)
+ compute_rpcapi.ComputeAPI.run_instance(fake_context, host='host4',
+ instance=instance1_2, requested_networks=None,
+ injected_files=None, admin_password=None, is_first_time=None,
+ request_spec=request_spec1, filter_properties=mox.IgnoreArg(),
+ node='node4')
+ self.mox.ReplayAll()
+ sched.schedule_run_instance(fake_context, request_spec1,
+ None, None, None, None, filter_properties)
+
+ def test_schedule_host_pool(self):
+ """Make sure the scheduler_host_subset_size property works properly."""
+
+ self.flags(scheduler_host_subset_size=2)
+ sched = fakes.FakeFilterScheduler()
+
+ fake_context = context.RequestContext('user', 'project',
+ is_admin=True)
+ self.stubs.Set(sched.host_manager, 'get_filtered_hosts',
+ fake_get_filtered_hosts)
+ fakes.mox_host_manager_db_calls(self.mox, fake_context)
+
+ instance_properties = {'project_id': 1,
+ 'root_gb': 512,
+ 'memory_mb': 512,
+ 'ephemeral_gb': 0,
+ 'vcpus': 1,
+ 'os_type': 'Linux'}
+
+ request_spec = dict(instance_properties=instance_properties)
+ filter_properties = {}
+ self.mox.ReplayAll()
+ hosts = sched._schedule(self.context, request_spec,
+ filter_properties=filter_properties)
+
+ # one host should be chosen
+ self.assertEqual(len(hosts), 1)
+
+ def test_schedule_large_host_pool(self):
+ """Hosts should still be chosen if pool size
+ is larger than number of filtered hosts"""
+
+ sched = fakes.FakeFilterScheduler()
+
+ fake_context = context.RequestContext('user', 'project',
+ is_admin=True)
+ self.flags(scheduler_host_subset_size=20)
+ self.stubs.Set(sched.host_manager, 'get_filtered_hosts',
+ fake_get_filtered_hosts)
+ fakes.mox_host_manager_db_calls(self.mox, fake_context)
+
+ instance_properties = {'project_id': 1,
+ 'root_gb': 512,
+ 'memory_mb': 512,
+ 'ephemeral_gb': 0,
+ 'vcpus': 1,
+ 'os_type': 'Linux'}
+ request_spec = dict(instance_properties=instance_properties)
+ filter_properties = {}
+ self.mox.ReplayAll()
+ hosts = sched._schedule(self.context, request_spec,
+ filter_properties=filter_properties)
+
+ # one host should be chose
+ self.assertEqual(len(hosts), 1)
+
+ def test_schedule_chooses_best_host(self):
+ """If scheduler_host_subset_size is 1, the largest host with greatest
+ weight should be returned"""
+
+ self.flags(scheduler_host_subset_size=1)
+
+ sched = fakes.FakeFilterScheduler()
+
+ fake_context = context.RequestContext('user', 'project',
+ is_admin=True)
+ self.stubs.Set(sched.host_manager, 'get_filtered_hosts',
+ fake_get_filtered_hosts)
+ fakes.mox_host_manager_db_calls(self.mox, fake_context)
+
+ self.next_weight = 50
+
+ def _fake_weigh_objects(_self, functions, hosts, options):
+ this_weight = self.next_weight
+ self.next_weight = 0
+ host_state = hosts[0]
+ return [weights.WeighedHost(host_state, this_weight)]
+
+ instance_properties = {'project_id': 1,
+ 'root_gb': 512,
+ 'memory_mb': 512,
+ 'ephemeral_gb': 0,
+ 'vcpus': 1,
+ 'os_type': 'Linux'}
+
+ request_spec = dict(instance_properties=instance_properties)
+
+ self.stubs.Set(weights.HostWeightHandler,
+ 'get_weighed_objects', _fake_weigh_objects)
+
+ filter_properties = {}
+ self.mox.ReplayAll()
+ hosts = sched._schedule(self.context, request_spec,
+ filter_properties=filter_properties)
+
+ # one host should be chosen
+ self.assertEquals(1, len(hosts))
+
+ self.assertEquals(50, hosts[0].weight)
diff --git a/nova/tests/scheduler/test_host_filters.py b/nova/tests/scheduler/test_host_filters.py
index 230e2ea03..edd2e0d61 100644
--- a/nova/tests/scheduler/test_host_filters.py
+++ b/nova/tests/scheduler/test_host_filters.py
@@ -1400,3 +1400,17 @@ class HostFiltersTestCase(test.TestCase):
{'num_instances': 5})
filter_properties = {}
self.assertFalse(filt_cls.host_passes(host, filter_properties))
+
+ def test_group_anti_affinity_filter_passes(self):
+ filt_cls = self.class_map['GroupAntiAffinityFilter']()
+ host = fakes.FakeHostState('host1', 'node1', {})
+ filter_properties = {'group_hosts': []}
+ self.assertTrue(filt_cls.host_passes(host, filter_properties))
+ filter_properties = {'group_hosts': ['host2']}
+ self.assertTrue(filt_cls.host_passes(host, filter_properties))
+
+ def test_group_anti_affinity_filter_fails(self):
+ filt_cls = self.class_map['GroupAntiAffinityFilter']()
+ host = fakes.FakeHostState('host1', 'node1', {})
+ filter_properties = {'group_hosts': ['host1']}
+ self.assertFalse(filt_cls.host_passes(host, filter_properties))
diff --git a/nova/tests/scheduler/test_scheduler.py b/nova/tests/scheduler/test_scheduler.py
index 44e1f3537..01d3f6a50 100644
--- a/nova/tests/scheduler/test_scheduler.py
+++ b/nova/tests/scheduler/test_scheduler.py
@@ -24,6 +24,7 @@ import mox
from nova.compute import api as compute_api
from nova.compute import power_state
from nova.compute import rpcapi as compute_rpcapi
+from nova.compute import task_states
from nova.compute import utils as compute_utils
from nova.compute import vm_states
from nova.conductor import api as conductor_api
@@ -199,6 +200,38 @@ class SchedulerManagerTestCase(test.TestCase):
self.manager.run_instance(self.context, request_spec,
None, None, None, None, {})
+ def test_live_migration_compute_service_notavailable(self):
+ inst = {"uuid": "fake-instance-id",
+ "vm_state": vm_states.ACTIVE,
+ "task_state": task_states.MIGRATING, }
+
+ dest = 'fake_host'
+ block_migration = False
+ disk_over_commit = False
+
+ self._mox_schedule_method_helper('schedule_live_migration')
+ self.mox.StubOutWithMock(compute_utils, 'add_instance_fault_from_exc')
+ self.mox.StubOutWithMock(db, 'instance_update_and_get_original')
+
+ self.manager.driver.schedule_live_migration(self.context,
+ inst, dest, block_migration, disk_over_commit).AndRaise(
+ exception.ComputeServiceUnavailable(host="src"))
+ db.instance_update_and_get_original(self.context, inst["uuid"],
+ {"vm_state": inst['vm_state'],
+ "task_state": None,
+ "expected_task_state": task_states.MIGRATING,
+ }).AndReturn((inst, inst))
+ compute_utils.add_instance_fault_from_exc(self.context,
+ mox.IsA(conductor_api.LocalAPI), inst,
+ mox.IsA(exception.ComputeServiceUnavailable),
+ mox.IgnoreArg())
+
+ self.mox.ReplayAll()
+ self.assertRaises(exception.ComputeServiceUnavailable,
+ self.manager.live_migration,
+ self.context, inst, dest, block_migration,
+ disk_over_commit)
+
def test_prep_resize_no_valid_host_back_in_active_state(self):
fake_instance_uuid = 'fake-instance-id'
fake_instance = {'uuid': fake_instance_uuid}
@@ -510,6 +543,29 @@ class SchedulerTestCase(test.TestCase):
block_migration=block_migration,
disk_over_commit=disk_over_commit)
+ def test_live_migration_compute_dest_not_exist(self):
+ # Raise exception when dest compute node does not exist.
+
+ self.mox.StubOutWithMock(self.driver, '_live_migration_src_check')
+ self.mox.StubOutWithMock(db, 'service_get_by_compute_host')
+
+ dest = 'fake_host2'
+ block_migration = False
+ disk_over_commit = False
+ instance = self._live_migration_instance()
+
+ self.driver._live_migration_src_check(self.context, instance)
+ # Compute down
+ db.service_get_by_compute_host(self.context,
+ dest).AndRaise(exception.NotFound())
+
+ self.mox.ReplayAll()
+ self.assertRaises(exception.ComputeServiceUnavailable,
+ self.driver.schedule_live_migration, self.context,
+ instance=instance, dest=dest,
+ block_migration=block_migration,
+ disk_over_commit=disk_over_commit)
+
def test_live_migration_compute_dest_not_alive(self):
# Raise exception when dest compute node is not alive.
diff --git a/nova/tests/servicegroup/test_zk_driver.py b/nova/tests/servicegroup/test_zk_driver.py
new file mode 100644
index 000000000..753153bb5
--- /dev/null
+++ b/nova/tests/servicegroup/test_zk_driver.py
@@ -0,0 +1,65 @@
+# Copyright (c) AT&T 2012-2013 Yun Mao <yunmao@gmail.com>
+# Copyright (c) IBM 2012 Alexey Roytman <roytman at il dot ibm dot com>.
+#
+# 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.
+
+"""Test the ZooKeeper driver for servicegroup.
+
+You need to install ZooKeeper locally and related dependencies
+to run the test. It's unclear how to install python-zookeeper lib
+in venv so you might have to run the test without it.
+
+To set up in Ubuntu 12.04:
+$ sudo apt-get install zookeeper zookeeperd python-zookeeper
+$ sudo pip install evzookeeper
+$ nosetests nova.tests.servicegroup.test_zk_driver
+"""
+
+import eventlet
+
+from nova import servicegroup
+from nova import test
+
+
+class ZKServiceGroupTestCase(test.TestCase):
+
+ def setUp(self):
+ super(ZKServiceGroupTestCase, self).setUp()
+ servicegroup.API._driver = None
+ try:
+ from nova.servicegroup.drivers import zk
+ _unused = zk
+ except ImportError:
+ self.skipTest("Unable to test due to lack of ZooKeeper")
+ self.flags(servicegroup_driver='zk')
+ self.flags(address='localhost:2181', group="zk")
+
+ def test_join_leave(self):
+ self.servicegroup_api = servicegroup.API()
+ service_id = {'topic': 'unittest', 'host': 'serviceA'}
+ self.servicegroup_api.join(service_id['host'], service_id['topic'])
+ self.assertTrue(self.servicegroup_api.service_is_up(service_id))
+ self.servicegroup_api.leave(service_id['host'], service_id['topic'])
+ # make sure zookeeper is updated and watcher is triggered
+ eventlet.sleep(1)
+ self.assertFalse(self.servicegroup_api.service_is_up(service_id))
+
+ def test_stop(self):
+ self.servicegroup_api = servicegroup.API()
+ service_id = {'topic': 'unittest', 'host': 'serviceA'}
+ pulse = self.servicegroup_api.join(service_id['host'],
+ service_id['topic'], None)
+ self.assertTrue(self.servicegroup_api.service_is_up(service_id))
+ pulse.stop()
+ eventlet.sleep(1)
+ self.assertFalse(self.servicegroup_api.service_is_up(service_id))
diff --git a/nova/tests/test_api.py b/nova/tests/test_api.py
index 11c16d6dd..949f54512 100644
--- a/nova/tests/test_api.py
+++ b/nova/tests/test_api.py
@@ -22,12 +22,13 @@ import random
import StringIO
import boto
+import boto.connection
from boto.ec2 import regioninfo
from boto import exception as boto_exc
# newer versions of boto use their own wrapper on top of httplib.HTTPResponse
-try:
- import boto.connection as httplib
-except ImportError:
+if hasattr(boto.connection, 'HTTPResponse'):
+ httplib = boto.connection
+else:
import httplib
import fixtures
import webob
diff --git a/nova/tests/test_crypto.py b/nova/tests/test_crypto.py
index 25df336fb..cec3ca9c1 100644
--- a/nova/tests/test_crypto.py
+++ b/nova/tests/test_crypto.py
@@ -212,3 +212,31 @@ e6fCXWECgYEAqgpGvva5kJ1ISgNwnJbwiNw0sOT9BMOsdNZBElf0kJIIy6FMPvap
def test_ssh_encrypt_failure(self):
self.assertRaises(exception.EncryptionFailure,
crypto.ssh_encrypt_text, '', self.text)
+
+
+class ConversionTests(test.TestCase):
+ k1 = ("ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEA4CqmrxfU7x4sJrubpMNxeglul+d"
+ "ByrsicnvQcHDEjPzdvoz+BaoAG9bjCA5mCeTBIISsVTVXz/hxNeiuBV6LH/UR/c"
+ "27yl53ypN+821ImoexQZcKItdnjJ3gVZlDob1f9+1qDVy63NJ1c+TstkrCTRVeo"
+ "9VyE7RpdSS4UCiBe8Xwk3RkedioFxePrI0Ktc2uASw2G0G2Rl7RN7KZOJbCivfF"
+ "LQMAOu6e+7fYvuE1gxGHHj7dxaBY/ioGOm1W4JmQ1V7AKt19zTBlZKduN8FQMSF"
+ "r35CDlvoWs0+OP8nwlebKNCi/5sdL8qiSLrAcPB4LqdkAf/blNSVA2Yl83/c4lQ"
+ "== test@test")
+
+ k2 = ("-----BEGIN PUBLIC KEY-----\n"
+ "MIIBIDANBgkqhkiG9w0BAQEFAAOCAQ0AMIIBCAKCAQEA4CqmrxfU7x4sJrubpMNx\n"
+ "eglul+dByrsicnvQcHDEjPzdvoz+BaoAG9bjCA5mCeTBIISsVTVXz/hxNeiuBV6L\n"
+ "H/UR/c27yl53ypN+821ImoexQZcKItdnjJ3gVZlDob1f9+1qDVy63NJ1c+TstkrC\n"
+ "TRVeo9VyE7RpdSS4UCiBe8Xwk3RkedioFxePrI0Ktc2uASw2G0G2Rl7RN7KZOJbC\n"
+ "ivfFLQMAOu6e+7fYvuE1gxGHHj7dxaBY/ioGOm1W4JmQ1V7AKt19zTBlZKduN8FQ\n"
+ "MSFr35CDlvoWs0+OP8nwlebKNCi/5sdL8qiSLrAcPB4LqdkAf/blNSVA2Yl83/c4\n"
+ "lQIBIw==\n"
+ "-----END PUBLIC KEY-----\n")
+
+ def test_convert_keys(self):
+ result = crypto.convert_from_sshrsa_to_pkcs8(self.k1)
+ self.assertEqual(result, self.k2)
+
+ def test_convert_failure(self):
+ self.assertRaises(exception.EncryptionFailure,
+ crypto.convert_from_sshrsa_to_pkcs8, '')
diff --git a/nova/tests/test_db_api.py b/nova/tests/test_db_api.py
index c6bf2941e..22de9346f 100644
--- a/nova/tests/test_db_api.py
+++ b/nova/tests/test_db_api.py
@@ -685,9 +685,9 @@ class DbApiTestCase(test.TestCase):
db.action_start(ctxt2, action_values)
actions = db.actions_get(ctxt1, uuid1)
- action_id = actions[0]['id']
- action = db.action_get_by_id(ctxt1, uuid1, action_id)
- self.assertEqual('resize', action['action'])
+ request_id = actions[0]['request_id']
+ action = db.action_get_by_request_id(ctxt1, uuid1, request_id)
+ self.assertEqual('run_instance', action['action'])
self.assertEqual(ctxt1.request_id, action['request_id'])
def test_instance_action_event_start(self):
diff --git a/nova/tests/test_hypervapi.py b/nova/tests/test_hypervapi.py
index 0c2f90a4d..025d3a454 100644
--- a/nova/tests/test_hypervapi.py
+++ b/nova/tests/test_hypervapi.py
@@ -80,6 +80,7 @@ class HyperVAPITestCase(test.TestCase):
self._instance_ide_disks = []
self._instance_ide_dvds = []
self._instance_volume_disks = []
+ self._test_vm_name = None
self._setup_stubs()
@@ -116,6 +117,14 @@ class HyperVAPITestCase(test.TestCase):
self.stubs.Set(pathutils, 'PathUtils', fake.PathUtils)
self._mox.StubOutWithMock(fake.PathUtils, 'open')
+ self._mox.StubOutWithMock(fake.PathUtils, 'copyfile')
+ self._mox.StubOutWithMock(fake.PathUtils, 'rmtree')
+ self._mox.StubOutWithMock(fake.PathUtils, 'copy')
+ self._mox.StubOutWithMock(fake.PathUtils, 'remove')
+ self._mox.StubOutWithMock(fake.PathUtils, 'rename')
+ self._mox.StubOutWithMock(fake.PathUtils, 'makedirs')
+ self._mox.StubOutWithMock(fake.PathUtils,
+ 'get_instance_migr_revert_dir')
self._mox.StubOutWithMock(vmutils.VMUtils, 'vm_exists')
self._mox.StubOutWithMock(vmutils.VMUtils, 'create_vm')
@@ -137,11 +146,13 @@ class HyperVAPITestCase(test.TestCase):
self._mox.StubOutWithMock(vmutils.VMUtils,
'get_mounted_disk_by_drive_number')
self._mox.StubOutWithMock(vmutils.VMUtils, 'detach_vm_disk')
+ self._mox.StubOutWithMock(vmutils.VMUtils, 'get_vm_storage_paths')
self._mox.StubOutWithMock(vhdutils.VHDUtils, 'create_differencing_vhd')
self._mox.StubOutWithMock(vhdutils.VHDUtils, 'reconnect_parent_vhd')
self._mox.StubOutWithMock(vhdutils.VHDUtils, 'merge_vhd')
self._mox.StubOutWithMock(vhdutils.VHDUtils, 'get_vhd_parent_path')
+ self._mox.StubOutWithMock(vhdutils.VHDUtils, 'get_vhd_info')
self._mox.StubOutWithMock(hostutils.HostUtils, 'get_cpus_info')
self._mox.StubOutWithMock(hostutils.HostUtils,
@@ -149,6 +160,7 @@ class HyperVAPITestCase(test.TestCase):
self._mox.StubOutWithMock(hostutils.HostUtils, 'get_memory_info')
self._mox.StubOutWithMock(hostutils.HostUtils, 'get_volume_info')
self._mox.StubOutWithMock(hostutils.HostUtils, 'get_windows_version')
+ self._mox.StubOutWithMock(hostutils.HostUtils, 'get_local_ips')
self._mox.StubOutWithMock(networkutils.NetworkUtils,
'get_external_vswitch')
@@ -181,11 +193,6 @@ class HyperVAPITestCase(test.TestCase):
self._mox.StubOutWithMock(volumeutilsv2.VolumeUtilsV2,
'execute_log_out')
- self._mox.StubOutWithMock(shutil, 'copyfile')
- self._mox.StubOutWithMock(shutil, 'rmtree')
-
- self._mox.StubOutWithMock(os, 'remove')
-
self._mox.StubOutClassWithMocks(instance_metadata, 'InstanceMetadata')
self._mox.StubOutWithMock(instance_metadata.InstanceMetadata,
'metadata_for_config_drive')
@@ -332,7 +339,7 @@ class HyperVAPITestCase(test.TestCase):
mox.IsA(str),
mox.IsA(str),
attempts=1)
- os.remove(mox.IsA(str))
+ fake.PathUtils.remove(mox.IsA(str))
m = vmutils.VMUtils.attach_ide_drive(mox.IsA(str),
mox.IsA(str),
@@ -490,15 +497,22 @@ class HyperVAPITestCase(test.TestCase):
None)
self._mox.VerifyAll()
- def test_destroy(self):
- self._instance_data = self._get_instance_data()
-
+ def _setup_destroy_mocks(self):
m = vmutils.VMUtils.vm_exists(mox.Func(self._check_instance_name))
m.AndReturn(True)
- m = vmutils.VMUtils.destroy_vm(mox.Func(self._check_instance_name),
- True)
- m.AndReturn([])
+ func = mox.Func(self._check_instance_name)
+ vmutils.VMUtils.set_vm_state(func, constants.HYPERV_VM_STATE_DISABLED)
+
+ m = vmutils.VMUtils.get_vm_storage_paths(func)
+ m.AndReturn(([], []))
+
+ vmutils.VMUtils.destroy_vm(func)
+
+ def test_destroy(self):
+ self._instance_data = self._get_instance_data()
+
+ self._setup_destroy_mocks()
self._mox.ReplayAll()
self._conn.destroy(self._instance_data)
@@ -562,7 +576,9 @@ class HyperVAPITestCase(test.TestCase):
if cow:
m = basevolumeutils.BaseVolumeUtils.volume_in_mapping(mox.IsA(str),
None)
- m.AndReturn([])
+ m.AndReturn(False)
+
+ vhdutils.VHDUtils.get_vhd_info(mox.Func(self._check_img_path))
self._mox.ReplayAll()
self._conn.pre_live_migration(self._context, instance_data,
@@ -617,7 +633,7 @@ class HyperVAPITestCase(test.TestCase):
def copy_dest_disk_path(src, dest):
self._fake_dest_disk_path = dest
- m = shutil.copyfile(mox.IsA(str), mox.IsA(str))
+ m = fake.PathUtils.copyfile(mox.IsA(str), mox.IsA(str))
m.WithSideEffects(copy_dest_disk_path)
self._fake_dest_base_disk_path = None
@@ -625,7 +641,7 @@ class HyperVAPITestCase(test.TestCase):
def copy_dest_base_disk_path(src, dest):
self._fake_dest_base_disk_path = dest
- m = shutil.copyfile(fake_parent_vhd_path, mox.IsA(str))
+ m = fake.PathUtils.copyfile(fake_parent_vhd_path, mox.IsA(str))
m.WithSideEffects(copy_dest_base_disk_path)
def check_dest_disk_path(path):
@@ -647,7 +663,7 @@ class HyperVAPITestCase(test.TestCase):
func = mox.Func(check_snapshot_path)
vmutils.VMUtils.remove_vm_snapshot(func)
- shutil.rmtree(mox.IsA(str))
+ fake.PathUtils.rmtree(mox.IsA(str))
m = fake.PathUtils.open(func2, 'rb')
m.AndReturn(io.BytesIO(b'fake content'))
@@ -702,65 +718,70 @@ class HyperVAPITestCase(test.TestCase):
mounted_disk_path):
self._instance_volume_disks.append(mounted_disk_path)
- def _setup_spawn_instance_mocks(self, cow, setup_vif_mocks_func=None,
- with_exception=False,
- block_device_info=None):
- self._test_vm_name = None
-
- def set_vm_name(vm_name):
- self._test_vm_name = vm_name
-
- def check_vm_name(vm_name):
- return vm_name == self._test_vm_name
-
- m = vmutils.VMUtils.vm_exists(mox.IsA(str))
- m.WithSideEffects(set_vm_name).AndReturn(False)
-
- if not block_device_info:
- m = basevolumeutils.BaseVolumeUtils.volume_in_mapping(mox.IsA(str),
- None)
- m.AndReturn([])
- else:
- m = basevolumeutils.BaseVolumeUtils.volume_in_mapping(
- mox.IsA(str), block_device_info)
- m.AndReturn(True)
-
- if cow:
- def check_path(parent_path):
- return parent_path == self._fetched_image
-
- vhdutils.VHDUtils.create_differencing_vhd(mox.IsA(str),
- mox.Func(check_path))
+ def _check_img_path(self, image_path):
+ return image_path == self._fetched_image
- vmutils.VMUtils.create_vm(mox.Func(check_vm_name), mox.IsA(int),
+ def _setup_create_instance_mocks(self, setup_vif_mocks_func=None,
+ boot_from_volume=False):
+ vmutils.VMUtils.create_vm(mox.Func(self._check_vm_name), mox.IsA(int),
mox.IsA(int), mox.IsA(bool))
- if not block_device_info:
- m = vmutils.VMUtils.attach_ide_drive(mox.Func(check_vm_name),
+ if not boot_from_volume:
+ m = vmutils.VMUtils.attach_ide_drive(mox.Func(self._check_vm_name),
mox.IsA(str),
mox.IsA(int),
mox.IsA(int),
mox.IsA(str))
m.WithSideEffects(self._add_ide_disk).InAnyOrder()
- m = vmutils.VMUtils.create_scsi_controller(mox.Func(check_vm_name))
+ func = mox.Func(self._check_vm_name)
+ m = vmutils.VMUtils.create_scsi_controller(func)
m.InAnyOrder()
- vmutils.VMUtils.create_nic(mox.Func(check_vm_name), mox.IsA(str),
+ vmutils.VMUtils.create_nic(mox.Func(self._check_vm_name), mox.IsA(str),
mox.IsA(str)).InAnyOrder()
if setup_vif_mocks_func:
setup_vif_mocks_func()
+ def _set_vm_name(self, vm_name):
+ self._test_vm_name = vm_name
+
+ def _check_vm_name(self, vm_name):
+ return vm_name == self._test_vm_name
+
+ def _setup_spawn_instance_mocks(self, cow, setup_vif_mocks_func=None,
+ with_exception=False,
+ block_device_info=None,
+ boot_from_volume=False):
+ m = vmutils.VMUtils.vm_exists(mox.IsA(str))
+ m.WithSideEffects(self._set_vm_name).AndReturn(False)
+
+ m = basevolumeutils.BaseVolumeUtils.volume_in_mapping(
+ mox.IsA(str), block_device_info)
+ m.AndReturn(boot_from_volume)
+
+ if not boot_from_volume:
+ vhdutils.VHDUtils.get_vhd_info(mox.Func(self._check_img_path))
+
+ if cow:
+ vhdutils.VHDUtils.create_differencing_vhd(
+ mox.IsA(str), mox.Func(self._check_img_path))
+ else:
+ fake.PathUtils.copyfile(mox.IsA(str), mox.IsA(str))
+
+ self._setup_create_instance_mocks(setup_vif_mocks_func,
+ boot_from_volume)
+
# TODO(alexpilotti) Based on where the exception is thrown
# some of the above mock calls need to be skipped
if with_exception:
- m = vmutils.VMUtils.vm_exists(mox.Func(check_vm_name))
+ m = vmutils.VMUtils.vm_exists(mox.Func(self._check_vm_name))
m.AndReturn(True)
- vmutils.VMUtils.destroy_vm(mox.Func(check_vm_name), True)
+ vmutils.VMUtils.destroy_vm(mox.Func(self._check_vm_name))
else:
- vmutils.VMUtils.set_vm_state(mox.Func(check_vm_name),
+ vmutils.VMUtils.set_vm_state(mox.Func(self._check_vm_name),
constants.HYPERV_VM_STATE_ENABLED)
def _test_spawn_instance(self, cow=True,
@@ -772,14 +793,14 @@ class HyperVAPITestCase(test.TestCase):
with_exception)
self._mox.ReplayAll()
- self._spawn_instance(cow, )
+ self._spawn_instance(cow)
self._mox.VerifyAll()
self.assertEquals(len(self._instance_ide_disks), expected_ide_disks)
self.assertEquals(len(self._instance_ide_dvds), expected_ide_dvds)
- if not cow:
- self.assertEquals(self._fetched_image, self._instance_ide_disks[0])
+ vhd_path = pathutils.PathUtils().get_vhd_path(self._test_vm_name)
+ self.assertEquals(vhd_path, self._instance_ide_disks[0])
def test_attach_volume(self):
instance_data = self._get_instance_data()
@@ -897,10 +918,165 @@ class HyperVAPITestCase(test.TestCase):
m.WithSideEffects(self._add_volume_disk)
self._setup_spawn_instance_mocks(cow=False,
- block_device_info=block_device_info)
+ block_device_info=block_device_info,
+ boot_from_volume=True)
self._mox.ReplayAll()
self._spawn_instance(False, block_device_info)
self._mox.VerifyAll()
self.assertEquals(len(self._instance_volume_disks), 1)
+
+ def _setup_test_migrate_disk_and_power_off_mocks(self, same_host=False,
+ with_exception=False):
+ self._instance_data = self._get_instance_data()
+ instance = db.instance_create(self._context, self._instance_data)
+ network_info = fake_network.fake_get_instance_nw_info(
+ self.stubs, spectacular=True)
+
+ fake_local_ip = '10.0.0.1'
+ if same_host:
+ fake_dest_ip = fake_local_ip
+ else:
+ fake_dest_ip = '10.0.0.2'
+
+ fake_root_vhd_path = 'C:\\FakePath\\root.vhd'
+ fake_revert_path = ('C:\\FakeInstancesPath\\%s\\_revert' %
+ instance['name'])
+
+ func = mox.Func(self._check_instance_name)
+ vmutils.VMUtils.set_vm_state(func, constants.HYPERV_VM_STATE_DISABLED)
+
+ m = vmutils.VMUtils.get_vm_storage_paths(func)
+ m.AndReturn(([fake_root_vhd_path], []))
+
+ m = hostutils.HostUtils.get_local_ips()
+ m.AndReturn([fake_local_ip])
+
+ m = pathutils.PathUtils.get_instance_migr_revert_dir(instance['name'],
+ remove_dir=True)
+ m.AndReturn(fake_revert_path)
+
+ if same_host:
+ fake.PathUtils.makedirs(mox.IsA(str))
+
+ m = fake.PathUtils.copy(fake_root_vhd_path, mox.IsA(str))
+ if with_exception:
+ m.AndRaise(shutil.Error('Simulated copy error'))
+ else:
+ fake.PathUtils.rename(mox.IsA(str), mox.IsA(str))
+ if same_host:
+ fake.PathUtils.rename(mox.IsA(str), mox.IsA(str))
+
+ self._setup_destroy_mocks()
+
+ return (instance, fake_dest_ip, network_info)
+
+ def test_migrate_disk_and_power_off(self):
+ (instance,
+ fake_dest_ip,
+ network_info) = self._setup_test_migrate_disk_and_power_off_mocks()
+
+ self._mox.ReplayAll()
+ self._conn.migrate_disk_and_power_off(self._context, instance,
+ fake_dest_ip, None,
+ network_info)
+ self._mox.VerifyAll()
+
+ def test_migrate_disk_and_power_off_same_host(self):
+ args = self._setup_test_migrate_disk_and_power_off_mocks(
+ same_host=True)
+ (instance, fake_dest_ip, network_info) = args
+
+ self._mox.ReplayAll()
+ self._conn.migrate_disk_and_power_off(self._context, instance,
+ fake_dest_ip, None,
+ network_info)
+ self._mox.VerifyAll()
+
+ def test_migrate_disk_and_power_off_exception(self):
+ args = self._setup_test_migrate_disk_and_power_off_mocks(
+ with_exception=True)
+ (instance, fake_dest_ip, network_info) = args
+
+ self._mox.ReplayAll()
+ self.assertRaises(shutil.Error, self._conn.migrate_disk_and_power_off,
+ self._context, instance, fake_dest_ip, None,
+ network_info)
+ self._mox.VerifyAll()
+
+ def test_finish_migration(self):
+ self._instance_data = self._get_instance_data()
+ instance = db.instance_create(self._context, self._instance_data)
+ network_info = fake_network.fake_get_instance_nw_info(
+ self.stubs, spectacular=True)
+
+ m = basevolumeutils.BaseVolumeUtils.volume_in_mapping(mox.IsA(str),
+ None)
+ m.AndReturn(False)
+
+ self._mox.StubOutWithMock(fake.PathUtils, 'exists')
+ m = fake.PathUtils.exists(mox.IsA(str))
+ m.AndReturn(True)
+
+ fake_parent_vhd_path = (os.path.join('FakeParentPath', '%s.vhd' %
+ instance["image_ref"]))
+
+ m = vhdutils.VHDUtils.get_vhd_info(mox.IsA(str))
+ m.AndReturn({'ParentPath': fake_parent_vhd_path,
+ 'MaxInternalSize': 1})
+
+ m = fake.PathUtils.exists(mox.IsA(str))
+ m.AndReturn(True)
+
+ vhdutils.VHDUtils.reconnect_parent_vhd(mox.IsA(str), mox.IsA(str))
+
+ self._set_vm_name(instance['name'])
+ self._setup_create_instance_mocks(None, False)
+
+ vmutils.VMUtils.set_vm_state(mox.Func(self._check_instance_name),
+ constants.HYPERV_VM_STATE_ENABLED)
+
+ self._mox.ReplayAll()
+ self._conn.finish_migration(self._context, None, instance, "",
+ network_info, None, False, None)
+ self._mox.VerifyAll()
+
+ def test_confirm_migration(self):
+ self._instance_data = self._get_instance_data()
+ instance = db.instance_create(self._context, self._instance_data)
+ network_info = fake_network.fake_get_instance_nw_info(
+ self.stubs, spectacular=True)
+
+ pathutils.PathUtils.get_instance_migr_revert_dir(instance['name'],
+ remove_dir=True)
+ self._mox.ReplayAll()
+ self._conn.confirm_migration(None, instance, network_info)
+ self._mox.VerifyAll()
+
+ def test_finish_revert_migration(self):
+ self._instance_data = self._get_instance_data()
+ instance = db.instance_create(self._context, self._instance_data)
+ network_info = fake_network.fake_get_instance_nw_info(
+ self.stubs, spectacular=True)
+
+ fake_revert_path = ('C:\\FakeInstancesPath\\%s\\_revert' %
+ instance['name'])
+
+ m = basevolumeutils.BaseVolumeUtils.volume_in_mapping(mox.IsA(str),
+ None)
+ m.AndReturn(False)
+
+ m = pathutils.PathUtils.get_instance_migr_revert_dir(instance['name'])
+ m.AndReturn(fake_revert_path)
+ fake.PathUtils.rename(fake_revert_path, mox.IsA(str))
+
+ self._set_vm_name(instance['name'])
+ self._setup_create_instance_mocks(None, False)
+
+ vmutils.VMUtils.set_vm_state(mox.Func(self._check_instance_name),
+ constants.HYPERV_VM_STATE_ENABLED)
+
+ self._mox.ReplayAll()
+ self._conn.finish_revert_migration(instance, network_info, None)
+ self._mox.VerifyAll()
diff --git a/nova/tests/test_imagebackend.py b/nova/tests/test_imagebackend.py
index 76fd1d5b6..87e51819d 100644
--- a/nova/tests/test_imagebackend.py
+++ b/nova/tests/test_imagebackend.py
@@ -241,8 +241,8 @@ class LvmTestCase(_ImageTestCase, test.TestCase):
sparse=sparse)
self.disk.get_disk_size(self.TEMPLATE_PATH
).AndReturn(self.TEMPLATE_SIZE)
- cmd = ('dd', 'if=%s' % self.TEMPLATE_PATH,
- 'of=%s' % self.PATH, 'bs=4M')
+ cmd = ('qemu-img', 'convert', '-O', 'raw', self.TEMPLATE_PATH,
+ self.PATH)
self.utils.execute(*cmd, run_as_root=True)
self.mox.ReplayAll()
@@ -271,8 +271,8 @@ class LvmTestCase(_ImageTestCase, test.TestCase):
self.SIZE, sparse=sparse)
self.disk.get_disk_size(self.TEMPLATE_PATH
).AndReturn(self.TEMPLATE_SIZE)
- cmd = ('dd', 'if=%s' % self.TEMPLATE_PATH,
- 'of=%s' % self.PATH, 'bs=4M')
+ cmd = ('qemu-img', 'convert', '-O', 'raw', self.TEMPLATE_PATH,
+ self.PATH)
self.utils.execute(*cmd, run_as_root=True)
self.disk.resize2fs(self.PATH, run_as_root=True)
self.mox.ReplayAll()
diff --git a/nova/tests/test_instance_types.py b/nova/tests/test_instance_types.py
index 0829df2c6..6ae28a1c9 100644
--- a/nova/tests/test_instance_types.py
+++ b/nova/tests/test_instance_types.py
@@ -142,6 +142,17 @@ class InstanceTypeTestCase(test.TestCase):
self.assertRaises(exception.InvalidInput, instance_types.create,
name, 256, 1, 120, 100, flavorid)
+ def test_instance_type_create_with_long_flavor_name(self):
+ # Flavor name with 255 characters or less is valid.
+ name = 'a' * 255
+ inst_type = instance_types.create(name, 64, 1, 120, flavorid=11)
+ self.assertEqual(inst_type['name'], name)
+
+ # Flavor name which is more than 255 characters will cause error.
+ name = 'a' * 256
+ self.assertRaises(exception.InvalidInput, instance_types.create,
+ name, 64, 1, 120, flavorid=11)
+
def test_add_instance_type_access(self):
user_id = 'fake'
project_id = 'fake'
diff --git a/nova/tests/test_libvirt_blockinfo.py b/nova/tests/test_libvirt_blockinfo.py
index e8d548399..68f1fa394 100644
--- a/nova/tests/test_libvirt_blockinfo.py
+++ b/nova/tests/test_libvirt_blockinfo.py
@@ -421,7 +421,7 @@ class LibvirtBlockInfoTest(test.TestCase):
self.assertEqual(bus, 'usb')
image_meta = {'properties': {'disk_bus': 'xen'}}
- self.assertRaises(exception.NovaException,
+ self.assertRaises(exception.UnsupportedHardware,
blockinfo.get_disk_bus_for_device_type,
'kvm',
image_meta)
diff --git a/nova/tests/test_libvirt_vif.py b/nova/tests/test_libvirt_vif.py
index 916b961da..749fda33a 100644
--- a/nova/tests/test_libvirt_vif.py
+++ b/nova/tests/test_libvirt_vif.py
@@ -171,7 +171,7 @@ class LibvirtVifTestCase(test.TestCase):
self.stubs.Set(utils, 'execute', fake_execute)
- def _get_instance_xml(self, driver, net, mapping):
+ def _get_instance_xml(self, driver, net, mapping, image_meta=None):
conf = vconfig.LibvirtConfigGuest()
conf.virt_type = "qemu"
conf.name = "fake-name"
@@ -179,7 +179,7 @@ class LibvirtVifTestCase(test.TestCase):
conf.memory = 100 * 1024
conf.vcpus = 4
- nic = driver.get_config(self.instance, net, mapping)
+ nic = driver.get_config(self.instance, net, mapping, image_meta)
conf.add_device(nic)
return conf.to_xml()
@@ -269,6 +269,46 @@ class LibvirtVifTestCase(test.TestCase):
ret = node.findall("driver")
self.assertEqual(len(ret), 0)
+ def test_model_kvm_custom(self):
+ self.flags(libvirt_use_virtio_for_bridges=True,
+ libvirt_type='kvm')
+
+ def get_connection():
+ return fakelibvirt.Connection("qemu:///session",
+ False)
+ d = vif.LibvirtGenericVIFDriver(get_connection)
+ image_meta = {'properties': {'vif_model': 'e1000'}}
+ xml = self._get_instance_xml(d,
+ self.net_bridge,
+ self.mapping_bridge,
+ image_meta)
+
+ doc = etree.fromstring(xml)
+ ret = doc.findall('./devices/interface')
+ self.assertEqual(len(ret), 1)
+ node = ret[0]
+
+ model = node.find("model").get("type")
+ self.assertEqual(model, "e1000")
+ ret = node.findall("driver")
+ self.assertEqual(len(ret), 0)
+
+ def test_model_kvm_bogus(self):
+ self.flags(libvirt_use_virtio_for_bridges=True,
+ libvirt_type='kvm')
+
+ def get_connection():
+ return fakelibvirt.Connection("qemu:///session",
+ False)
+ d = vif.LibvirtGenericVIFDriver(get_connection)
+ image_meta = {'properties': {'vif_model': 'acme'}}
+ self.assertRaises(exception.UnsupportedHardware,
+ self._get_instance_xml,
+ d,
+ self.net_bridge,
+ self.mapping_bridge,
+ image_meta)
+
def test_model_qemu(self):
self.flags(libvirt_use_virtio_for_bridges=True,
libvirt_type='qemu')
diff --git a/nova/tests/test_libvirt_volume.py b/nova/tests/test_libvirt_volume.py
index b9f95735f..0098215b2 100644
--- a/nova/tests/test_libvirt_volume.py
+++ b/nova/tests/test_libvirt_volume.py
@@ -364,3 +364,59 @@ class LibvirtVolumeTestCase(test.TestCase):
('stat', export_mnt_base),
('mount', '-t', 'nfs', export_string, export_mnt_base)]
self.assertEqual(self.executes, expected_commands)
+
+ def aoe_connection(self, shelf, lun):
+ return {
+ 'driver_volume_type': 'aoe',
+ 'data': {
+ 'target_shelf': shelf,
+ 'target_lun': lun,
+ }
+ }
+
+ def test_libvirt_aoe_driver(self):
+ # NOTE(jbr_) exists is to make driver assume connecting worked
+ self.stubs.Set(os.path, 'exists', lambda x: True)
+ libvirt_driver = volume.LibvirtAOEVolumeDriver(self.fake_conn)
+ shelf = '100'
+ lun = '1'
+ connection_info = self.aoe_connection(shelf, lun)
+ disk_info = {
+ "bus": "virtio",
+ "dev": "vde",
+ "type": "disk",
+ }
+ conf = libvirt_driver.connect_volume(connection_info, disk_info)
+ tree = conf.format_dom()
+ aoedevpath = '/dev/etherd/e%s.%s' % (shelf, lun)
+ self.assertEqual(tree.get('type'), 'block')
+ self.assertEqual(tree.find('./source').get('dev'), aoedevpath)
+ libvirt_driver.disconnect_volume(connection_info, "vde")
+
+ def test_libvirt_glusterfs_driver(self):
+ mnt_base = '/mnt'
+ self.flags(glusterfs_mount_point_base=mnt_base)
+
+ libvirt_driver = volume.LibvirtGlusterfsVolumeDriver(self.fake_conn)
+ export_string = '192.168.1.1:/volume-00001'
+ name = 'volume-00001'
+ export_mnt_base = os.path.join(mnt_base,
+ libvirt_driver.get_hash_str(export_string))
+ file_path = os.path.join(export_mnt_base, name)
+
+ connection_info = {'data': {'export': export_string, 'name': name}}
+ disk_info = {
+ "bus": "virtio",
+ "dev": "vde",
+ "type": "disk",
+ }
+ conf = libvirt_driver.connect_volume(connection_info, disk_info)
+ tree = conf.format_dom()
+ self.assertEqual(tree.get('type'), 'file')
+ self.assertEqual(tree.find('./source').get('file'), file_path)
+ libvirt_driver.disconnect_volume(connection_info, "vde")
+
+ expected_commands = [
+ ('stat', export_mnt_base),
+ ('mount', '-t', 'glusterfs', export_string, export_mnt_base)]
+ self.assertEqual(self.executes, expected_commands)
diff --git a/nova/tests/test_metadata.py b/nova/tests/test_metadata.py
index 827bfb398..95399e33d 100644
--- a/nova/tests/test_metadata.py
+++ b/nova/tests/test_metadata.py
@@ -31,6 +31,7 @@ from nova.api.metadata import base
from nova.api.metadata import handler
from nova.api.metadata import password
from nova import block_device
+from nova.conductor import api as conductor_api
from nova import db
from nova.db.sqlalchemy import api
from nova import exception
@@ -118,6 +119,7 @@ class MetadataTestCase(test.TestCase):
def setUp(self):
super(MetadataTestCase, self).setUp()
self.instance = INSTANCES[0]
+ self.flags(use_local=True, group='conductor')
fake_network.stub_out_nw_api_get_instance_nw_info(self.stubs,
spectacular=True)
@@ -191,10 +193,11 @@ class MetadataTestCase(test.TestCase):
'swap': '/dev/sdc',
'ebs0': '/dev/sdh'}
- self.assertEqual(base._format_instance_mapping(ctxt, instance_ref0),
- block_device._DEFAULT_MAPPINGS)
- self.assertEqual(base._format_instance_mapping(ctxt, instance_ref1),
- expected)
+ capi = conductor_api.LocalAPI()
+ self.assertEqual(base._format_instance_mapping(capi, ctxt,
+ instance_ref0), block_device._DEFAULT_MAPPINGS)
+ self.assertEqual(base._format_instance_mapping(capi, ctxt,
+ instance_ref1), expected)
def test_pubkey(self):
md = fake_InstanceMetadata(self.stubs, copy.copy(self.instance))
@@ -247,6 +250,7 @@ class OpenStackMetadataTestCase(test.TestCase):
def setUp(self):
super(OpenStackMetadataTestCase, self).setUp()
self.instance = INSTANCES[0]
+ self.flags(use_local=True, group='conductor')
fake_network.stub_out_nw_api_get_instance_nw_info(self.stubs,
spectacular=True)
@@ -382,6 +386,7 @@ class MetadataHandlerTestCase(test.TestCase):
fake_network.stub_out_nw_api_get_instance_nw_info(self.stubs,
spectacular=True)
self.instance = INSTANCES[0]
+ self.flags(use_local=True, group='conductor')
self.mdinst = fake_InstanceMetadata(self.stubs, self.instance,
address=None, sgroups=None)
@@ -547,6 +552,7 @@ class MetadataPasswordTestCase(test.TestCase):
fake_network.stub_out_nw_api_get_instance_nw_info(self.stubs,
spectacular=True)
self.instance = copy.copy(INSTANCES[0])
+ self.flags(use_local=True, group='conductor')
self.mdinst = fake_InstanceMetadata(self.stubs, self.instance,
address=None, sgroups=None)
self.flags(use_local=True, group='conductor')
diff --git a/nova/tests/test_migration_utils.py b/nova/tests/test_migration_utils.py
new file mode 100644
index 000000000..45b6d86d4
--- /dev/null
+++ b/nova/tests/test_migration_utils.py
@@ -0,0 +1,126 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright (c) 2013 Boris Pavlovic (boris@pavlovic.me).
+# 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 migrate.changeset import UniqueConstraint
+from sqlalchemy import MetaData, Table, Column, Integer, BigInteger
+
+from nova.db.sqlalchemy import utils
+from nova import exception
+from nova.tests import test_migrations
+
+
+class TestMigrationUtils(test_migrations.BaseMigrationTestCase):
+ """Class for testing utils that are used in db migrations."""
+
+ def test_utils_drop_unique_constraint(self):
+ table_name = "__test_tmp_table__"
+ uc_name = 'uniq_foo'
+ values = [
+ {'id': 1, 'a': 3, 'foo': 10},
+ {'id': 2, 'a': 2, 'foo': 20},
+ {'id': 3, 'a': 1, 'foo': 30}
+ ]
+ for key, engine in self.engines.items():
+ meta = MetaData()
+ meta.bind = engine
+ test_table = Table(table_name, meta,
+ Column('id', Integer, primary_key=True,
+ nullable=False),
+ Column('a', Integer),
+ Column('foo', Integer),
+ UniqueConstraint('a', name='uniq_a'),
+ UniqueConstraint('foo', name=uc_name))
+ test_table.create()
+
+ engine.execute(test_table.insert(), values)
+ # NOTE(boris-42): This method is generic UC dropper.
+ utils.drop_unique_constraint(engine, table_name, uc_name, 'foo')
+
+ s = test_table.select().order_by(test_table.c.id)
+ rows = engine.execute(s).fetchall()
+
+ for i in xrange(0, len(values)):
+ v = values[i]
+ self.assertEqual((v['id'], v['a'], v['foo']), rows[i])
+
+ # NOTE(boris-42): Update data about Table from DB.
+ meta = MetaData()
+ meta.bind = engine
+ test_table = Table(table_name, meta, autoload=True)
+ constraints = filter(lambda c: c.name == uc_name,
+ test_table.constraints)
+ self.assertEqual(len(constraints), 0)
+ self.assertEqual(len(test_table.constraints), 1)
+
+ test_table.drop()
+
+ def test_util_drop_unique_constraint_with_not_supported_sqlite_type(self):
+ table_name = "__test_tmp_table__"
+ uc_name = 'uniq_foo'
+ values = [
+ {'id': 1, 'a': 3, 'foo': 10},
+ {'id': 2, 'a': 2, 'foo': 20},
+ {'id': 3, 'a': 1, 'foo': 30}
+ ]
+
+ for key, engine in self.engines.items():
+ meta = MetaData()
+ meta.bind = engine
+ test_table = Table(table_name, meta,
+ Column('id', Integer, primary_key=True,
+ nullable=False),
+ Column('a', Integer),
+ Column('foo', BigInteger, default=0),
+ UniqueConstraint('a', name='uniq_a'),
+ UniqueConstraint('foo', name=uc_name))
+ test_table.create()
+
+ engine.execute(test_table.insert(), values)
+ if key == "sqlite":
+ # NOTE(boris-42): Missing info about column `foo` that has
+ # unsupported type BigInteger.
+ self.assertRaises(exception.NovaException,
+ utils.drop_unique_constraint,
+ engine, table_name, uc_name, 'foo')
+
+ # NOTE(boris-42): Wrong type of foo instance. it should be
+ # instance of sqlalchemy.Column.
+ self.assertRaises(exception.NovaException,
+ utils.drop_unique_constraint,
+ engine, table_name, uc_name, 'foo',
+ foo=Integer())
+
+ foo = Column('foo', BigInteger, default=0)
+ utils.drop_unique_constraint(engine, table_name, uc_name, 'foo',
+ foo=foo)
+
+ s = test_table.select().order_by(test_table.c.id)
+ rows = engine.execute(s).fetchall()
+
+ for i in xrange(0, len(values)):
+ v = values[i]
+ self.assertEqual((v['id'], v['a'], v['foo']), rows[i])
+
+ # NOTE(boris-42): Update data about Table from DB.
+ meta = MetaData()
+ meta.bind = engine
+ test_table = Table(table_name, meta, autoload=True)
+ constraints = filter(lambda c: c.name == uc_name,
+ test_table.constraints)
+ self.assertEqual(len(constraints), 0)
+ self.assertEqual(len(test_table.constraints), 1)
+ test_table.drop()
diff --git a/nova/tests/test_migrations.py b/nova/tests/test_migrations.py
index 02d7462d2..a0c5db9c4 100644
--- a/nova/tests/test_migrations.py
+++ b/nova/tests/test_migrations.py
@@ -43,6 +43,7 @@ postgres=# create database openstack_citest with owner openstack_citest;
import collections
import commands
import ConfigParser
+import datetime
import os
import urlparse
@@ -53,6 +54,7 @@ import nova.db.migration as migration
import nova.db.sqlalchemy.migrate_repo
from nova.db.sqlalchemy.migration import versioning_api as migration_api
from nova.openstack.common import log as logging
+from nova.openstack.common import timeutils
from nova import test
@@ -116,8 +118,8 @@ def get_table(engine, name):
return sqlalchemy.Table(name, metadata, autoload=True)
-class TestMigrations(test.TestCase):
- """Test sqlalchemy-migrate migrations."""
+class BaseMigrationTestCase(test.TestCase):
+ """Base class fort testing migrations and migration utils."""
DEFAULT_CONFIG_FILE = os.path.join(os.path.dirname(__file__),
'test_migrations.conf')
@@ -130,18 +132,18 @@ class TestMigrations(test.TestCase):
os.path.abspath(os.path.dirname(MIGRATE_FILE)))
def setUp(self):
- super(TestMigrations, self).setUp()
+ super(BaseMigrationTestCase, self).setUp()
self.snake_walk = False
self.test_databases = {}
# Load test databases from the config file. Only do this
# once. No need to re-run this on each test...
- LOG.debug('config_path is %s' % TestMigrations.CONFIG_FILE_PATH)
- if os.path.exists(TestMigrations.CONFIG_FILE_PATH):
+ LOG.debug('config_path is %s' % BaseMigrationTestCase.CONFIG_FILE_PATH)
+ if os.path.exists(BaseMigrationTestCase.CONFIG_FILE_PATH):
cp = ConfigParser.RawConfigParser()
try:
- cp.read(TestMigrations.CONFIG_FILE_PATH)
+ cp.read(BaseMigrationTestCase.CONFIG_FILE_PATH)
defaults = cp.defaults()
for key, value in defaults.items():
self.test_databases[key] = value
@@ -165,7 +167,7 @@ class TestMigrations(test.TestCase):
# and recreate it, which ensures that we have no side-effects
# from the tests
self._reset_databases()
- super(TestMigrations, self).tearDown()
+ super(BaseMigrationTestCase, self).tearDown()
def _reset_databases(self):
def execute_cmd(cmd=None):
@@ -232,6 +234,10 @@ class TestMigrations(test.TestCase):
os.unsetenv('PGPASSWORD')
os.unsetenv('PGUSER')
+
+class TestMigrations(BaseMigrationTestCase):
+ """Test sqlalchemy-migrate migrations."""
+
def test_walk_versions(self):
"""
Walks all version scripts for each tested database, ensuring
@@ -381,18 +387,70 @@ class TestMigrations(test.TestCase):
(version, engine))
raise
+ def _prerun_134(self, engine):
+ now = timeutils.utcnow()
+ data = [{
+ 'id': 1,
+ 'uuid': '1d739808-d7ec-4944-b252-f8363e119755',
+ 'mac': '00:00:00:00:00:01',
+ 'start_period': now,
+ 'last_refreshed': now + datetime.timedelta(seconds=10),
+ 'bw_in': 100000,
+ 'bw_out': 200000,
+ }, {
+ 'id': 2,
+ 'uuid': '1d739808-d7ec-4944-b252-f8363e119756',
+ 'mac': '2a:f2:48:31:c1:60',
+ 'start_period': now,
+ 'last_refreshed': now + datetime.timedelta(seconds=20),
+ 'bw_in': 1000000000,
+ 'bw_out': 200000000,
+ }, {
+ 'id': 3,
+ # This is intended to be the same as above.
+ 'uuid': '1d739808-d7ec-4944-b252-f8363e119756',
+ 'mac': '00:00:00:00:00:02',
+ 'start_period': now,
+ 'last_refreshed': now + datetime.timedelta(seconds=30),
+ 'bw_in': 0,
+ 'bw_out': 0,
+ }]
+
+ bw_usage_cache = get_table(engine, 'bw_usage_cache')
+ engine.execute(bw_usage_cache.insert(), data)
+ return data
+
+ def _check_134(self, engine, data):
+ bw_usage_cache = get_table(engine, 'bw_usage_cache')
+
+ # Checks if both columns have been successfuly created.
+ self.assertIn('last_ctr_in', bw_usage_cache.c)
+ self.assertIn('last_ctr_out', bw_usage_cache.c)
+
+ # Checks if all rows have been inserted.
+ bw_items = bw_usage_cache.select().execute().fetchall()
+ self.assertEqual(len(bw_items), 3)
+
+ bw = bw_usage_cache.select(
+ bw_usage_cache.c.id == 1).execute().first()
+
+ # New columns have 'NULL' as default value.
+ self.assertEqual(bw['last_ctr_in'], None)
+ self.assertEqual(bw['last_ctr_out'], None)
+
+ self.assertEqual(data[0]['mac'], bw['mac'])
+
# migration 146, availability zone transition
def _prerun_146(self, engine):
data = {
'availability_zone': 'custom_az',
- 'aggregate_name': 1,
'name': 'name',
}
aggregates = get_table(engine, 'aggregates')
result = aggregates.insert().values(data).execute()
# NOTE(sdague) it's important you don't insert keys by value in
- # postgresql, because it's autoincrement counter won't get updated
+ # postgresql, because its autoincrement counter won't get updated
data['id'] = result.inserted_primary_key[0]
return data
diff --git a/nova/tests/test_utils.py b/nova/tests/test_utils.py
index aaa826a70..0aa2a310c 100644
--- a/nova/tests/test_utils.py
+++ b/nova/tests/test_utils.py
@@ -25,6 +25,7 @@ import StringIO
import tempfile
import mox
+import netaddr
import nova
from nova import exception
@@ -481,6 +482,29 @@ class GenericUtilsTestCase(test.TestCase):
self.assertFalse(utils.is_valid_ipv4('::1'))
self.assertFalse(utils.is_valid_ipv4('bacon'))
+ def test_is_valid_ipv6(self):
+ self.assertTrue(utils.is_valid_ipv6("::1"))
+ self.assertTrue(utils.is_valid_ipv6(
+ "abcd:ef01:2345:6789:abcd:ef01:192.168.254.254"))
+ self.assertTrue(utils.is_valid_ipv6(
+ "0000:0000:0000:0000:0000:0000:0000:0001"))
+ self.assertFalse(utils.is_valid_ipv6("foo"))
+ self.assertFalse(utils.is_valid_ipv6("127.0.0.1"))
+
+ def test_get_shortened_ipv6(self):
+ self.assertEquals("abcd:ef01:2345:6789:abcd:ef01:c0a8:fefe",
+ utils.get_shortened_ipv6(
+ "abcd:ef01:2345:6789:abcd:ef01:192.168.254.254"))
+ self.assertEquals("::1", utils.get_shortened_ipv6(
+ "0000:0000:0000:0000:0000:0000:0000:0001"))
+ self.assertEquals("caca::caca:0:babe:201:102",
+ utils.get_shortened_ipv6(
+ "caca:0000:0000:caca:0000:babe:0201:0102"))
+ self.assertRaises(netaddr.AddrFormatError, utils.get_shortened_ipv6,
+ "127.0.0.1")
+ self.assertRaises(netaddr.AddrFormatError, utils.get_shortened_ipv6,
+ "failure")
+
class MonkeyPatchTestCase(test.TestCase):
"""Unit test for utils.monkey_patch()."""
@@ -964,3 +988,18 @@ class GetCallArgsTestCase(test.TestCase):
self.assertEqual(3, callargs['red'])
self.assertTrue('blue' in callargs)
self.assertEqual(None, callargs['blue'])
+
+
+class StringLengthTestCase(test.TestCase):
+ def test_check_string_length(self):
+ self.assertIsNone(utils.check_string_length(
+ 'test', 'name', max_length=255))
+ self.assertRaises(exception.InvalidInput,
+ utils.check_string_length,
+ 11, 'name', max_length=255)
+ self.assertRaises(exception.InvalidInput,
+ utils.check_string_length,
+ '', 'name', min_length=1)
+ self.assertRaises(exception.InvalidInput,
+ utils.check_string_length,
+ 'a' * 256, 'name', max_length=255)
diff --git a/nova/tests/test_versions.py b/nova/tests/test_versions.py
index 5568ff0de..780e5ae12 100644
--- a/nova/tests/test_versions.py
+++ b/nova/tests/test_versions.py
@@ -24,38 +24,14 @@ from nova import version
class VersionTestCase(test.TestCase):
"""Test cases for Versions code."""
- def setUp(self):
- """setup test with unchanging values."""
- super(VersionTestCase, self).setUp()
- self.version = version
- self.version.FINAL = False
- self.version.NOVA_VERSION = ['2012', '10']
- self.version.YEAR, self.version.COUNT = self.version.NOVA_VERSION
- self.version.version_info = {'branch_nick': u'LOCALBRANCH',
- 'revision_id': 'LOCALREVISION',
- 'revno': 0}
- self.version.NOVA_PACKAGE = "g9ec3421"
-
- def test_version_string_is_good(self):
- # Ensure version string works.
- self.assertEqual("2012.10-dev", self.version.version_string())
-
- def test_canonical_version_string_is_good(self):
- # Ensure canonical version works.
- self.assertEqual("2012.10", self.version.canonical_version_string())
-
- def test_final_version_strings_are_identical(self):
- # Ensure final version strings match only at release.
- self.assertNotEqual(self.version.canonical_version_string(),
- self.version.version_string())
- self.version.FINAL = True
- self.assertEqual(self.version.canonical_version_string(),
- self.version.version_string())
def test_version_string_with_package_is_good(self):
- # Ensure uninstalled code get version string.
- self.assertEqual("2012.10-g9ec3421",
- self.version.version_string_with_package())
+ """Ensure uninstalled code get version string."""
+
+ self.stubs.Set(version.version_info, 'version', '5.5.5.5')
+ self.stubs.Set(version, 'NOVA_PACKAGE', 'g9ec3421')
+ self.assertEqual("5.5.5.5-g9ec3421",
+ version.version_string_with_package())
def test_release_file(self):
version.loaded = False
diff --git a/nova/tests/test_vmwareapi.py b/nova/tests/test_vmwareapi.py
index 22544fd2d..e20a5a7b7 100644
--- a/nova/tests/test_vmwareapi.py
+++ b/nova/tests/test_vmwareapi.py
@@ -28,6 +28,7 @@ from nova import exception
from nova import test
import nova.tests.image.fake
from nova.tests import matchers
+from nova.tests import utils
from nova.tests.vmwareapi import db_fakes
from nova.tests.vmwareapi import stubs
from nova.virt.vmwareapi import driver
@@ -54,24 +55,7 @@ class VMwareAPIVMTestCase(test.TestCase):
self.conn = driver.VMwareESXDriver(None, False)
# NOTE(vish): none of the network plugging code is actually
# being tested
- self.network_info = [({'bridge': 'fa0',
- 'id': 0,
- 'vlan': None,
- 'bridge_interface': None,
- 'injected': True},
- {'broadcast': '192.168.0.255',
- 'dns': ['192.168.0.1'],
- 'gateway': '192.168.0.1',
- 'gateway_v6': 'dead:beef::1',
- 'ip6s': [{'enabled': '1',
- 'ip': 'dead:beef::dcad:beff:feef:0',
- 'netmask': '64'}],
- 'ips': [{'enabled': '1',
- 'ip': '192.168.0.100',
- 'netmask': '255.255.255.0'}],
- 'label': 'fake',
- 'mac': 'DE:AD:BE:EF:00:00',
- 'rxtx_cap': 3})]
+ self.network_info = utils.get_test_network_info(legacy_model=False)
self.image = {
'id': 'c1c8ce3d-c2e0-4247-890c-ccf5cc1c004c',
diff --git a/nova/tests/test_vmwareapi_vmops.py b/nova/tests/test_vmwareapi_vmops.py
new file mode 100644
index 000000000..ad83cd21d
--- /dev/null
+++ b/nova/tests/test_vmwareapi_vmops.py
@@ -0,0 +1,62 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+#
+# Copyright 2013 OpenStack LLC.
+# All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+from nova.network import model as network_model
+from nova import test
+from nova.virt.vmwareapi import vmops
+
+
+class VMwareVMOpsTestCase(test.TestCase):
+ def setUp(self):
+ super(VMwareVMOpsTestCase, self).setUp()
+ subnet_4 = network_model.Subnet(cidr='192.168.0.1/24',
+ dns=[network_model.IP('192.168.0.1')],
+ gateway=
+ network_model.IP('192.168.0.1'),
+ ips=[
+ network_model.IP('192.168.0.100')],
+ routes=None)
+ subnet_6 = network_model.Subnet(cidr='dead:beef::1/64',
+ dns=None,
+ gateway=
+ network_model.IP('dead:beef::1'),
+ ips=[network_model.IP(
+ 'dead:beef::dcad:beff:feef:0')],
+ routes=None)
+ network = network_model.Network(id=0,
+ bridge='fa0',
+ label='fake',
+ subnets=[subnet_4, subnet_6],
+ vlan=None,
+ bridge_interface=None,
+ injected=True)
+ self.network_info = network_model.NetworkInfo([
+ network_model.VIF(id=None,
+ address='DE:AD:BE:EF:00:00',
+ network=network,
+ type=None,
+ devname=None,
+ ovs_interfaceid=None,
+ rxtx_cap=3)
+ ])
+
+ def test_get_machine_id_str(self):
+ result = vmops.VMwareVMOps._get_machine_id_str(self.network_info)
+ print result
+ self.assertEqual(result,
+ 'DE:AD:BE:EF:00:00;192.168.0.100;255.255.255.0;'
+ '192.168.0.1;192.168.0.255;192.168.0.1#')
diff --git a/nova/tests/test_xenapi.py b/nova/tests/test_xenapi.py
index cc71ba31e..2a484d832 100644
--- a/nova/tests/test_xenapi.py
+++ b/nova/tests/test_xenapi.py
@@ -2677,9 +2677,10 @@ class XenAPILiveMigrateTestCase(stubs.XenAPITestBase):
'destination_sr_ref': None,
'migrate_send_data': None
}}
- self.conn.check_can_live_migrate_source(self.context,
- {'host': 'host'},
- dest_check_data)
+ result = self.conn.check_can_live_migrate_source(self.context,
+ {'host': 'host'},
+ dest_check_data)
+ self.assertEqual(dest_check_data, result)
def test_check_can_live_migrate_source_with_block_migrate_fails(self):
stubs.stubout_session(self.stubs,
diff --git a/nova/tests/utils.py b/nova/tests/utils.py
index a5d4b4712..56be3ab71 100644
--- a/nova/tests/utils.py
+++ b/nova/tests/utils.py
@@ -89,7 +89,7 @@ def get_test_instance(context=None, instance_type=None):
return instance_ref
-def get_test_network_info(count=1):
+def get_test_network_info(count=1, legacy_model=True):
ipv6 = CONF.use_ipv6
fake = 'fake'
fake_ip = '0.0.0.0/0'
@@ -98,26 +98,69 @@ def get_test_network_info(count=1):
fake_netmask = '255.255.255.255'
fake_vlan = 100
fake_bridge_interface = 'eth0'
- network = {'bridge': fake,
- 'cidr': fake_ip,
- 'cidr_v6': fake_ip,
- 'vlan': fake_vlan,
- 'bridge_interface': fake_bridge_interface,
- 'injected': False}
- mapping = {'mac': fake,
- 'vif_type': network_model.VIF_TYPE_BRIDGE,
- 'vif_uuid': 'vif-xxx-yyy-zzz',
- 'dhcp_server': fake,
- 'dns': ['fake1', 'fake2'],
- 'gateway': fake,
- 'gateway_v6': fake,
- 'ips': [{'ip': fake_ip, 'netmask': fake_netmask},
- {'ip': fake_ip, 'netmask': fake_netmask}]}
- if ipv6:
- mapping['ip6s'] = [{'ip': fake_ip, 'netmask': fake_netmask},
- {'ip': fake_ip_2},
- {'ip': fake_ip_3}]
- return [(network, mapping) for x in xrange(0, count)]
+
+ def legacy():
+ network = {'bridge': fake,
+ 'cidr': fake_ip,
+ 'cidr_v6': fake_ip,
+ 'vlan': fake_vlan,
+ 'bridge_interface': fake_bridge_interface,
+ 'injected': False}
+ mapping = {'mac': fake,
+ 'vif_type': network_model.VIF_TYPE_BRIDGE,
+ 'vif_uuid': 'vif-xxx-yyy-zzz',
+ 'dhcp_server': fake,
+ 'dns': ['fake1', 'fake2'],
+ 'gateway': fake,
+ 'gateway_v6': fake,
+ 'ips': [{'ip': fake_ip, 'netmask': fake_netmask},
+ {'ip': fake_ip, 'netmask': fake_netmask}]}
+ if ipv6:
+ mapping['ip6s'] = [{'ip': fake_ip, 'netmask': fake_netmask},
+ {'ip': fake_ip_2},
+ {'ip': fake_ip_3}]
+ return network, mapping
+
+ def current():
+ fake_ip = '0.0.0.0'
+ subnet_4 = network_model.Subnet(cidr=fake_ip,
+ dns=[network_model.IP(fake_ip),
+ network_model.IP(fake_ip)],
+ gateway=network_model.IP(fake_ip),
+ ips=[network_model.IP(fake_ip),
+ network_model.IP(fake_ip)],
+ routes=None,
+ dhcp_server=network_model.IP(fake_ip))
+ subnet_6 = network_model.Subnet(cidr=fake_ip,
+ gateway=network_model.IP(fake_ip),
+ ips=[network_model.IP(fake_ip),
+ network_model.IP(fake_ip),
+ network_model.IP(fake_ip)],
+ routes=None,
+ version=6)
+ subnets = [subnet_4]
+ if ipv6:
+ subnets.append(subnet_6)
+ network = network_model.Network(id=None,
+ bridge=fake,
+ label=None,
+ subnets=subnets,
+ vlan=fake_vlan,
+ bridge_interface=fake_bridge_interface,
+ injected=False)
+ vif = network_model.VIF(id='vif-xxx-yyy-zzz',
+ address=fake,
+ network=network,
+ type=network_model.VIF_TYPE_BRIDGE,
+ devname=None,
+ ovs_interfaceid=None)
+
+ return vif
+
+ if legacy_model:
+ return [legacy() for x in xrange(0, count)]
+ else:
+ return network_model.NetworkInfo([current() for x in xrange(0, count)])
def is_osx():
diff --git a/nova/tests/virt/xenapi/test_volumeops.py b/nova/tests/virt/xenapi/test_volumeops.py
index 844ae8459..3497babf2 100644
--- a/nova/tests/virt/xenapi/test_volumeops.py
+++ b/nova/tests/virt/xenapi/test_volumeops.py
@@ -14,6 +14,8 @@
# License for the specific language governing permissions and limitations
# under the License.
+import collections
+
from nova import test
from nova.tests.xenapi import stubs
from nova.virt.xenapi import volumeops
@@ -125,31 +127,33 @@ class VolumeAttachTestCase(test.TestCase):
vm_ref = 'vm_ref'
dev_number = 1
- called = {'xenapi': False}
+ called = collections.defaultdict(bool)
- def fake_call_xenapi(self, *args, **kwargs):
- # Only used for VBD.plug in this code path.
- called['xenapi'] = True
- raise Exception()
+ def fake_call_xenapi(self, method, *args, **kwargs):
+ called[method] = True
self.stubs.Set(ops._session, 'call_xenapi', fake_call_xenapi)
self.mox.StubOutWithMock(volumeops.volume_utils, 'parse_sr_info')
- self.mox.StubOutWithMock(
- volumeops.volume_utils, 'introduce_sr_unless_present')
- self.mox.StubOutWithMock(volumeops.volume_utils, 'introduce_vdi')
- self.mox.StubOutWithMock(volumeops.vm_utils, 'create_vbd')
-
volumeops.volume_utils.parse_sr_info(
connection_data, sr_label).AndReturn(
tuple([sr_uuid, sr_label, sr_params]))
- volumeops.volume_utils.introduce_sr_unless_present(
+ self.mox.StubOutWithMock(
+ volumeops.volume_utils, 'find_sr_by_uuid')
+ volumeops.volume_utils.find_sr_by_uuid(session, sr_uuid).AndReturn(
+ None)
+
+ self.mox.StubOutWithMock(
+ volumeops.volume_utils, 'introduce_sr')
+ volumeops.volume_utils.introduce_sr(
session, sr_uuid, sr_label, sr_params).AndReturn(sr_ref)
+ self.mox.StubOutWithMock(volumeops.volume_utils, 'introduce_vdi')
volumeops.volume_utils.introduce_vdi(
- session, sr_ref, vdi_uuid, None).AndReturn(vdi_ref)
+ session, sr_ref, vdi_uuid=vdi_uuid).AndReturn(vdi_ref)
+ self.mox.StubOutWithMock(volumeops.vm_utils, 'create_vbd')
volumeops.vm_utils.create_vbd(
session, vm_ref, vdi_ref, dev_number,
bootable=False, osvol=True).AndReturn(vbd_ref)
@@ -157,6 +161,6 @@ class VolumeAttachTestCase(test.TestCase):
self.mox.ReplayAll()
ops._connect_volume(connection_data, dev_number, instance_name,
- vm_ref, hotplug=False)
+ vm_ref, hotplug=False)
- self.assertEquals(False, called['xenapi'])
+ self.assertEquals(False, called['VBD.plug'])