diff --git a/doc/api_samples/images/images-details-get-resp.json b/doc/api_samples/images/images-details-get-resp.json index 034c35f0c081..33cf667287f2 100644 --- a/doc/api_samples/images/images-details-get-resp.json +++ b/doc/api_samples/images/images-details-get-resp.json @@ -1,5 +1,190 @@ { "images": [ + { + "OS-EXT-IMG-SIZE:size": "25165824", + "created": "2011-01-01T01:02:03Z", + "id": "155d900f-4e14-4e4c-a73d-069cbf4541e6", + "links": [ + { + "href": "http://openstack.example.com/v2/6f70656e737461636b20342065766572/images/155d900f-4e14-4e4c-a73d-069cbf4541e6", + "rel": "self" + }, + { + "href": "http://openstack.example.com/6f70656e737461636b20342065766572/images/155d900f-4e14-4e4c-a73d-069cbf4541e6", + "rel": "bookmark" + }, + { + "href": "http://glance.openstack.example.com/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" + }, + { + "OS-EXT-IMG-SIZE:size": "58145823", + "created": "2011-01-01T01:02:03Z", + "id": "a2459075-d96c-40d5-893e-577ff92e721c", + "links": [ + { + "href": "http://openstack.example.com/v2/6f70656e737461636b20342065766572/images/a2459075-d96c-40d5-893e-577ff92e721c", + "rel": "self" + }, + { + "href": "http://openstack.example.com/6f70656e737461636b20342065766572/images/a2459075-d96c-40d5-893e-577ff92e721c", + "rel": "bookmark" + }, + { + "href": "http://glance.openstack.example.com/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-EXT-IMG-SIZE:size": "83594576", + "created": "2011-01-01T01:02:03Z", + "id": "76fa36fc-c930-4bf3-8c8a-ea2a2420deb6", + "links": [ + { + "href": "http://openstack.example.com/v2/6f70656e737461636b20342065766572/images/76fa36fc-c930-4bf3-8c8a-ea2a2420deb6", + "rel": "self" + }, + { + "href": "http://openstack.example.com/6f70656e737461636b20342065766572/images/76fa36fc-c930-4bf3-8c8a-ea2a2420deb6", + "rel": "bookmark" + }, + { + "href": "http://glance.openstack.example.com/images/76fa36fc-c930-4bf3-8c8a-ea2a2420deb6", + "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" + }, + { + "OS-EXT-IMG-SIZE:size": "84035174", + "created": "2011-01-01T01:02:03Z", + "id": "cedef40a-ed67-4d10-800e-17455edce175", + "links": [ + { + "href": "http://openstack.example.com/v2/6f70656e737461636b20342065766572/images/cedef40a-ed67-4d10-800e-17455edce175", + "rel": "self" + }, + { + "href": "http://openstack.example.com/6f70656e737461636b20342065766572/images/cedef40a-ed67-4d10-800e-17455edce175", + "rel": "bookmark" + }, + { + "href": "http://glance.openstack.example.com/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" + }, + { + "OS-EXT-IMG-SIZE:size": "26360814", + "created": "2011-01-01T01:02:03Z", + "id": "c905cedb-7281-47e4-8a62-f26bc5fc4c77", + "links": [ + { + "href": "http://openstack.example.com/v2/6f70656e737461636b20342065766572/images/c905cedb-7281-47e4-8a62-f26bc5fc4c77", + "rel": "self" + }, + { + "href": "http://openstack.example.com/6f70656e737461636b20342065766572/images/c905cedb-7281-47e4-8a62-f26bc5fc4c77", + "rel": "bookmark" + }, + { + "href": "http://glance.openstack.example.com/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" + }, + { + "OS-DCF:diskConfig": "MANUAL", + "OS-EXT-IMG-SIZE:size": "49163826", + "created": "2011-01-01T01:02:03Z", + "id": "a440c04b-79fa-479c-bed1-0b816eaec379", + "links": [ + { + "href": "http://openstack.example.com/v2/6f70656e737461636b20342065766572/images/a440c04b-79fa-479c-bed1-0b816eaec379", + "rel": "self" + }, + { + "href": "http://openstack.example.com/6f70656e737461636b20342065766572/images/a440c04b-79fa-479c-bed1-0b816eaec379", + "rel": "bookmark" + }, + { + "href": "http://glance.openstack.example.com/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" + }, { "OS-DCF:diskConfig": "AUTO", "OS-EXT-IMG-SIZE:size": "74185822", @@ -34,28 +219,26 @@ "updated": "2011-01-01T01:02:03Z" }, { - "OS-EXT-IMG-SIZE:size": "74185822", + "OS-EXT-IMG-SIZE:size": "25165824", "created": "2011-01-01T01:02:03Z", - "id": "155d900f-4e14-4e4c-a73d-069cbf4541e6", + "id": "95fad737-9325-4855-b37e-20a62268ec88", "links": [ { - "href": "http://openstack.example.com/v2/6f70656e737461636b20342065766572/images/155d900f-4e14-4e4c-a73d-069cbf4541e6", + "href": "http://openstack.example.com/v2/6f70656e737461636b20342065766572/images/95fad737-9325-4855-b37e-20a62268ec88", "rel": "self" }, { - "href": "http://openstack.example.com/6f70656e737461636b20342065766572/images/155d900f-4e14-4e4c-a73d-069cbf4541e6", + "href": "http://openstack.example.com/6f70656e737461636b20342065766572/images/95fad737-9325-4855-b37e-20a62268ec88", "rel": "bookmark" }, { - "href": "http://glance.openstack.example.com/images/155d900f-4e14-4e4c-a73d-069cbf4541e6", + "href": "http://glance.openstack.example.com/images/95fad737-9325-4855-b37e-20a62268ec88", "rel": "alternate", "type": "application/vnd.openstack.image" } ], "metadata": { - "architecture": "x86_64", - "kernel_id": "nokernel", - "ramdisk_id": "nokernel" + "hw_ephemeral_encryption": "True" }, "minDisk": 0, "minRam": 0, @@ -65,27 +248,26 @@ "updated": "2011-01-01T01:02:03Z" }, { - "OS-EXT-IMG-SIZE:size": "74185822", + "OS-EXT-IMG-SIZE:size": "25165824", "created": "2011-01-01T01:02:03Z", - "id": "a2459075-d96c-40d5-893e-577ff92e721c", + "id": "535426d4-5d75-44f4-9591-a2123d23c33f", "links": [ { - "href": "http://openstack.example.com/v2/6f70656e737461636b20342065766572/images/a2459075-d96c-40d5-893e-577ff92e721c", + "href": "http://openstack.example.com/v2/6f70656e737461636b20342065766572/images/535426d4-5d75-44f4-9591-a2123d23c33f", "rel": "self" }, { - "href": "http://openstack.example.com/6f70656e737461636b20342065766572/images/a2459075-d96c-40d5-893e-577ff92e721c", + "href": "http://openstack.example.com/6f70656e737461636b20342065766572/images/535426d4-5d75-44f4-9591-a2123d23c33f", "rel": "bookmark" }, { - "href": "http://glance.openstack.example.com/images/a2459075-d96c-40d5-893e-577ff92e721c", + "href": "http://glance.openstack.example.com/images/535426d4-5d75-44f4-9591-a2123d23c33f", "rel": "alternate", "type": "application/vnd.openstack.image" } ], "metadata": { - "kernel_id": "nokernel", - "ramdisk_id": "nokernel" + "hw_ephemeral_encryption": "False" }, "minDisk": 0, "minRam": 0, @@ -95,60 +277,27 @@ "updated": "2011-01-01T01:02:03Z" }, { - "OS-DCF:diskConfig": "MANUAL", - "OS-EXT-IMG-SIZE:size": "74185822", + "OS-EXT-IMG-SIZE:size": "25165824", "created": "2011-01-01T01:02:03Z", - "id": "a440c04b-79fa-479c-bed1-0b816eaec379", + "id": "5f7d4f5b-3781-4a4e-9046-a2a800e807e5", "links": [ { - "href": "http://openstack.example.com/v2/6f70656e737461636b20342065766572/images/a440c04b-79fa-479c-bed1-0b816eaec379", + "href": "http://openstack.example.com/v2/6f70656e737461636b20342065766572/images/5f7d4f5b-3781-4a4e-9046-a2a800e807e5", "rel": "self" }, { - "href": "http://openstack.example.com/6f70656e737461636b20342065766572/images/a440c04b-79fa-479c-bed1-0b816eaec379", + "href": "http://openstack.example.com/6f70656e737461636b20342065766572/images/5f7d4f5b-3781-4a4e-9046-a2a800e807e5", "rel": "bookmark" }, { - "href": "http://glance.openstack.example.com/images/a440c04b-79fa-479c-bed1-0b816eaec379", + "href": "http://glance.openstack.example.com/images/5f7d4f5b-3781-4a4e-9046-a2a800e807e5", "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" - }, - { - "OS-EXT-IMG-SIZE:size": "74185822", - "created": "2011-01-01T01:02:03Z", - "id": "c905cedb-7281-47e4-8a62-f26bc5fc4c77", - "links": [ - { - "href": "http://openstack.example.com/v2/6f70656e737461636b20342065766572/images/c905cedb-7281-47e4-8a62-f26bc5fc4c77", - "rel": "self" - }, - { - "href": "http://openstack.example.com/6f70656e737461636b20342065766572/images/c905cedb-7281-47e4-8a62-f26bc5fc4c77", - "rel": "bookmark" - }, - { - "href": "http://glance.openstack.example.com/images/c905cedb-7281-47e4-8a62-f26bc5fc4c77", - "rel": "alternate", - "type": "application/vnd.openstack.image" - } - ], - "metadata": { - "kernel_id": "155d900f-4e14-4e4c-a73d-069cbf4541e6", - "ramdisk_id": null + "hw_ephemeral_encryption": "True", + "hw_ephemeral_encryption_format": "luks" }, "minDisk": 0, "minRam": 0, @@ -158,58 +307,27 @@ "updated": "2011-01-01T01:02:03Z" }, { - "OS-EXT-IMG-SIZE:size": "74185822", + "OS-EXT-IMG-SIZE:size": "25165824", "created": "2011-01-01T01:02:03Z", - "id": "cedef40a-ed67-4d10-800e-17455edce175", + "id": "261b52ed-f693-4147-8f3b-d25df5efd968", "links": [ { - "href": "http://openstack.example.com/v2/6f70656e737461636b20342065766572/images/cedef40a-ed67-4d10-800e-17455edce175", + "href": "http://openstack.example.com/v2/6f70656e737461636b20342065766572/images/261b52ed-f693-4147-8f3b-d25df5efd968", "rel": "self" }, { - "href": "http://openstack.example.com/6f70656e737461636b20342065766572/images/cedef40a-ed67-4d10-800e-17455edce175", + "href": "http://openstack.example.com/6f70656e737461636b20342065766572/images/261b52ed-f693-4147-8f3b-d25df5efd968", "rel": "bookmark" }, { - "href": "http://glance.openstack.example.com/images/cedef40a-ed67-4d10-800e-17455edce175", + "href": "http://glance.openstack.example.com/images/261b52ed-f693-4147-8f3b-d25df5efd968", "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-EXT-IMG-SIZE:size": "74185822", - "created": "2011-01-01T01:02:03Z", - "id": "76fa36fc-c930-4bf3-8c8a-ea2a2420deb6", - "links": [ - { - "href": "http://openstack.example.com/v2/6f70656e737461636b20342065766572/images/76fa36fc-c930-4bf3-8c8a-ea2a2420deb6", - "rel": "self" - }, - { - "href": "http://openstack.example.com/6f70656e737461636b20342065766572/images/76fa36fc-c930-4bf3-8c8a-ea2a2420deb6", - "rel": "bookmark" - }, - { - "href": "http://glance.openstack.example.com/images/76fa36fc-c930-4bf3-8c8a-ea2a2420deb6", - "rel": "alternate", - "type": "application/vnd.openstack.image" - } - ], - "metadata": { - "architecture": "x86_64", - "kernel_id": "nokernel", - "ramdisk_id": "nokernel" + "hw_ephemeral_encryption": "True", + "hw_ephemeral_encryption_format": "plain" }, "minDisk": 0, "minRam": 0, @@ -219,4 +337,4 @@ "updated": "2011-01-01T01:02:03Z" } ] -} +} \ No newline at end of file diff --git a/doc/api_samples/images/images-list-get-resp.json b/doc/api_samples/images/images-list-get-resp.json index 00d06f96b3ac..e2207b9271c7 100644 --- a/doc/api_samples/images/images-list-get-resp.json +++ b/doc/api_samples/images/images-list-get-resp.json @@ -1,24 +1,5 @@ { "images": [ - { - "id": "70a599e0-31e7-49b7-b260-868f441e862b", - "links": [ - { - "href": "http://openstack.example.com/v2/6f70656e737461636b20342065766572/images/70a599e0-31e7-49b7-b260-868f441e862b", - "rel": "self" - }, - { - "href": "http://openstack.example.com/6f70656e737461636b20342065766572/images/70a599e0-31e7-49b7-b260-868f441e862b", - "rel": "bookmark" - }, - { - "href": "http://glance.openstack.example.com/images/70a599e0-31e7-49b7-b260-868f441e862b", - "rel": "alternate", - "type": "application/vnd.openstack.image" - } - ], - "name": "fakeimage7" - }, { "id": "155d900f-4e14-4e4c-a73d-069cbf4541e6", "links": [ @@ -58,37 +39,18 @@ "name": "fakeimage123456" }, { - "id": "a440c04b-79fa-479c-bed1-0b816eaec379", + "id": "76fa36fc-c930-4bf3-8c8a-ea2a2420deb6", "links": [ { - "href": "http://openstack.example.com/v2/6f70656e737461636b20342065766572/images/a440c04b-79fa-479c-bed1-0b816eaec379", + "href": "http://openstack.example.com/v2/6f70656e737461636b20342065766572/images/76fa36fc-c930-4bf3-8c8a-ea2a2420deb6", "rel": "self" }, { - "href": "http://openstack.example.com/6f70656e737461636b20342065766572/images/a440c04b-79fa-479c-bed1-0b816eaec379", + "href": "http://openstack.example.com/6f70656e737461636b20342065766572/images/76fa36fc-c930-4bf3-8c8a-ea2a2420deb6", "rel": "bookmark" }, { - "href": "http://glance.openstack.example.com/images/a440c04b-79fa-479c-bed1-0b816eaec379", - "rel": "alternate", - "type": "application/vnd.openstack.image" - } - ], - "name": "fakeimage6" - }, - { - "id": "c905cedb-7281-47e4-8a62-f26bc5fc4c77", - "links": [ - { - "href": "http://openstack.example.com/v2/6f70656e737461636b20342065766572/images/c905cedb-7281-47e4-8a62-f26bc5fc4c77", - "rel": "self" - }, - { - "href": "http://openstack.example.com/6f70656e737461636b20342065766572/images/c905cedb-7281-47e4-8a62-f26bc5fc4c77", - "rel": "bookmark" - }, - { - "href": "http://glance.openstack.example.com/images/c905cedb-7281-47e4-8a62-f26bc5fc4c77", + "href": "http://glance.openstack.example.com/images/76fa36fc-c930-4bf3-8c8a-ea2a2420deb6", "rel": "alternate", "type": "application/vnd.openstack.image" } @@ -115,18 +77,132 @@ "name": "fakeimage123456" }, { - "id": "76fa36fc-c930-4bf3-8c8a-ea2a2420deb6", + "id": "c905cedb-7281-47e4-8a62-f26bc5fc4c77", "links": [ { - "href": "http://openstack.example.com/v2/6f70656e737461636b20342065766572/images/76fa36fc-c930-4bf3-8c8a-ea2a2420deb6", + "href": "http://openstack.example.com/v2/6f70656e737461636b20342065766572/images/c905cedb-7281-47e4-8a62-f26bc5fc4c77", "rel": "self" }, { - "href": "http://openstack.example.com/6f70656e737461636b20342065766572/images/76fa36fc-c930-4bf3-8c8a-ea2a2420deb6", + "href": "http://openstack.example.com/6f70656e737461636b20342065766572/images/c905cedb-7281-47e4-8a62-f26bc5fc4c77", "rel": "bookmark" }, { - "href": "http://glance.openstack.example.com/images/76fa36fc-c930-4bf3-8c8a-ea2a2420deb6", + "href": "http://glance.openstack.example.com/images/c905cedb-7281-47e4-8a62-f26bc5fc4c77", + "rel": "alternate", + "type": "application/vnd.openstack.image" + } + ], + "name": "fakeimage123456" + }, + { + "id": "a440c04b-79fa-479c-bed1-0b816eaec379", + "links": [ + { + "href": "http://openstack.example.com/v2/6f70656e737461636b20342065766572/images/a440c04b-79fa-479c-bed1-0b816eaec379", + "rel": "self" + }, + { + "href": "http://openstack.example.com/6f70656e737461636b20342065766572/images/a440c04b-79fa-479c-bed1-0b816eaec379", + "rel": "bookmark" + }, + { + "href": "http://glance.openstack.example.com/images/a440c04b-79fa-479c-bed1-0b816eaec379", + "rel": "alternate", + "type": "application/vnd.openstack.image" + } + ], + "name": "fakeimage6" + }, + { + "id": "70a599e0-31e7-49b7-b260-868f441e862b", + "links": [ + { + "href": "http://openstack.example.com/v2/6f70656e737461636b20342065766572/images/70a599e0-31e7-49b7-b260-868f441e862b", + "rel": "self" + }, + { + "href": "http://openstack.example.com/6f70656e737461636b20342065766572/images/70a599e0-31e7-49b7-b260-868f441e862b", + "rel": "bookmark" + }, + { + "href": "http://glance.openstack.example.com/images/70a599e0-31e7-49b7-b260-868f441e862b", + "rel": "alternate", + "type": "application/vnd.openstack.image" + } + ], + "name": "fakeimage7" + }, + { + "id": "a2293931-dc33-45cc-85ef-232aa9491710", + "links": [ + { + "href": "http://openstack.example.com/v2/6f70656e737461636b20342065766572/images/a2293931-dc33-45cc-85ef-232aa9491710", + "rel": "self" + }, + { + "href": "http://openstack.example.com/6f70656e737461636b20342065766572/images/a2293931-dc33-45cc-85ef-232aa9491710", + "rel": "bookmark" + }, + { + "href": "http://glance.openstack.example.com/images/a2293931-dc33-45cc-85ef-232aa9491710", + "rel": "alternate", + "type": "application/vnd.openstack.image" + } + ], + "name": "fakeimage123456" + }, + { + "id": "e78f0ee9-96ef-4ce7-accf-e816f273be45", + "links": [ + { + "href": "http://openstack.example.com/v2/6f70656e737461636b20342065766572/images/e78f0ee9-96ef-4ce7-accf-e816f273be45", + "rel": "self" + }, + { + "href": "http://openstack.example.com/6f70656e737461636b20342065766572/images/e78f0ee9-96ef-4ce7-accf-e816f273be45", + "rel": "bookmark" + }, + { + "href": "http://glance.openstack.example.com/images/e78f0ee9-96ef-4ce7-accf-e816f273be45", + "rel": "alternate", + "type": "application/vnd.openstack.image" + } + ], + "name": "fakeimage123456" + }, + { + "id": "54eadb78-eeb6-4b13-beed-20b9894eeadf", + "links": [ + { + "href": "http://openstack.example.com/v2/6f70656e737461636b20342065766572/images/54eadb78-eeb6-4b13-beed-20b9894eeadf", + "rel": "self" + }, + { + "href": "http://openstack.example.com/6f70656e737461636b20342065766572/images/54eadb78-eeb6-4b13-beed-20b9894eeadf", + "rel": "bookmark" + }, + { + "href": "http://glance.openstack.example.com/images/54eadb78-eeb6-4b13-beed-20b9894eeadf", + "rel": "alternate", + "type": "application/vnd.openstack.image" + } + ], + "name": "fakeimage123456" + }, + { + "id": "eb7458f3-d003-4187-8027-595591dc2723", + "links": [ + { + "href": "http://openstack.example.com/v2/6f70656e737461636b20342065766572/images/eb7458f3-d003-4187-8027-595591dc2723", + "rel": "self" + }, + { + "href": "http://openstack.example.com/6f70656e737461636b20342065766572/images/eb7458f3-d003-4187-8027-595591dc2723", + "rel": "bookmark" + }, + { + "href": "http://glance.openstack.example.com/images/eb7458f3-d003-4187-8027-595591dc2723", "rel": "alternate", "type": "application/vnd.openstack.image" } @@ -134,4 +210,4 @@ "name": "fakeimage123456" } ] -} +} \ No newline at end of file diff --git a/nova/scheduler/request_filter.py b/nova/scheduler/request_filter.py index bd237b06cac0..1f88dc3b77f2 100644 --- a/nova/scheduler/request_filter.py +++ b/nova/scheduler/request_filter.py @@ -24,7 +24,7 @@ from nova.network import neutron from nova import objects from nova.scheduler.client import report from nova.scheduler import utils - +from nova.virt import hardware CONF = nova.conf.CONF LOG = logging.getLogger(__name__) @@ -394,6 +394,41 @@ def remote_managed_ports_filter( return True +@trace_request_filter +def ephemeral_encryption_filter( + ctxt: nova_context.RequestContext, + request_spec: 'objects.RequestSpec' +) -> bool: + """Pre-filter resource provides by ephemeral encryption support + + This filter will only retain compute node resource providers that support + ephemeral storage encryption when the associated image properties or flavor + extra specs are present within the request spec. + """ + # Skip if ephemeral encryption isn't requested in the flavor or image + if not hardware.get_ephemeral_encryption_constraint( + request_spec.flavor, request_spec.image): + LOG.debug("ephemeral_encryption_filter skipped") + return False + + # Always add the feature trait regardless of the format being provided + request_spec.root_required.add(os_traits.COMPUTE_EPHEMERAL_ENCRYPTION) + LOG.debug("ephemeral_encryption_filter added trait " + "COMPUTE_EPHEMERAL_ENCRYPTION") + + # Try to find the format in the flavor or image and add as a trait + eph_format = hardware.get_ephemeral_encryption_format( + request_spec.flavor, request_spec.image) + if eph_format: + # We don't need to validate the trait here because the earlier call to + # get_ephemeral_encryption_format will raise if it is not valid + trait_name = f"COMPUTE_EPHEMERAL_ENCRYPTION_{eph_format.upper()}" + request_spec.root_required.add(trait_name) + LOG.debug(f"ephemeral_encryption_filter added trait {trait_name}") + + return True + + ALL_REQUEST_FILTERS = [ require_tenant_aggregate, map_az_to_placement_aggregate, @@ -404,6 +439,7 @@ ALL_REQUEST_FILTERS = [ accelerators_filter, routed_networks_filter, remote_managed_ports_filter, + ephemeral_encryption_filter, ] diff --git a/nova/tests/fixtures/glance.py b/nova/tests/fixtures/glance.py index cf68f490b42d..b718f28c2aff 100644 --- a/nova/tests/fixtures/glance.py +++ b/nova/tests/fixtures/glance.py @@ -15,6 +15,7 @@ import datetime import fixtures from oslo_log import log as logging +from oslo_utils.fixture import uuidsentinel from oslo_utils import uuidutils from nova import exception @@ -198,6 +199,32 @@ class GlanceFixture(fixtures.Fixture): }, } + eph_encryption = copy.deepcopy(image1) + eph_encryption['id'] = uuidsentinel.eph_encryption + eph_encryption['properties'] = { + 'hw_ephemeral_encryption': 'True' + } + + eph_encryption_disabled = copy.deepcopy(image1) + eph_encryption_disabled['id'] = uuidsentinel.eph_encryption_disabled + eph_encryption_disabled['properties'] = { + 'hw_ephemeral_encryption': 'False' + } + + eph_encryption_luks = copy.deepcopy(image1) + eph_encryption_luks['id'] = uuidsentinel.eph_encryption_luks + eph_encryption_luks['properties'] = { + 'hw_ephemeral_encryption': 'True', + 'hw_ephemeral_encryption_format': 'luks' + } + + eph_encryption_plain = copy.deepcopy(image1) + eph_encryption_plain['id'] = uuidsentinel.eph_encryption_plain + eph_encryption_plain['properties'] = { + 'hw_ephemeral_encryption': 'True', + 'hw_ephemeral_encryption_format': 'plain' + } + def __init__(self, test): super().__init__() self.test = test @@ -222,6 +249,10 @@ class GlanceFixture(fixtures.Fixture): self.create(None, self.image5) self.create(None, self.auto_disk_config_disabled_image) self.create(None, self.auto_disk_config_enabled_image) + self.create(None, self.eph_encryption) + self.create(None, self.eph_encryption_disabled) + self.create(None, self.eph_encryption_luks) + self.create(None, self.eph_encryption_plain) self._imagedata = {} diff --git a/nova/tests/functional/api_sample_tests/api_samples/images/images-details-get-resp.json.tpl b/nova/tests/functional/api_sample_tests/api_samples/images/images-details-get-resp.json.tpl index 6b56f72139aa..d35850baed01 100644 --- a/nova/tests/functional/api_sample_tests/api_samples/images/images-details-get-resp.json.tpl +++ b/nova/tests/functional/api_sample_tests/api_samples/images/images-details-get-resp.json.tpl @@ -217,6 +217,124 @@ "progress": 100, "status": "ACTIVE", "updated": "2011-01-01T01:02:03Z" + }, + { + "created": "2011-01-01T01:02:03Z", + "id": "%(eph_encryption_id)s", + "links": [ + { + "href": "%(versioned_compute_endpoint)s/images/%(eph_encryption_id)s", + "rel": "self" + }, + { + "href": "%(compute_endpoint)s/images/%(eph_encryption_id)s", + "rel": "bookmark" + }, + { + "href": "http://glance.openstack.example.com/images/%(eph_encryption_id)s", + "rel": "alternate", + "type": "application/vnd.openstack.image" + } + ], + "metadata": { + "hw_ephemeral_encryption": "True" + }, + "minDisk": 0, + "minRam": 0, + "name": "fakeimage123456", + "OS-EXT-IMG-SIZE:size": %(int)s, + "progress": 100, + "status": "ACTIVE", + "updated": "2011-01-01T01:02:03Z" + }, + { + "created": "2011-01-01T01:02:03Z", + "id": "%(eph_encryption_disabled_id)s", + "links": [ + { + "href": "%(versioned_compute_endpoint)s/images/%(eph_encryption_disabled_id)s", + "rel": "self" + }, + { + "href": "%(compute_endpoint)s/images/%(eph_encryption_disabled_id)s", + "rel": "bookmark" + }, + { + "href": "http://glance.openstack.example.com/images/%(eph_encryption_disabled_id)s", + "rel": "alternate", + "type": "application/vnd.openstack.image" + } + ], + "metadata": { + "hw_ephemeral_encryption": "False" + }, + "minDisk": 0, + "minRam": 0, + "name": "fakeimage123456", + "OS-EXT-IMG-SIZE:size": %(int)s, + "progress": 100, + "status": "ACTIVE", + "updated": "2011-01-01T01:02:03Z" + }, + { + "created": "2011-01-01T01:02:03Z", + "id": "%(eph_encryption_luks_id)s", + "links": [ + { + "href": "%(versioned_compute_endpoint)s/images/%(eph_encryption_luks_id)s", + "rel": "self" + }, + { + "href": "%(compute_endpoint)s/images/%(eph_encryption_luks_id)s", + "rel": "bookmark" + }, + { + "href": "http://glance.openstack.example.com/images/%(eph_encryption_luks_id)s", + "rel": "alternate", + "type": "application/vnd.openstack.image" + } + ], + "metadata": { + "hw_ephemeral_encryption": "True", + "hw_ephemeral_encryption_format": "luks" + }, + "minDisk": 0, + "minRam": 0, + "name": "fakeimage123456", + "OS-EXT-IMG-SIZE:size": %(int)s, + "progress": 100, + "status": "ACTIVE", + "updated": "2011-01-01T01:02:03Z" + }, + { + "created": "2011-01-01T01:02:03Z", + "id": "%(eph_encryption_plain_id)s", + "links": [ + { + "href": "%(versioned_compute_endpoint)s/images/%(eph_encryption_plain_id)s", + "rel": "self" + }, + { + "href": "%(compute_endpoint)s/images/%(eph_encryption_plain_id)s", + "rel": "bookmark" + }, + { + "href": "http://glance.openstack.example.com/images/%(eph_encryption_plain_id)s", + "rel": "alternate", + "type": "application/vnd.openstack.image" + } + ], + "metadata": { + "hw_ephemeral_encryption": "True", + "hw_ephemeral_encryption_format": "plain" + }, + "minDisk": 0, + "minRam": 0, + "name": "fakeimage123456", + "OS-EXT-IMG-SIZE:size": %(int)s, + "progress": 100, + "status": "ACTIVE", + "updated": "2011-01-01T01:02:03Z" } ] } diff --git a/nova/tests/functional/api_sample_tests/api_samples/images/images-list-get-resp.json.tpl b/nova/tests/functional/api_sample_tests/api_samples/images/images-list-get-resp.json.tpl index 035cc83695dd..dc08ba70537e 100644 --- a/nova/tests/functional/api_sample_tests/api_samples/images/images-list-get-resp.json.tpl +++ b/nova/tests/functional/api_sample_tests/api_samples/images/images-list-get-resp.json.tpl @@ -132,6 +132,82 @@ } ], "name": "fakeimage123456" + }, + { + "id": "%(eph_encryption_id)s", + "links": [ + { + "href": "%(versioned_compute_endpoint)s/images/%(eph_encryption_id)s", + "rel": "self" + }, + { + "href": "%(compute_endpoint)s/images/%(eph_encryption_id)s", + "rel": "bookmark" + }, + { + "href": "http://glance.openstack.example.com/images/%(eph_encryption_id)s", + "rel": "alternate", + "type": "application/vnd.openstack.image" + } + ], + "name": "fakeimage123456" + }, + { + "id": "%(eph_encryption_disabled_id)s", + "links": [ + { + "href": "%(versioned_compute_endpoint)s/images/%(eph_encryption_disabled_id)s", + "rel": "self" + }, + { + "href": "%(compute_endpoint)s/images/%(eph_encryption_disabled_id)s", + "rel": "bookmark" + }, + { + "href": "http://glance.openstack.example.com/images/%(eph_encryption_disabled_id)s", + "rel": "alternate", + "type": "application/vnd.openstack.image" + } + ], + "name": "fakeimage123456" + }, + { + "id": "%(eph_encryption_luks_id)s", + "links": [ + { + "href": "%(versioned_compute_endpoint)s/images/%(eph_encryption_luks_id)s", + "rel": "self" + }, + { + "href": "%(compute_endpoint)s/images/%(eph_encryption_luks_id)s", + "rel": "bookmark" + }, + { + "href": "http://glance.openstack.example.com/images/%(eph_encryption_luks_id)s", + "rel": "alternate", + "type": "application/vnd.openstack.image" + } + ], + "name": "fakeimage123456" + }, + { + "id": "%(eph_encryption_plain_id)s", + "links": [ + { + "href": "%(versioned_compute_endpoint)s/images/%(eph_encryption_plain_id)s", + "rel": "self" + }, + { + "href": "%(compute_endpoint)s/images/%(eph_encryption_plain_id)s", + "rel": "bookmark" + }, + { + "href": "http://glance.openstack.example.com/images/%(eph_encryption_plain_id)s", + "rel": "alternate", + "type": "application/vnd.openstack.image" + } + ], + "name": "fakeimage123456" } ] } diff --git a/nova/tests/functional/api_sample_tests/test_images.py b/nova/tests/functional/api_sample_tests/test_images.py index 924bc7768fba..c84e56640997 100644 --- a/nova/tests/functional/api_sample_tests/test_images.py +++ b/nova/tests/functional/api_sample_tests/test_images.py @@ -19,10 +19,29 @@ from nova.tests.functional.api_sample_tests import api_sample_base class ImagesSampleJsonTest(api_sample_base.ApiSampleTestBaseV21): sample_dir = 'images' + def generalize_subs(self, subs, vanilla_regexes): + """Give the test a chance to modify subs after the server response + was verified, and before the on-disk doc/api_samples file is checked. + """ + # When comparing the template to the sample we just care that the image + # IDs are UUIDs. + subs['eph_encryption_id'] = vanilla_regexes['uuid'] + subs['eph_encryption_disabled_id'] = vanilla_regexes['uuid'] + subs['eph_encryption_luks_id'] = vanilla_regexes['uuid'] + subs['eph_encryption_plain_id'] = vanilla_regexes['uuid'] + return subs + def test_images_list(self): # Get api sample of images get list request. response = self._do_get('images') - self._verify_response('images-list-get-resp', {}, response, 200) + subs = { + 'eph_encryption_id': self.glance.eph_encryption['id'], + 'eph_encryption_disabled_id': + self.glance.eph_encryption_disabled['id'], + 'eph_encryption_luks_id': self.glance.eph_encryption_luks['id'], + 'eph_encryption_plain_id': self.glance.eph_encryption_plain['id'], + } + self._verify_response('images-list-get-resp', subs, response, 200) def test_image_get(self): # Get api sample of one single image details request. @@ -34,7 +53,14 @@ class ImagesSampleJsonTest(api_sample_base.ApiSampleTestBaseV21): def test_images_details(self): # Get api sample of all images details request. response = self._do_get('images/detail') - self._verify_response('images-details-get-resp', {}, response, 200) + subs = { + 'eph_encryption_id': self.glance.eph_encryption['id'], + 'eph_encryption_disabled_id': + self.glance.eph_encryption_disabled['id'], + 'eph_encryption_luks_id': self.glance.eph_encryption_luks['id'], + 'eph_encryption_plain_id': self.glance.eph_encryption_plain['id'], + } + self._verify_response('images-details-get-resp', subs, response, 200) def test_image_metadata_get(self): # Get api sample of an image metadata request. diff --git a/nova/tests/functional/integrated_helpers.py b/nova/tests/functional/integrated_helpers.py index 028ef53d7ea5..623c4f0ef705 100644 --- a/nova/tests/functional/integrated_helpers.py +++ b/nova/tests/functional/integrated_helpers.py @@ -247,6 +247,27 @@ class InstanceHelperMixin: self.assertIn(error_in_tb, event['traceback']) return event + def _assert_build_request_success(self, server_request): + server = self.api.post_server({'server': server_request}) + self._wait_for_state_change(server, 'ACTIVE') + return server['id'] + + def _assert_build_request_schedule_failure(self, server_request): + server = self.api.post_server({'server': server_request}) + self._wait_for_state_change(server, 'ERROR') + + def _assert_bad_build_request_error(self, server_request): + ex = self.assertRaises( + api_client.OpenStackApiException, self.api.post_server, + {'server': server_request}) + self.assertEqual(400, ex.response.status_code) + + def _assert_build_request_error(self, server_request): + ex = self.assertRaises( + api_client.OpenStackApiException, self.api.post_server, + {'server': server_request}) + self.assertEqual(500, ex.response.status_code) + def _wait_for_migration_status(self, server, expected_statuses): """Waits for a migration record with the given statuses to be found for the given server, else the test fails. The migration record, if diff --git a/nova/tests/functional/test_ephemeral_encryption.py b/nova/tests/functional/test_ephemeral_encryption.py new file mode 100644 index 000000000000..ba5e4119025d --- /dev/null +++ b/nova/tests/functional/test_ephemeral_encryption.py @@ -0,0 +1,381 @@ +# 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 oslo_utils.fixture import uuidsentinel + +from nova import context +from nova import objects +from nova.tests.functional import integrated_helpers + + +class _TestEphemeralEncryptionBase( + integrated_helpers.ProviderUsageBaseTestCase +): + # NOTE(lyarwood): A dict of test flavors defined per test class, + # keyed by flavor name and providing an additional dict containing an 'id' + # and optional 'extra_specs' dict. For example: + # { + # 'name': { + # 'id': uuidsentinel.flavor_id + # 'extra_specs': { + # 'hw:foo': 'bar' + # } + # } + # } + flavors = {} + + def setUp(self): + super().setUp() + + self.ctxt = context.get_admin_context() + + # Create the required test flavors + for name, details in self.flavors.items(): + flavor = self.admin_api.post_flavor({ + 'flavor': { + 'name': name, + 'id': details['id'], + 'ram': 512, + 'vcpus': 1, + 'disk': 1024, + } + }) + # Add the optional extra_specs + if details.get('extra_specs'): + self.admin_api.post_extra_spec( + flavor['id'], {'extra_specs': details['extra_specs']}) + + # We only need a single compute for these tests + self._start_compute(host='compute1') + + def _assert_ephemeral_encryption_enabled( + self, server_id, encryption_format=None): + bdms = objects.BlockDeviceMappingList.get_by_instance_uuid( + self.ctxt, server_id) + for bdm in bdms: + if bdm.is_local: + self.assertTrue(bdm.encrypted) + if encryption_format: + self.assertEqual( + encryption_format, bdm.encryption_format) + + def _assert_ephemeral_encryption_disabled(self, server_id): + bdms = objects.BlockDeviceMappingList.get_by_instance_uuid( + self.ctxt, server_id) + for bdm in bdms: + if bdm.is_local: + self.assertFalse(bdm.encrypted) + + +class TestEphemeralEncryptionAvailable(_TestEphemeralEncryptionBase): + + compute_driver = 'fake.EphEncryptionDriver' + flavors = { + 'no_eph_encryption': { + 'id': uuidsentinel.no_eph_encryption + }, + 'eph_encryption': { + 'id': uuidsentinel.eph_encryption_flavor, + 'extra_specs': { + 'hw:ephemeral_encryption': 'True' + } + }, + 'eph_encryption_disabled': { + 'id': uuidsentinel.eph_encryption_disabled_flavor, + 'extra_specs': { + 'hw:ephemeral_encryption': 'False' + } + }, + } + + def test_image_requested(self): + server_request = self._build_server( + flavor_id=uuidsentinel.no_eph_encryption, + image_uuid=uuidsentinel.eph_encryption, + networks=[]) + server_id = self._assert_build_request_success(server_request) + self._assert_ephemeral_encryption_enabled(server_id) + + def test_image_disabled(self): + server_request = self._build_server( + flavor_id=uuidsentinel.no_eph_encryption, + image_uuid=uuidsentinel.eph_encryption_disabled, + networks=[]) + server_id = self._assert_build_request_success(server_request) + self._assert_ephemeral_encryption_disabled(server_id) + + def test_flavor_requested(self): + server_request = self._build_server( + flavor_id=uuidsentinel.eph_encryption_flavor, + networks=[]) + server_id = self._assert_build_request_success(server_request) + self._assert_ephemeral_encryption_enabled(server_id) + + def test_flavor_disabled(self): + server_request = self._build_server( + flavor_id=uuidsentinel.eph_encryption_disabled_flavor, + networks=[]) + server_id = self._assert_build_request_success(server_request) + self._assert_ephemeral_encryption_disabled(server_id) + + def test_flavor_and_image_requested(self): + server_request = self._build_server( + flavor_id=uuidsentinel.eph_encryption_flavor, + image_uuid=uuidsentinel.eph_encryption, + networks=[]) + server_id = self._assert_build_request_success(server_request) + self._assert_ephemeral_encryption_enabled(server_id) + + def test_flavor_and_image_disabled(self): + server_request = self._build_server( + flavor_id=uuidsentinel.eph_encryption_disabled_flavor, + image_uuid=uuidsentinel.eph_encryption_disabled, + networks=[]) + server_id = self._assert_build_request_success(server_request) + self._assert_ephemeral_encryption_disabled(server_id) + + def test_flavor_requested_and_image_disabled(self): + server_request = self._build_server( + flavor_id=uuidsentinel.eph_encryption_flavor, + image_uuid=uuidsentinel.eph_encryption_disabled, + networks=[]) + self._assert_bad_build_request_error(server_request) + + def test_flavor_disabled_and_image_requested(self): + server_request = self._build_server( + flavor_id=uuidsentinel.eph_encryption_disabled_flavor, + image_uuid=uuidsentinel.eph_encryption, + networks=[]) + self._assert_bad_build_request_error(server_request) + + +class TestEphemeralEncryptionUnavailable(_TestEphemeralEncryptionBase): + + compute_driver = 'fake.MediumFakeDriver' + flavors = { + 'no_eph_encryption': { + 'id': uuidsentinel.no_eph_encryption + }, + 'eph_encryption': { + 'id': uuidsentinel.eph_encryption_flavor, + 'extra_specs': { + 'hw:ephemeral_encryption': 'True' + } + }, + 'eph_encryption_disabled': { + 'id': uuidsentinel.eph_encryption_disabled_flavor, + 'extra_specs': { + 'hw:ephemeral_encryption': 'False' + } + }, + } + + def test_requested_but_unavailable(self): + server_request = self._build_server( + flavor_id=uuidsentinel.eph_encryption_flavor, + image_uuid=uuidsentinel.eph_encryption, + networks=[]) + self._assert_build_request_schedule_failure(server_request) + + def test_image_disabled(self): + server_request = self._build_server( + image_uuid=uuidsentinel.eph_encryption_disabled, + flavor_id=uuidsentinel.no_eph_encryption, + networks=[]) + server_id = self._assert_build_request_success(server_request) + self._assert_ephemeral_encryption_disabled(server_id) + + def test_flavor_disabled(self): + server_request = self._build_server( + flavor_id=uuidsentinel.eph_encryption_disabled_flavor, + networks=[]) + server_id = self._assert_build_request_success(server_request) + self._assert_ephemeral_encryption_disabled(server_id) + + +class TestEphemeralEncryptionLUKS(TestEphemeralEncryptionAvailable): + + compute_driver = 'fake.EphEncryptionDriverLUKS' + flavors = { + 'no_eph_encryption': { + 'id': uuidsentinel.no_eph_encryption + }, + 'eph_encryption': { + 'id': uuidsentinel.eph_encryption_flavor, + 'extra_specs': { + 'hw:ephemeral_encryption': 'True' + } + }, + 'eph_encryption_disabled': { + 'id': uuidsentinel.eph_encryption_disabled_flavor, + 'extra_specs': { + 'hw:ephemeral_encryption': 'False' + } + }, + 'eph_encryption_luks': { + 'id': uuidsentinel.eph_encryption_luks_flavor, + 'extra_specs': { + 'hw:ephemeral_encryption': 'True', + 'hw:ephemeral_encryption_format': 'luks' + } + }, + 'eph_encryption_plain': { + 'id': uuidsentinel.eph_encryption_plain_flavor, + 'extra_specs': { + 'hw:ephemeral_encryption': 'True', + 'hw:ephemeral_encryption_format': 'plain' + } + }, + + } + + def test_image_requested_luks(self): + server_request = self._build_server( + flavor_id=uuidsentinel.no_eph_encryption, + image_uuid=uuidsentinel.eph_encryption_luks, + networks=[]) + server_id = self._assert_build_request_success(server_request) + self._assert_ephemeral_encryption_enabled( + server_id, encryption_format='luks') + + def test_flavor_requested_luks(self): + server_request = self._build_server( + flavor_id=uuidsentinel.eph_encryption_luks_flavor, + networks=[]) + server_id = self._assert_build_request_success(server_request) + self._assert_ephemeral_encryption_enabled( + server_id, encryption_format='luks') + + def test_flavor_and_image_requested_luks(self): + server_request = self._build_server( + flavor_id=uuidsentinel.eph_encryption_luks_flavor, + image_uuid=uuidsentinel.eph_encryption_luks, + networks=[]) + server_id = self._assert_build_request_success(server_request) + self._assert_ephemeral_encryption_enabled( + server_id, encryption_format='luks') + + def test_image_requested_plain(self): + server_request = self._build_server( + flavor_id=uuidsentinel.no_eph_encryption, + image_uuid=uuidsentinel.eph_encryption_plain, + networks=[]) + self._assert_build_request_schedule_failure(server_request) + + def test_flavor_requested_plain(self): + server_request = self._build_server( + flavor_id=uuidsentinel.eph_encryption_plain_flavor, + networks=[]) + self._assert_build_request_schedule_failure(server_request) + + def test_image_requested_luks_flavor_requested_plain(self): + server_request = self._build_server( + image_uuid=uuidsentinel.eph_encryption_luks, + flavor_id=uuidsentinel.eph_encryption_plain_flavor, + networks=[]) + self._assert_bad_build_request_error(server_request) + + def test_image_requested_plain_flavor_requested_luks(self): + server_request = self._build_server( + image_uuid=uuidsentinel.eph_encryption_plain, + flavor_id=uuidsentinel.eph_encryption_luks_flavor, + networks=[]) + self._assert_bad_build_request_error(server_request) + + +class TestEphemeralEncryptionPLAIN(_TestEphemeralEncryptionBase): + + compute_driver = 'fake.EphEncryptionDriverPLAIN' + flavors = { + 'no_eph_encryption': { + 'id': uuidsentinel.no_eph_encryption + }, + 'eph_encryption': { + 'id': uuidsentinel.eph_encryption_flavor, + 'extra_specs': { + 'hw:ephemeral_encryption': 'True' + } + }, + 'eph_encryption_disabled': { + 'id': uuidsentinel.eph_encryption_disabled_flavor, + 'extra_specs': { + 'hw:ephemeral_encryption': 'False' + } + }, + 'eph_encryption_luks': { + 'id': uuidsentinel.eph_encryption_luks_flavor, + 'extra_specs': { + 'hw:ephemeral_encryption': 'True', + 'hw:ephemeral_encryption_format': 'luks' + } + }, + 'eph_encryption_plain': { + 'id': uuidsentinel.eph_encryption_plain_flavor, + 'extra_specs': { + 'hw:ephemeral_encryption': 'True', + 'hw:ephemeral_encryption_format': 'plain' + } + }, + } + + def test_image_requested_plain(self): + server_request = self._build_server( + flavor_id=uuidsentinel.no_eph_encryption, + image_uuid=uuidsentinel.eph_encryption_plain, + networks=[]) + server_id = self._assert_build_request_success(server_request) + self._assert_ephemeral_encryption_enabled( + server_id, encryption_format='plain') + + def test_flavor_requested_plain(self): + server_request = self._build_server( + flavor_id=uuidsentinel.eph_encryption_plain_flavor, + networks=[]) + server_id = self._assert_build_request_success(server_request) + self._assert_ephemeral_encryption_enabled( + server_id, encryption_format='plain') + + def test_flavor_and_image_requested_plain(self): + server_request = self._build_server( + flavor_id=uuidsentinel.eph_encryption_plain_flavor, + image_uuid=uuidsentinel.eph_encryption_plain, + networks=[]) + server_id = self._assert_build_request_success(server_request) + self._assert_ephemeral_encryption_enabled( + server_id, encryption_format='plain') + + def test_image_requested_luks(self): + server_request = self._build_server( + flavor_id=uuidsentinel.no_eph_encryption, + image_uuid=uuidsentinel.eph_encryption_luks, + networks=[]) + self._assert_build_request_schedule_failure(server_request) + + def test_flavor_requested_luks(self): + server_request = self._build_server( + flavor_id=uuidsentinel.eph_encryption_luks_flavor, + networks=[]) + self._assert_build_request_schedule_failure(server_request) + + def test_image_requested_plain_flavor_requested_luks(self): + server_request = self._build_server( + image_uuid=uuidsentinel.eph_encryption_plain, + flavor_id=uuidsentinel.eph_encryption_luks_flavor, + networks=[]) + self._assert_bad_build_request_error(server_request) + + def test_image_requested_luks_flavor_requested_plain(self): + server_request = self._build_server( + image_uuid=uuidsentinel.eph_encryption_luks, + flavor_id=uuidsentinel.eph_encryption_plain_flavor, + networks=[]) + self._assert_bad_build_request_error(server_request) diff --git a/nova/tests/unit/scheduler/test_request_filter.py b/nova/tests/unit/scheduler/test_request_filter.py index 186482d4a853..77e538006a8f 100644 --- a/nova/tests/unit/scheduler/test_request_filter.py +++ b/nova/tests/unit/scheduler/test_request_filter.py @@ -612,3 +612,90 @@ class TestRequestFilter(test.NoDBTestCase): mock_get_aggs_network.assert_has_calls([ mock.call(self.context, mock.ANY, mock.ANY, uuids.net1), mock.call(self.context, mock.ANY, mock.ANY, uuids.net2)]) + + def test_ephemeral_encryption_filter_no_encryption(self): + # First ensure that ephemeral_encryption_filter is included + self.assertIn(request_filter.ephemeral_encryption_filter, + request_filter.ALL_REQUEST_FILTERS) + + reqspec = objects.RequestSpec( + flavor=objects.Flavor(extra_specs={}), + image=objects.ImageMeta( + properties=objects.ImageMetaProps())) + + self.assertEqual(set(), reqspec.root_required) + self.assertEqual(set(), reqspec.root_forbidden) + + # Assert that the filter returns false and doesn't update the reqspec + self.assertFalse( + request_filter.ephemeral_encryption_filter(self.context, reqspec)) + self.assertEqual(set(), reqspec.root_required) + self.assertEqual(set(), reqspec.root_forbidden) + + def test_ephemeral_encryption_filter_encryption_disabled(self): + # First ensure that ephemeral_encryption_filter is included + self.assertIn(request_filter.ephemeral_encryption_filter, + request_filter.ALL_REQUEST_FILTERS) + + reqspec = objects.RequestSpec( + flavor=objects.Flavor(extra_specs={}), + image=objects.ImageMeta( + properties=objects.ImageMetaProps( + hw_ephemeral_encryption=False))) + self.assertFalse( + request_filter.ephemeral_encryption_filter( + self.context, reqspec)) + self.assertEqual(set(), reqspec.root_required) + self.assertEqual(set(), reqspec.root_forbidden) + + reqspec = objects.RequestSpec( + flavor=objects.Flavor(extra_specs={ + 'hw:ephemeral_encryption': 'False'}), + image=objects.ImageMeta( + properties=objects.ImageMetaProps())) + self.assertFalse( + request_filter.ephemeral_encryption_filter( + self.context, reqspec)) + self.assertEqual(set(), reqspec.root_required) + self.assertEqual(set(), reqspec.root_forbidden) + + def test_ephemeral_encryption_filter_encryption_no_format(self): + # First ensure that ephemeral_encryption_filter is included + self.assertIn(request_filter.ephemeral_encryption_filter, + request_filter.ALL_REQUEST_FILTERS) + + reqspec = objects.RequestSpec( + flavor=objects.Flavor(extra_specs={ + 'hw:ephemeral_encryption': 'True'}), + image=objects.ImageMeta( + properties=objects.ImageMetaProps())) + self.assertEqual(set(), reqspec.root_required) + self.assertEqual(set(), reqspec.root_forbidden) + self.assertTrue( + request_filter.ephemeral_encryption_filter(self.context, reqspec)) + self.assertEqual( + {ot.COMPUTE_EPHEMERAL_ENCRYPTION}, reqspec.root_required) + self.assertEqual(set(), reqspec.root_forbidden) + + def test_ephemeral_encryption_filter_encryption_and_format(self): + # First ensure that ephemeral_encryption_filter is included + self.assertIn(request_filter.ephemeral_encryption_filter, + request_filter.ALL_REQUEST_FILTERS) + + reqspec = objects.RequestSpec( + flavor=objects.Flavor( + extra_specs={ + 'hw:ephemeral_encryption': 'True', + 'hw:ephemeral_encryption_format': 'luks' + }), + image=objects.ImageMeta( + properties=objects.ImageMetaProps())) + self.assertEqual(set(), reqspec.root_required) + self.assertEqual(set(), reqspec.root_forbidden) + self.assertTrue( + request_filter.ephemeral_encryption_filter(self.context, reqspec)) + self.assertEqual( + {ot.COMPUTE_EPHEMERAL_ENCRYPTION, + ot.COMPUTE_EPHEMERAL_ENCRYPTION_LUKS}, + reqspec.root_required) + self.assertEqual(set(), reqspec.root_forbidden) diff --git a/nova/virt/fake.py b/nova/virt/fake.py index 02fc1f07bcb6..523363942f03 100644 --- a/nova/virt/fake.py +++ b/nova/virt/fake.py @@ -1099,3 +1099,23 @@ class FakeDriverWithCaching(FakeDriver): else: self.cached_images.add(image_id) return True + + +class EphEncryptionDriver(MediumFakeDriver): + capabilities = dict( + FakeDriver.capabilities, + supports_ephemeral_encryption=True) + + +class EphEncryptionDriverLUKS(MediumFakeDriver): + capabilities = dict( + FakeDriver.capabilities, + supports_ephemeral_encryption=True, + supports_ephemeral_encryption_luks=True) + + +class EphEncryptionDriverPLAIN(MediumFakeDriver): + capabilities = dict( + FakeDriver.capabilities, + supports_ephemeral_encryption=True, + supports_ephemeral_encryption_plain=True)