From bf96ca7c9a270a8b13892c0062c8fbb5c5f4c494 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Ribaud?= Date: Tue, 26 Jul 2022 11:36:24 +0200 Subject: [PATCH] Add shares to InstancePayload This patch add share information to the InstancePayload that can be sent if the include_share_mapping configuration parameter is enabled. Manila is the OpenStack Shared Filesystems service. These series of patches implement changes required in Nova to allow the shares provided by Manila to be associated with and attached to instances using virtiofs. Implements: blueprint libvirt-virtiofs-attach-manila-shares Change-Id: I3d5005eab9e3f23be149e955e8cb4608a6ee1312 --- .../InstanceActionPayload.json | 2 +- .../InstanceActionPayloadShareActive.json | 9 ++ .../InstanceActionPayloadShareInactive.json | 9 ++ .../InstanceActionRebuildPayload.json | 19 ++- .../InstanceActionRescuePayload.json | 12 +- .../InstanceActionResizePrepPayload.json | 54 ++++----- .../InstanceActionSnapshotPayload.json | 14 +-- .../InstanceActionVolumePayload.json | 16 +-- .../InstanceActionVolumeSwapPayload.json | 2 +- .../InstanceCreatePayload.json | 49 ++++---- .../InstanceExistsPayload.json | 12 +- .../common_payloads/InstancePayload.json | 5 +- .../InstancePayloadShareActive.json | 57 +++++++++ .../InstancePayloadShareInactive.json | 57 +++++++++ .../InstanceUpdatePayload.json | 58 ++++----- .../common_payloads/ShareActivePayload.json | 12 ++ .../common_payloads/ShareInactivePayload.json | 12 ++ .../instance-power_on_share-end.json | 8 ++ .../instance-power_on_share-start.json | 13 +++ nova/conf/notifications.py | 9 ++ nova/notifications/objects/instance.py | 82 +++++++++++-- nova/objects/instance.py | 4 + nova/tests/functional/integrated_helpers.py | 4 +- .../test_instance.py | 110 +++++++++++++++++- .../notifications/objects/test_instance.py | 41 +++++++ .../objects/test_notification.py | 25 ++-- 26 files changed, 542 insertions(+), 153 deletions(-) create mode 100644 doc/notification_samples/common_payloads/InstanceActionPayloadShareActive.json create mode 100644 doc/notification_samples/common_payloads/InstanceActionPayloadShareInactive.json create mode 100644 doc/notification_samples/common_payloads/InstancePayloadShareActive.json create mode 100644 doc/notification_samples/common_payloads/InstancePayloadShareInactive.json create mode 100644 doc/notification_samples/common_payloads/ShareActivePayload.json create mode 100644 doc/notification_samples/common_payloads/ShareInactivePayload.json create mode 100644 doc/notification_samples/instance-power_on_share-end.json create mode 100644 doc/notification_samples/instance-power_on_share-start.json diff --git a/doc/notification_samples/common_payloads/InstanceActionPayload.json b/doc/notification_samples/common_payloads/InstanceActionPayload.json index 4906f1428e..92fb00ea27 100644 --- a/doc/notification_samples/common_payloads/InstanceActionPayload.json +++ b/doc/notification_samples/common_payloads/InstanceActionPayload.json @@ -5,5 +5,5 @@ }, "nova_object.name":"InstanceActionPayload", "nova_object.namespace":"nova", - "nova_object.version":"1.8" + "nova_object.version":"1.9" } diff --git a/doc/notification_samples/common_payloads/InstanceActionPayloadShareActive.json b/doc/notification_samples/common_payloads/InstanceActionPayloadShareActive.json new file mode 100644 index 0000000000..9d72e4aff4 --- /dev/null +++ b/doc/notification_samples/common_payloads/InstanceActionPayloadShareActive.json @@ -0,0 +1,9 @@ +{ + "$ref": "InstancePayloadShareActive.json", + "nova_object.data": { + "fault": null + }, + "nova_object.name": "InstanceActionPayload", + "nova_object.namespace": "nova", + "nova_object.version": "1.9" +} diff --git a/doc/notification_samples/common_payloads/InstanceActionPayloadShareInactive.json b/doc/notification_samples/common_payloads/InstanceActionPayloadShareInactive.json new file mode 100644 index 0000000000..27c9b279d7 --- /dev/null +++ b/doc/notification_samples/common_payloads/InstanceActionPayloadShareInactive.json @@ -0,0 +1,9 @@ +{ + "$ref": "InstancePayloadShareInactive.json", + "nova_object.data": { + "fault": null + }, + "nova_object.name": "InstanceActionPayload", + "nova_object.namespace": "nova", + "nova_object.version": "1.9" +} diff --git a/doc/notification_samples/common_payloads/InstanceActionRebuildPayload.json b/doc/notification_samples/common_payloads/InstanceActionRebuildPayload.json index 2d05adaded..df1b1d29dd 100644 --- a/doc/notification_samples/common_payloads/InstanceActionRebuildPayload.json +++ b/doc/notification_samples/common_payloads/InstanceActionRebuildPayload.json @@ -1,13 +1,10 @@ { - "$ref": "InstanceActionPayload.json", - "nova_object.data": { - "architecture": null, - "image_uuid": "a2459075-d96c-40d5-893e-577ff92e721c", - "trusted_image_certificates": [ - "rebuild-cert-id-1", - "rebuild-cert-id-2" - ] - }, - "nova_object.name": "InstanceActionRebuildPayload", - "nova_object.version": "1.9" + "$ref": "InstanceActionPayload.json", + "nova_object.data": { + "architecture": null, + "image_uuid": "a2459075-d96c-40d5-893e-577ff92e721c", + "trusted_image_certificates": ["rebuild-cert-id-1", "rebuild-cert-id-2"] + }, + "nova_object.name": "InstanceActionRebuildPayload", + "nova_object.version": "1.10" } diff --git a/doc/notification_samples/common_payloads/InstanceActionRescuePayload.json b/doc/notification_samples/common_payloads/InstanceActionRescuePayload.json index 6970372225..25caa66c8f 100644 --- a/doc/notification_samples/common_payloads/InstanceActionRescuePayload.json +++ b/doc/notification_samples/common_payloads/InstanceActionRescuePayload.json @@ -1,8 +1,8 @@ { - "$ref": "InstanceActionPayload.json", - "nova_object.data": { - "rescue_image_ref": "a2459075-d96c-40d5-893e-577ff92e721c" - }, - "nova_object.name": "InstanceActionRescuePayload", - "nova_object.version": "1.3" + "$ref": "InstanceActionPayload.json", + "nova_object.data": { + "rescue_image_ref": "a2459075-d96c-40d5-893e-577ff92e721c" + }, + "nova_object.name": "InstanceActionRescuePayload", + "nova_object.version": "1.4" } diff --git a/doc/notification_samples/common_payloads/InstanceActionResizePrepPayload.json b/doc/notification_samples/common_payloads/InstanceActionResizePrepPayload.json index 9c32576d69..f5d603a7cc 100644 --- a/doc/notification_samples/common_payloads/InstanceActionResizePrepPayload.json +++ b/doc/notification_samples/common_payloads/InstanceActionResizePrepPayload.json @@ -1,31 +1,31 @@ { - "$ref": "InstanceActionPayload.json", - "nova_object.data":{ - "new_flavor": { - "nova_object.name": "FlavorPayload", - "nova_object.data": { - "description": null, - "disabled": false, - "ephemeral_gb": 0, - "extra_specs": { - "hw:watchdog_action": "reset" - }, - "flavorid": "d5a8bb54-365a-45ae-abdb-38d249df7845", - "is_public": true, - "memory_mb": 256, - "name": "other_flavor", - "projects": null, - "root_gb": 1, - "rxtx_factor": 1.0, - "swap": 0, - "vcpu_weight": 0, - "vcpus": 1 - }, - "nova_object.namespace": "nova", - "nova_object.version": "1.4" + "$ref": "InstanceActionPayload.json", + "nova_object.data": { + "new_flavor": { + "nova_object.name": "FlavorPayload", + "nova_object.data": { + "description": null, + "disabled": false, + "ephemeral_gb": 0, + "extra_specs": { + "hw:watchdog_action": "reset" }, - "task_state": "resize_prep" + "flavorid": "d5a8bb54-365a-45ae-abdb-38d249df7845", + "is_public": true, + "memory_mb": 256, + "name": "other_flavor", + "projects": null, + "root_gb": 1, + "rxtx_factor": 1.0, + "swap": 0, + "vcpu_weight": 0, + "vcpus": 1 + }, + "nova_object.namespace": "nova", + "nova_object.version": "1.4" }, - "nova_object.name": "InstanceActionResizePrepPayload", - "nova_object.version": "1.3" + "task_state": "resize_prep" + }, + "nova_object.name": "InstanceActionResizePrepPayload", + "nova_object.version": "1.4" } diff --git a/doc/notification_samples/common_payloads/InstanceActionSnapshotPayload.json b/doc/notification_samples/common_payloads/InstanceActionSnapshotPayload.json index d0dd7b7f5b..ad813a7b0e 100644 --- a/doc/notification_samples/common_payloads/InstanceActionSnapshotPayload.json +++ b/doc/notification_samples/common_payloads/InstanceActionSnapshotPayload.json @@ -1,9 +1,9 @@ { - "$ref": "InstanceActionPayload.json", - "nova_object.data":{ - "snapshot_image_id": "d2aae36f-785c-4518-8016-bc9534d9fc7f" - }, - "nova_object.name":"InstanceActionSnapshotPayload", - "nova_object.namespace":"nova", - "nova_object.version":"1.9" + "$ref": "InstanceActionPayload.json", + "nova_object.data": { + "snapshot_image_id": "d2aae36f-785c-4518-8016-bc9534d9fc7f" + }, + "nova_object.name": "InstanceActionSnapshotPayload", + "nova_object.namespace": "nova", + "nova_object.version": "1.10" } diff --git a/doc/notification_samples/common_payloads/InstanceActionVolumePayload.json b/doc/notification_samples/common_payloads/InstanceActionVolumePayload.json index 50108e8215..5ca155ad29 100644 --- a/doc/notification_samples/common_payloads/InstanceActionVolumePayload.json +++ b/doc/notification_samples/common_payloads/InstanceActionVolumePayload.json @@ -1,9 +1,9 @@ { - "$ref": "InstanceActionPayload.json", - "nova_object.data":{ - "volume_id": "a07f71dc-8151-4e7d-a0cc-cd24a3f11113" - }, - "nova_object.name": "InstanceActionVolumePayload", - "nova_object.namespace": "nova", - "nova_object.version": "1.6" -} \ No newline at end of file + "$ref": "InstanceActionPayload.json", + "nova_object.data": { + "volume_id": "a07f71dc-8151-4e7d-a0cc-cd24a3f11113" + }, + "nova_object.name": "InstanceActionVolumePayload", + "nova_object.namespace": "nova", + "nova_object.version": "1.7" +} diff --git a/doc/notification_samples/common_payloads/InstanceActionVolumeSwapPayload.json b/doc/notification_samples/common_payloads/InstanceActionVolumeSwapPayload.json index ac56306a74..e0077754bb 100644 --- a/doc/notification_samples/common_payloads/InstanceActionVolumeSwapPayload.json +++ b/doc/notification_samples/common_payloads/InstanceActionVolumeSwapPayload.json @@ -6,5 +6,5 @@ }, "nova_object.name": "InstanceActionVolumeSwapPayload", "nova_object.namespace": "nova", - "nova_object.version": "1.8" + "nova_object.version": "1.9" } diff --git a/doc/notification_samples/common_payloads/InstanceCreatePayload.json b/doc/notification_samples/common_payloads/InstanceCreatePayload.json index c7e6adc981..cddbf5b64d 100644 --- a/doc/notification_samples/common_payloads/InstanceCreatePayload.json +++ b/doc/notification_samples/common_payloads/InstanceCreatePayload.json @@ -1,28 +1,25 @@ { - "$ref":"InstanceActionPayload.json", - "nova_object.data": { - "block_devices": [], - "keypairs": [ - { - "nova_object.version": "1.0", - "nova_object.namespace": "nova", - "nova_object.name": "KeypairPayload", - "nova_object.data": { - "user_id": "fake", - "name": "my-key", - "fingerprint": "1e:2c:9b:56:79:4b:45:77:f9:ca:7a:98:2c:b0:d5:3c", - "public_key": "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAgQDx8nkQv/zgGgB4rMYmIf+6A4l6Rr+o/6lHBQdW5aYd44bd8JttDCE/F/pNRr0lRE+PiqSPO8nDPHw0010JeMH9gYgnnFlyY3/OcJ02RhIPyyxYpv9FhY+2YiUkpwFOcLImyrxEsYXpD/0d3ac30bNH6Sw9JD9UZHYcpSxsIbECHw== Generated-by-Nova", - "type": "ssh" - } - } - ], - "tags": ["tag"], - "trusted_image_certificates": [ - "cert-id-1", - "cert-id-2" - ], - "instance_name": "instance-00000001" - }, - "nova_object.name":"InstanceCreatePayload", - "nova_object.version": "1.12" + "$ref": "InstanceActionPayload.json", + "nova_object.data": { + "block_devices": [], + "keypairs": [ + { + "nova_object.version": "1.0", + "nova_object.namespace": "nova", + "nova_object.name": "KeypairPayload", + "nova_object.data": { + "user_id": "fake", + "name": "my-key", + "fingerprint": "1e:2c:9b:56:79:4b:45:77:f9:ca:7a:98:2c:b0:d5:3c", + "public_key": "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAgQDx8nkQv/zgGgB4rMYmIf+6A4l6Rr+o/6lHBQdW5aYd44bd8JttDCE/F/pNRr0lRE+PiqSPO8nDPHw0010JeMH9gYgnnFlyY3/OcJ02RhIPyyxYpv9FhY+2YiUkpwFOcLImyrxEsYXpD/0d3ac30bNH6Sw9JD9UZHYcpSxsIbECHw== Generated-by-Nova", + "type": "ssh" + } + } + ], + "tags": ["tag"], + "trusted_image_certificates": ["cert-id-1", "cert-id-2"], + "instance_name": "instance-00000001" + }, + "nova_object.name": "InstanceCreatePayload", + "nova_object.version": "1.13" } diff --git a/doc/notification_samples/common_payloads/InstanceExistsPayload.json b/doc/notification_samples/common_payloads/InstanceExistsPayload.json index fe8d6ecef1..a78644c833 100644 --- a/doc/notification_samples/common_payloads/InstanceExistsPayload.json +++ b/doc/notification_samples/common_payloads/InstanceExistsPayload.json @@ -1,9 +1,11 @@ { "$ref": "InstancePayload.json", - "nova_object.data":{ - "audit_period": {"$ref": "AuditPeriodPayload.json#"} + "nova_object.data": { + "audit_period": { + "$ref": "AuditPeriodPayload.json#" + } }, - "nova_object.name":"InstanceExistsPayload", - "nova_object.namespace":"nova", - "nova_object.version":"2.0" + "nova_object.name": "InstanceExistsPayload", + "nova_object.namespace": "nova", + "nova_object.version": "2.1" } diff --git a/doc/notification_samples/common_payloads/InstancePayload.json b/doc/notification_samples/common_payloads/InstancePayload.json index 9053ba76d2..fa1e9eed5d 100644 --- a/doc/notification_samples/common_payloads/InstancePayload.json +++ b/doc/notification_samples/common_payloads/InstancePayload.json @@ -38,9 +38,10 @@ "request_id": "req-5b6c791d-5709-4f36-8fbe-c3e02869e35d", "action_initiator_user": "fake", "action_initiator_project": "6f70656e737461636b20342065766572", - "locked_reason": null + "locked_reason": null, + "shares": [] }, "nova_object.name":"InstancePayload", "nova_object.namespace":"nova", - "nova_object.version":"1.8" + "nova_object.version":"1.9" } diff --git a/doc/notification_samples/common_payloads/InstancePayloadShareActive.json b/doc/notification_samples/common_payloads/InstancePayloadShareActive.json new file mode 100644 index 0000000000..1dd1cd41e6 --- /dev/null +++ b/doc/notification_samples/common_payloads/InstancePayloadShareActive.json @@ -0,0 +1,57 @@ +{ + "nova_object.data": { + "architecture": "x86_64", + "availability_zone": "nova", + "block_devices": [ + { + "$ref": "BlockDevicePayload.json#" + } + ], + "created_at": "2012-10-29T13:42:11Z", + "deleted_at": null, + "display_name": "some-server", + "display_description": "some-server", + "host": "compute", + "host_name": "some-server", + "ip_addresses": [ + { + "$ref": "IpPayload.json#" + } + ], + "kernel_id": "", + "key_name": "my-key", + "launched_at": "2012-10-29T13:42:11Z", + "image_uuid": "155d900f-4e14-4e4c-a73d-069cbf4541e6", + "metadata": {}, + "locked": false, + "node": "fake-mini", + "os_type": null, + "progress": 0, + "ramdisk_id": "", + "reservation_id": "r-npxv0e40", + "state": "active", + "task_state": null, + "power_state": "running", + "tenant_id": "6f70656e737461636b20342065766572", + "terminated_at": null, + "auto_disk_config": "MANUAL", + "flavor": { + "$ref": "FlavorPayload.json#" + }, + "updated_at": "2012-10-29T13:42:11Z", + "user_id": "fake", + "uuid": "178b0921-8f85-4257-88b6-2e743b5a975c", + "request_id": "req-5b6c791d-5709-4f36-8fbe-c3e02869e35d", + "action_initiator_user": "fake", + "action_initiator_project": "6f70656e737461636b20342065766572", + "locked_reason": null, + "shares": [ + { + "$ref": "ShareActivePayload.json#" + } + ] + }, + "nova_object.name": "InstancePayload", + "nova_object.namespace": "nova", + "nova_object.version": "1.9" +} diff --git a/doc/notification_samples/common_payloads/InstancePayloadShareInactive.json b/doc/notification_samples/common_payloads/InstancePayloadShareInactive.json new file mode 100644 index 0000000000..76fd49dc3e --- /dev/null +++ b/doc/notification_samples/common_payloads/InstancePayloadShareInactive.json @@ -0,0 +1,57 @@ +{ + "nova_object.data": { + "architecture": "x86_64", + "availability_zone": "nova", + "block_devices": [ + { + "$ref": "BlockDevicePayload.json#" + } + ], + "created_at": "2012-10-29T13:42:11Z", + "deleted_at": null, + "display_name": "some-server", + "display_description": "some-server", + "host": "compute", + "host_name": "some-server", + "ip_addresses": [ + { + "$ref": "IpPayload.json#" + } + ], + "kernel_id": "", + "key_name": "my-key", + "launched_at": "2012-10-29T13:42:11Z", + "image_uuid": "155d900f-4e14-4e4c-a73d-069cbf4541e6", + "metadata": {}, + "locked": false, + "node": "fake-mini", + "os_type": null, + "progress": 0, + "ramdisk_id": "", + "reservation_id": "r-npxv0e40", + "state": "active", + "task_state": null, + "power_state": "running", + "tenant_id": "6f70656e737461636b20342065766572", + "terminated_at": null, + "auto_disk_config": "MANUAL", + "flavor": { + "$ref": "FlavorPayload.json#" + }, + "updated_at": "2012-10-29T13:42:11Z", + "user_id": "fake", + "uuid": "178b0921-8f85-4257-88b6-2e743b5a975c", + "request_id": "req-5b6c791d-5709-4f36-8fbe-c3e02869e35d", + "action_initiator_user": "fake", + "action_initiator_project": "6f70656e737461636b20342065766572", + "locked_reason": null, + "shares": [ + { + "$ref": "ShareInactivePayload.json#" + } + ] + }, + "nova_object.name": "InstancePayload", + "nova_object.namespace": "nova", + "nova_object.version": "1.9" +} diff --git a/doc/notification_samples/common_payloads/InstanceUpdatePayload.json b/doc/notification_samples/common_payloads/InstanceUpdatePayload.json index 7d66ad3475..158b5d6b55 100644 --- a/doc/notification_samples/common_payloads/InstanceUpdatePayload.json +++ b/doc/notification_samples/common_payloads/InstanceUpdatePayload.json @@ -1,32 +1,32 @@ { - "$ref": "InstancePayload.json", - "nova_object.data": { - "audit_period": { - "nova_object.data": { - "audit_period_beginning": "2012-10-01T00:00:00Z", - "audit_period_ending": "2012-10-29T13:42:11Z" - }, - "nova_object.name": "AuditPeriodPayload", - "nova_object.namespace": "nova", - "nova_object.version": "1.0" - }, - "block_devices": [], - "old_display_name": null, - "state_update": { - "nova_object.data": { - "new_task_state": null, - "old_state": "active", - "old_task_state": null, - "state": "active" - }, - "nova_object.name": "InstanceStateUpdatePayload", - "nova_object.namespace": "nova", - "nova_object.version": "1.0" - }, - "tags": [], - "updated_at": "2012-10-29T13:42:11Z" + "$ref": "InstancePayload.json", + "nova_object.data": { + "audit_period": { + "nova_object.data": { + "audit_period_beginning": "2012-10-01T00:00:00Z", + "audit_period_ending": "2012-10-29T13:42:11Z" + }, + "nova_object.name": "AuditPeriodPayload", + "nova_object.namespace": "nova", + "nova_object.version": "1.0" }, - "nova_object.name": "InstanceUpdatePayload", - "nova_object.namespace": "nova", - "nova_object.version": "2.0" + "block_devices": [], + "old_display_name": null, + "state_update": { + "nova_object.data": { + "new_task_state": null, + "old_state": "active", + "old_task_state": null, + "state": "active" + }, + "nova_object.name": "InstanceStateUpdatePayload", + "nova_object.namespace": "nova", + "nova_object.version": "1.0" + }, + "tags": [], + "updated_at": "2012-10-29T13:42:11Z" + }, + "nova_object.name": "InstanceUpdatePayload", + "nova_object.namespace": "nova", + "nova_object.version": "2.1" } diff --git a/doc/notification_samples/common_payloads/ShareActivePayload.json b/doc/notification_samples/common_payloads/ShareActivePayload.json new file mode 100644 index 0000000000..a661c504f7 --- /dev/null +++ b/doc/notification_samples/common_payloads/ShareActivePayload.json @@ -0,0 +1,12 @@ +{ + "nova_object.data": { + "share_mapping_uuid": "f7c1726d-7622-42b3-8b2c-4473239d60d1", + "export_location": "10.0.0.50:/mnt/foo", + "share_id": "e8debdc0-447a-4376-a10a-4cd9122d7986", + "status": "active", + "tag": "e8debdc0-447a-4376-a10a-4cd9122d7986" + }, + "nova_object.name": "SharePayload", + "nova_object.namespace": "nova", + "nova_object.version": "1.0" +} diff --git a/doc/notification_samples/common_payloads/ShareInactivePayload.json b/doc/notification_samples/common_payloads/ShareInactivePayload.json new file mode 100644 index 0000000000..013ea2f8a0 --- /dev/null +++ b/doc/notification_samples/common_payloads/ShareInactivePayload.json @@ -0,0 +1,12 @@ +{ + "nova_object.data": { + "share_mapping_uuid": "f7c1726d-7622-42b3-8b2c-4473239d60d1", + "export_location": "10.0.0.50:/mnt/foo", + "share_id": "e8debdc0-447a-4376-a10a-4cd9122d7986", + "status": "inactive", + "tag": "e8debdc0-447a-4376-a10a-4cd9122d7986" + }, + "nova_object.name": "SharePayload", + "nova_object.namespace": "nova", + "nova_object.version": "1.0" +} diff --git a/doc/notification_samples/instance-power_on_share-end.json b/doc/notification_samples/instance-power_on_share-end.json new file mode 100644 index 0000000000..bbf2e30170 --- /dev/null +++ b/doc/notification_samples/instance-power_on_share-end.json @@ -0,0 +1,8 @@ +{ + "event_type": "instance.power_on.end", + "payload": { + "$ref": "common_payloads/InstanceActionPayloadShareActive.json#" + }, + "priority": "INFO", + "publisher_id": "nova-compute:compute" +} diff --git a/doc/notification_samples/instance-power_on_share-start.json b/doc/notification_samples/instance-power_on_share-start.json new file mode 100644 index 0000000000..61313047ac --- /dev/null +++ b/doc/notification_samples/instance-power_on_share-start.json @@ -0,0 +1,13 @@ +{ + "event_type": "instance.power_on.start", + "payload": { + "$ref": "common_payloads/InstanceActionPayloadShareInactive.json#", + "nova_object.data": { + "task_state": "powering-on", + "state": "stopped", + "power_state": "shutdown" + } + }, + "priority": "INFO", + "publisher_id": "nova-compute:compute" +} diff --git a/nova/conf/notifications.py b/nova/conf/notifications.py index a5946ddb3c..e10c094b72 100644 --- a/nova/conf/notifications.py +++ b/nova/conf/notifications.py @@ -105,6 +105,15 @@ If enabled, include block device information in the versioned notification payload. Sending block device information is disabled by default as providing that information can incur some overhead on the system since the information may need to be loaded from the database. +"""), + cfg.BoolOpt( + 'include_share_mapping', + default=False, + help=""" +If enabled, include share mapping information in the versioned notification +payload. Sending share mapping information is disabled by default as providing +that information can incur some overhead on the system since the information +may need to be loaded from the database. """) ] diff --git a/nova/notifications/objects/instance.py b/nova/notifications/objects/instance.py index 1f8370b4d3..c29c7cf7e4 100644 --- a/nova/notifications/objects/instance.py +++ b/nova/notifications/objects/instance.py @@ -69,7 +69,8 @@ class InstancePayload(base.NotificationPayloadBase): # Version 1.7: Added action_initiator_user and action_initiator_project to # InstancePayload # Version 1.8: Added locked_reason field - VERSION = '1.8' + # Version 1.9: Add shares related data + VERSION = '1.9' fields = { 'uuid': fields.UUIDField(), 'user_id': fields.StringField(nullable=True), @@ -115,6 +116,7 @@ class InstancePayload(base.NotificationPayloadBase): 'action_initiator_user': fields.StringField(nullable=True), 'action_initiator_project': fields.StringField(nullable=True), 'locked_reason': fields.StringField(nullable=True), + 'shares': fields.ListOfObjectsField('SharePayload', nullable=True), } def __init__(self, context, instance, bdms=None): @@ -126,6 +128,7 @@ class InstancePayload(base.NotificationPayloadBase): self.block_devices = BlockDevicePayload.from_bdms(bdms) else: self.block_devices = BlockDevicePayload.from_instance(instance) + self.shares = SharePayload.from_instance(instance) # NOTE(Kevin_Zheng): Don't include request_id for periodic tasks, # RequestContext for periodic tasks does not include project_id # and user_id. Consider modify this once periodic tasks got a @@ -151,7 +154,8 @@ class InstanceActionPayload(InstancePayload): # Version 1.7: Added action_initiator_user and action_initiator_project to # InstancePayload # Version 1.8: Added locked_reason field to InstancePayload - VERSION = '1.8' + # Version 1.9: Add shares related data + VERSION = '1.9' fields = { 'fault': fields.ObjectField('ExceptionPayload', nullable=True), 'request_id': fields.StringField(nullable=True), @@ -174,7 +178,8 @@ class InstanceActionVolumePayload(InstanceActionPayload): # Version 1.5: Added action_initiator_user and action_initiator_project to # InstancePayload # Version 1.6: Added locked_reason field to InstancePayload - VERSION = '1.6' + # Version 1.7: Add shares to InstancePayload + VERSION = '1.7' fields = { 'volume_id': fields.UUIDField() } @@ -216,7 +221,8 @@ class InstanceActionVolumeSwapPayload(InstanceActionPayload): # Version 1.7: Added action_initiator_user and action_initiator_project to # InstancePayload # Version 1.8: Added locked_reason field to InstancePayload - VERSION = '1.8' + # Version 1.9: Add shares to InstancePayload + VERSION = '1.9' fields = { 'old_volume_id': fields.UUIDField(), 'new_volume_id': fields.UUIDField(), @@ -252,7 +258,8 @@ class InstanceCreatePayload(InstanceActionPayload): # InstancePayload # 1.11: Added instance_name to InstanceCreatePayload # Version 1.12: Added locked_reason field to InstancePayload - VERSION = '1.12' + # Version 1.13: Add shares to InstancePayload + VERSION = '1.13' fields = { 'keypairs': fields.ListOfObjectsField('KeypairPayload'), 'tags': fields.ListOfStringsField(), @@ -286,7 +293,8 @@ class InstanceActionResizePrepPayload(InstanceActionPayload): # Version 1.2: Added action_initiator_user and action_initiator_project to # InstancePayload # Version 1.3: Added locked_reason field to InstancePayload - VERSION = '1.3' + # Version 1.4: Add shares to InstancePayload + VERSION = '1.4' fields = { 'new_flavor': fields.ObjectField('FlavorPayload', nullable=True) } @@ -313,7 +321,8 @@ class InstanceUpdatePayload(InstancePayload): # InstancePayload # Version 1.9: Added locked_reason field to InstancePayload # Version 2.0: Remove bandwidth field - VERSION = '2.0' + # Version 2.1: Add shares to InstancePayload + VERSION = '2.1' fields = { 'state_update': fields.ObjectField('InstanceStateUpdatePayload'), 'audit_period': fields.ObjectField('AuditPeriodPayload'), @@ -339,7 +348,8 @@ class InstanceActionRescuePayload(InstanceActionPayload): # Version 1.2: Added action_initiator_user and action_initiator_project to # InstancePayload # Version 1.3: Added locked_reason field to InstancePayload - VERSION = '1.3' + # Version 1.4: Add shares to InstancePayload + VERSION = '1.4' fields = { 'rescue_image_ref': fields.UUIDField(nullable=True) } @@ -364,7 +374,8 @@ class InstanceActionRebuildPayload(InstanceActionPayload): # Version 1.8: Added action_initiator_user and action_initiator_project to # InstancePayload # Version 1.9: Added locked_reason field to InstancePayload - VERSION = '1.9' + # Version 1.10: Add shares to InstancePayload + VERSION = '1.10' fields = { 'trusted_image_certificates': fields.ListOfStringsField( nullable=True) @@ -492,6 +503,51 @@ class BlockDevicePayload(base.NotificationPayloadBase): return payloads +@nova_base.NovaObjectRegistry.register_notification +class SharePayload(base.NotificationPayloadBase): + # Version 1.0: Initial version + VERSION = '1.0' + + SCHEMA = { + 'share_mapping_uuid': ('share', 'uuid'), + 'share_id': ('share', 'share_id'), + 'status': ('share', 'status'), + 'tag': ('share', 'tag'), + # Do not include 'export_location' as it could contains sensitive data + # 'export_location': ('share', 'export_location') + } + + fields = { + 'share_mapping_uuid': fields.UUIDField(), + 'share_id': fields.UUIDField(), + 'status': fields.StringField(nullable=False), + 'tag': fields.StringField(nullable=False), + # 'export_location': fields.StringField(nullable=False), + } + + def __init__(self, share): + super(SharePayload, self).__init__() + self.populate_schema(share=share) + + @classmethod + def from_instance(cls, instance): + """Returns a list of SharePayload objects based on the passed + shares. + """ + if not CONF.notifications.include_share_mapping: + return None + + instance_shares = instance.get_shares() + return [cls(share) for share in instance_shares] + + @classmethod + def from_shares(cls, shares): + """Returns a list of SharePayload objects based on the passed + ShareMappingList. + """ + return [cls(share) for share in shares] + + @nova_base.NovaObjectRegistry.register_notification class InstanceStateUpdatePayload(base.NotificationPayloadBase): # Version 1.0: Initial version @@ -523,7 +579,9 @@ class InstanceStateUpdatePayload(base.NotificationPayloadBase): @base.notification_sample('instance-suspend-start.json') @base.notification_sample('instance-suspend-end.json') @base.notification_sample('instance-power_on-start.json') +@base.notification_sample('instance-power_on_share-start.json') @base.notification_sample('instance-power_on-end.json') +@base.notification_sample('instance-power_on_share-end.json') @base.notification_sample('instance-power_off-start.json') @base.notification_sample('instance-power_off-end.json') @base.notification_sample('instance-reboot-start.json') @@ -712,7 +770,8 @@ class InstanceActionSnapshotPayload(InstanceActionPayload): # Version 1.8: Added action_initiator_user and action_initiator_project to # InstancePayload # Version 1.9: Added locked_reason field to InstancePayload - VERSION = '1.9' + # Version 1.10: Add shares to InstancePayload + VERSION = '1.10' fields = { 'snapshot_image_id': fields.UUIDField(), } @@ -732,7 +791,8 @@ class InstanceExistsPayload(InstancePayload): # InstancePayload # Version 1.2: Added locked_reason field to InstancePayload # Version 2.0: Remove bandwidth field - VERSION = '2.0' + # Version 2.1: Add shares to InstancePayload + VERSION = '2.1' fields = { 'audit_period': fields.ObjectField('AuditPeriodPayload'), } diff --git a/nova/objects/instance.py b/nova/objects/instance.py index 36172fbbe7..8f76fd4f5a 100644 --- a/nova/objects/instance.py +++ b/nova/objects/instance.py @@ -1260,6 +1260,10 @@ class Instance(base.NovaPersistentObject, base.NovaObject, return objects.BlockDeviceMappingList.get_by_instance_uuid( self._context, self.uuid) + def get_shares(self): + return objects.ShareMappingList.get_by_instance_uuid( + self._context, self.uuid) + def remove_pci_device_and_request(self, pci_device): """Remove the PciDevice and the related InstancePciRequest""" if pci_device in self.pci_devices.objects: diff --git a/nova/tests/functional/integrated_helpers.py b/nova/tests/functional/integrated_helpers.py index 9fe134ced6..045f22ace7 100644 --- a/nova/tests/functional/integrated_helpers.py +++ b/nova/tests/functional/integrated_helpers.py @@ -550,7 +550,9 @@ class InstanceHelperMixin: self.notifier.wait_for_versioned_notifications( 'instance.interface_detach.end') - def _get_share(self, server, share_id): + def _get_share(self, server, share_id, admin=False): + if admin: + return (self.admin_api.get_server_share(server['id'], share_id)) return (self.api.get_server_share(server['id'], share_id)) def _attach_share(self, server, share_id, tag=None): diff --git a/nova/tests/functional/notification_sample_tests/test_instance.py b/nova/tests/functional/notification_sample_tests/test_instance.py index 7852b4455f..1c7487f480 100644 --- a/nova/tests/functional/notification_sample_tests/test_instance.py +++ b/nova/tests/functional/notification_sample_tests/test_instance.py @@ -28,6 +28,7 @@ class TestInstanceNotificationSampleWithMultipleCompute( def setUp(self): self.flags(compute_driver='fake.FakeLiveMigrateDriver') self.flags(bdms_in_notifications='True', group='notifications') + self.flags(include_share_mapping='True', group='notifications') super(TestInstanceNotificationSampleWithMultipleCompute, self).setUp() self.neutron = fixtures.NeutronFixture(self) self.useFixture(self.neutron) @@ -337,6 +338,7 @@ class TestInstanceNotificationSample( def setUp(self): self.flags(bdms_in_notifications='True', group='notifications') + self.flags(include_share_mapping='True', group='notifications') super(TestInstanceNotificationSample, self).setUp() self.neutron = fixtures.NeutronFixture(self) self.useFixture(self.neutron) @@ -389,8 +391,7 @@ class TestInstanceNotificationSample( self._test_interface_attach_error, self._test_lock_unlock_instance, self._test_lock_unlock_instance_with_reason, - self._test_share_attach, - self._test_share_detach, + self._test_share_attach_detach, ] for action in actions: @@ -1703,12 +1704,35 @@ class TestInstanceNotificationSample( 'uuid': server['id']}, actual=self.notifier.versioned_notifications[1]) - def _test_share_attach(self, server): + def _test_share_attach_detach(self, server): + + expected_shares = [ + { + "nova_object.name": "SharePayload", + "nova_object.namespace": "nova", + "nova_object.version": "1.0", + "nova_object.data": { + "share_mapping_uuid": ( + "f7c1726d-7622-42b3-8b2c-4473239d60d1"), + "share_id": "e8debdc0-447a-4376-a10a-4cd9122d7986", + "status": "attaching", + "tag": "e8debdc0-447a-4376-a10a-4cd9122d7986", + # 'export_location': '10.0.0.50:/mnt/foo', + }, + } + ] + self.api.post_server_action(server['id'], {'os-stop': {}}) self._wait_for_state_change(server, expected_status='SHUTOFF') self.notifier.reset() self._attach_share(server, "e8debdc0-447a-4376-a10a-4cd9122d7986") + share_info = self._get_share( + server, "e8debdc0-447a-4376-a10a-4cd9122d7986", admin=True + ) + expected_shares[0]["nova_object.data"][ + "share_mapping_uuid" + ] = share_info["uuid"] self.assertEqual(2, len(self.notifier.versioned_notifications), self.notifier.versioned_notifications) @@ -1718,24 +1742,76 @@ class TestInstanceNotificationSample( 'reservation_id': server['reservation_id'], 'uuid': server['id'], 'state': 'stopped', - 'power_state': 'shutdown'}, + 'power_state': 'shutdown', + 'shares': expected_shares + }, actual=self.notifier.versioned_notifications[0]) + expected_shares[0]['nova_object.data']['status'] = 'inactive' self._verify_notification( 'instance-share_attach-end', replacements={ 'reservation_id': server['reservation_id'], 'uuid': server['id'], 'state': 'stopped', - 'power_state': 'shutdown'}, + 'power_state': 'shutdown', + 'shares': expected_shares + }, actual=self.notifier.versioned_notifications[1]) # Start server + self.notifier.reset() self.api.post_server_action(server['id'], {'os-start': {}}) self._wait_for_state_change(server, expected_status='ACTIVE') + self.assertEqual(2, len(self.notifier.versioned_notifications), + self.notifier.versioned_notifications) + self._verify_notification( + 'instance-power_on_share-start', + replacements={ + 'reservation_id': server['reservation_id'], + 'uuid': server['id'], + 'state': 'stopped', + 'power_state': 'shutdown', + 'shares': expected_shares, + }, + actual=self.notifier.versioned_notifications[0]) + expected_shares[0]['nova_object.data']['status'] = 'active' + self._verify_notification( + 'instance-power_on_share-end', + replacements={ + 'reservation_id': server['reservation_id'], + 'uuid': server['id'], + 'state': 'active', + 'power_state': 'running', + 'shares': expected_shares, + }, + actual=self.notifier.versioned_notifications[1]) def _test_share_detach(self, server): + # Shutdown server + self.notifier.reset() self.api.post_server_action(server['id'], {'os-stop': {}}) self._wait_for_state_change(server, expected_status='SHUTOFF') + self.assertEqual(2, len(self.notifier.versioned_notifications), + self.notifier.versioned_notifications) + self._verify_notification( + 'instance-power_off-start', + replacements={ + 'reservation_id': server['reservation_id'], + 'uuid': server['id'], + 'state': 'active', + 'power_state': 'running', + }, + actual=self.notifier.versioned_notifications[0]) + self._verify_notification( + 'instance-power_off-end', + replacements={ + 'reservation_id': server['reservation_id'], + 'uuid': server['id'], + 'state': 'stopped', + 'power_state': 'shutdown', + }, + actual=self.notifier.versioned_notifications[1]) + self.notifier.reset() # Detach share @@ -1749,7 +1825,8 @@ class TestInstanceNotificationSample( 'reservation_id': server['reservation_id'], 'uuid': server['id'], 'state': 'stopped', - 'power_state': 'shutdown'}, + 'power_state': 'shutdown', + }, actual=self.notifier.versioned_notifications[0]) self._verify_notification( 'instance-share_detach-end', @@ -1762,8 +1839,29 @@ class TestInstanceNotificationSample( actual=self.notifier.versioned_notifications[1]) # Restart server + self.notifier.reset() self.api.post_server_action(server['id'], {'os-start': {}}) self._wait_for_state_change(server, expected_status='ACTIVE') + self.assertEqual(2, len(self.notifier.versioned_notifications), + self.notifier.versioned_notifications) + self._verify_notification( + 'instance-power_on-start', + replacements={ + 'reservation_id': server['reservation_id'], + 'uuid': server['id'], + 'state': 'stopped', + 'power_state': 'shutdown', + }, + actual=self.notifier.versioned_notifications[0]) + self._verify_notification( + 'instance-power_on-end', + replacements={ + 'reservation_id': server['reservation_id'], + 'uuid': server['id'], + 'state': 'active', + 'power_state': 'running', + }, + actual=self.notifier.versioned_notifications[1]) def _test_rescue_unrescue_server(self, server): # Both "rescue" and "unrescue" notification asserts are made here diff --git a/nova/tests/unit/notifications/objects/test_instance.py b/nova/tests/unit/notifications/objects/test_instance.py index 8735e972dc..c51a7d483c 100644 --- a/nova/tests/unit/notifications/objects/test_instance.py +++ b/nova/tests/unit/notifications/objects/test_instance.py @@ -172,3 +172,44 @@ class TestBlockDevicePayload(test.NoDBTestCase): bmds = instance_notification.BlockDevicePayload.from_instance( instance) self.assertIsNone(bmds) + + +class TestSharePayload(test.NoDBTestCase): + @mock.patch('nova.objects.instance.Instance.get_shares') + def test_payload_contains_shares_if_requested(self, mock_get_shares): + self.flags(include_share_mapping='True', group='notifications') + context = mock.Mock() + instance = objects.Instance(uuid=uuids.instance_uuid) + + share_mapping = objects.ShareMapping(context) + share_mapping.uuid = uuids.share_mapping + share_mapping.instance_uuid = uuids.instance + share_mapping.share_id = uuids.share + share_mapping.status = 'inactive' + share_mapping.tag = 'fake_tag' + share_mapping.export_location = '192.168.122.152:/manila/share' + share_mapping.share_proto = 'NFS' + + mock_get_shares.return_value = [share_mapping] + + shares = instance_notification.SharePayload.from_instance( + instance) + + self.assertEqual(1, len(shares)) + share = shares[0] + self.assertIsInstance(share, instance_notification.SharePayload) + self.assertEqual(uuids.share_mapping, share.share_mapping_uuid) + self.assertEqual(uuids.share, share.share_id) + self.assertEqual('inactive', share.status) + self.assertEqual('fake_tag', share.tag) + # self.assertEqual('192.168.122.152:/manila/share', + # share.export_location) + self.assertNotIn('export_location', share) + + @mock.patch('nova.objects.instance.Instance.get_shares', + return_value=mock.NonCallableMock()) + def test_shares_are_skipped_by_default(self, mock_get_shares): + instance = objects.Instance(uuid=uuids.instance_uuid) + shares = instance_notification.SharePayload.from_instance( + instance) + self.assertIsNone(shares) diff --git a/nova/tests/unit/notifications/objects/test_notification.py b/nova/tests/unit/notifications/objects/test_notification.py index 01eada6656..bde7fd3f5e 100644 --- a/nova/tests/unit/notifications/objects/test_notification.py +++ b/nova/tests/unit/notifications/objects/test_notification.py @@ -387,37 +387,37 @@ notification_object_data = { # more information. 'ImageMetaPropsPayload': '1.15-a3d7a75fedbf373bcab2d9d6ece249df', 'InstanceActionNotification': '1.0-a73147b93b520ff0061865849d3dfa56', - 'InstanceActionPayload': '1.8-b948818df6ec562e4eb4b23e515e451b', + 'InstanceActionPayload': '1.9-525dcf81b6e4592d935712a2675309dc', 'InstanceActionRebuildNotification': '1.0-a73147b93b520ff0061865849d3dfa56', - 'InstanceActionRebuildPayload': '1.9-3c1ac23f70c03665797f792ace3d9176', + 'InstanceActionRebuildPayload': '1.10-b741a7add29a8c1f584fd5d5b3362372', 'InstanceActionRescueNotification': '1.0-a73147b93b520ff0061865849d3dfa56', - 'InstanceActionRescuePayload': '1.3-329dda4c0a516c0fedc68aa02ccf3e88', + 'InstanceActionRescuePayload': '1.4-29e0327c2ad6953d367db68d9aceef20', 'InstanceActionResizePrepNotification': '1.0-a73147b93b520ff0061865849d3dfa56', - 'InstanceActionResizePrepPayload': '1.3-8969438a48c496569c2add19b170dca1', + 'InstanceActionResizePrepPayload': '1.4-214cb6123beb0ffe5eb1e08ce424086b', 'InstanceActionShareNotification': '1.0-a73147b93b520ff0061865849d3dfa56', - 'InstanceActionSharePayload': '1.0-024003b187136ba4db3b958e8d22d540', + 'InstanceActionSharePayload': '1.0-6dafbbd061f582e9c0ce100eeee790b9', 'InstanceActionVolumeNotification': '1.0-a73147b93b520ff0061865849d3dfa56', - 'InstanceActionVolumePayload': '1.6-b5fd2b23dbafe33b72cdbbb7b937bf18', + 'InstanceActionVolumePayload': '1.7-542d9e1485c6b925958df9912dc744ec', 'InstanceActionVolumeSwapNotification': '1.0-a73147b93b520ff0061865849d3dfa56', - 'InstanceActionVolumeSwapPayload': '1.8-9d8edd0a3556a69f0bfe17ab2641ca19', + 'InstanceActionVolumeSwapPayload': '1.9-dc4e9852819bc3283b0c809a1f6602d4', 'InstanceCreateNotification': '1.0-a73147b93b520ff0061865849d3dfa56', - 'InstanceCreatePayload': '1.12-bd007423bfdb634448ec589b28f7cd39', - 'InstancePayload': '1.8-0bfe0b258ae4cf6ff68463c9e75adb80', + 'InstanceCreatePayload': '1.13-95a394da335944f074ac1bf58696ad87', + 'InstancePayload': '1.9-164048a4d38ed9a4b2f9c3927f1c9038', 'InstanceActionSnapshotNotification': '1.0-a73147b93b520ff0061865849d3dfa56', - 'InstanceActionSnapshotPayload': '1.9-75809b8ef913f7d2e262c5c804213ac8', + 'InstanceActionSnapshotPayload': '1.10-7a4878ef67da0939ee069bb78eab07ae', 'InstanceExistsNotification': '1.0-a73147b93b520ff0061865849d3dfa56', - 'InstanceExistsPayload': '2.0-5eb1efc3d1b03d87be82062219adaf6d', + 'InstanceExistsPayload': '2.1-264c20f9c5d76320c9129865b9bc6f8f', 'InstanceNUMACellPayload': '1.2-93c3cadf4f6ee427664c00039d0a1fed', 'InstanceNUMATopologyPayload': '1.0-c7885d5da4c66525f20e7d637a7267c4', 'InstancePCIRequestPayload': '1.1-ee482d38f6c84bb77bba3f4c8708231c', 'InstancePCIRequestsPayload': '1.0-29cb0fa1ba6756423a9606437c3f247f', 'InstanceStateUpdatePayload': '1.0-9d136730749479042d47f2a08c2c2e69', 'InstanceUpdateNotification': '1.0-a73147b93b520ff0061865849d3dfa56', - 'InstanceUpdatePayload': '2.0-f6edbd2b53373f120debf5570ec14676', + 'InstanceUpdatePayload': '2.1-25c1e9c521bd350c20cbda94b7cc7dc0', 'IpPayload': '1.0-a9f0b3f1ef17ab12378096816faa4e55', 'KeypairNotification': '1.0-a73147b93b520ff0061865849d3dfa56', 'KeypairPayload': '1.0-84f5e6da739af31ea10b89858c67b512', @@ -434,6 +434,7 @@ notification_object_data = { 'ServerGroupPayload': '1.1-f866cf95bf64bfa799193807e66a6a1e', 'ServiceStatusNotification': '1.0-a73147b93b520ff0061865849d3dfa56', 'ServiceStatusPayload': '1.1-64c5f80b3865832b936898f11dcddad0', + 'SharePayload': '1.0-80797287e01668692ee9beb70f269821', 'VirtCPUTopologyPayload': '1.0-24fa607e20f48c829953edad6b0b5cc8', 'VolumeUsageNotification': '1.0-a73147b93b520ff0061865849d3dfa56', 'VolumeUsagePayload': '1.0-a12c300f0ddbc7488685c9d9ed36d9e8',