diff options
36 files changed, 298 insertions, 89 deletions
diff --git a/doc/api_samples/os-coverage/coverage-report-post-req.json b/doc/api_samples/os-coverage/coverage-report-post-req.json new file mode 100644 index 000000000..cb16cfc85 --- /dev/null +++ b/doc/api_samples/os-coverage/coverage-report-post-req.json @@ -0,0 +1,5 @@ +{ + "report" : { + "file" : "report" + } +}
\ No newline at end of file diff --git a/doc/api_samples/os-coverage/coverage-report-post-req.xml b/doc/api_samples/os-coverage/coverage-report-post-req.xml new file mode 100644 index 000000000..1cc9b7433 --- /dev/null +++ b/doc/api_samples/os-coverage/coverage-report-post-req.xml @@ -0,0 +1,4 @@ +<?xml version="1.0" encoding="UTF-8"?> +<report> + <file>report</file> +</report>
\ No newline at end of file diff --git a/doc/api_samples/os-coverage/coverage-report-post-resp.json b/doc/api_samples/os-coverage/coverage-report-post-resp.json new file mode 100644 index 000000000..e7db3076a --- /dev/null +++ b/doc/api_samples/os-coverage/coverage-report-post-resp.json @@ -0,0 +1,3 @@ +{ + "path": "/tmp/tmpV0Pno7/nova-coverage_D8L8SB/report" +}
\ No newline at end of file diff --git a/doc/api_samples/os-coverage/coverage-report-post-resp.xml b/doc/api_samples/os-coverage/coverage-report-post-resp.xml new file mode 100644 index 000000000..8b7188ad0 --- /dev/null +++ b/doc/api_samples/os-coverage/coverage-report-post-resp.xml @@ -0,0 +1,2 @@ +<?xml version='1.0' encoding='UTF-8'?> +<path>/tmp/tmpAqRtz5/nova-coverage_Iqja9E/report</path>
\ No newline at end of file diff --git a/doc/api_samples/os-coverage/coverage-start-combine-post-req.json b/doc/api_samples/os-coverage/coverage-start-combine-post-req.json new file mode 100644 index 000000000..6d41ba598 --- /dev/null +++ b/doc/api_samples/os-coverage/coverage-start-combine-post-req.json @@ -0,0 +1,5 @@ +{ + "start" : { + "combine": true + } +}
\ No newline at end of file diff --git a/doc/api_samples/os-coverage/coverage-start-combine-post-req.xml b/doc/api_samples/os-coverage/coverage-start-combine-post-req.xml new file mode 100644 index 000000000..10489b3be --- /dev/null +++ b/doc/api_samples/os-coverage/coverage-start-combine-post-req.xml @@ -0,0 +1,4 @@ +<?xml version="1.0" encoding="UTF-8"?> +<start> + <combine>True</combine> +</start>
\ No newline at end of file diff --git a/doc/api_samples/os-coverage/coverage-start-post-req.json b/doc/api_samples/os-coverage/coverage-start-post-req.json new file mode 100644 index 000000000..8e5ef033c --- /dev/null +++ b/doc/api_samples/os-coverage/coverage-start-post-req.json @@ -0,0 +1,4 @@ +{ + "start" : { + } +}
\ No newline at end of file diff --git a/doc/api_samples/os-coverage/coverage-start-post-req.xml b/doc/api_samples/os-coverage/coverage-start-post-req.xml new file mode 100644 index 000000000..398971d54 --- /dev/null +++ b/doc/api_samples/os-coverage/coverage-start-post-req.xml @@ -0,0 +1,2 @@ +<?xml version="1.0" encoding="UTF-8"?> +<start></start>
\ No newline at end of file diff --git a/doc/api_samples/os-coverage/coverage-stop-post-req.json b/doc/api_samples/os-coverage/coverage-stop-post-req.json new file mode 100644 index 000000000..57de88191 --- /dev/null +++ b/doc/api_samples/os-coverage/coverage-stop-post-req.json @@ -0,0 +1,4 @@ +{ + "stop" : { + } +}
\ No newline at end of file diff --git a/doc/api_samples/os-coverage/coverage-stop-post-req.xml b/doc/api_samples/os-coverage/coverage-stop-post-req.xml new file mode 100644 index 000000000..7092c81e2 --- /dev/null +++ b/doc/api_samples/os-coverage/coverage-stop-post-req.xml @@ -0,0 +1,2 @@ +<?xml version="1.0" encoding="UTF-8"?> +<stop></stop>
\ No newline at end of file diff --git a/doc/api_samples/os-coverage/coverage-xml-report-post-req.json b/doc/api_samples/os-coverage/coverage-xml-report-post-req.json new file mode 100644 index 000000000..bcbe0c4a0 --- /dev/null +++ b/doc/api_samples/os-coverage/coverage-xml-report-post-req.json @@ -0,0 +1,6 @@ +{ + "report": { + "xml": true, + "file": "report" + } +} diff --git a/doc/api_samples/os-coverage/coverage-xml-report-post-req.xml b/doc/api_samples/os-coverage/coverage-xml-report-post-req.xml new file mode 100644 index 000000000..62e5bc6f4 --- /dev/null +++ b/doc/api_samples/os-coverage/coverage-xml-report-post-req.xml @@ -0,0 +1,5 @@ +<?xml version="1.0" encoding="UTF-8"?> +<report> + <file>report</file> + <xml>True</xml> +</report>
\ No newline at end of file diff --git a/doc/api_samples/os-coverage/coverage-xml-report-post-resp.json b/doc/api_samples/os-coverage/coverage-xml-report-post-resp.json new file mode 100644 index 000000000..0648b2ebc --- /dev/null +++ b/doc/api_samples/os-coverage/coverage-xml-report-post-resp.json @@ -0,0 +1,3 @@ +{ + "path": "/tmp/tmp6kdYaa/nova-coverage_TOTUbz/report" +}
\ No newline at end of file diff --git a/doc/api_samples/os-coverage/coverage-xml-report-post-resp.xml b/doc/api_samples/os-coverage/coverage-xml-report-post-resp.xml new file mode 100644 index 000000000..72f584003 --- /dev/null +++ b/doc/api_samples/os-coverage/coverage-xml-report-post-resp.xml @@ -0,0 +1,2 @@ +<?xml version='1.0' encoding='UTF-8'?> +<path>/tmp/tmp4j87bp/nova-coverage_7ViTA7/report</path>
\ No newline at end of file diff --git a/nova/locale/nova.pot b/nova/locale/nova.pot index 4aab88bdd..af5c0fc32 100644 --- a/nova/locale/nova.pot +++ b/nova/locale/nova.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: nova 2013.1\n" "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" -"POT-Creation-Date: 2012-12-24 00:02+0000\n" +"POT-Creation-Date: 2012-12-27 00:01+0000\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Language-Team: LANGUAGE <LL@li.org>\n" @@ -5930,7 +5930,7 @@ msgstr "" msgid "The ISCSI initiator name can't be found. Choosing the default one" msgstr "" -#: nova/virt/hyperv/basevolumeutils.py:79 nova/virt/libvirt/driver.py:1510 +#: nova/virt/hyperv/basevolumeutils.py:79 nova/virt/libvirt/driver.py:1494 #: nova/virt/xenapi/vm_utils.py:504 #, python-format msgid "block_device_list %s" @@ -5979,7 +5979,7 @@ msgstr "" msgid "get_available_resource called" msgstr "" -#: nova/virt/hyperv/hostops.py:163 nova/virt/libvirt/driver.py:3173 +#: nova/virt/hyperv/hostops.py:163 nova/virt/libvirt/driver.py:3179 #: nova/virt/xenapi/host.py:149 msgid "Updating host stats" msgstr "" @@ -6163,16 +6163,16 @@ msgstr "" msgid "Invalid config_drive_format \"%s\"" msgstr "" -#: nova/virt/hyperv/vmops.py:183 nova/virt/libvirt/driver.py:1443 +#: nova/virt/hyperv/vmops.py:183 nova/virt/libvirt/driver.py:1432 msgid "Using config drive" msgstr "" -#: nova/virt/hyperv/vmops.py:194 nova/virt/libvirt/driver.py:1453 +#: nova/virt/hyperv/vmops.py:194 nova/virt/libvirt/driver.py:1442 #, python-format msgid "Creating config drive at %(path)s" msgstr "" -#: nova/virt/hyperv/vmops.py:201 nova/virt/libvirt/driver.py:1458 +#: nova/virt/hyperv/vmops.py:201 nova/virt/libvirt/driver.py:1447 #, python-format msgid "Creating config drive failed with error: %s" msgstr "" @@ -6424,7 +6424,7 @@ msgstr "" msgid "Failed to remove volume from VM %s" msgstr "" -#: nova/virt/hyperv/volumeops.py:228 nova/virt/libvirt/driver.py:629 +#: nova/virt/hyperv/volumeops.py:228 nova/virt/libvirt/driver.py:624 msgid "Could not determine iscsi initiator name" msgstr "" @@ -6594,183 +6594,183 @@ msgstr "" msgid "Deleting instance files %(target)s" msgstr "" -#: nova/virt/libvirt/driver.py:592 +#: nova/virt/libvirt/driver.py:587 #, python-format msgid "Failed to cleanup directory %(target)s: %(e)s" msgstr "" -#: nova/virt/libvirt/driver.py:752 +#: nova/virt/libvirt/driver.py:747 msgid "During detach_volume, instance disappeared." msgstr "" -#: nova/virt/libvirt/driver.py:762 +#: nova/virt/libvirt/driver.py:757 msgid "attaching LXC block device" msgstr "" -#: nova/virt/libvirt/driver.py:782 +#: nova/virt/libvirt/driver.py:777 msgid "detaching LXC block device" msgstr "" -#: nova/virt/libvirt/driver.py:914 +#: nova/virt/libvirt/driver.py:909 msgid "Instance soft rebooted successfully." msgstr "" -#: nova/virt/libvirt/driver.py:918 +#: nova/virt/libvirt/driver.py:913 msgid "Failed to soft reboot instance." msgstr "" -#: nova/virt/libvirt/driver.py:950 +#: nova/virt/libvirt/driver.py:945 msgid "Instance shutdown successfully." msgstr "" -#: nova/virt/libvirt/driver.py:986 +#: nova/virt/libvirt/driver.py:981 msgid "Instance rebooted successfully." msgstr "" -#: nova/virt/libvirt/driver.py:1114 +#: nova/virt/libvirt/driver.py:1109 msgid "Instance is running" msgstr "" -#: nova/virt/libvirt/driver.py:1121 nova/virt/powervm/operator.py:255 +#: nova/virt/libvirt/driver.py:1116 nova/virt/powervm/operator.py:255 msgid "Instance spawned successfully." msgstr "" -#: nova/virt/libvirt/driver.py:1137 +#: nova/virt/libvirt/driver.py:1132 #, python-format msgid "data: %(data)r, fpath: %(fpath)r" msgstr "" -#: nova/virt/libvirt/driver.py:1175 nova/virt/libvirt/driver.py:1201 +#: nova/virt/libvirt/driver.py:1170 nova/virt/libvirt/driver.py:1196 #, python-format msgid "Truncated console log returned, %d bytes ignored" msgstr "" -#: nova/virt/libvirt/driver.py:1190 +#: nova/virt/libvirt/driver.py:1185 msgid "Guest does not have a console available" msgstr "" -#: nova/virt/libvirt/driver.py:1239 +#: nova/virt/libvirt/driver.py:1234 #, python-format msgid "Path '%(path)s' supports direct I/O" msgstr "" -#: nova/virt/libvirt/driver.py:1243 +#: nova/virt/libvirt/driver.py:1238 #, python-format msgid "Path '%(path)s' does not support direct I/O: '%(ex)s'" msgstr "" -#: nova/virt/libvirt/driver.py:1247 nova/virt/libvirt/driver.py:1251 +#: nova/virt/libvirt/driver.py:1242 nova/virt/libvirt/driver.py:1246 #, python-format msgid "Error on '%(path)s' while checking direct I/O: '%(ex)s'" msgstr "" -#: nova/virt/libvirt/driver.py:1317 +#: nova/virt/libvirt/driver.py:1312 msgid "Creating image" msgstr "" -#: nova/virt/libvirt/driver.py:1473 +#: nova/virt/libvirt/driver.py:1462 #, python-format msgid "Injecting %(injection)s into image %(img_id)s" msgstr "" -#: nova/virt/libvirt/driver.py:1483 +#: nova/virt/libvirt/driver.py:1472 #, python-format msgid "Ignoring error injecting data into image %(img_id)s (%(e)s)" msgstr "" -#: nova/virt/libvirt/driver.py:1562 +#: nova/virt/libvirt/driver.py:1546 #, python-format msgid "" "Config requested an explicit CPU model, but the current libvirt " "hypervisor '%s' does not support selecting CPU models" msgstr "" -#: nova/virt/libvirt/driver.py:1568 +#: nova/virt/libvirt/driver.py:1552 msgid "Config requested a custom CPU model, but no model name was provided" msgstr "" -#: nova/virt/libvirt/driver.py:1572 +#: nova/virt/libvirt/driver.py:1556 msgid "A CPU model name should not be set when a host CPU model is requested" msgstr "" -#: nova/virt/libvirt/driver.py:1576 +#: nova/virt/libvirt/driver.py:1560 #, python-format msgid "CPU mode '%(mode)s' model '%(model)s' was chosen" msgstr "" -#: nova/virt/libvirt/driver.py:1592 +#: nova/virt/libvirt/driver.py:1576 msgid "" "Passthrough of the host CPU was requested but this libvirt version does " "not support this feature" msgstr "" -#: nova/virt/libvirt/driver.py:1909 +#: nova/virt/libvirt/driver.py:1893 msgid "Starting toXML method" msgstr "" -#: nova/virt/libvirt/driver.py:1913 +#: nova/virt/libvirt/driver.py:1897 msgid "Finished toXML method" msgstr "" -#: nova/virt/libvirt/driver.py:1930 +#: nova/virt/libvirt/driver.py:1914 #, python-format msgid "" "Error from libvirt while looking up %(instance_name)s: [Error Code " "%(error_code)s] %(ex)s" msgstr "" -#: nova/virt/libvirt/driver.py:2062 +#: nova/virt/libvirt/driver.py:2068 msgid "" "Cannot get the number of cpu, because this function is not implemented " "for this platform. " msgstr "" -#: nova/virt/libvirt/driver.py:2179 +#: nova/virt/libvirt/driver.py:2185 msgid "libvirt version is too old (does not support getVersion)" msgstr "" -#: nova/virt/libvirt/driver.py:2262 +#: nova/virt/libvirt/driver.py:2268 #, python-format msgid "Trying to get stats for the volume %s" msgstr "" -#: nova/virt/libvirt/driver.py:2286 +#: nova/virt/libvirt/driver.py:2292 #, python-format msgid "" "Getting block stats failed, device might have been detached. " "Code=%(errcode)s Error=%(e)s" msgstr "" -#: nova/virt/libvirt/driver.py:2290 +#: nova/virt/libvirt/driver.py:2296 #, python-format msgid "" "Could not find domain in libvirt for instance %s. Cannot get block stats " "for device" msgstr "" -#: nova/virt/libvirt/driver.py:2406 +#: nova/virt/libvirt/driver.py:2412 msgid "Block migration can not be used with shared storage." msgstr "" -#: nova/virt/libvirt/driver.py:2414 +#: nova/virt/libvirt/driver.py:2420 msgid "Live migration can not be used without shared storage." msgstr "" -#: nova/virt/libvirt/driver.py:2451 +#: nova/virt/libvirt/driver.py:2457 #, python-format msgid "" "Unable to migrate %(instance_uuid)s: Disk of instance is too " "large(available on destination host:%(available)s < need:%(necessary)s)" msgstr "" -#: nova/virt/libvirt/driver.py:2476 +#: nova/virt/libvirt/driver.py:2482 #, python-format msgid "" "Instance launched has CPU info:\n" "%s" msgstr "" -#: nova/virt/libvirt/driver.py:2488 +#: nova/virt/libvirt/driver.py:2494 #, python-format msgid "" "CPU doesn't have compatibility.\n" @@ -6780,51 +6780,51 @@ msgid "" "Refer to %(u)s" msgstr "" -#: nova/virt/libvirt/driver.py:2505 +#: nova/virt/libvirt/driver.py:2511 #, python-format msgid "" "Creating tmpfile %s to notify to other compute nodes that they should " "mount the same storage." msgstr "" -#: nova/virt/libvirt/driver.py:2553 +#: nova/virt/libvirt/driver.py:2559 #, python-format msgid "The firewall filter for %s does not exist" msgstr "" -#: nova/virt/libvirt/driver.py:2625 +#: nova/virt/libvirt/driver.py:2631 #, python-format msgid "Live Migration failure: %(e)s" msgstr "" -#: nova/virt/libvirt/driver.py:2715 +#: nova/virt/libvirt/driver.py:2721 #, python-format msgid "plug_vifs() failed %(cnt)d.Retry up to %(max_retry)d for %(hostname)s." msgstr "" -#: nova/virt/libvirt/driver.py:2830 +#: nova/virt/libvirt/driver.py:2836 #, python-format msgid "skipping %(path)s since it looks like volume" msgstr "" -#: nova/virt/libvirt/driver.py:2879 +#: nova/virt/libvirt/driver.py:2885 #, python-format msgid "Getting disk size of %(i_name)s: %(e)s" msgstr "" -#: nova/virt/libvirt/driver.py:2928 +#: nova/virt/libvirt/driver.py:2934 msgid "Starting migrate_disk_and_power_off" msgstr "" -#: nova/virt/libvirt/driver.py:2987 +#: nova/virt/libvirt/driver.py:2993 msgid "Instance running successfully." msgstr "" -#: nova/virt/libvirt/driver.py:2994 +#: nova/virt/libvirt/driver.py:3000 msgid "Starting finish_migration" msgstr "" -#: nova/virt/libvirt/driver.py:3045 +#: nova/virt/libvirt/driver.py:3051 msgid "Starting finish_revert_migration" msgstr "" diff --git a/nova/tests/api/openstack/compute/test_servers.py b/nova/tests/api/openstack/compute/test_servers.py index 15be74d15..d32640bf2 100644 --- a/nova/tests/api/openstack/compute/test_servers.py +++ b/nova/tests/api/openstack/compute/test_servers.py @@ -1520,9 +1520,9 @@ class ServersControllerTest(test.TestCase): self.assertEqual(s['hostId'], host_ids[i % 2]) self.assertEqual(s['name'], 'server%d' % (i + 1)) - def test_delete_server_instance(self): + def _delete_server_instance(self, uuid=FAKE_UUID): fakes.stub_out_instance_quota(self.stubs, 0, 10) - req = fakes.HTTPRequest.blank('/v2/fake/servers/%s' % FAKE_UUID) + req = fakes.HTTPRequest.blank('/v2/fake/servers/%s' % uuid) req.method = 'DELETE' self.server_delete_called = False @@ -1534,10 +1534,17 @@ class ServersControllerTest(test.TestCase): self.server_delete_called = True self.stubs.Set(db, 'instance_destroy', instance_destroy_mock) - self.controller.delete(req, FAKE_UUID) + self.controller.delete(req, uuid) + def test_delete_server_instance(self): + self._delete_server_instance() self.assertEqual(self.server_delete_called, True) + def test_delete_server_instance_not_found(self): + self.assertRaises(webob.exc.HTTPNotFound, + self._delete_server_instance, + uuid='non-existent-uuid') + def test_delete_server_instance_while_building(self): fakes.stub_out_instance_quota(self.stubs, 0, 10) req = fakes.HTTPRequest.blank('/v2/fake/servers/%s' % FAKE_UUID) diff --git a/nova/tests/integrated/api_samples/os-coverage/coverage-report-post-req.json.tpl b/nova/tests/integrated/api_samples/os-coverage/coverage-report-post-req.json.tpl new file mode 100644 index 000000000..c228b05f0 --- /dev/null +++ b/nova/tests/integrated/api_samples/os-coverage/coverage-report-post-req.json.tpl @@ -0,0 +1,5 @@ +{ + "report" : { + "file" : "%(filename)s" + } +} diff --git a/nova/tests/integrated/api_samples/os-coverage/coverage-report-post-req.xml.tpl b/nova/tests/integrated/api_samples/os-coverage/coverage-report-post-req.xml.tpl new file mode 100644 index 000000000..02b8fc97c --- /dev/null +++ b/nova/tests/integrated/api_samples/os-coverage/coverage-report-post-req.xml.tpl @@ -0,0 +1,4 @@ +<?xml version="1.0" encoding="UTF-8"?> +<report> + <file>%(filename)s</file> +</report> diff --git a/nova/tests/integrated/api_samples/os-coverage/coverage-report-post-resp.json.tpl b/nova/tests/integrated/api_samples/os-coverage/coverage-report-post-resp.json.tpl new file mode 100644 index 000000000..6cdd1f37d --- /dev/null +++ b/nova/tests/integrated/api_samples/os-coverage/coverage-report-post-resp.json.tpl @@ -0,0 +1,3 @@ +{ + "path" : "%(path)s" +} diff --git a/nova/tests/integrated/api_samples/os-coverage/coverage-report-post-resp.xml.tpl b/nova/tests/integrated/api_samples/os-coverage/coverage-report-post-resp.xml.tpl new file mode 100644 index 000000000..51b9773d3 --- /dev/null +++ b/nova/tests/integrated/api_samples/os-coverage/coverage-report-post-resp.xml.tpl @@ -0,0 +1,2 @@ +<?xml version="1.0" encoding="UTF-8"?> +<path>%(path)s</path> diff --git a/nova/tests/integrated/api_samples/os-coverage/coverage-start-combine-post-req.json.tpl b/nova/tests/integrated/api_samples/os-coverage/coverage-start-combine-post-req.json.tpl new file mode 100644 index 000000000..296049df9 --- /dev/null +++ b/nova/tests/integrated/api_samples/os-coverage/coverage-start-combine-post-req.json.tpl @@ -0,0 +1,5 @@ +{ + "start" : { + "combine": true + } +} diff --git a/nova/tests/integrated/api_samples/os-coverage/coverage-start-combine-post-req.xml.tpl b/nova/tests/integrated/api_samples/os-coverage/coverage-start-combine-post-req.xml.tpl new file mode 100644 index 000000000..11bdb44f9 --- /dev/null +++ b/nova/tests/integrated/api_samples/os-coverage/coverage-start-combine-post-req.xml.tpl @@ -0,0 +1,4 @@ +<?xml version="1.0" encoding="UTF-8"?> +<start> + <combine>True</combine> +</start> diff --git a/nova/tests/integrated/api_samples/os-coverage/coverage-start-post-req.json.tpl b/nova/tests/integrated/api_samples/os-coverage/coverage-start-post-req.json.tpl new file mode 100644 index 000000000..a046b9207 --- /dev/null +++ b/nova/tests/integrated/api_samples/os-coverage/coverage-start-post-req.json.tpl @@ -0,0 +1,4 @@ +{ + "start" : { + } +} diff --git a/nova/tests/integrated/api_samples/os-coverage/coverage-start-post-req.xml.tpl b/nova/tests/integrated/api_samples/os-coverage/coverage-start-post-req.xml.tpl new file mode 100644 index 000000000..aeaff102a --- /dev/null +++ b/nova/tests/integrated/api_samples/os-coverage/coverage-start-post-req.xml.tpl @@ -0,0 +1,2 @@ +<?xml version="1.0" encoding="UTF-8"?> +<start></start> diff --git a/nova/tests/integrated/api_samples/os-coverage/coverage-stop-post-req.json.tpl b/nova/tests/integrated/api_samples/os-coverage/coverage-stop-post-req.json.tpl new file mode 100644 index 000000000..c46e49cca --- /dev/null +++ b/nova/tests/integrated/api_samples/os-coverage/coverage-stop-post-req.json.tpl @@ -0,0 +1,4 @@ +{ + "stop" : { + } +} diff --git a/nova/tests/integrated/api_samples/os-coverage/coverage-stop-post-req.xml.tpl b/nova/tests/integrated/api_samples/os-coverage/coverage-stop-post-req.xml.tpl new file mode 100644 index 000000000..1dd5c7bc7 --- /dev/null +++ b/nova/tests/integrated/api_samples/os-coverage/coverage-stop-post-req.xml.tpl @@ -0,0 +1,2 @@ +<?xml version="1.0" encoding="UTF-8"?> +<stop></stop> diff --git a/nova/tests/integrated/api_samples/os-coverage/coverage-xml-report-post-req.json.tpl b/nova/tests/integrated/api_samples/os-coverage/coverage-xml-report-post-req.json.tpl new file mode 100644 index 000000000..906d629ed --- /dev/null +++ b/nova/tests/integrated/api_samples/os-coverage/coverage-xml-report-post-req.json.tpl @@ -0,0 +1,6 @@ +{ + "report": { + "xml": true, + "file": "%(filename)s" + } +} diff --git a/nova/tests/integrated/api_samples/os-coverage/coverage-xml-report-post-req.xml.tpl b/nova/tests/integrated/api_samples/os-coverage/coverage-xml-report-post-req.xml.tpl new file mode 100644 index 000000000..902e0e537 --- /dev/null +++ b/nova/tests/integrated/api_samples/os-coverage/coverage-xml-report-post-req.xml.tpl @@ -0,0 +1,5 @@ +<?xml version="1.0" encoding="UTF-8"?> +<report> + <file>%(filename)s</file> + <xml>True</xml> +</report> diff --git a/nova/tests/integrated/api_samples/os-coverage/coverage-xml-report-post-resp.json.tpl b/nova/tests/integrated/api_samples/os-coverage/coverage-xml-report-post-resp.json.tpl new file mode 100644 index 000000000..6cdd1f37d --- /dev/null +++ b/nova/tests/integrated/api_samples/os-coverage/coverage-xml-report-post-resp.json.tpl @@ -0,0 +1,3 @@ +{ + "path" : "%(path)s" +} diff --git a/nova/tests/integrated/api_samples/os-coverage/coverage-xml-report-post-resp.xml.tpl b/nova/tests/integrated/api_samples/os-coverage/coverage-xml-report-post-resp.xml.tpl new file mode 100644 index 000000000..65f5e16bc --- /dev/null +++ b/nova/tests/integrated/api_samples/os-coverage/coverage-xml-report-post-resp.xml.tpl @@ -0,0 +1,2 @@ +<?xml version='1.0' encoding='UTF-8'?> +<path>%(path)s</path> diff --git a/nova/tests/integrated/test_api_samples.py b/nova/tests/integrated/test_api_samples.py index a33b39da4..a8099a6bb 100644 --- a/nova/tests/integrated/test_api_samples.py +++ b/nova/tests/integrated/test_api_samples.py @@ -21,8 +21,10 @@ import re import urllib import uuid as uuid_lib +from coverage import coverage from lxml import etree +from nova.api.openstack.compute.contrib import coverage_ext # Import extensions to pull in osapi_compute_extension CONF option used below. from nova.api.openstack.compute import extensions from nova.cloudpipe.pipelib import CloudPipe @@ -353,7 +355,6 @@ class ApiSamplesTrap(ApiSampleTestBase): do_not_approve_additions.append('NMN') do_not_approve_additions.append('OS-FLV-DISABLED') do_not_approve_additions.append('os-config-drive') - do_not_approve_additions.append('os-coverage') do_not_approve_additions.append('os-create-server-ext') do_not_approve_additions.append('os-fixed-ips') do_not_approve_additions.append('os-flavor-access') @@ -729,6 +730,74 @@ class LimitsSampleXmlTest(LimitsSampleJsonTest): ctype = 'xml' +class CoverageExtJsonTests(ApiSampleTestBase): + extension_name = ("nova.api.openstack.compute.contrib.coverage_ext." + "Coverage_ext") + + def setUp(self): + super(CoverageExtJsonTests, self).setUp() + + def _fake_check_coverage(self): + return False + + def _fake_xml_report(self, outfile=None): + return + + self.stubs.Set(coverage_ext.CoverageController, '_check_coverage', + _fake_check_coverage) + self.stubs.Set(coverage, 'xml_report', _fake_xml_report) + + def test_start_coverage(self): + """Start coverage data collection""" + subs = {} + response = self._do_post('os-coverage/action', + 'coverage-start-post-req', subs) + self.assertEqual(response.status, 200) + + def test_start_coverage_combine(self): + """Start coverage data collection""" + subs = {} + response = self._do_post('os-coverage/action', + 'coverage-start-combine-post-req', subs) + self.assertEqual(response.status, 200) + + def test_stop_coverage(self): + """Stop coverage data collection""" + subs = {} + response = self._do_post('os-coverage/action', + 'coverage-stop-post-req', subs) + self.assertEqual(response.status, 200) + + def test_report_coverage(self): + """Generate a coverage report""" + subs = { + 'filename': 'report', + 'path': '/.*/report', + } + response = self._do_post('os-coverage/action', + 'coverage-report-post-req', subs) + self.assertEqual(response.status, 200) + subs.update(self._get_regexes()) + return self._verify_response('coverage-report-post-resp', + subs, response) + + def test_xml_report_coverage(self): + subs = { + 'filename': 'report', + 'path': '/.*/report', + } + response = self._do_post('os-coverage/action', + 'coverage-xml-report-post-req', subs) + self.assertEqual(response.status, 200) + subs.update(self._get_regexes()) + return self._verify_response('coverage-xml-report-post-resp', + subs, response) + + +class CoverageExtXmlTests(CoverageExtJsonTests): + ctype = "xml" + + class ServersActionsJsonTest(ServersSampleBase): def _test_server_action(self, uuid, action, subs={}, resp_tpl=None, code=202): diff --git a/nova/tests/test_libvirt.py b/nova/tests/test_libvirt.py index 6dcf49803..c1016f1f4 100644 --- a/nova/tests/test_libvirt.py +++ b/nova/tests/test_libvirt.py @@ -4213,7 +4213,7 @@ class LibvirtDriverTestCase(test.TestCase): block_device_info=None): pass - def fake_create_domain(xml): + def fake_create_domain(xml, inst_name=''): return None def fake_enable_hairpin(instance): @@ -4259,7 +4259,7 @@ class LibvirtDriverTestCase(test.TestCase): def fake_plug_vifs(instance, network_info): pass - def fake_create_domain(xml): + def fake_create_domain(xml, inst_name=''): return None def fake_enable_hairpin(instance): diff --git a/nova/tests/test_virt.py b/nova/tests/test_virt.py index 99d69f33f..452277c54 100644 --- a/nova/tests/test_virt.py +++ b/nova/tests/test_virt.py @@ -95,7 +95,7 @@ class TestVirtDisk(test.TestCase): self.stubs.Set(utils, 'execute', fake_execute) - def test_lxc_destroy_container(self): + def test_lxc_teardown_container(self): def proc_mounts(self, mount_point): mount_points = { @@ -110,26 +110,26 @@ class TestVirtDisk(test.TestCase): self.stubs.Set(disk_api._DiskImage, '_device_for_path', proc_mounts) expected_commands = [] - disk_api.destroy_container('/mnt/loop/nopart') + disk_api.teardown_container('/mnt/loop/nopart') expected_commands += [ ('umount', '/dev/loop0'), ('losetup', '--detach', '/dev/loop0'), ] - disk_api.destroy_container('/mnt/loop/part') + disk_api.teardown_container('/mnt/loop/part') expected_commands += [ ('umount', '/dev/mapper/loop0p1'), ('kpartx', '-d', '/dev/loop0'), ('losetup', '--detach', '/dev/loop0'), ] - disk_api.destroy_container('/mnt/nbd/nopart') + disk_api.teardown_container('/mnt/nbd/nopart') expected_commands += [ ('umount', '/dev/nbd15'), ('qemu-nbd', '-d', '/dev/nbd15'), ] - disk_api.destroy_container('/mnt/nbd/part') + disk_api.teardown_container('/mnt/nbd/part') expected_commands += [ ('umount', '/dev/mapper/nbd15p1'), ('kpartx', '-d', '/dev/nbd15'), diff --git a/nova/tests/test_virt_disk.py b/nova/tests/test_virt_disk.py index 1177aef6f..902d49704 100644 --- a/nova/tests/test_virt_disk.py +++ b/nova/tests/test_virt_disk.py @@ -84,6 +84,28 @@ class VirtDiskTest(test.TestCase): vfs.teardown() + def test_inject_data_key_with_selinux_append_with_newline(self): + + vfs = vfsguestfs.VFSGuestFS("/some/file", "qcow2") + vfs.setup() + + vfs.replace_file("/etc/rc.d/rc.local", "#!/bin/sh\necho done") + vfs.make_path("etc/selinux") + vfs.make_path("etc/rc.d") + diskapi._inject_key_into_fs("mysshkey", vfs) + + self.assertTrue("/etc/rc.d/rc.local" in vfs.handle.files) + self.assertEquals(vfs.handle.files["/etc/rc.d/rc.local"], + {'isdir': False, + 'content': "#!/bin/sh\necho done\n# Added " + "by Nova to ensure injected ssh keys have " + "the right context\nrestorecon -RF " + "root/.ssh 2>/dev/null || :\n", + 'gid': 100, + 'uid': 100, + 'mode': 0700}) + vfs.teardown() + def test_inject_net(self): vfs = vfsguestfs.VFSGuestFS("/some/file", "qcow2") diff --git a/nova/virt/disk/api.py b/nova/virt/disk/api.py index 9d9d672d7..758299f16 100644 --- a/nova/virt/disk/api.py +++ b/nova/virt/disk/api.py @@ -294,11 +294,11 @@ def setup_container(image, container_dir, use_cow=False): raise exception.NovaException(img.errors) -def destroy_container(container_dir): - """Destroy the container once it terminates. +def teardown_container(container_dir): + """Teardown the container rootfs mounting once it is spawned. It will umount the container that is mounted, - and delete any linked devices. + and delete any linked devices. """ try: img = _DiskImage(image=None, mount_dir=container_dir) @@ -357,11 +357,14 @@ def _setup_selinux_for_keys(fs, sshdir): # and so to append there you'd need something like: # utils.execute('sed', '-i', '${/^exit 0$/d}' rclocal, run_as_root=True) restorecon = [ - '#!/bin/sh\n', + '\n', '# Added by Nova to ensure injected ssh keys have the right context\n', 'restorecon -RF %s 2>/dev/null || :\n' % sshdir, ] + if not fs.has_file(rclocal): + restorecon.insert(0, '#!/bin/sh') + _inject_file_into_fs(fs, rclocal, ''.join(restorecon), append=True) fs.set_permissions(rclocal, 0700) diff --git a/nova/virt/libvirt/driver.py b/nova/virt/libvirt/driver.py index 3c78f58eb..cfed962d0 100644 --- a/nova/virt/libvirt/driver.py +++ b/nova/virt/libvirt/driver.py @@ -577,11 +577,6 @@ class LibvirtDriver(driver.ComputeDriver): target = os.path.join(CONF.instances_path, instance['name']) LOG.info(_('Deleting instance files %(target)s') % locals(), instance=instance) - if CONF.libvirt_type == 'lxc': - container_dir = os.path.join(CONF.instances_path, - instance['name'], - 'rootfs') - disk.destroy_container(container_dir=container_dir) if os.path.exists(target): # If we fail to get rid of the directory # tree, this shouldn't block deletion of @@ -877,7 +872,7 @@ class LibvirtDriver(driver.ComputeDriver): power_state.CRASHED]: LOG.info(_("Instance shutdown successfully."), instance=instance) - self._create_domain(domain=dom) + self._create_domain(domain=dom, inst_name=instance['name']) timer = utils.LoopingCall(self._wait_for_running, instance) timer.start(interval=0.5).wait() return True @@ -939,7 +934,7 @@ class LibvirtDriver(driver.ComputeDriver): def power_on(self, instance): """Power on the specified instance""" dom = self._lookup_by_name(instance['name']) - self._create_domain(domain=dom) + self._create_domain(domain=dom, inst_name=instance['name']) timer = utils.LoopingCall(self._wait_for_running, instance) timer.start(interval=0.5).wait() @@ -1245,12 +1240,6 @@ class LibvirtDriver(driver.ComputeDriver): LOG.info(_('Creating image'), instance=instance) libvirt_utils.write_to_file(basepath('libvirt.xml'), libvirt_xml) - if CONF.libvirt_type == 'lxc': - container_dir = os.path.join(CONF.instances_path, - instance['name'], - 'rootfs') - fileutils.ensure_tree(container_dir) - # NOTE(dprince): for rescue console.log may already exist... chown it. self._chown_console_log_for_instance(instance['name']) @@ -1412,11 +1401,6 @@ class LibvirtDriver(driver.ComputeDriver): '%(img_id)s (%(e)s)') % locals(), instance=instance) - if CONF.libvirt_type == 'lxc': - disk.setup_container(image('disk').path, - container_dir=container_dir, - use_cow=CONF.use_cow_images) - if CONF.libvirt_type == 'uml': libvirt_utils.chown(image('disk').path, 'root') @@ -1875,16 +1859,37 @@ class LibvirtDriver(driver.ComputeDriver): 'num_cpu': num_cpu, 'cpu_time': cpu_time} - def _create_domain(self, xml=None, domain=None, launch_flags=0): + def _create_domain(self, xml=None, domain=None, + inst_name='', launch_flags=0): """Create a domain. Either domain or xml must be passed in. If both are passed, then the domain definition is overwritten from the xml. """ + if CONF.libvirt_type == 'lxc': + container_dir = os.path.join(CONF.instances_path, + inst_name, + 'rootfs') + fileutils.ensure_tree(container_dir) + image = self.image_backend.image(inst_name, 'disk') + disk.setup_container(image.path, + container_dir=container_dir, + use_cow=CONF.use_cow_images) + if xml: domain = self._conn.defineXML(xml) domain.createWithFlags(launch_flags) self._enable_hairpin(domain.XMLDesc(0)) + + # NOTE(uni): Now the container is running with its own private mount + # namespace and so there is no need to keep the container rootfs + # mounted in the host namespace + if CONF.libvirt_type == 'lxc': + container_dir = os.path.join(CONF.instances_path, + inst_name, + 'rootfs') + disk.teardown_container(container_dir=container_dir) + return domain def _create_domain_and_network(self, xml, instance, network_info, @@ -1904,7 +1909,8 @@ class LibvirtDriver(driver.ComputeDriver): self.plug_vifs(instance, network_info) self.firewall_driver.setup_basic_filtering(instance, network_info) self.firewall_driver.prepare_instance_filter(instance, network_info) - domain = self._create_domain(xml) + domain = self._create_domain(xml, inst_name=instance['name']) + self.firewall_driver.apply_instance_filter(instance, network_info) return domain |