From 8a5611f9b2fa632ccfcd04523ee42f69b223ea6e Mon Sep 17 00:00:00 2001 From: Soren Hansen Date: Fri, 2 Sep 2011 13:44:10 +0200 Subject: Fix protocol-less security groups. --- nova/tests/test_libvirt.py | 11 +++++++++++ nova/virt/libvirt/firewall.py | 4 +++- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/nova/tests/test_libvirt.py b/nova/tests/test_libvirt.py index 8c6775b29..f0aa2a918 100644 --- a/nova/tests/test_libvirt.py +++ b/nova/tests/test_libvirt.py @@ -1033,6 +1033,13 @@ class IptablesFirewallTestCase(test.TestCase): 'to_port': 81, 'group_id': src_secgroup['id']}) + db.security_group_rule_create(admin_ctxt, + {'parent_group_id': secgroup['id'], + 'group_id': src_secgroup['id']}) + + db.instance_add_security_group(admin_ctxt, instance_ref['id'], + secgroup['id']) + db.instance_add_security_group(admin_ctxt, instance_ref['id'], secgroup['id']) db.instance_add_security_group(admin_ctxt, src_instance_ref['id'], @@ -1106,6 +1113,10 @@ class IptablesFirewallTestCase(test.TestCase): self.assertTrue(len(filter(regex.match, self.out_rules)) > 0, "TCP port 80/81 acceptance rule wasn't added") + regex = re.compile('-A .* -j ACCEPT -s %s' % (src_ip,)) + self.assertTrue(len(filter(regex.match, self.out_rules)) > 0, + "TCP port 80/81 acceptance rule wasn't added") + regex = re.compile('-A .* -j ACCEPT -p tcp ' '-m multiport --dports 80:81 -s 192.168.10.0/24') self.assertTrue(len(filter(regex.match, self.out_rules)) > 0, diff --git a/nova/virt/libvirt/firewall.py b/nova/virt/libvirt/firewall.py index c2f4f91e8..dfa1deba7 100644 --- a/nova/virt/libvirt/firewall.py +++ b/nova/virt/libvirt/firewall.py @@ -663,7 +663,9 @@ class IptablesFirewallDriver(FirewallDriver): if version == 6 and rule.protocol == 'icmp': protocol = 'icmpv6' - args = ['-j ACCEPT', '-p', protocol] + args = ['-j ACCEPT'] + if protocol: + args += ['-p', protocol] if protocol in ['udp', 'tcp']: if rule.from_port == rule.to_port: -- cgit From 1b93fdbf13c67bd5b0a5efc1306b95f30c64cc34 Mon Sep 17 00:00:00 2001 From: Thuleau Édouard Date: Fri, 2 Sep 2011 17:28:11 +0200 Subject: Add flag 'snapshot_image_format' to select the disk format of the snapshot image generated with the libvirt driver. --- nova/virt/libvirt/connection.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/nova/virt/libvirt/connection.py b/nova/virt/libvirt/connection.py index 363a20ed0..8e32ac2c4 100644 --- a/nova/virt/libvirt/connection.py +++ b/nova/virt/libvirt/connection.py @@ -126,6 +126,10 @@ flags.DEFINE_integer('live_migration_bandwidth', 0, 'Define live migration behavior') flags.DEFINE_string('qemu_img', 'qemu-img', 'binary to use for qemu-img commands') +flags.DEFINE_string('snapshot_image_format', 'raw', + 'Snapshot image format (valide option are : ' + 'all format supported by qemu-img binary') + FLAGS.snapshot_disk_format, flags.DEFINE_string('libvirt_vif_type', 'bridge', 'Type of VIF to create.') flags.DEFINE_string('libvirt_vif_driver', @@ -448,7 +452,7 @@ class LibvirtConnection(driver.ComputeDriver): '-f', 'qcow2', '-O', - 'raw', + FLAGS.snapshot_image_format, '-s', snapshot_name, disk_path, -- cgit From cae343eecdeba6b3f18dbdc330206edabd9ed287 Mon Sep 17 00:00:00 2001 From: Thuleau Édouard Date: Fri, 2 Sep 2011 17:39:37 +0200 Subject: Update snapshot image metada 'disk_format'. --- nova/virt/libvirt/connection.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/nova/virt/libvirt/connection.py b/nova/virt/libvirt/connection.py index 8e32ac2c4..5f53b9d5d 100644 --- a/nova/virt/libvirt/connection.py +++ b/nova/virt/libvirt/connection.py @@ -128,7 +128,8 @@ flags.DEFINE_string('qemu_img', 'qemu-img', 'binary to use for qemu-img commands') flags.DEFINE_string('snapshot_image_format', 'raw', 'Snapshot image format (valide option are : ' - 'all format supported by qemu-img binary') + 'raw, qcow2, vmdk, vdi.' + 'If the binary qemu_img supports it)') FLAGS.snapshot_disk_format, flags.DEFINE_string('libvirt_vif_type', 'bridge', 'Type of VIF to create.') @@ -424,7 +425,7 @@ class LibvirtConnection(driver.ComputeDriver): metadata['properties']['architecture'] = arch if 'disk_format' in base: - metadata['disk_format'] = base['disk_format'] + metadata['disk_format'] = FLAGS.snapshot_image_format if 'container_format' in base: metadata['container_format'] = base['container_format'] -- cgit From ccb5334c600de07f1c9aa2657dd29134fda29bc4 Mon Sep 17 00:00:00 2001 From: Thuleau Édouard Date: Fri, 2 Sep 2011 17:49:45 +0200 Subject: Add tests for flags 'snapshot_image_format'. --- nova/tests/test_libvirt.py | 41 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 40 insertions(+), 1 deletion(-) diff --git a/nova/tests/test_libvirt.py b/nova/tests/test_libvirt.py index 8c6775b29..a7b24c1b8 100644 --- a/nova/tests/test_libvirt.py +++ b/nova/tests/test_libvirt.py @@ -321,7 +321,7 @@ class LibvirtConnTestCase(test.TestCase): instance_data = dict(self.test_instance) self._check_xml_and_container(instance_data) - def test_snapshot(self): + def test_snapshot_in_raw_format(self): if not self.lazy_load_library_exists(): return @@ -354,8 +354,47 @@ class LibvirtConnTestCase(test.TestCase): snapshot = image_service.show(context, recv_meta['id']) self.assertEquals(snapshot['properties']['image_state'], 'available') self.assertEquals(snapshot['status'], 'active') + self.assertEquals(snapshot['disk_format'], FLAGS.snapshot_image_format) self.assertEquals(snapshot['name'], snapshot_name) + def test_snapshot_in_qcow2_format(self): + if not self.lazy_load_library_exists(): + return + + self.flags(image_service='nova.image.fake.FakeImageService') + self.flags(snapshot_image_format='qcow2') + + # Start test + image_service = utils.import_object(FLAGS.image_service) + + # Assuming that base image already exists in image_service + instance_ref = db.instance_create(self.context, self.test_instance) + properties = {'instance_id': instance_ref['id'], + 'user_id': str(self.context.user_id)} + snapshot_name = 'test-snap' + sent_meta = {'name': snapshot_name, 'is_public': False, + 'status': 'creating', 'properties': properties} + # Create new image. It will be updated in snapshot method + # To work with it from snapshot, the single image_service is needed + recv_meta = image_service.create(context, sent_meta) + + self.mox.StubOutWithMock(connection.LibvirtConnection, '_conn') + connection.LibvirtConnection._conn.lookupByName = self.fake_lookup + self.mox.StubOutWithMock(connection.utils, 'execute') + connection.utils.execute = self.fake_execute + + self.mox.ReplayAll() + + conn = connection.LibvirtConnection(False) + conn.snapshot(self.context, instance_ref, recv_meta['id']) + + snapshot = image_service.show(context, recv_meta['id']) + self.assertEquals(snapshot['properties']['image_state'], 'available') + self.assertEquals(snapshot['status'], 'active') + self.assertEquals(snapshot['disk_format'], FLAGS.snapshot_image_format) + self.assertEquals(snapshot['name'], snapshot_name) + + def test_snapshot_no_image_architecture(self): if not self.lazy_load_library_exists(): return -- cgit From 077a6971016b112fa7133f2b00aaed5d922386e1 Mon Sep 17 00:00:00 2001 From: Soren Hansen Date: Sun, 4 Sep 2011 21:06:10 +0200 Subject: Accidentally added instance to security group twice in the test. Fixed. --- nova/tests/test_libvirt.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/nova/tests/test_libvirt.py b/nova/tests/test_libvirt.py index f0aa2a918..1254c3299 100644 --- a/nova/tests/test_libvirt.py +++ b/nova/tests/test_libvirt.py @@ -1037,9 +1037,6 @@ class IptablesFirewallTestCase(test.TestCase): {'parent_group_id': secgroup['id'], 'group_id': src_secgroup['id']}) - db.instance_add_security_group(admin_ctxt, instance_ref['id'], - secgroup['id']) - db.instance_add_security_group(admin_ctxt, instance_ref['id'], secgroup['id']) db.instance_add_security_group(admin_ctxt, src_instance_ref['id'], -- cgit From 7d923d28d673340af1e168f99e7178cd01ea3ac3 Mon Sep 17 00:00:00 2001 From: Soren Hansen Date: Mon, 5 Sep 2011 09:32:14 +0200 Subject: Make a security group rule that references another security group return ipPermission for each of tcp, udp, and icmp. --- nova/api/ec2/cloud.py | 15 +++++++++++---- nova/tests/test_cloud.py | 30 ++++++++++++++++++++++++++++++ 2 files changed, 41 insertions(+), 4 deletions(-) diff --git a/nova/api/ec2/cloud.py b/nova/api/ec2/cloud.py index fe44191c8..14f5f69e2 100644 --- a/nova/api/ec2/cloud.py +++ b/nova/api/ec2/cloud.py @@ -572,18 +572,25 @@ class CloudController(object): g['ipPermissions'] = [] for rule in group.rules: r = {} - r['ipProtocol'] = rule.protocol - r['fromPort'] = rule.from_port - r['toPort'] = rule.to_port r['groups'] = [] r['ipRanges'] = [] if rule.group_id: source_group = db.security_group_get(context, rule.group_id) r['groups'] += [{'groupName': source_group.name, 'userId': source_group.project_id}] + for protocol, min_port, max_port in (('icmp', -1, -1), + ('tcp', 1, 65535), + ('udp', 1, 65536)): + r['ipProtocol'] = protocol + r['fromPort'] = min_port + r['toPort'] = max_port + g['ipPermissions'] += [dict(r)] else: + r['ipProtocol'] = rule.protocol + r['fromPort'] = rule.from_port + r['toPort'] = rule.to_port r['ipRanges'] += [{'cidrIp': rule.cidr}] - g['ipPermissions'] += [r] + g['ipPermissions'] += [r] return g def _rule_args_to_dict(self, context, kwargs): diff --git a/nova/tests/test_cloud.py b/nova/tests/test_cloud.py index 3fe6a9b42..f5a99fa2c 100644 --- a/nova/tests/test_cloud.py +++ b/nova/tests/test_cloud.py @@ -305,6 +305,36 @@ class CloudTestCase(test.TestCase): 'ip_protocol': u'tcp'}]} self.assertTrue(authz(self.context, group_name=sec['name'], **kwargs)) + def test_describe_security_group_ingress_groups(self): + kwargs = {'project_id': self.context.project_id, 'name': 'test'} + sec = db.security_group_create(self.context, + {'project_id': 'someuser', + 'name': 'somegroup1'}) + sec = db.security_group_create(self.context, + {'project_id': 'someuser', + 'name': 'othergroup2'}) + sec = db.security_group_create(self.context, kwargs) + authz = self.cloud.authorize_security_group_ingress + kwargs = {'ip_permissions': [{ + 'groups': {'1': {'user_id': u'someuser', + 'group_name': u'somegroup1'}, + '2': {'user_id': u'someuser', + 'group_name': u'othergroup2'}}}]} + self.assertTrue(authz(self.context, group_name=sec['name'], **kwargs)) + describe = self.cloud.describe_security_groups + groups = describe(self.context, group_name=['test']) + self.assertEquals(len(groups['securityGroupInfo']), 1) + for proto, min_port, max_port in (('icmp', -1, -1), + ('udp', 1, 65536), + ('tcp', 1, 65535)): + rules = filter(lambda g:g['ipProtocol'] == proto, + groups['securityGroupInfo'][0]['ipPermissions']) + self.assertEquals(len(rules), 2, + "Expected 2 rules for protocol %s" % proto) + for rule in rules: + self.assertEquals(rule['fromPort'], min_port) + self.assertEquals(rule['toPort'], max_port) + def test_revoke_security_group_ingress(self): kwargs = {'project_id': self.context.project_id, 'name': 'test'} sec = db.security_group_create(self.context, kwargs) -- cgit From 21e31635e699c5a1d5c64ddda03516174567483f Mon Sep 17 00:00:00 2001 From: Soren Hansen Date: Mon, 5 Sep 2011 12:05:47 +0200 Subject: Clean up security groups after use --- nova/tests/test_cloud.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/nova/tests/test_cloud.py b/nova/tests/test_cloud.py index f5a99fa2c..c5bfdd0f8 100644 --- a/nova/tests/test_cloud.py +++ b/nova/tests/test_cloud.py @@ -307,20 +307,20 @@ class CloudTestCase(test.TestCase): def test_describe_security_group_ingress_groups(self): kwargs = {'project_id': self.context.project_id, 'name': 'test'} - sec = db.security_group_create(self.context, + sec1 = db.security_group_create(self.context, kwargs) + sec2 = db.security_group_create(self.context, {'project_id': 'someuser', 'name': 'somegroup1'}) - sec = db.security_group_create(self.context, + sec3 = db.security_group_create(self.context, {'project_id': 'someuser', 'name': 'othergroup2'}) - sec = db.security_group_create(self.context, kwargs) authz = self.cloud.authorize_security_group_ingress kwargs = {'ip_permissions': [{ 'groups': {'1': {'user_id': u'someuser', 'group_name': u'somegroup1'}, '2': {'user_id': u'someuser', 'group_name': u'othergroup2'}}}]} - self.assertTrue(authz(self.context, group_name=sec['name'], **kwargs)) + self.assertTrue(authz(self.context, group_name=sec1['name'], **kwargs)) describe = self.cloud.describe_security_groups groups = describe(self.context, group_name=['test']) self.assertEquals(len(groups['securityGroupInfo']), 1) @@ -334,6 +334,9 @@ class CloudTestCase(test.TestCase): for rule in rules: self.assertEquals(rule['fromPort'], min_port) self.assertEquals(rule['toPort'], max_port) + db.security_group_destroy(self.context, sec3['id']) + db.security_group_destroy(self.context, sec2['id']) + db.security_group_destroy(self.context, sec1['id']) def test_revoke_security_group_ingress(self): kwargs = {'project_id': self.context.project_id, 'name': 'test'} -- cgit From 95fc404a5e3588d9f40cf7236fbda129346d134d Mon Sep 17 00:00:00 2001 From: Soren Hansen Date: Mon, 5 Sep 2011 12:06:13 +0200 Subject: Adjust test_api to account to multiple rules getting returned for a single set rule. --- nova/tests/test_api.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nova/tests/test_api.py b/nova/tests/test_api.py index 526d1c490..e9f1145dd 100644 --- a/nova/tests/test_api.py +++ b/nova/tests/test_api.py @@ -515,7 +515,7 @@ class ApiEc2TestCase(test.TestCase): # be good enough for that. for group in rv: if group.name == security_group_name: - self.assertEquals(len(group.rules), 1) + self.assertEquals(len(group.rules), 3) self.assertEquals(len(group.rules[0].grants), 1) self.assertEquals(str(group.rules[0].grants[0]), '%s-%s' % (other_security_group_name, 'fake')) -- cgit From 2c16115e236760f3933eadd3a5d7d20dda39866d Mon Sep 17 00:00:00 2001 From: Dan Prince Date: Tue, 6 Sep 2011 07:31:39 -0400 Subject: Update the v1.0 rescue admin action and the v1.1 rescue extension to generate 'adminPass'. Fixes an issue where rescue commands were broken on XenServer. lp#838518 --- nova/api/openstack/contrib/rescue.py | 13 +++++-- nova/api/openstack/create_instance_helper.py | 4 +-- nova/api/openstack/servers.py | 20 +++++++---- nova/compute/api.py | 9 +++-- nova/compute/manager.py | 12 ++++--- nova/flags.py | 3 ++ nova/tests/api/openstack/contrib/test_rescue.py | 23 +++++++++++-- nova/tests/api/openstack/test_server_actions.py | 3 +- nova/tests/api/openstack/test_servers.py | 45 ++++++++++++++++++++----- 9 files changed, 103 insertions(+), 29 deletions(-) diff --git a/nova/api/openstack/contrib/rescue.py b/nova/api/openstack/contrib/rescue.py index 3de128895..f140664b3 100644 --- a/nova/api/openstack/contrib/rescue.py +++ b/nova/api/openstack/contrib/rescue.py @@ -18,11 +18,14 @@ import webob from webob import exc from nova import compute +from nova import flags from nova import log as logging +from nova import utils from nova.api.openstack import extensions as exts from nova.api.openstack import faults +FLAGS = flags.FLAGS LOG = logging.getLogger("nova.api.contrib.rescue") @@ -30,7 +33,7 @@ def wrap_errors(fn): """"Ensure errors are not passed along.""" def wrapped(*args): try: - fn(*args) + return fn(*args) except Exception, e: return faults.Fault(exc.HTTPInternalServerError()) return wrapped @@ -46,9 +49,13 @@ class Rescue(exts.ExtensionDescriptor): def _rescue(self, input_dict, req, instance_id): """Rescue an instance.""" context = req.environ["nova.context"] - self.compute_api.rescue(context, instance_id) + if input_dict['rescue'] and 'adminPass' in input_dict['rescue']: + password = input_dict["rescue"]["adminPass"] + else: + password = utils.generate_password(FLAGS.password_length) + self.compute_api.rescue(context, instance_id, rescue_password=password) - return webob.Response(status_int=202) + return {'adminPass': password} @wrap_errors def _unrescue(self, input_dict, req, instance_id): diff --git a/nova/api/openstack/create_instance_helper.py b/nova/api/openstack/create_instance_helper.py index 29e071609..9c331f2bc 100644 --- a/nova/api/openstack/create_instance_helper.py +++ b/nova/api/openstack/create_instance_helper.py @@ -316,14 +316,14 @@ class CreateInstanceHelper(object): def _get_server_admin_password_old_style(self, server): """ Determine the admin password for a server on creation """ - return utils.generate_password(16) + return utils.generate_password(FLAGS.password_length) def _get_server_admin_password_new_style(self, server): """ Determine the admin password for a server on creation """ password = server.get('adminPass') if password is None: - return utils.generate_password(16) + return utils.generate_password(FLAGS.password_length) if not isinstance(password, basestring) or password == '': msg = _("Invalid adminPass") raise exc.HTTPBadRequest(explanation=msg) diff --git a/nova/api/openstack/servers.py b/nova/api/openstack/servers.py index 977958f5d..3506a4bca 100644 --- a/nova/api/openstack/servers.py +++ b/nova/api/openstack/servers.py @@ -477,16 +477,22 @@ class Controller(object): return webob.Response(status_int=202) @scheduler_api.redirect_handler - def rescue(self, req, id): + def rescue(self, req, id, body={}): """Permit users to rescue the server.""" context = req.environ["nova.context"] try: - self.compute_api.rescue(context, id) + if 'rescue' in body and body['rescue'] and \ + 'adminPass' in body['rescue']: + password = body["rescue"]["adminPass"] + else: + password = utils.generate_password(FLAGS.password_length) + self.compute_api.rescue(context, id, rescue_password=password) except Exception: readable = traceback.format_exc() LOG.exception(_("compute.api::rescue %s"), readable) raise exc.HTTPUnprocessableEntity() - return webob.Response(status_int=202) + + return {'adminPass': password} @scheduler_api.redirect_handler def unrescue(self, req, id): @@ -618,7 +624,7 @@ class ControllerV10(Controller): LOG.debug(msg) raise exc.HTTPBadRequest(explanation=msg) - password = utils.generate_password(16) + password = utils.generate_password(FLAGS.password_length) try: self.compute_api.rebuild(context, instance_id, image_id, password) @@ -760,8 +766,10 @@ class ControllerV11(Controller): self._validate_metadata(metadata) self._decode_personalities(personalities) - password = info["rebuild"].get("adminPass", - utils.generate_password(16)) + if 'rebuild' in info and 'adminPass' in info['rebuild']: + password = info["rebuild"]["adminPass"] + else: + password = utils.generate_password(FLAGS.password_length) try: self.compute_api.rebuild(context, instance_id, image_href, diff --git a/nova/compute/api.py b/nova/compute/api.py index e045ef3de..ca59b5701 100644 --- a/nova/compute/api.py +++ b/nova/compute/api.py @@ -1271,13 +1271,18 @@ class API(base.Base): self._cast_compute_message('resume_instance', context, instance_id) @scheduler_api.reroute_compute("rescue") - def rescue(self, context, instance_id): + def rescue(self, context, instance_id, rescue_password=None): """Rescue the given instance.""" self.update(context, instance_id, vm_state=vm_states.ACTIVE, task_state=task_states.RESCUING) - self._cast_compute_message('rescue_instance', context, instance_id) + + rescue_params = { + "rescue_password": rescue_password + } + self._cast_compute_message('rescue_instance', context, instance_id, + params=rescue_params) @scheduler_api.reroute_compute("unrescue") def unrescue(self, context, instance_id): diff --git a/nova/compute/manager.py b/nova/compute/manager.py index 0477db745..d5c2f9184 100644 --- a/nova/compute/manager.py +++ b/nova/compute/manager.py @@ -70,8 +70,6 @@ flags.DEFINE_string('compute_driver', 'nova.virt.connection.get_connection', 'Driver to use for controlling virtualization') flags.DEFINE_string('stub_network', False, 'Stub network related code') -flags.DEFINE_integer('password_length', 12, - 'Length of generated admin passwords') flags.DEFINE_string('console_host', socket.gethostname(), 'Console proxy host to use to connect to instances on' 'this host.') @@ -796,12 +794,18 @@ class ComputeManager(manager.SchedulerDependentManager): @exception.wrap_exception(notifier=notifier, publisher_id=publisher_id()) @checks_instance_lock - def rescue_instance(self, context, instance_id): - """Rescue an instance on this host.""" + def rescue_instance(self, context, instance_id, **kwargs): + """ + Rescue an instance on this host. + :param rescue_password: password to set on rescue instance + """ + LOG.audit(_('instance %s: rescuing'), instance_id, context=context) context = context.elevated() instance_ref = self.db.instance_get(context, instance_id) + instance_ref.admin_pass = kwargs.get('rescue_password', + utils.generate_password(FLAGS.password_length)) network_info = self._get_instance_nw_info(context, instance_ref) # NOTE(blamar): None of the virt drivers use the 'callback' param diff --git a/nova/flags.py b/nova/flags.py index aa76defe5..971e78807 100644 --- a/nova/flags.py +++ b/nova/flags.py @@ -421,6 +421,9 @@ DEFINE_string('root_helper', 'sudo', DEFINE_bool('use_ipv6', False, 'use ipv6') +DEFINE_integer('password_length', 12, + 'Length of generated instance admin passwords') + DEFINE_bool('monkey_patch', False, 'Whether to log monkey patching') diff --git a/nova/tests/api/openstack/contrib/test_rescue.py b/nova/tests/api/openstack/contrib/test_rescue.py index f8126d461..403bcfd4c 100644 --- a/nova/tests/api/openstack/contrib/test_rescue.py +++ b/nova/tests/api/openstack/contrib/test_rescue.py @@ -16,11 +16,14 @@ import json import webob from nova import compute +from nova import flags from nova import test from nova.tests.api.openstack import fakes +FLAGS = flags.FLAGS -def rescue(self, context, instance_id): + +def rescue(self, context, instance_id, rescue_password=None): pass @@ -34,7 +37,19 @@ class RescueTest(test.TestCase): self.stubs.Set(compute.api.API, "rescue", rescue) self.stubs.Set(compute.api.API, "unrescue", unrescue) - def test_rescue(self): + def test_rescue_with_preset_password(self): + body = {"rescue": {"adminPass": "AABBCC112233"}} + req = webob.Request.blank('/v1.1/123/servers/test_inst/action') + req.method = "POST" + req.body = json.dumps(body) + req.headers["content-type"] = "application/json" + + resp = req.get_response(fakes.wsgi_app()) + self.assertEqual(resp.status_int, 200) + resp_json = json.loads(resp.body) + self.assertEqual("AABBCC112233", resp_json['adminPass']) + + def test_rescue_generates_password(self): body = dict(rescue=None) req = webob.Request.blank('/v1.1/123/servers/test_inst/action') req.method = "POST" @@ -43,6 +58,8 @@ class RescueTest(test.TestCase): resp = req.get_response(fakes.wsgi_app()) self.assertEqual(resp.status_int, 200) + resp_json = json.loads(resp.body) + self.assertEqual(FLAGS.password_length, len(resp_json['adminPass'])) def test_unrescue(self): body = dict(unrescue=None) @@ -52,4 +69,4 @@ class RescueTest(test.TestCase): req.headers["content-type"] = "application/json" resp = req.get_response(fakes.wsgi_app()) - self.assertEqual(resp.status_int, 200) + self.assertEqual(resp.status_int, 202) diff --git a/nova/tests/api/openstack/test_server_actions.py b/nova/tests/api/openstack/test_server_actions.py index b9ef41465..4a215dd74 100644 --- a/nova/tests/api/openstack/test_server_actions.py +++ b/nova/tests/api/openstack/test_server_actions.py @@ -622,7 +622,8 @@ class ServerActionsTestV11(test.TestCase): self.assertEqual(res.status_int, 202) body = json.loads(res.body) self.assertEqual(body['server']['image']['id'], '2') - self.assertEqual(len(body['server']['adminPass']), 16) + self.assertEqual(len(body['server']['adminPass']), + FLAGS.password_length) def test_server_rebuild_rejected_when_building(self): body = { diff --git a/nova/tests/api/openstack/test_servers.py b/nova/tests/api/openstack/test_servers.py index 1591ea56c..b5116b496 100644 --- a/nova/tests/api/openstack/test_servers.py +++ b/nova/tests/api/openstack/test_servers.py @@ -28,6 +28,7 @@ import webob from nova import context from nova import db from nova import exception +from nova import flags from nova import test from nova import utils import nova.api.openstack @@ -49,6 +50,7 @@ from nova.tests.api.openstack import common from nova.tests.api.openstack import fakes +FLAGS = flags.FLAGS FAKE_UUID = 'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa' NS = "{http://docs.openstack.org/compute/api/v1.1}" ATOMNS = "{http://www.w3.org/2005/Atom}" @@ -1508,7 +1510,7 @@ class ServersTest(test.TestCase): self.assertEqual(res.status_int, 202) server = json.loads(res.body)['server'] - self.assertEqual(16, len(server['adminPass'])) + self.assertEqual(FLAGS.password_length, len(server['adminPass'])) self.assertEqual('server_test', server['name']) self.assertEqual(1, server['id']) self.assertEqual(2, server['flavorId']) @@ -1709,7 +1711,7 @@ class ServersTest(test.TestCase): self.assertEqual(res.status_int, 202) server = json.loads(res.body)['server'] - self.assertEqual(16, len(server['adminPass'])) + self.assertEqual(FLAGS.password_length, len(server['adminPass'])) self.assertEqual(1, server['id']) self.assertEqual(0, server['progress']) self.assertEqual('server_test', server['name']) @@ -1769,7 +1771,7 @@ class ServersTest(test.TestCase): self.assertEqual(res.status_int, 202) server = json.loads(res.body)['server'] - self.assertEqual(16, len(server['adminPass'])) + self.assertEqual(FLAGS.password_length, len(server['adminPass'])) self.assertEqual(1, server['id']) self.assertEqual("BUILD", server["status"]) self.assertEqual(0, server['progress']) @@ -2480,9 +2482,8 @@ class ServersTest(test.TestCase): self.assertEqual(res.status, '202 Accepted') self.assertEqual(self.server_delete_called, True) - def test_rescue_accepted(self): + def test_rescue_generates_password(self): self.flags(allow_admin_api=True) - body = {} self.called = False @@ -2497,7 +2498,33 @@ class ServersTest(test.TestCase): res = req.get_response(fakes.wsgi_app()) self.assertEqual(self.called, True) - self.assertEqual(res.status_int, 202) + self.assertEqual(res.status_int, 200) + res_body = json.loads(res.body) + self.assertTrue('adminPass' in res_body) + self.assertEqual(FLAGS.password_length, len(res_body['adminPass'])) + + def test_rescue_with_preset_password(self): + self.flags(allow_admin_api=True) + + self.called = False + + def rescue_mock(*args, **kwargs): + self.called = True + + self.stubs.Set(nova.compute.api.API, 'rescue', rescue_mock) + req = webob.Request.blank('/v1.0/servers/1/rescue') + body = {"rescue": {"adminPass": "AABBCC112233"}} + req.body = json.dumps(body) + req.method = 'POST' + req.content_type = 'application/json' + + res = req.get_response(fakes.wsgi_app()) + + self.assertEqual(self.called, True) + self.assertEqual(res.status_int, 200) + res_body = json.loads(res.body) + self.assertTrue('adminPass' in res_body) + self.assertEqual('AABBCC112233', res_body['adminPass']) def test_rescue_raises_handled(self): self.flags(allow_admin_api=True) @@ -3540,7 +3567,8 @@ class TestServerInstanceCreation(test.TestCase): self.assertEquals(response.status_int, 202) response = json.loads(response.body) self.assertTrue('adminPass' in response['server']) - self.assertEqual(16, len(response['server']['adminPass'])) + self.assertEqual(FLAGS.password_length, + len(response['server']['adminPass'])) def test_create_instance_admin_pass_xml(self): request, response, dummy = \ @@ -3549,7 +3577,8 @@ class TestServerInstanceCreation(test.TestCase): dom = minidom.parseString(response.body) server = dom.childNodes[0] self.assertEquals(server.nodeName, 'server') - self.assertEqual(16, len(server.getAttribute('adminPass'))) + self.assertEqual(FLAGS.password_length, + len(server.getAttribute('adminPass'))) class TestGetKernelRamdiskFromImage(test.TestCase): -- cgit From 9dd628cd7a4ac32281702f653fd8285cb758c700 Mon Sep 17 00:00:00 2001 From: Johannes Erdfelt Date: Wed, 7 Sep 2011 17:22:48 +0000 Subject: Wait longer for all agents, not just Windows --- nova/virt/xenapi/vmops.py | 64 +++++++++++++++++++++++------------------------ 1 file changed, 31 insertions(+), 33 deletions(-) diff --git a/nova/virt/xenapi/vmops.py b/nova/virt/xenapi/vmops.py index c5f105f40..74209050b 100644 --- a/nova/virt/xenapi/vmops.py +++ b/nova/virt/xenapi/vmops.py @@ -48,9 +48,9 @@ XenAPI = None LOG = logging.getLogger("nova.virt.xenapi.vmops") FLAGS = flags.FLAGS -flags.DEFINE_integer('windows_version_timeout', 300, - 'number of seconds to wait for windows agent to be ' - 'fully operational') +flags.DEFINE_integer('agent_version_timeout', 300, + 'number of seconds to wait for agent to be fully ' + 'operational') flags.DEFINE_string('xenapi_vif_driver', 'nova.virt.xenapi.vif.XenAPIBridgeDriver', 'The XenAPI VIF driver using XenServer Network APIs.') @@ -313,15 +313,8 @@ class VMOps(object): def _check_agent_version(): LOG.debug(_("Querying agent version")) - if instance.os_type == 'windows': - # Windows will generally perform a setup process on first boot - # that can take a couple of minutes and then reboot. So we - # need to be more patient than normal as well as watch for - # domid changes - version = self.get_agent_version(instance, - timeout=FLAGS.windows_version_timeout) - else: - version = self.get_agent_version(instance) + + version = self.get_agent_version(instance) if not version: return @@ -623,9 +616,15 @@ class VMOps(object): task = self._session.call_xenapi('Async.VM.clean_reboot', vm_ref) self._session.wait_for_task(task, instance.id) - def get_agent_version(self, instance, timeout=None): + def get_agent_version(self, instance): """Get the version of the agent running on the VM instance.""" + # The agent can be slow to start for a variety of reasons. On Windows, + # it will generally perform a setup process on first boot that can + # take a couple of minutes and then reboot. On Linux, the system can + # also take a while to boot. So we need to be more partient than + # normal as well as watch for domid changes + def _call(): # Send the encrypted password transaction_id = str(uuid.uuid4()) @@ -639,27 +638,26 @@ class VMOps(object): # (ie CRLF escaped) for some reason. Strip that off. return resp['message'].replace('\\r\\n', '') - if timeout: - vm_ref = self._get_vm_opaque_ref(instance) - vm_rec = self._session.get_xenapi().VM.get_record(vm_ref) + vm_ref = self._get_vm_opaque_ref(instance) + vm_rec = self._session.get_xenapi().VM.get_record(vm_ref) - domid = vm_rec['domid'] - - expiration = time.time() + timeout - while time.time() < expiration: - ret = _call() - if ret: - return ret - - vm_rec = self._session.get_xenapi().VM.get_record(vm_ref) - if vm_rec['domid'] != domid: - LOG.info(_('domid changed from %(olddomid)s to ' - '%(newdomid)s') % { - 'olddomid': domid, - 'newdomid': vm_rec['domid']}) - domid = vm_rec['domid'] - else: - return _call() + domid = vm_rec['domid'] + + expiration = time.time() + FLAGS.agent_version_timeout + while time.time() < expiration: + ret = _call() + if ret: + return ret + + vm_rec = self._session.get_xenapi().VM.get_record(vm_ref) + if vm_rec['domid'] != domid: + LOG.info(_('domid changed from %(olddomid)s to ' + '%(newdomid)s') % { + 'olddomid': domid, + 'newdomid': vm_rec['domid']}) + domid = vm_rec['domid'] + + return None def agent_update(self, instance, url, md5sum): """Update agent on the VM instance.""" -- cgit From e11c56ff3c8894895274f65f7a33a1460434baa3 Mon Sep 17 00:00:00 2001 From: Johannes Erdfelt Date: Wed, 7 Sep 2011 17:23:20 +0000 Subject: PEP8 cleanup --- nova/tests/api/openstack/test_servers.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nova/tests/api/openstack/test_servers.py b/nova/tests/api/openstack/test_servers.py index 2ef687709..d063a60c2 100644 --- a/nova/tests/api/openstack/test_servers.py +++ b/nova/tests/api/openstack/test_servers.py @@ -3615,7 +3615,7 @@ class TestGetKernelRamdiskFromImage(test.TestCase): self.assertRaises(exception.NotFound, self._get_k_r, image_meta) def test_ami_no_ramdisk(self): - """If an ami is missing a ramdisk, return kernel ID and None for + """If an ami is missing a ramdisk, return kernel ID and None for ramdisk ID """ image_meta = {'id': 1, 'status': 'active', 'container_format': 'ami', -- cgit From e1d38ca90c259a44035cf3bd5ad17d9ca5d93472 Mon Sep 17 00:00:00 2001 From: Thuleau Édouard Date: Fri, 9 Sep 2011 15:21:00 +0200 Subject: Authorize to start a LXC instance withour, key, network file to inject or metadata. --- nova/virt/libvirt/connection.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/nova/virt/libvirt/connection.py b/nova/virt/libvirt/connection.py index 363a20ed0..fc060703a 100644 --- a/nova/virt/libvirt/connection.py +++ b/nova/virt/libvirt/connection.py @@ -981,15 +981,16 @@ class LibvirtConnection(driver.ComputeDriver): nbd=FLAGS.use_cow_images, tune2fs=tune2fs) - if FLAGS.libvirt_type == 'lxc': - disk.setup_container(basepath('disk'), - container_dir=container_dir, - nbd=FLAGS.use_cow_images) except Exception as e: # This could be a windows image, or a vmdk format disk LOG.warn(_('instance %(inst_name)s: ignoring error injecting' ' data into image %(img_id)s (%(e)s)') % locals()) + if FLAGS.libvirt_type == 'lxc': + disk.setup_container(basepath('disk'), + container_dir=container_dir, + nbd=FLAGS.use_cow_images) + if FLAGS.libvirt_type == 'uml': utils.execute('chown', 'root', basepath('disk'), run_as_root=True) -- cgit From 3a0df2ca9b145d0ef5808def1f2f990a74e607e0 Mon Sep 17 00:00:00 2001 From: Vishvananda Ishaya Date: Fri, 9 Sep 2011 10:27:00 -0700 Subject: remove unnecessary qemu-img flag, use base image type by default --- nova/virt/libvirt/connection.py | 29 +++++++++++++---------------- 1 file changed, 13 insertions(+), 16 deletions(-) diff --git a/nova/virt/libvirt/connection.py b/nova/virt/libvirt/connection.py index 5f53b9d5d..5a5802fb4 100644 --- a/nova/virt/libvirt/connection.py +++ b/nova/virt/libvirt/connection.py @@ -124,13 +124,10 @@ flags.DEFINE_string('block_migration_flag', 'Define block migration behavior.') flags.DEFINE_integer('live_migration_bandwidth', 0, 'Define live migration behavior') -flags.DEFINE_string('qemu_img', 'qemu-img', - 'binary to use for qemu-img commands') -flags.DEFINE_string('snapshot_image_format', 'raw', - 'Snapshot image format (valide option are : ' - 'raw, qcow2, vmdk, vdi.' - 'If the binary qemu_img supports it)') - FLAGS.snapshot_disk_format, +flags.DEFINE_string('snapshot_image_format', None, + 'Snapshot image format (valid options are : ' + 'raw, qcow2, vmdk, vdi).' + 'Defaults to same as source image') flags.DEFINE_string('libvirt_vif_type', 'bridge', 'Type of VIF to create.') flags.DEFINE_string('libvirt_vif_driver', @@ -395,10 +392,7 @@ class LibvirtConnection(driver.ComputeDriver): def snapshot(self, context, instance, image_href): """Create snapshot from a running VM instance. - This command only works with qemu 0.14+, the qemu_img flag is - provided so that a locally compiled binary of qemu-img can be used - to support this command. - + This command only works with qemu 0.14+ """ virt_dom = self._lookup_by_name(instance['name']) @@ -424,8 +418,11 @@ class LibvirtConnection(driver.ComputeDriver): arch = base['properties']['architecture'] metadata['properties']['architecture'] = arch - if 'disk_format' in base: - metadata['disk_format'] = FLAGS.snapshot_image_format + source_format = base.get('disk_format') or 'raw' + if FLAGS.use_cow_images: + source_format = 'qcow2' + image_format = FLAGS.snapshot_image_format or source_format + metadata['disk_format'] = image_format if 'container_format' in base: metadata['container_format'] = base['container_format'] @@ -448,12 +445,12 @@ class LibvirtConnection(driver.ComputeDriver): # Export the snapshot to a raw image temp_dir = tempfile.mkdtemp() out_path = os.path.join(temp_dir, snapshot_name) - qemu_img_cmd = (FLAGS.qemu_img, + qemu_img_cmd = ('qemu-img', 'convert', '-f', - 'qcow2', + source_format, '-O', - FLAGS.snapshot_image_format, + image_format, '-s', snapshot_name, disk_path, -- cgit From 2127b587a1870cd0f08466e8fe53697337292645 Mon Sep 17 00:00:00 2001 From: Vishvananda Ishaya Date: Fri, 9 Sep 2011 10:44:06 -0700 Subject: remove extra line for pep8 --- nova/tests/test_libvirt.py | 1 - 1 file changed, 1 deletion(-) diff --git a/nova/tests/test_libvirt.py b/nova/tests/test_libvirt.py index a7b24c1b8..61f98f63d 100644 --- a/nova/tests/test_libvirt.py +++ b/nova/tests/test_libvirt.py @@ -394,7 +394,6 @@ class LibvirtConnTestCase(test.TestCase): self.assertEquals(snapshot['disk_format'], FLAGS.snapshot_image_format) self.assertEquals(snapshot['name'], snapshot_name) - def test_snapshot_no_image_architecture(self): if not self.lazy_load_library_exists(): return -- cgit From 6fafde1fa52d1eba0c77f403b9e2a6f77b5379cd Mon Sep 17 00:00:00 2001 From: Dan Prince Date: Mon, 12 Sep 2011 09:20:11 -0400 Subject: Make quoting consistent. --- nova/api/openstack/contrib/rescue.py | 2 +- nova/api/openstack/servers.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/nova/api/openstack/contrib/rescue.py b/nova/api/openstack/contrib/rescue.py index f140664b3..2e5dbab73 100644 --- a/nova/api/openstack/contrib/rescue.py +++ b/nova/api/openstack/contrib/rescue.py @@ -50,7 +50,7 @@ class Rescue(exts.ExtensionDescriptor): """Rescue an instance.""" context = req.environ["nova.context"] if input_dict['rescue'] and 'adminPass' in input_dict['rescue']: - password = input_dict["rescue"]["adminPass"] + password = input_dict['rescue']['adminPass'] else: password = utils.generate_password(FLAGS.password_length) self.compute_api.rescue(context, instance_id, rescue_password=password) diff --git a/nova/api/openstack/servers.py b/nova/api/openstack/servers.py index 49f267eb9..2c6f9724c 100644 --- a/nova/api/openstack/servers.py +++ b/nova/api/openstack/servers.py @@ -483,7 +483,7 @@ class Controller(object): try: if 'rescue' in body and body['rescue'] and \ 'adminPass' in body['rescue']: - password = body["rescue"]["adminPass"] + password = body['rescue']['adminPass'] else: password = utils.generate_password(FLAGS.password_length) self.compute_api.rescue(context, id, rescue_password=password) @@ -767,7 +767,7 @@ class ControllerV11(Controller): self._decode_personalities(personalities) if 'rebuild' in info and 'adminPass' in info['rebuild']: - password = info["rebuild"]["adminPass"] + password = info['rebuild']['adminPass'] else: password = utils.generate_password(FLAGS.password_length) -- cgit From ff721f2b52bdb9abab4b7af0e6fcdab09e8de092 Mon Sep 17 00:00:00 2001 From: Johannes Erdfelt Date: Mon, 12 Sep 2011 19:19:04 +0000 Subject: Fix typo (woops) --- nova/virt/xenapi/vmops.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nova/virt/xenapi/vmops.py b/nova/virt/xenapi/vmops.py index 1f7494d59..6b8e60acb 100644 --- a/nova/virt/xenapi/vmops.py +++ b/nova/virt/xenapi/vmops.py @@ -634,7 +634,7 @@ class VMOps(object): # The agent can be slow to start for a variety of reasons. On Windows, # it will generally perform a setup process on first boot that can # take a couple of minutes and then reboot. On Linux, the system can - # also take a while to boot. So we need to be more partient than + # also take a while to boot. So we need to be more patient than # normal as well as watch for domid changes def _call(): -- cgit From 84136418aef3922989ba269604a6cb1125d5014b Mon Sep 17 00:00:00 2001 From: Johannes Erdfelt Date: Mon, 12 Sep 2011 22:45:38 +0000 Subject: PEP8 cleanups --- nova/db/sqlalchemy/api.py | 2 +- nova/virt/disk.py | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/nova/db/sqlalchemy/api.py b/nova/db/sqlalchemy/api.py index 40e2ca167..e5a661c7f 100644 --- a/nova/db/sqlalchemy/api.py +++ b/nova/db/sqlalchemy/api.py @@ -672,7 +672,7 @@ def floating_ip_update(context, address, values): def fixed_ip_associate(context, address, instance_id, network_id=None, reserved=False): """Keyword arguments: - reserved -- should be a boolean value(True or False), exact value will be + reserved -- should be a boolean value(True or False), exact value will be used to filter on the fixed ip address """ session = get_session() diff --git a/nova/virt/disk.py b/nova/virt/disk.py index d0745c82d..cd3422829 100644 --- a/nova/virt/disk.py +++ b/nova/virt/disk.py @@ -160,6 +160,7 @@ def destroy_container(target, instance, nbd=False): except Exception, exn: LOG.exception(_('Failed to remove container: %s'), exn) + def _link_device(image, nbd): """Link image to device using loopback or nbd""" -- cgit From cf9c76cae68ef8efcc8f3a82ade728fed8175c73 Mon Sep 17 00:00:00 2001 From: Johannes Erdfelt Date: Mon, 12 Sep 2011 22:58:07 +0000 Subject: PEP8 cleanup --- nova/tests/api/openstack/test_images.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nova/tests/api/openstack/test_images.py b/nova/tests/api/openstack/test_images.py index c63d1203a..10c7663ff 100644 --- a/nova/tests/api/openstack/test_images.py +++ b/nova/tests/api/openstack/test_images.py @@ -1182,7 +1182,7 @@ class ImageControllerWithGlanceServiceTest(test.TestCase): # Snapshot for User 1 server_ref = 'http://localhost/v1.1/servers/42' snapshot_properties = {'instance_ref': server_ref, 'user_id': 'fake'} - statuses = ('queued', 'saving', 'active','killed', + statuses = ('queued', 'saving', 'active', 'killed', 'deleted', 'pending_delete') for status in statuses: add_fixture(id=image_id, name='%s snapshot' % status, -- cgit From db70c96fce51d39e51d480b38f4d8d1e9e7ecff5 Mon Sep 17 00:00:00 2001 From: Scott Moser Date: Tue, 13 Sep 2011 15:46:29 -0400 Subject: interpret 'swap' to be in MB, not in GB. This fixes libvirt connection to interpret swap in MB. I'm not sure if virt/xen needs updating. --- nova/virt/libvirt/connection.py | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/nova/virt/libvirt/connection.py b/nova/virt/libvirt/connection.py index 0a9b1912f..977a099a7 100644 --- a/nova/virt/libvirt/connection.py +++ b/nova/virt/libvirt/connection.py @@ -768,19 +768,19 @@ class LibvirtConnection(driver.ComputeDriver): if size: disk.extend(target, size) - def _create_local(self, target, local_size, prefix='G', fs_format=None): + def _create_local(self, target, local_size, unit='G', fs_format=None): """Create a blank image of specified size""" if not fs_format: fs_format = FLAGS.default_local_format - utils.execute('truncate', target, '-s', "%d%c" % (local_size, prefix)) + utils.execute('truncate', target, '-s', "%d%c" % (local_size, unit)) if fs_format: utils.execute('mkfs', '-t', fs_format, target) - def _create_swap(self, target, swap_gb): + def _create_swap(self, target, swap_mb): """Create a swap file of specified size""" - self._create_local(target, swap_gb) + self._create_local(target, swap_mb, unit='M') utils.execute('mkswap', target) def _create_image(self, context, inst, libvirt_xml, suffix='', @@ -872,22 +872,22 @@ class LibvirtConnection(driver.ComputeDriver): cow=FLAGS.use_cow_images, local_size=eph['size']) - swap_gb = 0 + swap_mb = 0 swap = driver.block_device_info_get_swap(block_device_info) if driver.swap_is_usable(swap): - swap_gb = swap['swap_size'] + swap_mb = swap['swap_size'] elif (inst_type['swap'] > 0 and not self._volume_in_mapping(self.default_swap_device, block_device_info)): - swap_gb = inst_type['swap'] + swap_mb = inst_type['swap'] - if swap_gb > 0: + if swap_mb > 0: self._cache_image(fn=self._create_swap, target=basepath('disk.swap'), - fname="swap_%s" % swap_gb, + fname="swap_%s" % swap_mb, cow=FLAGS.use_cow_images, - swap_gb=swap_gb) + swap_mb=swap_mb) # For now, we assume that if we're not using a kernel, we're using a # partitioned disk image where the target partition is the first @@ -911,7 +911,7 @@ class LibvirtConnection(driver.ComputeDriver): user=user, project=project) elif config_drive: - self._create_local(basepath('disk.config'), 64, prefix="M", + self._create_local(basepath('disk.config'), 64, unit='M', fs_format='msdos') # 64MB if inst['key_data']: -- cgit From 7139d7459f2bedc055080a5effc2377b55bffe6b Mon Sep 17 00:00:00 2001 From: Vishvananda Ishaya Date: Wed, 14 Sep 2011 09:37:24 -0700 Subject: fixed tests --- nova/tests/test_libvirt.py | 4 ++-- nova/virt/libvirt/connection.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/nova/tests/test_libvirt.py b/nova/tests/test_libvirt.py index 61f98f63d..9b349dd4e 100644 --- a/nova/tests/test_libvirt.py +++ b/nova/tests/test_libvirt.py @@ -354,7 +354,7 @@ class LibvirtConnTestCase(test.TestCase): snapshot = image_service.show(context, recv_meta['id']) self.assertEquals(snapshot['properties']['image_state'], 'available') self.assertEquals(snapshot['status'], 'active') - self.assertEquals(snapshot['disk_format'], FLAGS.snapshot_image_format) + self.assertEquals(snapshot['disk_format'], 'raw') self.assertEquals(snapshot['name'], snapshot_name) def test_snapshot_in_qcow2_format(self): @@ -391,7 +391,7 @@ class LibvirtConnTestCase(test.TestCase): snapshot = image_service.show(context, recv_meta['id']) self.assertEquals(snapshot['properties']['image_state'], 'available') self.assertEquals(snapshot['status'], 'active') - self.assertEquals(snapshot['disk_format'], FLAGS.snapshot_image_format) + self.assertEquals(snapshot['disk_format'], 'qcow2') self.assertEquals(snapshot['name'], snapshot_name) def test_snapshot_no_image_architecture(self): diff --git a/nova/virt/libvirt/connection.py b/nova/virt/libvirt/connection.py index 5a5802fb4..02d06d98d 100644 --- a/nova/virt/libvirt/connection.py +++ b/nova/virt/libvirt/connection.py @@ -419,9 +419,9 @@ class LibvirtConnection(driver.ComputeDriver): metadata['properties']['architecture'] = arch source_format = base.get('disk_format') or 'raw' + image_format = FLAGS.snapshot_image_format or source_format if FLAGS.use_cow_images: source_format = 'qcow2' - image_format = FLAGS.snapshot_image_format or source_format metadata['disk_format'] = image_format if 'container_format' in base: -- cgit From 3d88e123624694b557f44cad44335bcadc404631 Mon Sep 17 00:00:00 2001 From: Vishvananda Ishaya Date: Wed, 14 Sep 2011 14:38:07 -0700 Subject: fix rescue to use the base image, reset firewall rules, and accept network_info --- nova/virt/libvirt/connection.py | 41 ++++++++++++++++++++++++++--------------- 1 file changed, 26 insertions(+), 15 deletions(-) diff --git a/nova/virt/libvirt/connection.py b/nova/virt/libvirt/connection.py index 363a20ed0..c7445fe50 100644 --- a/nova/virt/libvirt/connection.py +++ b/nova/virt/libvirt/connection.py @@ -29,9 +29,9 @@ Supports KVM, LXC, QEMU, UML, and XEN. (default: kvm). :libvirt_uri: Override for the default libvirt URI (depends on libvirt_type). :libvirt_xml_template: Libvirt XML Template. -:rescue_image_id: Rescue ami image (default: ami-rescue). -:rescue_kernel_id: Rescue aki image (default: aki-rescue). -:rescue_ramdisk_id: Rescue ari image (default: ari-rescue). +:rescue_image_id: Rescue ami image (None = original image). +:rescue_kernel_id: Rescue aki image (None = original image). +:rescue_ramdisk_id: Rescue ari image (None = original image). :injected_network_template: Template file for injected network :allow_same_net_traffic: Whether to allow in project network traffic @@ -83,9 +83,9 @@ LOG = logging.getLogger('nova.virt.libvirt_conn') FLAGS = flags.FLAGS flags.DECLARE('live_migration_retry_count', 'nova.compute.manager') # TODO(vish): These flags should probably go into a shared location -flags.DEFINE_string('rescue_image_id', 'ami-rescue', 'Rescue ami image') -flags.DEFINE_string('rescue_kernel_id', 'aki-rescue', 'Rescue aki image') -flags.DEFINE_string('rescue_ramdisk_id', 'ari-rescue', 'Rescue ari image') +flags.DEFINE_string('rescue_image_id', None, 'Rescue ami image') +flags.DEFINE_string('rescue_kernel_id', None, 'Rescue aki image') +flags.DEFINE_string('rescue_ramdisk_id', None, 'Rescue ari image') flags.DEFINE_string('libvirt_xml_template', utils.abspath('virt/libvirt.xml.template'), 'Libvirt XML Template') @@ -466,18 +466,22 @@ class LibvirtConnection(driver.ComputeDriver): shutil.rmtree(temp_dir) @exception.wrap_exception() - def reboot(self, instance, network_info): + def reboot(self, instance, network_info, regenerate_xml=False): """Reboot a virtual machine, given an instance reference. This method actually destroys and re-creates the domain to ensure the reboot happens, as the guest OS cannot ignore this action. """ + # NOTE(vish): this should accept block device info virt_dom = self._conn.lookupByName(instance['name']) # NOTE(itoumsn): Use XML delived from the running instance # instead of using to_xml(instance, network_info). This is almost # the ultimate stupid workaround. - xml = virt_dom.XMLDesc(0) + if regenerate_xml: + xml = self.to_xml(instance, network_info, False) + else: + xml = virt_dom.XMLDesc(0) # NOTE(itoumsn): self.shutdown() and wait instead of self.destroy() is # better because we cannot ensure flushing dirty buffers # in the guest OS. But, in case of KVM, shutdown() does not work... @@ -544,11 +548,17 @@ class LibvirtConnection(driver.ComputeDriver): self.destroy(instance, network_info, cleanup=False) xml = self.to_xml(instance, network_info, rescue=True) - rescue_images = {'image_id': FLAGS.rescue_image_id, - 'kernel_id': FLAGS.rescue_kernel_id, - 'ramdisk_id': FLAGS.rescue_ramdisk_id} - self._create_image(context, instance, xml, '.rescue', rescue_images) + rescue_images = { + 'image_id': FLAGS.rescue_image_id or instance['image_ref'], + 'kernel_id': FLAGS.rescue_kernel_id or instance['kernel_id'], + 'ramdisk_id': FLAGS.rescue_ramdisk_id or instance['ramdisk_id'], + } + self._create_image(context, instance, xml, '.rescue', rescue_images, + network_info=network_info) + self.firewall_driver.setup_basic_filtering(instance, network_info) + self.firewall_driver.prepare_instance_filter(instance, network_info) self._create_new_domain(xml) + self.firewall_driver.apply_instance_filter(instance, network_info) def _wait_for_rescue(): """Called at an interval until the VM is running again.""" @@ -557,7 +567,7 @@ class LibvirtConnection(driver.ComputeDriver): try: state = self.get_info(instance_name)['state'] except exception.NotFound: - msg = _("During reboot, %s disappeared.") % instance_name + msg = _("During rescue, %s disappeared.") % instance_name LOG.error(msg) raise utils.LoopingCallDone @@ -570,14 +580,15 @@ class LibvirtConnection(driver.ComputeDriver): return timer.start(interval=0.5, now=True) @exception.wrap_exception() - def unrescue(self, instance, network_info): + def unrescue(self, instance, callback, network_info): """Reboot the VM which is being rescued back into primary images. Because reboot destroys and re-creates instances, unresue should simply call reboot. """ - self.reboot(instance, network_info) + # NOTE(vish): this should accept block device info + self.reboot(instance, network_info, regenerate_xml=True) @exception.wrap_exception() def poll_rescued_instances(self, timeout): -- cgit From d0daaaa320ecb408e721d5e856676a87d7e98ea6 Mon Sep 17 00:00:00 2001 From: Vishvananda Ishaya Date: Wed, 14 Sep 2011 15:28:22 -0700 Subject: write out xml for rescue --- nova/virt/libvirt/connection.py | 52 +++++++++++++++++------------------------ 1 file changed, 21 insertions(+), 31 deletions(-) diff --git a/nova/virt/libvirt/connection.py b/nova/virt/libvirt/connection.py index c7445fe50..56a0f3bb0 100644 --- a/nova/virt/libvirt/connection.py +++ b/nova/virt/libvirt/connection.py @@ -466,22 +466,20 @@ class LibvirtConnection(driver.ComputeDriver): shutil.rmtree(temp_dir) @exception.wrap_exception() - def reboot(self, instance, network_info, regenerate_xml=False): + def reboot(self, instance, network_info, xml=None): """Reboot a virtual machine, given an instance reference. This method actually destroys and re-creates the domain to ensure the reboot happens, as the guest OS cannot ignore this action. """ - # NOTE(vish): this should accept block device info virt_dom = self._conn.lookupByName(instance['name']) # NOTE(itoumsn): Use XML delived from the running instance # instead of using to_xml(instance, network_info). This is almost # the ultimate stupid workaround. - if regenerate_xml: - xml = self.to_xml(instance, network_info, False) - else: + if not xml: xml = virt_dom.XMLDesc(0) + # NOTE(itoumsn): self.shutdown() and wait instead of self.destroy() is # better because we cannot ensure flushing dirty buffers # in the guest OS. But, in case of KVM, shutdown() does not work... @@ -545,7 +543,15 @@ class LibvirtConnection(driver.ComputeDriver): data recovery. """ - self.destroy(instance, network_info, cleanup=False) + + virt_dom = self._conn.lookupByName(instance['name']) + unrescue_xml = virt_dom.XMLDesc(0) + unrescue_xml_path = os.path.join(FLAGS.instances_path, + instance['name'], + 'unrescue.xml') + f = open(unrescue_xml_path, 'w') + f.write(unrescue_xml) + f.close() xml = self.to_xml(instance, network_info, rescue=True) rescue_images = { @@ -555,29 +561,7 @@ class LibvirtConnection(driver.ComputeDriver): } self._create_image(context, instance, xml, '.rescue', rescue_images, network_info=network_info) - self.firewall_driver.setup_basic_filtering(instance, network_info) - self.firewall_driver.prepare_instance_filter(instance, network_info) - self._create_new_domain(xml) - self.firewall_driver.apply_instance_filter(instance, network_info) - - def _wait_for_rescue(): - """Called at an interval until the VM is running again.""" - instance_name = instance['name'] - - try: - state = self.get_info(instance_name)['state'] - except exception.NotFound: - msg = _("During rescue, %s disappeared.") % instance_name - LOG.error(msg) - raise utils.LoopingCallDone - - if state == power_state.RUNNING: - msg = _("Instance %s rescued successfully.") % instance_name - LOG.info(msg) - raise utils.LoopingCallDone - - timer = utils.LoopingCall(_wait_for_rescue) - return timer.start(interval=0.5, now=True) + self.reboot(instance, network_info, xml=xml) @exception.wrap_exception() def unrescue(self, instance, callback, network_info): @@ -587,8 +571,14 @@ class LibvirtConnection(driver.ComputeDriver): simply call reboot. """ - # NOTE(vish): this should accept block device info - self.reboot(instance, network_info, regenerate_xml=True) + unrescue_xml_path = os.path.join(FLAGS.instances_path, + instance['name'], + 'unrescue.xml') + f = open(unrescue_xml_path) + unrescue_xml = f.read() + f.close() + os.remove(unrescue_xml_path) + self.reboot(instance, network_info, xml=unrescue_xml) @exception.wrap_exception() def poll_rescued_instances(self, timeout): -- cgit From 63c4cc459a5b27040610ca9071ac578ecd43c059 Mon Sep 17 00:00:00 2001 From: Soren Hansen Date: Thu, 15 Sep 2011 18:15:19 +0200 Subject: Return three rules for describe_security_groups if a rule refers to a foreign group, but does not specify protocol/port. --- nova/api/ec2/cloud.py | 18 +++++++++++------ nova/tests/test_cloud.py | 52 ++++++++++++++++++++++++++++++++++-------------- 2 files changed, 49 insertions(+), 21 deletions(-) diff --git a/nova/api/ec2/cloud.py b/nova/api/ec2/cloud.py index 14f5f69e2..5c876a3b7 100644 --- a/nova/api/ec2/cloud.py +++ b/nova/api/ec2/cloud.py @@ -578,13 +578,19 @@ class CloudController(object): source_group = db.security_group_get(context, rule.group_id) r['groups'] += [{'groupName': source_group.name, 'userId': source_group.project_id}] - for protocol, min_port, max_port in (('icmp', -1, -1), - ('tcp', 1, 65535), - ('udp', 1, 65536)): - r['ipProtocol'] = protocol - r['fromPort'] = min_port - r['toPort'] = max_port + if rule.protocol: + r['ipProtocol'] = rule.protocol + r['fromPort'] = rule.from_port + r['toPort'] = rule.to_port g['ipPermissions'] += [dict(r)] + else: + for protocol, min_port, max_port in (('icmp', -1, -1), + ('tcp', 1, 65535), + ('udp', 1, 65536)): + r['ipProtocol'] = protocol + r['fromPort'] = min_port + r['toPort'] = max_port + g['ipPermissions'] += [dict(r)] else: r['ipProtocol'] = rule.protocol r['fromPort'] = rule.from_port diff --git a/nova/tests/test_cloud.py b/nova/tests/test_cloud.py index c5bfdd0f8..96aebdd54 100644 --- a/nova/tests/test_cloud.py +++ b/nova/tests/test_cloud.py @@ -315,25 +315,47 @@ class CloudTestCase(test.TestCase): {'project_id': 'someuser', 'name': 'othergroup2'}) authz = self.cloud.authorize_security_group_ingress - kwargs = {'ip_permissions': [{ - 'groups': {'1': {'user_id': u'someuser', - 'group_name': u'somegroup1'}, - '2': {'user_id': u'someuser', - 'group_name': u'othergroup2'}}}]} + kwargs = {'ip_permissions': [ + {'groups': {'1': {'user_id': u'someuser', + 'group_name': u'somegroup1'}}}, + {'ip_protocol': 'tcp', + 'from_port': 80, + 'to_port': 80, + 'groups': {'1': {'user_id': u'someuser', + 'group_name': u'othergroup2'}}}]} self.assertTrue(authz(self.context, group_name=sec1['name'], **kwargs)) describe = self.cloud.describe_security_groups groups = describe(self.context, group_name=['test']) self.assertEquals(len(groups['securityGroupInfo']), 1) - for proto, min_port, max_port in (('icmp', -1, -1), - ('udp', 1, 65536), - ('tcp', 1, 65535)): - rules = filter(lambda g:g['ipProtocol'] == proto, - groups['securityGroupInfo'][0]['ipPermissions']) - self.assertEquals(len(rules), 2, - "Expected 2 rules for protocol %s" % proto) - for rule in rules: - self.assertEquals(rule['fromPort'], min_port) - self.assertEquals(rule['toPort'], max_port) + actual_rules = groups['securityGroupInfo'][0]['ipPermissions'] + self.assertEquals(len(actual_rules), 4) + expected_rules = [{'fromPort': -1, + 'groups': [{'groupName': 'somegroup1', + 'userId': 'someuser'}], + 'ipProtocol': 'icmp', + 'ipRanges': [], + 'toPort': -1}, + {'fromPort': 1, + 'groups': [{'groupName': u'somegroup1', + 'userId': u'someuser'}], + 'ipProtocol': 'tcp', + 'ipRanges': [], + 'toPort': 65535}, + {'fromPort': 1, + 'groups': [{'groupName': u'somegroup1', + 'userId': u'someuser'}], + 'ipProtocol': 'udp', + 'ipRanges': [], + 'toPort': 65536}, + {'fromPort': 80, + 'groups': [{'groupName': u'othergroup2', + 'userId': u'someuser'}], + 'ipProtocol': u'tcp', + 'ipRanges': [], + 'toPort': 80}] + for rule in expected_rules: + self.assertTrue(rule in actual_rules) + db.security_group_destroy(self.context, sec3['id']) db.security_group_destroy(self.context, sec2['id']) db.security_group_destroy(self.context, sec1['id']) -- cgit From 24db80baa4a5125ba32250b7aa495b58465cfdf5 Mon Sep 17 00:00:00 2001 From: Isaku Yamahata Date: Fri, 16 Sep 2011 17:04:27 +0900 Subject: compute/api: swap size issue When --block-device-mapping swap= is specified, its swap size is wrongly set to 0. Thus swap device will be missing. This is reported by https://bugs.launchpad.net/bugs/851218 This patch fixes it. --- nova/compute/api.py | 37 +++++++++++++++++++------------------ nova/tests/test_compute.py | 14 +++++++++----- 2 files changed, 28 insertions(+), 23 deletions(-) diff --git a/nova/compute/api.py b/nova/compute/api.py index 4220f47ae..7ac504d32 100644 --- a/nova/compute/api.py +++ b/nova/compute/api.py @@ -287,18 +287,24 @@ class API(base.Base): return (num_instances, base_options, image) @staticmethod - def _ephemeral_size(instance_type, ephemeral_name): - num = block_device.ephemeral_num(ephemeral_name) + def _volume_size(instance_type, virtual_name): + size = 0 + if virtual_name == 'swap': + size = instance_type.get('swap', 0) + elif block_device.is_ephemeral(virtual_name): + num = block_device.ephemeral_num(virtual_name) - # TODO(yamahata): ephemeralN where N > 0 - # Only ephemeral0 is allowed for now because InstanceTypes - # table only allows single local disk, local_gb. - # In order to enhance it, we need to add a new columns to - # instance_types table. - if num > 0: - return 0 + # TODO(yamahata): ephemeralN where N > 0 + # Only ephemeral0 is allowed for now because InstanceTypes + # table only allows single local disk, local_gb. + # In order to enhance it, we need to add a new columns to + # instance_types table. + if num > 0: + return 0 - return instance_type.get('local_gb') + size = instance_type.get('local_gb') + + return size def _update_image_block_device_mapping(self, elevated_context, instance_type, instance_id, @@ -319,12 +325,7 @@ class API(base.Base): if not block_device.is_swap_or_ephemeral(virtual_name): continue - size = 0 - if virtual_name == 'swap': - size = instance_type.get('swap', 0) - elif block_device.is_ephemeral(virtual_name): - size = self._ephemeral_size(instance_type, virtual_name) - + size = self._volume_size(instance_type, virtual_name) if size == 0: continue @@ -354,8 +355,8 @@ class API(base.Base): virtual_name = bdm.get('virtual_name') if (virtual_name is not None and - block_device.is_ephemeral(virtual_name)): - size = self._ephemeral_size(instance_type, virtual_name) + block_device.is_swap_or_ephemeral(virtual_name)): + size = self._volume_size(instance_type, virtual_name) if size == 0: continue values['volume_size'] = size diff --git a/nova/tests/test_compute.py b/nova/tests/test_compute.py index 4d463572b..d600c9f15 100644 --- a/nova/tests/test_compute.py +++ b/nova/tests/test_compute.py @@ -1563,12 +1563,16 @@ class ComputeTestCase(test.TestCase): db.block_device_mapping_destroy(self.context, bdm['id']) self.compute.terminate_instance(self.context, instance_id) - def test_ephemeral_size(self): + def test_volume_size(self): local_size = 2 - inst_type = {'local_gb': local_size} - self.assertEqual(self.compute_api._ephemeral_size(inst_type, + swap_size = 3 + inst_type = {'local_gb': local_size, 'swap': swap_size} + self.assertEqual(self.compute_api._volume_size(inst_type, 'ephemeral0'), local_size) - self.assertEqual(self.compute_api._ephemeral_size(inst_type, - 'ephemeral1'), + self.assertEqual(self.compute_api._volume_size(inst_type, + 'ephemeral1'), 0) + self.assertEqual(self.compute_api._volume_size(inst_type, + 'swap'), + swap_size) -- cgit From 1d2a5bd706736bff2e2d82ebeb813438493cea41 Mon Sep 17 00:00:00 2001 From: Soren Hansen Date: Fri, 16 Sep 2011 14:28:57 +0200 Subject: Make sure grantee_group is eagerly loaded. --- nova/db/sqlalchemy/api.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/nova/db/sqlalchemy/api.py b/nova/db/sqlalchemy/api.py index b99667afc..6c3c2d038 100644 --- a/nova/db/sqlalchemy/api.py +++ b/nova/db/sqlalchemy/api.py @@ -2790,12 +2790,14 @@ def security_group_rule_get_by_security_group(context, security_group_id, result = session.query(models.SecurityGroupIngressRule).\ filter_by(deleted=can_read_deleted(context)).\ filter_by(parent_group_id=security_group_id).\ + options(joinedload_all('grantee_group')).\ all() else: # TODO(vish): Join to group and check for project_id result = session.query(models.SecurityGroupIngressRule).\ filter_by(deleted=False).\ filter_by(parent_group_id=security_group_id).\ + options(joinedload_all('grantee_group')).\ all() return result -- cgit From 6b3ac77dabc3891648399c367546474fe3450fd1 Mon Sep 17 00:00:00 2001 From: Dan Prince Date: Fri, 16 Sep 2011 09:40:24 -0400 Subject: Add a FakeVirDomainSnapshot and return it from snapshotCreateXML. Fixes libvirt snapshot tests. --- nova/tests/test_libvirt.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/nova/tests/test_libvirt.py b/nova/tests/test_libvirt.py index b7c1ef1ab..1924ae050 100644 --- a/nova/tests/test_libvirt.py +++ b/nova/tests/test_libvirt.py @@ -52,6 +52,15 @@ def _concurrency(wait, done, target): done.send() +class FakeVirDomainSnapshot(object): + + def __init__(self, dom=None): + self.dom = dom + + def delete(self, flags): + pass + + class FakeVirtDomain(object): def __init__(self, fake_xml=None): @@ -69,7 +78,7 @@ class FakeVirtDomain(object): """ def snapshotCreateXML(self, *args): - return None + return FakeVirDomainSnapshot(self) def createWithFlags(self, launch_flags): pass -- cgit From e09b3d70e5a4aaa00f5ba62d1eab5d6d57a800e1 Mon Sep 17 00:00:00 2001 From: Vishvananda Ishaya Date: Fri, 16 Sep 2011 08:44:25 -0700 Subject: fix permissions --- nova/virt/libvirt/connection.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/nova/virt/libvirt/connection.py b/nova/virt/libvirt/connection.py index 31b08be68..4e91415a7 100644 --- a/nova/virt/libvirt/connection.py +++ b/nova/virt/libvirt/connection.py @@ -814,8 +814,10 @@ class LibvirtConnection(driver.ComputeDriver): utils.execute('mkdir', '-p', container_dir) # NOTE(vish): No need add the suffix to console.log - os.close(os.open(basepath('console.log', ''), - os.O_CREAT | os.O_WRONLY, 0660)) + console_log = basepath('console.log', '') + if os.path.exists(console_log): + utils.execute('chown', os.getuid(), console_log, run_as_root=True) + os.close(os.open(console_log, os.O_CREAT | os.O_WRONLY, 0660)) if not disk_images: disk_images = {'image_id': inst['image_ref'], -- cgit From fa359fa8024f247f119d97be46fb7886e999969b Mon Sep 17 00:00:00 2001 From: Jason Koelker Date: Fri, 16 Sep 2011 13:02:13 -0500 Subject: remove getting fixed_ips directly from the db --- nova/compute/manager.py | 5 ----- 1 file changed, 5 deletions(-) diff --git a/nova/compute/manager.py b/nova/compute/manager.py index 7915830ec..138e6c58d 100644 --- a/nova/compute/manager.py +++ b/nova/compute/manager.py @@ -1388,11 +1388,6 @@ class ComputeManager(manager.SchedulerDependentManager): instance_ref = self.db.instance_get(context, instance_id) hostname = instance_ref['hostname'] - # Getting fixed ips - fixed_ips = self.db.instance_get_fixed_addresses(context, instance_id) - if not fixed_ips: - raise exception.FixedIpNotFoundForInstance(instance_id=instance_id) - # If any volume is mounted, prepare here. if not instance_ref['volumes']: LOG.info(_("%s has no volume."), hostname) -- cgit From 5d5a05bddb59cff6cf5ac1f7104da6030197a9c3 Mon Sep 17 00:00:00 2001 From: Dan Prince Date: Fri, 16 Sep 2011 14:35:10 -0400 Subject: Update test_volumes to use FLAGS.password_length. --- nova/tests/api/openstack/contrib/test_volumes.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/nova/tests/api/openstack/contrib/test_volumes.py b/nova/tests/api/openstack/contrib/test_volumes.py index 443ec399f..52b65f5e1 100644 --- a/nova/tests/api/openstack/contrib/test_volumes.py +++ b/nova/tests/api/openstack/contrib/test_volumes.py @@ -19,6 +19,7 @@ import webob import nova from nova import context +from nova import flags from nova import test from nova.api.openstack.contrib.volumes import BootFromVolumeController from nova.compute import instance_types @@ -26,6 +27,9 @@ from nova.tests.api.openstack import fakes from nova.tests.api.openstack.test_servers import fake_gen_uuid +FLAGS = flags.FLAGS + + def fake_compute_api_create(cls, context, instance_type, image_href, **kwargs): inst_type = instance_types.get_instance_type_by_flavor_id(2) return [{'id': 1, @@ -70,4 +74,4 @@ class BootFromVolumeTest(test.TestCase): self.assertEqual(2, int(server['flavor']['id'])) self.assertEqual(u'test_server', server['name']) self.assertEqual(3, int(server['image']['id'])) - self.assertEqual(16, len(server['adminPass'])) + self.assertEqual(FLAGS.password_length, len(server['adminPass'])) -- cgit From d503671714645115eef0345e9ed1dbb6ff2fb883 Mon Sep 17 00:00:00 2001 From: Jason Koelker Date: Fri, 16 Sep 2011 13:43:31 -0500 Subject: make sure to raise since the tests require it --- nova/compute/manager.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/nova/compute/manager.py b/nova/compute/manager.py index 138e6c58d..694792781 100644 --- a/nova/compute/manager.py +++ b/nova/compute/manager.py @@ -1403,6 +1403,11 @@ class ComputeManager(manager.SchedulerDependentManager): # Retry operation is necessary because continuously request comes, # concorrent request occurs to iptables, then it complains. network_info = self._get_instance_nw_info(context, instance_ref) + + fixed_ips = [nw_info[1]['ips'] for nw_info in network_info] + if not fixed_ips: + raise exception.FixedIpNotFoundForInstance(instance_id=instance_id) + max_retry = FLAGS.live_migration_retry_count for cnt in range(max_retry): try: -- cgit From d468902389d794c97f7dcb678cfac8e9d9b53bce Mon Sep 17 00:00:00 2001 From: Jason Koelker Date: Fri, 16 Sep 2011 13:44:16 -0500 Subject: update tests to return fake_nw_info that is valid for the pre_live_migrate --- nova/tests/test_compute.py | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/nova/tests/test_compute.py b/nova/tests/test_compute.py index 4d463572b..2de2ce38e 100644 --- a/nova/tests/test_compute.py +++ b/nova/tests/test_compute.py @@ -647,7 +647,6 @@ class ComputeTestCase(test.TestCase): dbmock = self.mox.CreateMock(db) dbmock.instance_get(c, i_id).AndReturn(instance_ref) - dbmock.instance_get_fixed_addresses(c, i_id).AndReturn(None) self.compute.db = dbmock self.mox.ReplayAll() @@ -657,6 +656,9 @@ class ComputeTestCase(test.TestCase): def test_pre_live_migration_instance_has_volume(self): """Confirm setup_compute_volume is called when volume is mounted.""" + def fake_nw_info(*args, **kwargs): + return [(0, {'ips':['dummy']})] + i_ref = self._get_dummy_instance() c = context.get_admin_context() @@ -666,13 +668,13 @@ class ComputeTestCase(test.TestCase): drivermock = self.mox.CreateMock(self.compute_driver) dbmock.instance_get(c, i_ref['id']).AndReturn(i_ref) - dbmock.instance_get_fixed_addresses(c, i_ref['id']).AndReturn('dummy') for i in range(len(i_ref['volumes'])): vid = i_ref['volumes'][i]['id'] volmock.setup_compute_volume(c, vid).InAnyOrder('g1') - drivermock.plug_vifs(i_ref, []) - drivermock.ensure_filtering_rules_for_instance(i_ref, []) + drivermock.plug_vifs(i_ref, fake_nw_info()) + drivermock.ensure_filtering_rules_for_instance(i_ref, fake_nw_info()) + self.stubs.Set(self.compute, '_get_instance_nw_info', fake_nw_info) self.compute.db = dbmock self.compute.volume_manager = volmock self.compute.driver = drivermock @@ -683,6 +685,9 @@ class ComputeTestCase(test.TestCase): def test_pre_live_migration_instance_has_no_volume(self): """Confirm log meg when instance doesn't mount any volumes.""" + def fake_nw_info(*args, **kwargs): + return [(0, {'ips':['dummy']})] + i_ref = self._get_dummy_instance() i_ref['volumes'] = [] c = context.get_admin_context() @@ -692,12 +697,12 @@ class ComputeTestCase(test.TestCase): drivermock = self.mox.CreateMock(self.compute_driver) dbmock.instance_get(c, i_ref['id']).AndReturn(i_ref) - dbmock.instance_get_fixed_addresses(c, i_ref['id']).AndReturn('dummy') self.mox.StubOutWithMock(compute_manager.LOG, 'info') compute_manager.LOG.info(_("%s has no volume."), i_ref['hostname']) - drivermock.plug_vifs(i_ref, []) - drivermock.ensure_filtering_rules_for_instance(i_ref, []) + drivermock.plug_vifs(i_ref, fake_nw_info()) + drivermock.ensure_filtering_rules_for_instance(i_ref, fake_nw_info()) + self.stubs.Set(self.compute, '_get_instance_nw_info', fake_nw_info) self.compute.db = dbmock self.compute.driver = drivermock @@ -711,6 +716,9 @@ class ComputeTestCase(test.TestCase): It retries and raise exception when timeout exceeded. """ + def fake_nw_info(*args, **kwargs): + return [(0, {'ips':['dummy']})] + i_ref = self._get_dummy_instance() c = context.get_admin_context() @@ -722,13 +730,13 @@ class ComputeTestCase(test.TestCase): drivermock = self.mox.CreateMock(self.compute_driver) dbmock.instance_get(c, i_ref['id']).AndReturn(i_ref) - dbmock.instance_get_fixed_addresses(c, i_ref['id']).AndReturn('dummy') for i in range(len(i_ref['volumes'])): volmock.setup_compute_volume(c, i_ref['volumes'][i]['id']) for i in range(FLAGS.live_migration_retry_count): - drivermock.plug_vifs(i_ref, []).\ + drivermock.plug_vifs(i_ref, fake_nw_info()).\ AndRaise(exception.ProcessExecutionError()) + self.stubs.Set(self.compute, '_get_instance_nw_info', fake_nw_info) self.compute.db = dbmock self.compute.network_manager = netmock self.compute.volume_manager = volmock -- cgit From 364802336339eee72fdacd0ee2935822f7bfdc93 Mon Sep 17 00:00:00 2001 From: Jason Koelker Date: Fri, 16 Sep 2011 13:52:06 -0500 Subject: pep8 --- nova/tests/test_compute.py | 1 - 1 file changed, 1 deletion(-) diff --git a/nova/tests/test_compute.py b/nova/tests/test_compute.py index 2de2ce38e..2fd812cf9 100644 --- a/nova/tests/test_compute.py +++ b/nova/tests/test_compute.py @@ -719,7 +719,6 @@ class ComputeTestCase(test.TestCase): def fake_nw_info(*args, **kwargs): return [(0, {'ips':['dummy']})] - i_ref = self._get_dummy_instance() c = context.get_admin_context() -- cgit From 2d3027da762cdac0c5a12adee15d1bb28fb7bf10 Mon Sep 17 00:00:00 2001 From: Soren Hansen Date: Fri, 16 Sep 2011 21:27:25 +0200 Subject: Fix failing test. --- nova/tests/test_libvirt.py | 8 -------- 1 file changed, 8 deletions(-) diff --git a/nova/tests/test_libvirt.py b/nova/tests/test_libvirt.py index 769bc5291..b7c1ef1ab 100644 --- a/nova/tests/test_libvirt.py +++ b/nova/tests/test_libvirt.py @@ -1008,10 +1008,6 @@ class IptablesFirewallTestCase(test.TestCase): 'to_port': 81, 'group_id': src_secgroup['id']}) - db.security_group_rule_create(admin_ctxt, - {'parent_group_id': secgroup['id'], - 'group_id': src_secgroup['id']}) - db.instance_add_security_group(admin_ctxt, instance_ref['id'], secgroup['id']) db.instance_add_security_group(admin_ctxt, src_instance_ref['id'], @@ -1094,10 +1090,6 @@ class IptablesFirewallTestCase(test.TestCase): self.assertTrue(len(filter(regex.match, self.out_rules)) > 0, "TCP port 80/81 acceptance rule wasn't added") - regex = re.compile('-A .* -j ACCEPT -s %s' % (src_ip,)) - self.assertTrue(len(filter(regex.match, self.out_rules)) > 0, - "TCP port 80/81 acceptance rule wasn't added") - regex = re.compile('-A .* -j ACCEPT -p tcp ' '-m multiport --dports 80:81 -s 192.168.10.0/24') self.assertTrue(len(filter(regex.match, self.out_rules)) > 0, -- cgit From ad11c1c92d39d14c72ec5bf10394fca9021d87ce Mon Sep 17 00:00:00 2001 From: Christopher MacGown Date: Sat, 17 Sep 2011 13:05:42 -0700 Subject: Fix user_id, project_id reference for config_drive with imageRefs --- nova/tests/test_compute.py | 14 ++++++++++++++ nova/virt/libvirt/connection.py | 4 ++-- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/nova/tests/test_compute.py b/nova/tests/test_compute.py index 65fdffbd6..d5ee25e8c 100644 --- a/nova/tests/test_compute.py +++ b/nova/tests/test_compute.py @@ -174,6 +174,20 @@ class ComputeTestCase(test.TestCase): self.assertEqual(pre_build_len, len(db.instance_get_all(context.get_admin_context()))) + def test_create_instance_with_img_ref_associates_config_drive(self): + """Make sure create associates a config drive.""" + + instance_id = self._create_instance(params={'config_drive': '1234', }) + + try: + self.compute.run_instance(self.context, instance_id) + instances = db.instance_get_all(context.get_admin_context()) + instance = instances[0] + + self.assertTrue(instance.config_drive) + finally: + db.instance_destroy(self.context, instance_id) + def test_create_instance_associates_config_drive(self): """Make sure create associates a config drive.""" diff --git a/nova/virt/libvirt/connection.py b/nova/virt/libvirt/connection.py index 363a20ed0..78f9c8ac3 100644 --- a/nova/virt/libvirt/connection.py +++ b/nova/virt/libvirt/connection.py @@ -908,8 +908,8 @@ class LibvirtConnection(driver.ComputeDriver): target=basepath('disk.config'), fname=fname, image_id=config_drive_id, - user=user, - project=project) + user_id=inst['user_id'], + project_id=inst['project_id'],) elif config_drive: self._create_local(basepath('disk.config'), 64, prefix="M", fs_format='msdos') # 64MB -- cgit