diff --git a/doc/v3/api_samples/all_extensions/server-get-resp.json b/doc/v3/api_samples/all_extensions/server-get-resp.json index a3102309baab..e894a323ae1f 100644 --- a/doc/v3/api_samples/all_extensions/server-get-resp.json +++ b/doc/v3/api_samples/all_extensions/server-get-resp.json @@ -49,6 +49,7 @@ "accessIPv4": "", "accessIPv6": "", "config_drive": "", + "OS-DCF:diskConfig": "AUTO", "OS-EXT-AZ:availability_zone": "nova", "OS-EXT-SRV-ATTR:host": "b8b357f7100d4391828f2177c922ef93", "OS-EXT-SRV-ATTR:hypervisor_hostname": "fake-mini", diff --git a/doc/v3/api_samples/all_extensions/server-post-resp.json b/doc/v3/api_samples/all_extensions/server-post-resp.json index 253ba7178b62..6934d86a28e8 100644 --- a/doc/v3/api_samples/all_extensions/server-post-resp.json +++ b/doc/v3/api_samples/all_extensions/server-post-resp.json @@ -1,5 +1,6 @@ { "server": { + "OS-DCF:diskConfig": "AUTO", "adminPass": "zPnp2GseTqG4", "id": "8195065c-fea4-4d57-b93f-5c5c63fe90e8", "links": [ diff --git a/doc/v3/api_samples/all_extensions/servers-details-resp.json b/doc/v3/api_samples/all_extensions/servers-details-resp.json index 7e800511efbb..dcc36f22afb1 100644 --- a/doc/v3/api_samples/all_extensions/servers-details-resp.json +++ b/doc/v3/api_samples/all_extensions/servers-details-resp.json @@ -50,6 +50,7 @@ "accessIPv4": "", "accessIPv6": "", "config_drive": "", + "OS-DCF:diskConfig": "AUTO", "OS-EXT-AZ:availability_zone": "nova", "OS-EXT-SRV-ATTR:host": "c3f14e9812ad496baf92ccfb3c61e15f", "OS-EXT-SRV-ATTR:hypervisor_hostname": "fake-mini", diff --git a/doc/v3/api_samples/os-disk-config/image-get-resp.json b/doc/v3/api_samples/os-disk-config/image-get-resp.json new file mode 100644 index 000000000000..86cbc4937b8b --- /dev/null +++ b/doc/v3/api_samples/os-disk-config/image-get-resp.json @@ -0,0 +1,34 @@ +{ + "image": { + "OS-DCF:diskConfig": "AUTO", + "created": "2011-01-01T01:02:03Z", + "id": "70a599e0-31e7-49b7-b260-868f441e862b", + "links": [ + { + "href": "http://openstack.example.com/v3/images/70a599e0-31e7-49b7-b260-868f441e862b", + "rel": "self" + }, + { + "href": "http://openstack.example.com/images/70a599e0-31e7-49b7-b260-868f441e862b", + "rel": "bookmark" + }, + { + "href": "http://glance.openstack.example.com/openstack/images/70a599e0-31e7-49b7-b260-868f441e862b", + "rel": "alternate", + "type": "application/vnd.openstack.image" + } + ], + "metadata": { + "architecture": "x86_64", + "auto_disk_config": "True", + "kernel_id": "nokernel", + "ramdisk_id": "nokernel" + }, + "minDisk": 0, + "minRam": 0, + "name": "fakeimage7", + "progress": 100, + "status": "ACTIVE", + "updated": "2011-01-01T01:02:03Z" + } +} \ No newline at end of file diff --git a/doc/v3/api_samples/os-disk-config/image-list-resp.json b/doc/v3/api_samples/os-disk-config/image-list-resp.json new file mode 100644 index 000000000000..a613d731cb6f --- /dev/null +++ b/doc/v3/api_samples/os-disk-config/image-list-resp.json @@ -0,0 +1,214 @@ +{ + "images": [ + { + "OS-DCF:diskConfig": "AUTO", + "created": "2011-01-01T01:02:03Z", + "id": "70a599e0-31e7-49b7-b260-868f441e862b", + "links": [ + { + "href": "http://openstack.example.com/v3/images/70a599e0-31e7-49b7-b260-868f441e862b", + "rel": "self" + }, + { + "href": "http://openstack.example.com/images/70a599e0-31e7-49b7-b260-868f441e862b", + "rel": "bookmark" + }, + { + "href": "http://glance.openstack.example.com/openstack/images/70a599e0-31e7-49b7-b260-868f441e862b", + "rel": "alternate", + "type": "application/vnd.openstack.image" + } + ], + "metadata": { + "architecture": "x86_64", + "auto_disk_config": "True", + "kernel_id": "nokernel", + "ramdisk_id": "nokernel" + }, + "minDisk": 0, + "minRam": 0, + "name": "fakeimage7", + "progress": 100, + "status": "ACTIVE", + "updated": "2011-01-01T01:02:03Z" + }, + { + "created": "2011-01-01T01:02:03Z", + "id": "155d900f-4e14-4e4c-a73d-069cbf4541e6", + "links": [ + { + "href": "http://openstack.example.com/v3/images/155d900f-4e14-4e4c-a73d-069cbf4541e6", + "rel": "self" + }, + { + "href": "http://openstack.example.com/images/155d900f-4e14-4e4c-a73d-069cbf4541e6", + "rel": "bookmark" + }, + { + "href": "http://glance.openstack.example.com/openstack/images/155d900f-4e14-4e4c-a73d-069cbf4541e6", + "rel": "alternate", + "type": "application/vnd.openstack.image" + } + ], + "metadata": { + "architecture": "x86_64", + "kernel_id": "nokernel", + "ramdisk_id": "nokernel" + }, + "minDisk": 0, + "minRam": 0, + "name": "fakeimage123456", + "progress": 100, + "status": "ACTIVE", + "updated": "2011-01-01T01:02:03Z" + }, + { + "created": "2011-01-01T01:02:03Z", + "id": "a2459075-d96c-40d5-893e-577ff92e721c", + "links": [ + { + "href": "http://openstack.example.com/v3/images/a2459075-d96c-40d5-893e-577ff92e721c", + "rel": "self" + }, + { + "href": "http://openstack.example.com/images/a2459075-d96c-40d5-893e-577ff92e721c", + "rel": "bookmark" + }, + { + "href": "http://glance.openstack.example.com/openstack/images/a2459075-d96c-40d5-893e-577ff92e721c", + "rel": "alternate", + "type": "application/vnd.openstack.image" + } + ], + "metadata": { + "kernel_id": "nokernel", + "ramdisk_id": "nokernel" + }, + "minDisk": 0, + "minRam": 0, + "name": "fakeimage123456", + "progress": 100, + "status": "ACTIVE", + "updated": "2011-01-01T01:02:03Z" + }, + { + "OS-DCF:diskConfig": "MANUAL", + "created": "2011-01-01T01:02:03Z", + "id": "a440c04b-79fa-479c-bed1-0b816eaec379", + "links": [ + { + "href": "http://openstack.example.com/v3/images/a440c04b-79fa-479c-bed1-0b816eaec379", + "rel": "self" + }, + { + "href": "http://openstack.example.com/images/a440c04b-79fa-479c-bed1-0b816eaec379", + "rel": "bookmark" + }, + { + "href": "http://glance.openstack.example.com/openstack/images/a440c04b-79fa-479c-bed1-0b816eaec379", + "rel": "alternate", + "type": "application/vnd.openstack.image" + } + ], + "metadata": { + "architecture": "x86_64", + "auto_disk_config": "False", + "kernel_id": "nokernel", + "ramdisk_id": "nokernel" + }, + "minDisk": 0, + "minRam": 0, + "name": "fakeimage6", + "progress": 100, + "status": "ACTIVE", + "updated": "2011-01-01T01:02:03Z" + }, + { + "created": "2011-01-01T01:02:03Z", + "id": "c905cedb-7281-47e4-8a62-f26bc5fc4c77", + "links": [ + { + "href": "http://openstack.example.com/v3/images/c905cedb-7281-47e4-8a62-f26bc5fc4c77", + "rel": "self" + }, + { + "href": "http://openstack.example.com/images/c905cedb-7281-47e4-8a62-f26bc5fc4c77", + "rel": "bookmark" + }, + { + "href": "http://glance.openstack.example.com/openstack/images/c905cedb-7281-47e4-8a62-f26bc5fc4c77", + "rel": "alternate", + "type": "application/vnd.openstack.image" + } + ], + "metadata": { + "kernel_id": "155d900f-4e14-4e4c-a73d-069cbf4541e6", + "ramdisk_id": null + }, + "minDisk": 0, + "minRam": 0, + "name": "fakeimage123456", + "progress": 100, + "status": "ACTIVE", + "updated": "2011-01-01T01:02:03Z" + }, + { + "created": "2011-01-01T01:02:03Z", + "id": "cedef40a-ed67-4d10-800e-17455edce175", + "links": [ + { + "href": "http://openstack.example.com/v3/images/cedef40a-ed67-4d10-800e-17455edce175", + "rel": "self" + }, + { + "href": "http://openstack.example.com/images/cedef40a-ed67-4d10-800e-17455edce175", + "rel": "bookmark" + }, + { + "href": "http://glance.openstack.example.com/openstack/images/cedef40a-ed67-4d10-800e-17455edce175", + "rel": "alternate", + "type": "application/vnd.openstack.image" + } + ], + "metadata": { + "kernel_id": "nokernel", + "ramdisk_id": "nokernel" + }, + "minDisk": 0, + "minRam": 0, + "name": "fakeimage123456", + "progress": 100, + "status": "ACTIVE", + "updated": "2011-01-01T01:02:03Z" + }, + { + "created": "2011-01-01T01:02:03Z", + "id": "76fa36fc-c930-4bf3-8c8a-ea2a2420deb6", + "links": [ + { + "href": "http://openstack.example.com/v3/images/76fa36fc-c930-4bf3-8c8a-ea2a2420deb6", + "rel": "self" + }, + { + "href": "http://openstack.example.com/images/76fa36fc-c930-4bf3-8c8a-ea2a2420deb6", + "rel": "bookmark" + }, + { + "href": "http://glance.openstack.example.com/openstack/images/76fa36fc-c930-4bf3-8c8a-ea2a2420deb6", + "rel": "alternate", + "type": "application/vnd.openstack.image" + } + ], + "metadata": { + "kernel_id": "nokernel", + "ramdisk_id": "nokernel" + }, + "minDisk": 0, + "minRam": 0, + "name": "fakeimage123456", + "progress": 100, + "status": "ACTIVE", + "updated": "2011-01-01T01:02:03Z" + } + ] +} \ No newline at end of file diff --git a/doc/v3/api_samples/os-disk-config/list-servers-detail-get.json b/doc/v3/api_samples/os-disk-config/list-servers-detail-get.json new file mode 100644 index 000000000000..2ba696005c45 --- /dev/null +++ b/doc/v3/api_samples/os-disk-config/list-servers-detail-get.json @@ -0,0 +1,58 @@ +{ + "servers": [ + { + "OS-DCF:diskConfig": "AUTO", + "addresses": { + "private": [ + { + "addr": "192.168.0.3", + "OS-EXT-IPS-MAC:mac_addr": "aa:bb:cc:dd:ee:ff", + "OS-EXT-IPS:type": "fixed", + "version": 4 + } + ] + }, + "created": "2012-12-02T02:11:55Z", + "flavor": { + "id": "1", + "links": [ + { + "href": "http://openstack.example.com/flavors/1", + "rel": "bookmark" + } + ] + }, + "hostId": "99428f32351a5d89d0f7727c6eec68c1777c545a0972aaac645508dc", + "id": "05372e62-05b9-4ee2-9343-9a1fdf2a5fda", + "image": { + "id": "70a599e0-31e7-49b7-b260-868f441e862b", + "links": [ + { + "href": "http://openstack.example.com/images/70a599e0-31e7-49b7-b260-868f441e862b", + "rel": "bookmark" + } + ] + }, + "links": [ + { + "href": "http://openstack.example.com/v3/servers/05372e62-05b9-4ee2-9343-9a1fdf2a5fda", + "rel": "self" + }, + { + "href": "http://openstack.example.com/servers/05372e62-05b9-4ee2-9343-9a1fdf2a5fda", + "rel": "bookmark" + } + ], + "metadata": { + "My Server Name": "Apache1" + }, + "name": "new-server-test", + "progress": 0, + "status": "ACTIVE", + "tenant_id": "openstack", + "updated": "2012-12-02T02:11:56Z", + "key_name": null, + "user_id": "fake" + } + ] +} \ No newline at end of file diff --git a/doc/v3/api_samples/os-disk-config/server-action-rebuild-req.json b/doc/v3/api_samples/os-disk-config/server-action-rebuild-req.json new file mode 100644 index 000000000000..b500875c7afe --- /dev/null +++ b/doc/v3/api_samples/os-disk-config/server-action-rebuild-req.json @@ -0,0 +1,6 @@ +{ + "rebuild": { + "imageRef" : "http://openstack.example.com/images/70a599e0-31e7-49b7-b260-868f441e862b", + "OS-DCF:diskConfig": "AUTO" + } +} \ No newline at end of file diff --git a/doc/v3/api_samples/os-disk-config/server-action-rebuild-resp.json b/doc/v3/api_samples/os-disk-config/server-action-rebuild-resp.json new file mode 100644 index 000000000000..a5147ae5b8a2 --- /dev/null +++ b/doc/v3/api_samples/os-disk-config/server-action-rebuild-resp.json @@ -0,0 +1,56 @@ +{ + "server": { + "OS-DCF:diskConfig": "AUTO", + "addresses": { + "private": [ + { + "addr": "192.168.0.3", + "OS-EXT-IPS-MAC:mac_addr": "aa:bb:cc:dd:ee:ff", + "OS-EXT-IPS:type": "fixed", + "version": 4 + } + ] + }, + "adminPass": "NBjMaJoFL4EF", + "created": "2012-12-02T02:11:56Z", + "flavor": { + "id": "1", + "links": [ + { + "href": "http://openstack.example.com/flavors/1", + "rel": "bookmark" + } + ] + }, + "hostId": "c076393ad900d62c4805a42df10d9b364f629842681c00cce035487f", + "id": "63a8aa13-60fe-41c4-b079-77f6fdf3c841", + "image": { + "id": "70a599e0-31e7-49b7-b260-868f441e862b", + "links": [ + { + "href": "http://openstack.example.com/images/70a599e0-31e7-49b7-b260-868f441e862b", + "rel": "bookmark" + } + ] + }, + "links": [ + { + "href": "http://openstack.example.com/v3/servers/63a8aa13-60fe-41c4-b079-77f6fdf3c841", + "rel": "self" + }, + { + "href": "http://openstack.example.com/servers/63a8aa13-60fe-41c4-b079-77f6fdf3c841", + "rel": "bookmark" + } + ], + "metadata": { + "My Server Name": "Apache1" + }, + "name": "new-server-test", + "progress": 0, + "status": "ACTIVE", + "tenant_id": "openstack", + "updated": "2012-12-02T02:11:56Z", + "user_id": "fake" + } +} \ No newline at end of file diff --git a/doc/v3/api_samples/os-disk-config/server-get-resp.json b/doc/v3/api_samples/os-disk-config/server-get-resp.json new file mode 100644 index 000000000000..b7103cd576b4 --- /dev/null +++ b/doc/v3/api_samples/os-disk-config/server-get-resp.json @@ -0,0 +1,56 @@ +{ + "server": { + "OS-DCF:diskConfig": "AUTO", + "addresses": { + "private": [ + { + "addr": "192.168.0.3", + "OS-EXT-IPS-MAC:mac_addr": "aa:bb:cc:dd:ee:ff", + "OS-EXT-IPS:type": "fixed", + "version": 4 + } + ] + }, + "created": "2012-12-02T02:11:55Z", + "flavor": { + "id": "1", + "links": [ + { + "href": "http://openstack.example.com/flavors/1", + "rel": "bookmark" + } + ] + }, + "hostId": "c949ab4256cea23b6089b710aa2df48bf6577ed915278b62e33ad8bb", + "id": "5046e2f2-3b33-4041-b3cf-e085f73e78e7", + "image": { + "id": "70a599e0-31e7-49b7-b260-868f441e862b", + "links": [ + { + "href": "http://openstack.example.com/images/70a599e0-31e7-49b7-b260-868f441e862b", + "rel": "bookmark" + } + ] + }, + "links": [ + { + "href": "http://openstack.example.com/v3/servers/5046e2f2-3b33-4041-b3cf-e085f73e78e7", + "rel": "self" + }, + { + "href": "http://openstack.example.com/servers/5046e2f2-3b33-4041-b3cf-e085f73e78e7", + "rel": "bookmark" + } + ], + "metadata": { + "My Server Name": "Apache1" + }, + "name": "new-server-test", + "progress": 0, + "status": "ACTIVE", + "tenant_id": "openstack", + "updated": "2012-12-02T02:11:55Z", + "key_name": null, + "user_id": "fake" + } +} \ No newline at end of file diff --git a/doc/v3/api_samples/os-disk-config/server-post-req.json b/doc/v3/api_samples/os-disk-config/server-post-req.json new file mode 100644 index 000000000000..886a123e0549 --- /dev/null +++ b/doc/v3/api_samples/os-disk-config/server-post-req.json @@ -0,0 +1,16 @@ +{ + "server" : { + "name" : "new-server-test", + "imageRef" : "http://openstack.example.com/images/70a599e0-31e7-49b7-b260-868f441e862b", + "flavorRef" : "http://openstack.example.com/flavors/1", + "metadata" : { + "My Server Name" : "Apache1" + }, + "personality" : [ + { + "path" : "/etc/banner.txt", + "contents" : "ICAgICAgDQoiQSBjbG91ZCBkb2VzIG5vdCBrbm93IHdoeSBpdCBtb3ZlcyBpbiBqdXN0IHN1Y2ggYSBkaXJlY3Rpb24gYW5kIGF0IHN1Y2ggYSBzcGVlZC4uLkl0IGZlZWxzIGFuIGltcHVsc2lvbi4uLnRoaXMgaXMgdGhlIHBsYWNlIHRvIGdvIG5vdy4gQnV0IHRoZSBza3kga25vd3MgdGhlIHJlYXNvbnMgYW5kIHRoZSBwYXR0ZXJucyBiZWhpbmQgYWxsIGNsb3VkcywgYW5kIHlvdSB3aWxsIGtub3csIHRvbywgd2hlbiB5b3UgbGlmdCB5b3Vyc2VsZiBoaWdoIGVub3VnaCB0byBzZWUgYmV5b25kIGhvcml6b25zLiINCg0KLVJpY2hhcmQgQmFjaA==" + } + ] + } +} \ No newline at end of file diff --git a/doc/v3/api_samples/os-disk-config/server-post-resp.json b/doc/v3/api_samples/os-disk-config/server-post-resp.json new file mode 100644 index 000000000000..725dc09dedb6 --- /dev/null +++ b/doc/v3/api_samples/os-disk-config/server-post-resp.json @@ -0,0 +1,17 @@ +{ + "server": { + "OS-DCF:diskConfig": "AUTO", + "adminPass": "CQH9gWzgkVno", + "id": "324dfb7d-f4a9-419a-9a19-237df04b443b", + "links": [ + { + "href": "http://openstack.example.com/v3/servers/324dfb7d-f4a9-419a-9a19-237df04b443b", + "rel": "self" + }, + { + "href": "http://openstack.example.com/servers/324dfb7d-f4a9-419a-9a19-237df04b443b", + "rel": "bookmark" + } + ] + } +} \ No newline at end of file diff --git a/doc/v3/api_samples/os-disk-config/server-resize-post-req.json b/doc/v3/api_samples/os-disk-config/server-resize-post-req.json new file mode 100644 index 000000000000..55e11a31ed89 --- /dev/null +++ b/doc/v3/api_samples/os-disk-config/server-resize-post-req.json @@ -0,0 +1,6 @@ +{ + "resize": { + "flavorRef": "3", + "OS-DCF:diskConfig": "AUTO" + } +} \ No newline at end of file diff --git a/doc/v3/api_samples/os-disk-config/server-update-put-req.json b/doc/v3/api_samples/os-disk-config/server-update-put-req.json new file mode 100644 index 000000000000..898ab886ad8d --- /dev/null +++ b/doc/v3/api_samples/os-disk-config/server-update-put-req.json @@ -0,0 +1,5 @@ +{ + "server": { + "OS-DCF:diskConfig": "AUTO" + } +} \ No newline at end of file diff --git a/doc/v3/api_samples/os-disk-config/server-update-put-resp.json b/doc/v3/api_samples/os-disk-config/server-update-put-resp.json new file mode 100644 index 000000000000..e29d81a6e2e6 --- /dev/null +++ b/doc/v3/api_samples/os-disk-config/server-update-put-resp.json @@ -0,0 +1,55 @@ +{ + "server": { + "OS-DCF:diskConfig": "AUTO", + "addresses": { + "private": [ + { + "addr": "192.168.0.3", + "OS-EXT-IPS-MAC:mac_addr": "aa:bb:cc:dd:ee:ff", + "OS-EXT-IPS:type": "fixed", + "version": 4 + } + ] + }, + "created": "2012-12-02T02:11:57Z", + "flavor": { + "id": "1", + "links": [ + { + "href": "http://openstack.example.com/flavors/1", + "rel": "bookmark" + } + ] + }, + "hostId": "6e84af987b4e7ec1c039b16d21f508f4a505672bd94fb0218b668d07", + "id": "324dfb7d-f4a9-419a-9a19-237df04b443b", + "image": { + "id": "70a599e0-31e7-49b7-b260-868f441e862b", + "links": [ + { + "href": "http://openstack.example.com/images/70a599e0-31e7-49b7-b260-868f441e862b", + "rel": "bookmark" + } + ] + }, + "links": [ + { + "href": "http://openstack.example.com/v3/servers/324dfb7d-f4a9-419a-9a19-237df04b443b", + "rel": "self" + }, + { + "href": "http://openstack.example.com/servers/324dfb7d-f4a9-419a-9a19-237df04b443b", + "rel": "bookmark" + } + ], + "metadata": { + "My Server Name": "Apache1" + }, + "name": "new-server-test", + "progress": 0, + "status": "ACTIVE", + "tenant_id": "openstack", + "updated": "2012-12-02T02:11:58Z", + "user_id": "fake" + } +} \ No newline at end of file diff --git a/etc/nova/policy.json b/etc/nova/policy.json index 7f672c28d6ef..71e9fb728fbe 100644 --- a/etc/nova/policy.json +++ b/etc/nova/policy.json @@ -99,6 +99,8 @@ "compute_extension:v3:os-deferred-delete": "", "compute_extension:v3:os-deferred-delete:discoverable": "", "compute_extension:disk_config": "", + "compute_extension:v3:os-disk-config": "", + "compute_extension:v3:os-disk-config:discoverable": "", "compute_extension:evacuate": "rule:admin_api", "compute_extension:v3:os-evacuate": "rule:admin_api", "compute_extension:v3:os-evacuate:discoverable": "", diff --git a/nova/api/openstack/compute/plugins/v3/disk_config.py b/nova/api/openstack/compute/plugins/v3/disk_config.py new file mode 100644 index 000000000000..c306be8cd5b6 --- /dev/null +++ b/nova/api/openstack/compute/plugins/v3/disk_config.py @@ -0,0 +1,146 @@ +# Copyright 2011 OpenStack Foundation +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +"""Disk Config extension.""" + +from webob import exc + +from nova.api.openstack import extensions +from nova.api.openstack import wsgi +from nova.i18n import _ +from nova.openstack.common import strutils + +ALIAS = 'os-disk-config' +API_DISK_CONFIG = "OS-DCF:diskConfig" +INTERNAL_DISK_CONFIG = "auto_disk_config" +authorize = extensions.soft_extension_authorizer('compute', 'v3:' + ALIAS) + + +def disk_config_to_api(value): + return 'AUTO' if value else 'MANUAL' + + +def disk_config_from_api(value): + if value == 'AUTO': + return True + elif value == 'MANUAL': + return False + else: + msg = _("%s must be either 'MANUAL' or 'AUTO'.") % API_DISK_CONFIG + raise exc.HTTPBadRequest(explanation=msg) + + +class ImageDiskConfigController(wsgi.Controller): + def _add_disk_config(self, context, images): + for image in images: + metadata = image['metadata'] + if INTERNAL_DISK_CONFIG in metadata: + raw_value = metadata[INTERNAL_DISK_CONFIG] + value = strutils.bool_from_string(raw_value) + image[API_DISK_CONFIG] = disk_config_to_api(value) + + @wsgi.extends + def show(self, req, resp_obj, id): + context = req.environ['nova.context'] + if 'image' in resp_obj.obj and authorize(context): + image = resp_obj.obj['image'] + self._add_disk_config(context, [image]) + + @wsgi.extends + def detail(self, req, resp_obj): + context = req.environ['nova.context'] + if 'images' in resp_obj.obj and authorize(context): + images = resp_obj.obj['images'] + self._add_disk_config(context, images) + + +class ServerDiskConfigController(wsgi.Controller): + def _add_disk_config(self, req, servers): + for server in servers: + db_server = req.get_db_instance(server['id']) + # server['id'] is guaranteed to be in the cache due to + # the core API adding it in its 'show'/'detail' methods. + value = db_server.get(INTERNAL_DISK_CONFIG) + server[API_DISK_CONFIG] = disk_config_to_api(value) + + def _show(self, req, resp_obj): + if 'server' in resp_obj.obj: + server = resp_obj.obj['server'] + self._add_disk_config(req, [server]) + + @wsgi.extends + def show(self, req, resp_obj, id): + context = req.environ['nova.context'] + if authorize(context): + self._show(req, resp_obj) + + @wsgi.extends + def detail(self, req, resp_obj): + context = req.environ['nova.context'] + if 'servers' in resp_obj.obj and authorize(context): + servers = resp_obj.obj['servers'] + self._add_disk_config(req, servers) + + @wsgi.extends + def create(self, req, resp_obj, body): + context = req.environ['nova.context'] + if authorize(context): + self._show(req, resp_obj) + + @wsgi.extends + def update(self, req, resp_obj, id, body): + context = req.environ['nova.context'] + if authorize(context): + self._show(req, resp_obj) + + @wsgi.extends(action='rebuild') + def _action_rebuild(self, req, resp_obj, id, body): + context = req.environ['nova.context'] + if authorize(context): + self._show(req, resp_obj) + + +class DiskConfig(extensions.V3APIExtensionBase): + """Disk Management Extension.""" + + name = "DiskConfig" + alias = ALIAS + version = 1 + + def get_controller_extensions(self): + servers_extension = extensions.ControllerExtension( + self, 'servers', ServerDiskConfigController()) + + images_extension = extensions.ControllerExtension( + self, 'images', ImageDiskConfigController()) + + return [servers_extension, images_extension] + + def get_resources(self): + return [] + + # NOTE(gmann): This function is not supposed to use 'body_deprecated_param' + # parameter as this is placed to handle scheduler_hint extension for V2.1. + # making 'body_deprecated_param' as optional to avoid changes for + # server_update & server_rebuild + def server_create(self, server_dict, create_kwargs, + body_deprecated_param=None): + if API_DISK_CONFIG in server_dict: + api_value = server_dict[API_DISK_CONFIG] + internal_value = disk_config_from_api(api_value) + create_kwargs[INTERNAL_DISK_CONFIG] = internal_value + + server_update = server_create + server_rebuild = server_create + server_resize = server_create \ No newline at end of file diff --git a/nova/api/openstack/compute/plugins/v3/servers.py b/nova/api/openstack/compute/plugins/v3/servers.py index 534e1c3d117f..26678d5f9a12 100644 --- a/nova/api/openstack/compute/plugins/v3/servers.py +++ b/nova/api/openstack/compute/plugins/v3/servers.py @@ -70,6 +70,8 @@ class ServersController(wsgi.Controller): EXTENSION_UPDATE_NAMESPACE = 'nova.api.v3.extensions.server.update' + EXTENSION_RESIZE_NAMESPACE = 'nova.api.v3.extensions.server.resize' + _view_builder_class = views_servers.ViewBuilderV3 schema_server_create = schema_servers.base_create @@ -173,6 +175,17 @@ class ServersController(wsgi.Controller): if not list(self.update_extension_manager): LOG.debug("Did not find any server update extensions") + # Look for implementation of extension point of server resize + self.resize_extension_manager = \ + stevedore.enabled.EnabledExtensionManager( + namespace=self.EXTENSION_RESIZE_NAMESPACE, + check_func=_check_load_extension('server_resize'), + invoke_on_load=True, + invoke_kwds={"extension_info": self.extension_info}, + propagate_map_exceptions=True) + if not list(self.resize_extension_manager): + LOG.debug("Did not find any server resize extensions") + # Look for API schema of server create extension self.create_schema_manager = \ stevedore.enabled.EnabledExtensionManager( @@ -561,7 +574,8 @@ class ServersController(wsgi.Controller): exception.InvalidBDMImage, exception.InvalidBDMBootSequence, exception.InvalidBDMLocalsLimit, - exception.InvalidBDMVolumeNotBootable) as error: + exception.InvalidBDMVolumeNotBootable, + exception.AutoDiskConfigDisabledByImage) as error: raise exc.HTTPBadRequest(explanation=error.format_message()) except (exception.PortInUse, exception.InstanceExists, @@ -774,7 +788,8 @@ class ServersController(wsgi.Controller): except exception.CannotResizeToSameFlavor: msg = _("Resize requires a flavor change.") raise exc.HTTPBadRequest(explanation=msg) - except exception.CannotResizeDisk as e: + except (exception.CannotResizeDisk, + exception.AutoDiskConfigDisabledByImage) as e: raise exc.HTTPBadRequest(explanation=e.format_message()) except exception.InstanceIsLocked as e: raise exc.HTTPConflict(explanation=e.format_message()) @@ -862,6 +877,10 @@ class ServersController(wsgi.Controller): resize_kwargs = {} + if list(self.resize_extension_manager): + self.resize_extension_manager.map(self._resize_extension_point, + resize_dict, resize_kwargs) + return self._resize(req, id, flavor_ref, **resize_kwargs) @extensions.expected_errors((400, 403, 404, 409, 413)) diff --git a/nova/tests/api/openstack/compute/contrib/test_disk_config.py b/nova/tests/api/openstack/compute/contrib/test_disk_config.py index 9f28b0d43261..0333246e2499 100644 --- a/nova/tests/api/openstack/compute/contrib/test_disk_config.py +++ b/nova/tests/api/openstack/compute/contrib/test_disk_config.py @@ -38,14 +38,11 @@ def instance_addresses(context, instance_id): return None -class DiskConfigTestCase(test.TestCase): +class DiskConfigTestCaseV21(test.TestCase): def setUp(self): - super(DiskConfigTestCase, self).setUp() - self.flags(verbose=True, - osapi_compute_extension=[ - 'nova.api.openstack.compute.contrib.select_extensions'], - osapi_compute_ext_list=['Disk_config']) + super(DiskConfigTestCaseV21, self).setUp() + self._set_up_app() self._setup_fake_image_service() fakes.stub_out_nw_api(self.stubs) @@ -129,7 +126,9 @@ class DiskConfigTestCase(test.TestCase): self.stubs.Set(db, 'instance_create', fake_instance_create) - self.app = compute.APIRouter(init_only=('servers', 'images')) + def _set_up_app(self): + self.app = compute.APIRouterV21(init_only=('servers', 'images', + 'os-disk-config')) def _setup_fake_image_service(self): self.image_service = nova.tests.image.fake.stub_out_image_service( @@ -150,7 +149,7 @@ class DiskConfigTestCase(test.TestCase): self.image_service.create(None, image) def tearDown(self): - super(DiskConfigTestCase, self).tearDown() + super(DiskConfigTestCaseV21, self).tearDown() nova.tests.image.fake.FakeImageService_reset() def assertDiskConfig(self, dict_, value): @@ -376,15 +375,19 @@ class DiskConfigTestCase(test.TestCase): 'flavorRef': '1', API_DISK_CONFIG: 'AUTO' }} + old_create = compute_api.API.create def create(*args, **kwargs): self.assertIn('auto_disk_config', kwargs) self.assertEqual(True, kwargs['auto_disk_config']) + return old_create(*args, **kwargs) self.stubs.Set(compute_api.API, 'create', create) req.body = jsonutils.dumps(body) - req.get_response(self.app) + res = req.get_response(self.app) + server_dict = jsonutils.loads(res.body)['server'] + self.assertDiskConfig(server_dict, 'AUTO') def test_rebuild_server_with_auto_disk_config(self): req = fakes.HTTPRequest.blank( @@ -403,7 +406,9 @@ class DiskConfigTestCase(test.TestCase): self.stubs.Set(compute_api.API, 'rebuild', rebuild) req.body = jsonutils.dumps(body) - req.get_response(self.app) + res = req.get_response(self.app) + server_dict = jsonutils.loads(res.body)['server'] + self.assertDiskConfig(server_dict, 'AUTO') def test_resize_server_with_auto_disk_config(self): req = fakes.HTTPRequest.blank( @@ -423,3 +428,13 @@ class DiskConfigTestCase(test.TestCase): req.body = jsonutils.dumps(body) req.get_response(self.app) + + +class DiskConfigTestCaseV2(DiskConfigTestCaseV21): + def _set_up_app(self): + self.flags(verbose=True, + osapi_compute_extension=[ + 'nova.api.openstack.compute.contrib.select_extensions'], + osapi_compute_ext_list=['Disk_config']) + + self.app = compute.APIRouter(init_only=('servers', 'images')) diff --git a/nova/tests/api/openstack/compute/plugins/v3/test_servers.py b/nova/tests/api/openstack/compute/plugins/v3/test_servers.py index f734edb79c58..70528f44abf9 100644 --- a/nova/tests/api/openstack/compute/plugins/v3/test_servers.py +++ b/nova/tests/api/openstack/compute/plugins/v3/test_servers.py @@ -31,7 +31,7 @@ import webob from nova.api.openstack import compute from nova.api.openstack.compute import plugins -from nova.api.openstack.compute.plugins.v3 import access_ips +from nova.api.openstack.compute.plugins.v3 import disk_config from nova.api.openstack.compute.plugins.v3 import ips from nova.api.openstack.compute.plugins.v3 import keypairs from nova.api.openstack.compute.plugins.v3 import servers @@ -3240,8 +3240,8 @@ class ServersInvalidRequestTestCase(test.TestCase): class FakeExt(extensions.V3APIExtensionBase): - name = "AccessIPs" - alias = 'os-access-ips' + name = "DiskConfig" + alias = 'os-disk-config' version = 1 def fake_extension_point(self, *args, **kwargs): @@ -3257,9 +3257,9 @@ class FakeExt(extensions.V3APIExtensionBase): class TestServersExtensionPoint(test.NoDBTestCase): def setUp(self): super(TestServersExtensionPoint, self).setUp() - CONF.set_override('extensions_whitelist', ['os-access-ips'], + CONF.set_override('extensions_whitelist', ['os-disk-config'], 'osapi_v3') - self.stubs.Set(access_ips, 'AccessIPs', FakeExt) + self.stubs.Set(disk_config, 'DiskConfig', FakeExt) def _test_load_extension_point(self, name): setattr(FakeExt, 'server_%s' % name, @@ -3267,7 +3267,7 @@ class TestServersExtensionPoint(test.NoDBTestCase): ext_info = plugins.LoadedExtensionInfo() controller = servers.ServersController(extension_info=ext_info) self.assertEqual( - 'os-access-ips', + 'os-disk-config', list(getattr(controller, '%s_extension_manager' % name))[0].obj.alias) delattr(FakeExt, 'server_%s' % name) @@ -3281,6 +3281,9 @@ class TestServersExtensionPoint(test.NoDBTestCase): def test_load_create_extension_point(self): self._test_load_extension_point('create') + def test_load_resize_extension_point(self): + self._test_load_extension_point('resize') + class TestServersExtensionSchema(test.NoDBTestCase): def setUp(self): diff --git a/nova/tests/fake_policy.py b/nova/tests/fake_policy.py index 1619d1561324..8a63eef249ec 100644 --- a/nova/tests/fake_policy.py +++ b/nova/tests/fake_policy.py @@ -165,6 +165,7 @@ policy_data = """ "compute_extension:deferred_delete": "", "compute_extension:v3:os-deferred-delete": "", "compute_extension:disk_config": "", + "compute_extension:v3:os-disk-config": "", "compute_extension:evacuate": "is_admin:True", "compute_extension:v3:os-evacuate": "is_admin:True", "compute_extension:extended_server_attributes": "", diff --git a/nova/tests/integrated/v3/api_samples/all_extensions/server-get-resp.json.tpl b/nova/tests/integrated/v3/api_samples/all_extensions/server-get-resp.json.tpl index 240b255c81d0..add1a44c3263 100644 --- a/nova/tests/integrated/v3/api_samples/all_extensions/server-get-resp.json.tpl +++ b/nova/tests/integrated/v3/api_samples/all_extensions/server-get-resp.json.tpl @@ -49,6 +49,7 @@ }, "name": "new-server-test", "config_drive": "", + "OS-DCF:diskConfig": "AUTO", "OS-EXT-AZ:availability_zone": "nova", "OS-EXT-SRV-ATTR:host": "%(compute_host)s", "OS-EXT-SRV-ATTR:hypervisor_hostname": "%(hypervisor_hostname)s", diff --git a/nova/tests/integrated/v3/api_samples/all_extensions/server-post-resp.json.tpl b/nova/tests/integrated/v3/api_samples/all_extensions/server-post-resp.json.tpl index c7bcb4c2e72e..6f1d0b498efd 100644 --- a/nova/tests/integrated/v3/api_samples/all_extensions/server-post-resp.json.tpl +++ b/nova/tests/integrated/v3/api_samples/all_extensions/server-post-resp.json.tpl @@ -1,5 +1,6 @@ { "server": { + "OS-DCF:diskConfig": "AUTO", "adminPass": "%(password)s", "id": "%(id)s", "links": [ diff --git a/nova/tests/integrated/v3/api_samples/all_extensions/servers-details-resp.json.tpl b/nova/tests/integrated/v3/api_samples/all_extensions/servers-details-resp.json.tpl index ae6d35e7b50f..1e9edd05921b 100644 --- a/nova/tests/integrated/v3/api_samples/all_extensions/servers-details-resp.json.tpl +++ b/nova/tests/integrated/v3/api_samples/all_extensions/servers-details-resp.json.tpl @@ -50,6 +50,7 @@ }, "name": "new-server-test", "config_drive": "", + "OS-DCF:diskConfig": "AUTO", "OS-EXT-AZ:availability_zone": "nova", "OS-EXT-SRV-ATTR:host": "%(compute_host)s", "OS-EXT-SRV-ATTR:hypervisor_hostname": "%(hypervisor_hostname)s", diff --git a/nova/tests/integrated/v3/api_samples/os-disk-config/image-get-resp.json.tpl b/nova/tests/integrated/v3/api_samples/os-disk-config/image-get-resp.json.tpl new file mode 100644 index 000000000000..f18eff6ddb7d --- /dev/null +++ b/nova/tests/integrated/v3/api_samples/os-disk-config/image-get-resp.json.tpl @@ -0,0 +1,34 @@ +{ + "image": { + "OS-DCF:diskConfig": "AUTO", + "created": "2011-01-01T01:02:03Z", + "id": "%(image_id)s", + "links": [ + { + "href": "%(host)s/v3/images/%(image_id)s", + "rel": "self" + }, + { + "href": "%(host)s/images/%(image_id)s", + "rel": "bookmark" + }, + { + "href": "%(glance_host)s/openstack/images/%(image_id)s", + "rel": "alternate", + "type": "application/vnd.openstack.image" + } + ], + "metadata": { + "architecture": "x86_64", + "auto_disk_config": "True", + "kernel_id": "nokernel", + "ramdisk_id": "nokernel" + }, + "minDisk": 0, + "minRam": 0, + "name": "fakeimage7", + "progress": 100, + "status": "ACTIVE", + "updated": "2011-01-01T01:02:03Z" + } +} diff --git a/nova/tests/integrated/v3/api_samples/os-disk-config/image-list-resp.json.tpl b/nova/tests/integrated/v3/api_samples/os-disk-config/image-list-resp.json.tpl new file mode 100644 index 000000000000..348bb3a61c81 --- /dev/null +++ b/nova/tests/integrated/v3/api_samples/os-disk-config/image-list-resp.json.tpl @@ -0,0 +1,214 @@ +{ + "images": [ + { + "OS-DCF:diskConfig": "AUTO", + "created": "2011-01-01T01:02:03Z", + "id": "%(id)s", + "links": [ + { + "href": "%(host)s/v3/images/%(id)s", + "rel": "self" + }, + { + "href": "%(host)s/images/%(id)s", + "rel": "bookmark" + }, + { + "href": "%(glance_host)s/openstack/images/%(id)s", + "rel": "alternate", + "type": "application/vnd.openstack.image" + } + ], + "metadata": { + "architecture": "x86_64", + "auto_disk_config": "True", + "kernel_id": "nokernel", + "ramdisk_id": "nokernel" + }, + "minDisk": 0, + "minRam": 0, + "name": "fakeimage7", + "progress": 100, + "status": "ACTIVE", + "updated": "2011-01-01T01:02:03Z" + }, + { + "created": "2011-01-01T01:02:03Z", + "id": "%(id)s", + "links": [ + { + "href": "%(host)s/v3/images/%(id)s", + "rel": "self" + }, + { + "href": "%(host)s/images/%(id)s", + "rel": "bookmark" + }, + { + "href": "%(glance_host)s/openstack/images/%(id)s", + "rel": "alternate", + "type": "application/vnd.openstack.image" + } + ], + "metadata": { + "architecture": "x86_64", + "kernel_id": "nokernel", + "ramdisk_id": "nokernel" + }, + "minDisk": 0, + "minRam": 0, + "name": "fakeimage123456", + "progress": 100, + "status": "ACTIVE", + "updated": "2011-01-01T01:02:03Z" + }, + { + "created": "2011-01-01T01:02:03Z", + "id": "%(uuid)s", + "links": [ + { + "href": "%(host)s/v3/images/%(uuid)s", + "rel": "self" + }, + { + "href": "%(host)s/images/%(uuid)s", + "rel": "bookmark" + }, + { + "href": "%(glance_host)s/openstack/images/%(uuid)s", + "rel": "alternate", + "type": "application/vnd.openstack.image" + } + ], + "metadata": { + "kernel_id": "nokernel", + "ramdisk_id": "nokernel" + }, + "minDisk": 0, + "minRam": 0, + "name": "fakeimage123456", + "progress": 100, + "status": "ACTIVE", + "updated": "2011-01-01T01:02:03Z" + }, + { + "OS-DCF:diskConfig": "MANUAL", + "created": "2011-01-01T01:02:03Z", + "id": "%(uuid)s", + "links": [ + { + "href": "%(host)s/v3/images/%(uuid)s", + "rel": "self" + }, + { + "href": "%(host)s/images/%(uuid)s", + "rel": "bookmark" + }, + { + "href": "%(glance_host)s/openstack/images/%(uuid)s", + "rel": "alternate", + "type": "application/vnd.openstack.image" + } + ], + "metadata": { + "architecture": "x86_64", + "auto_disk_config": "False", + "kernel_id": "nokernel", + "ramdisk_id": "nokernel" + }, + "minDisk": 0, + "minRam": 0, + "name": "fakeimage6", + "progress": 100, + "status": "ACTIVE", + "updated": "2011-01-01T01:02:03Z" + }, + { + "created": "2011-01-01T01:02:03Z", + "id": "%(id)s", + "links": [ + { + "href": "%(host)s/v3/images/%(id)s", + "rel": "self" + }, + { + "href": "%(host)s/images/%(id)s", + "rel": "bookmark" + }, + { + "href": "%(glance_host)s/openstack/images/%(id)s", + "rel": "alternate", + "type": "application/vnd.openstack.image" + } + ], + "metadata": { + "kernel_id": "%(id)s", + "ramdisk_id": null + }, + "minDisk": 0, + "minRam": 0, + "name": "fakeimage123456", + "progress": 100, + "status": "ACTIVE", + "updated": "2011-01-01T01:02:03Z" + }, + { + "created": "2011-01-01T01:02:03Z", + "id": "%(id)s", + "links": [ + { + "href": "%(host)s/v3/images/%(id)s", + "rel": "self" + }, + { + "href": "%(host)s/images/%(id)s", + "rel": "bookmark" + }, + { + "href": "%(glance_host)s/openstack/images/%(id)s", + "rel": "alternate", + "type": "application/vnd.openstack.image" + } + ], + "metadata": { + "kernel_id": "nokernel", + "ramdisk_id": "nokernel" + }, + "minDisk": 0, + "minRam": 0, + "name": "fakeimage123456", + "progress": 100, + "status": "ACTIVE", + "updated": "2011-01-01T01:02:03Z" + }, + { + "created": "2011-01-01T01:02:03Z", + "id": "%(id)s", + "links": [ + { + "href": "%(host)s/v3/images/%(id)s", + "rel": "self" + }, + { + "href": "%(host)s/images/%(id)s", + "rel": "bookmark" + }, + { + "href": "%(glance_host)s/openstack/images/%(id)s", + "rel": "alternate", + "type": "application/vnd.openstack.image" + } + ], + "metadata": { + "kernel_id": "nokernel", + "ramdisk_id": "nokernel" + }, + "minDisk": 0, + "minRam": 0, + "name": "fakeimage123456", + "progress": 100, + "status": "ACTIVE", + "updated": "2011-01-01T01:02:03Z" + } + ] +} diff --git a/nova/tests/integrated/v3/api_samples/os-disk-config/list-servers-detail-get.json.tpl b/nova/tests/integrated/v3/api_samples/os-disk-config/list-servers-detail-get.json.tpl new file mode 100644 index 000000000000..8a08b3e01108 --- /dev/null +++ b/nova/tests/integrated/v3/api_samples/os-disk-config/list-servers-detail-get.json.tpl @@ -0,0 +1,58 @@ +{ + "servers": [ + { + "OS-DCF:diskConfig": "AUTO", + "addresses": { + "private": [ + { + "addr": "192.168.0.3", + "OS-EXT-IPS-MAC:mac_addr": "aa:bb:cc:dd:ee:ff", + "OS-EXT-IPS:type": "fixed", + "version": 4 + } + ] + }, + "created": "%(isotime)s", + "flavor": { + "id": "1", + "links": [ + { + "href": "%(host)s/flavors/1", + "rel": "bookmark" + } + ] + }, + "hostId": "%(hostid)s", + "id": "%(id)s", + "image": { + "id": "%(uuid)s", + "links": [ + { + "href": "%(host)s/images/%(uuid)s", + "rel": "bookmark" + } + ] + }, + "links": [ + { + "href": "%(host)s/v3/servers/%(id)s", + "rel": "self" + }, + { + "href": "%(host)s/servers/%(id)s", + "rel": "bookmark" + } + ], + "metadata": { + "My Server Name": "Apache1" + }, + "name": "new-server-test", + "progress": 0, + "status": "ACTIVE", + "tenant_id": "openstack", + "updated": "%(isotime)s", + "key_name": null, + "user_id": "fake" + } + ] +} diff --git a/nova/tests/integrated/v3/api_samples/os-disk-config/server-action-rebuild-req.json.tpl b/nova/tests/integrated/v3/api_samples/os-disk-config/server-action-rebuild-req.json.tpl new file mode 100644 index 000000000000..3d98b99bcbbb --- /dev/null +++ b/nova/tests/integrated/v3/api_samples/os-disk-config/server-action-rebuild-req.json.tpl @@ -0,0 +1,6 @@ +{ + "rebuild": { + "imageRef" : "%(host)s/images/%(image_id)s", + "OS-DCF:diskConfig": "AUTO" + } +} diff --git a/nova/tests/integrated/v3/api_samples/os-disk-config/server-action-rebuild-resp.json.tpl b/nova/tests/integrated/v3/api_samples/os-disk-config/server-action-rebuild-resp.json.tpl new file mode 100644 index 000000000000..ebb5f3d8a0c9 --- /dev/null +++ b/nova/tests/integrated/v3/api_samples/os-disk-config/server-action-rebuild-resp.json.tpl @@ -0,0 +1,56 @@ +{ + "server": { + "OS-DCF:diskConfig": "AUTO", + "addresses": { + "private": [ + { + "addr": "192.168.0.3", + "OS-EXT-IPS-MAC:mac_addr": "aa:bb:cc:dd:ee:ff", + "OS-EXT-IPS:type": "fixed", + "version": 4 + } + ] + }, + "adminPass": "%(password)s", + "created": "%(isotime)s", + "flavor": { + "id": "1", + "links": [ + { + "href": "%(host)s/flavors/1", + "rel": "bookmark" + } + ] + }, + "hostId": "%(hostid)s", + "id": "%(id)s", + "image": { + "id": "%(uuid)s", + "links": [ + { + "href": "%(host)s/images/%(uuid)s", + "rel": "bookmark" + } + ] + }, + "links": [ + { + "href": "%(host)s/v3/servers/%(id)s", + "rel": "self" + }, + { + "href": "%(host)s/servers/%(id)s", + "rel": "bookmark" + } + ], + "metadata": { + "My Server Name": "Apache1" + }, + "name": "new-server-test", + "progress": 0, + "status": "ACTIVE", + "tenant_id": "openstack", + "updated": "%(isotime)s", + "user_id": "fake" + } +} diff --git a/nova/tests/integrated/v3/api_samples/os-disk-config/server-get-resp.json.tpl b/nova/tests/integrated/v3/api_samples/os-disk-config/server-get-resp.json.tpl new file mode 100644 index 000000000000..f60c4af52f73 --- /dev/null +++ b/nova/tests/integrated/v3/api_samples/os-disk-config/server-get-resp.json.tpl @@ -0,0 +1,56 @@ +{ + "server": { + "OS-DCF:diskConfig": "AUTO", + "addresses": { + "private": [ + { + "addr": "192.168.0.3", + "OS-EXT-IPS-MAC:mac_addr": "aa:bb:cc:dd:ee:ff", + "OS-EXT-IPS:type": "fixed", + "version": 4 + } + ] + }, + "created": "%(isotime)s", + "flavor": { + "id": "1", + "links": [ + { + "href": "%(host)s/flavors/1", + "rel": "bookmark" + } + ] + }, + "hostId": "%(hostid)s", + "id": "%(id)s", + "image": { + "id": "%(uuid)s", + "links": [ + { + "href": "%(host)s/images/%(uuid)s", + "rel": "bookmark" + } + ] + }, + "links": [ + { + "href": "%(host)s/v3/servers/%(id)s", + "rel": "self" + }, + { + "href": "%(host)s/servers/%(id)s", + "rel": "bookmark" + } + ], + "metadata": { + "My Server Name": "Apache1" + }, + "name": "new-server-test", + "progress": 0, + "status": "ACTIVE", + "tenant_id": "openstack", + "updated": "%(isotime)s", + "key_name": null, + "user_id": "fake" + } +} diff --git a/nova/tests/integrated/v3/api_samples/os-disk-config/server-post-req.json.tpl b/nova/tests/integrated/v3/api_samples/os-disk-config/server-post-req.json.tpl new file mode 100644 index 000000000000..c012c48318e7 --- /dev/null +++ b/nova/tests/integrated/v3/api_samples/os-disk-config/server-post-req.json.tpl @@ -0,0 +1,17 @@ +{ + "server" : { + "OS-DCF:diskConfig": "AUTO", + "name" : "new-server-test", + "imageRef" : "%(host)s/images/%(image_id)s", + "flavorRef" : "%(host)s/flavors/1", + "metadata" : { + "My Server Name" : "Apache1" + }, + "personality" : [ + { + "path" : "/etc/banner.txt", + "contents" : "ICAgICAgDQoiQSBjbG91ZCBkb2VzIG5vdCBrbm93IHdoeSBpdCBtb3ZlcyBpbiBqdXN0IHN1Y2ggYSBkaXJlY3Rpb24gYW5kIGF0IHN1Y2ggYSBzcGVlZC4uLkl0IGZlZWxzIGFuIGltcHVsc2lvbi4uLnRoaXMgaXMgdGhlIHBsYWNlIHRvIGdvIG5vdy4gQnV0IHRoZSBza3kga25vd3MgdGhlIHJlYXNvbnMgYW5kIHRoZSBwYXR0ZXJucyBiZWhpbmQgYWxsIGNsb3VkcywgYW5kIHlvdSB3aWxsIGtub3csIHRvbywgd2hlbiB5b3UgbGlmdCB5b3Vyc2VsZiBoaWdoIGVub3VnaCB0byBzZWUgYmV5b25kIGhvcml6b25zLiINCg0KLVJpY2hhcmQgQmFjaA==" + } + ] + } +} diff --git a/nova/tests/integrated/v3/api_samples/os-disk-config/server-post-resp.json.tpl b/nova/tests/integrated/v3/api_samples/os-disk-config/server-post-resp.json.tpl new file mode 100644 index 000000000000..91aa3432ea21 --- /dev/null +++ b/nova/tests/integrated/v3/api_samples/os-disk-config/server-post-resp.json.tpl @@ -0,0 +1,17 @@ +{ + "server": { + "OS-DCF:diskConfig": "AUTO", + "adminPass": "%(password)s", + "id": "%(id)s", + "links": [ + { + "href": "%(host)s/v3/servers/%(uuid)s", + "rel": "self" + }, + { + "href": "%(host)s/servers/%(uuid)s", + "rel": "bookmark" + } + ] + } +} diff --git a/nova/tests/integrated/v3/api_samples/os-disk-config/server-resize-post-req.json.tpl b/nova/tests/integrated/v3/api_samples/os-disk-config/server-resize-post-req.json.tpl new file mode 100644 index 000000000000..a290485e1c26 --- /dev/null +++ b/nova/tests/integrated/v3/api_samples/os-disk-config/server-resize-post-req.json.tpl @@ -0,0 +1,6 @@ +{ + "resize": { + "flavorRef": "3", + "OS-DCF:diskConfig": "AUTO" + } +} diff --git a/nova/tests/integrated/v3/api_samples/os-disk-config/server-update-put-req.json.tpl b/nova/tests/integrated/v3/api_samples/os-disk-config/server-update-put-req.json.tpl new file mode 100644 index 000000000000..4ac22820df3b --- /dev/null +++ b/nova/tests/integrated/v3/api_samples/os-disk-config/server-update-put-req.json.tpl @@ -0,0 +1,5 @@ +{ + "server": { + "OS-DCF:diskConfig": "AUTO" + } +} diff --git a/nova/tests/integrated/v3/api_samples/os-disk-config/server-update-put-resp.json.tpl b/nova/tests/integrated/v3/api_samples/os-disk-config/server-update-put-resp.json.tpl new file mode 100644 index 000000000000..26cf74e80a61 --- /dev/null +++ b/nova/tests/integrated/v3/api_samples/os-disk-config/server-update-put-resp.json.tpl @@ -0,0 +1,55 @@ +{ + "server": { + "OS-DCF:diskConfig": "AUTO", + "addresses": { + "private": [ + { + "addr": "192.168.0.3", + "OS-EXT-IPS-MAC:mac_addr": "aa:bb:cc:dd:ee:ff", + "OS-EXT-IPS:type": "fixed", + "version": 4 + } + ] + }, + "created": "%(isotime)s", + "flavor": { + "id": "1", + "links": [ + { + "href": "%(host)s/flavors/1", + "rel": "bookmark" + } + ] + }, + "hostId": "%(hostid)s", + "id": "%(id)s", + "image": { + "id": "%(uuid)s", + "links": [ + { + "href": "%(host)s/images/%(uuid)s", + "rel": "bookmark" + } + ] + }, + "links": [ + { + "href": "%(host)s/v3/servers/%(id)s", + "rel": "self" + }, + { + "href": "%(host)s/servers/%(id)s", + "rel": "bookmark" + } + ], + "metadata": { + "My Server Name": "Apache1" + }, + "name": "new-server-test", + "progress": 0, + "status": "ACTIVE", + "tenant_id": "openstack", + "updated": "%(isotime)s", + "user_id": "fake" + } +} diff --git a/nova/tests/integrated/v3/test_disk_config.py b/nova/tests/integrated/v3/test_disk_config.py new file mode 100644 index 000000000000..6f40c43d0ee5 --- /dev/null +++ b/nova/tests/integrated/v3/test_disk_config.py @@ -0,0 +1,80 @@ +# Copyright 2012 Nebula, Inc. +# Copyright 2013 IBM Corp. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +from nova.tests.image import fake +from nova.tests.integrated.v3 import test_servers + + +class DiskConfigJsonTest(test_servers.ServersSampleBase): + extension_name = 'os-disk-config' + extra_extensions_to_load = ["images"] + + def test_list_servers_detail(self): + uuid = self._post_server() + response = self._do_get('servers/detail') + subs = self._get_regexes() + subs['hostid'] = '[a-f0-9]+' + subs['id'] = uuid + self._verify_response('list-servers-detail-get', subs, response, 200) + + def test_get_server(self): + uuid = self._post_server() + response = self._do_get('servers/%s' % uuid) + subs = self._get_regexes() + subs['hostid'] = '[a-f0-9]+' + self._verify_response('server-get-resp', subs, response, 200) + + def test_update_server(self): + uuid = self._post_server() + response = self._do_put('servers/%s' % uuid, + 'server-update-put-req', {}) + subs = self._get_regexes() + subs['hostid'] = '[a-f0-9]+' + self._verify_response('server-update-put-resp', subs, response, 200) + + def test_resize_server(self): + self.flags(allow_resize_to_same_host=True) + uuid = self._post_server() + response = self._do_post('servers/%s/action' % uuid, + 'server-resize-post-req', {}) + self.assertEqual(response.status_code, 202) + # NOTE(tmello): Resize does not return response body + # Bug #1085213. + self.assertEqual(response.content, "") + + def test_rebuild_server(self): + uuid = self._post_server() + subs = { + 'image_id': fake.get_valid_image_id(), + 'host': self._get_host(), + } + response = self._do_post('servers/%s/action' % uuid, + 'server-action-rebuild-req', subs) + subs = self._get_regexes() + subs['hostid'] = '[a-f0-9]+' + self._verify_response('server-action-rebuild-resp', + subs, response, 202) + + def test_get_image(self): + image_id = fake.get_valid_image_id() + response = self._do_get('images/%s' % image_id) + subs = self._get_regexes() + subs['image_id'] = image_id + self._verify_response('image-get-resp', subs, response, 200) + + def test_list_images(self): + response = self._do_get('images/detail') + subs = self._get_regexes() + self._verify_response('image-list-resp', subs, response, 200) diff --git a/setup.cfg b/setup.cfg index dc47cb785de2..c7431d0e36df 100644 --- a/setup.cfg +++ b/setup.cfg @@ -73,6 +73,7 @@ nova.api.v3.extensions = consoles = nova.api.openstack.compute.plugins.v3.consoles:Consoles create_backup = nova.api.openstack.compute.plugins.v3.create_backup:CreateBackup deferred_delete = nova.api.openstack.compute.plugins.v3.deferred_delete:DeferredDelete + disk_config = nova.api.openstack.compute.plugins.v3.disk_config:DiskConfig evacuate = nova.api.openstack.compute.plugins.v3.evacuate:Evacuate extended_availability_zone = nova.api.openstack.compute.plugins.v3.extended_availability_zone:ExtendedAvailabilityZone extended_server_attributes = nova.api.openstack.compute.plugins.v3.extended_server_attributes:ExtendedServerAttributes @@ -130,6 +131,7 @@ nova.api.v3.extensions.server.create = block_device_mapping = nova.api.openstack.compute.plugins.v3.block_device_mapping:BlockDeviceMapping block_device_mapping_v1 = nova.api.openstack.compute.plugins.v3.block_device_mapping_v1:BlockDeviceMappingV1 config_drive = nova.api.openstack.compute.plugins.v3.config_drive:ConfigDrive + disk_config = nova.api.openstack.compute.plugins.v3.disk_config:DiskConfig keypairs_create = nova.api.openstack.compute.plugins.v3.keypairs:Keypairs multiple_create = nova.api.openstack.compute.plugins.v3.multiple_create:MultipleCreate scheduler_hints = nova.api.openstack.compute.plugins.v3.scheduler_hints:SchedulerHints @@ -138,9 +140,14 @@ nova.api.v3.extensions.server.create = nova.api.v3.extensions.server.rebuild = access_ips = nova.api.openstack.compute.plugins.v3.access_ips:AccessIPs + disk_config = nova.api.openstack.compute.plugins.v3.disk_config:DiskConfig nova.api.v3.extensions.server.update = access_ips = nova.api.openstack.compute.plugins.v3.access_ips:AccessIPs + disk_config = nova.api.openstack.compute.plugins.v3.disk_config:DiskConfig + +nova.api.v3.extensions.server.resize = + disk_config = nova.api.openstack.compute.plugins.v3.disk_config:DiskConfig # These are for backwards compat with Havana notification_driver configuration values oslo.messaging.notify.drivers =