summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJenkins <jenkins@review.openstack.org>2017-06-16 11:07:41 +0000
committerGerrit Code Review <review@openstack.org>2017-06-16 11:07:41 +0000
commit8238e8aaa0103e96ddb67ad178ed9848e9071ea6 (patch)
tree02f43a427a94eac10769c6feec96293e64549845
parent2e57d29d00ce7f1714b2cb70da7c159e838a6756 (diff)
parentad56be6d225ef67892ecd29c0fff0b197c01c43a (diff)
Merge "Transform keypair.create notification"
-rw-r--r--doc/ext/versioned_notifications.py1
-rw-r--r--doc/notification_samples/keypair-create-end.json17
-rw-r--r--doc/notification_samples/keypair-create-start.json17
-rw-r--r--nova/compute/api.py21
-rw-r--r--nova/compute/utils.py22
-rw-r--r--nova/notifications/objects/keypair.py51
-rw-r--r--nova/tests/functional/api/client.py5
-rw-r--r--nova/tests/functional/notification_sample_tests/test_keypair.py40
-rw-r--r--nova/tests/unit/compute/test_keypairs.py9
-rw-r--r--nova/tests/unit/notifications/objects/test_notification.py2
10 files changed, 179 insertions, 6 deletions
diff --git a/doc/ext/versioned_notifications.py b/doc/ext/versioned_notifications.py
index c3fe54a..4f36b1c 100644
--- a/doc/ext/versioned_notifications.py
+++ b/doc/ext/versioned_notifications.py
@@ -30,6 +30,7 @@ from nova.objects import base
30from nova.notifications.objects import exception 30from nova.notifications.objects import exception
31from nova.notifications.objects import flavor 31from nova.notifications.objects import flavor
32from nova.notifications.objects import instance 32from nova.notifications.objects import instance
33from nova.notifications.objects import keypair
33from nova.notifications.objects import service 34from nova.notifications.objects import service
34 35
35 36
diff --git a/doc/notification_samples/keypair-create-end.json b/doc/notification_samples/keypair-create-end.json
new file mode 100644
index 0000000..52ac6cb
--- /dev/null
+++ b/doc/notification_samples/keypair-create-end.json
@@ -0,0 +1,17 @@
1{
2 "priority": "INFO",
3 "payload": {
4 "nova_object.version": "1.0",
5 "nova_object.namespace": "nova",
6 "nova_object.name": "KeypairPayload",
7 "nova_object.data": {
8 "user_id": "fake",
9 "name": "my-key",
10 "fingerprint": "1e:2c:9b:56:79:4b:45:77:f9:ca:7a:98:2c:b0:d5:3c",
11 "public_key": "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAgQDx8nkQv/zgGgB4rMYmIf+6A4l6Rr+o/6lHBQdW5aYd44bd8JttDCE/F/pNRr0lRE+PiqSPO8nDPHw0010JeMH9gYgnnFlyY3/OcJ02RhIPyyxYpv9FhY+2YiUkpwFOcLImyrxEsYXpD/0d3ac30bNH6Sw9JD9UZHYcpSxsIbECHw== Generated-by-Nova",
12 "type": "ssh"
13 }
14 },
15 "event_type": "keypair.create.end",
16 "publisher_id": "nova-api:fake-mini"
17}
diff --git a/doc/notification_samples/keypair-create-start.json b/doc/notification_samples/keypair-create-start.json
new file mode 100644
index 0000000..ccf4d9a
--- /dev/null
+++ b/doc/notification_samples/keypair-create-start.json
@@ -0,0 +1,17 @@
1{
2 "priority": "INFO",
3 "payload": {
4 "nova_object.version": "1.0",
5 "nova_object.namespace": "nova",
6 "nova_object.name": "KeypairPayload",
7 "nova_object.data": {
8 "user_id": "fake",
9 "name": "my-key",
10 "fingerprint": null,
11 "public_key": null,
12 "type": "ssh"
13 }
14 },
15 "event_type": "keypair.create.start",
16 "publisher_id": "nova-api:fake-mini"
17}
diff --git a/nova/compute/api.py b/nova/compute/api.py
index 9f22532..d04324f 100644
--- a/nova/compute/api.py
+++ b/nova/compute/api.py
@@ -4952,18 +4952,31 @@ class KeypairAPI(base.Base):
4952 """Create a new key pair.""" 4952 """Create a new key pair."""
4953 self._validate_new_key_pair(context, user_id, key_name, key_type) 4953 self._validate_new_key_pair(context, user_id, key_name, key_type)
4954 4954
4955 keypair = objects.KeyPair(context)
4956 keypair.user_id = user_id
4957 keypair.name = key_name
4958 keypair.type = key_type
4959 keypair.fingerprint = None
4960 keypair.public_key = None
4961
4955 self._notify(context, 'create.start', key_name) 4962 self._notify(context, 'create.start', key_name)
4963 compute_utils.notify_about_keypair_action(
4964 context=context,
4965 keypair=keypair,
4966 action=fields_obj.NotificationAction.CREATE,
4967 phase=fields_obj.NotificationPhase.START)
4956 4968
4957 private_key, public_key, fingerprint = self._generate_key_pair( 4969 private_key, public_key, fingerprint = self._generate_key_pair(
4958 user_id, key_type) 4970 user_id, key_type)
4959 4971
4960 keypair = objects.KeyPair(context)
4961 keypair.user_id = user_id
4962 keypair.name = key_name
4963 keypair.type = key_type
4964 keypair.fingerprint = fingerprint 4972 keypair.fingerprint = fingerprint
4965 keypair.public_key = public_key 4973 keypair.public_key = public_key
4966 keypair.create() 4974 keypair.create()
4975 compute_utils.notify_about_keypair_action(
4976 context=context,
4977 keypair=keypair,
4978 action=fields_obj.NotificationAction.CREATE,
4979 phase=fields_obj.NotificationPhase.END)
4967 4980
4968 self._notify(context, 'create.end', key_name) 4981 self._notify(context, 'create.end', key_name)
4969 4982
diff --git a/nova/compute/utils.py b/nova/compute/utils.py
index e741ff9..784f56b 100644
--- a/nova/compute/utils.py
+++ b/nova/compute/utils.py
@@ -35,6 +35,7 @@ from nova.notifications.objects import aggregate as aggregate_notification
35from nova.notifications.objects import base as notification_base 35from nova.notifications.objects import base as notification_base
36from nova.notifications.objects import exception as notification_exception 36from nova.notifications.objects import exception as notification_exception
37from nova.notifications.objects import instance as instance_notification 37from nova.notifications.objects import instance as instance_notification
38from nova.notifications.objects import keypair as keypair_notification
38from nova import objects 39from nova import objects
39from nova.objects import fields 40from nova.objects import fields
40from nova import rpc 41from nova import rpc
@@ -394,6 +395,27 @@ def notify_about_volume_attach_detach(context, instance, host, action, phase,
394 notification.emit(context) 395 notification.emit(context)
395 396
396 397
398def notify_about_keypair_action(context, keypair, action, phase):
399 """Send versioned notification about the keypair action on the instance
400
401 :param context: the request context
402 :param keypair: the keypair which the action performed on
403 :param action: the name of the action
404 :param phase: the phase of the action
405 """
406 payload = keypair_notification.KeypairPayload(keypair=keypair)
407 notification = keypair_notification.KeypairNotification(
408 priority=fields.NotificationPriority.INFO,
409 publisher=notification_base.NotificationPublisher(
410 host=CONF.host, binary='nova-api'),
411 event_type=notification_base.EventType(
412 object='keypair',
413 action=action,
414 phase=phase),
415 payload=payload)
416 notification.emit(context)
417
418
397def notify_about_volume_swap(context, instance, host, action, phase, 419def notify_about_volume_swap(context, instance, host, action, phase,
398 old_volume_id, new_volume_id, exception=None): 420 old_volume_id, new_volume_id, exception=None):
399 """Send versioned notification about the volume swap action 421 """Send versioned notification about the volume swap action
diff --git a/nova/notifications/objects/keypair.py b/nova/notifications/objects/keypair.py
new file mode 100644
index 0000000..44df1a0
--- /dev/null
+++ b/nova/notifications/objects/keypair.py
@@ -0,0 +1,51 @@
1# Licensed under the Apache License, Version 2.0 (the "License"); you may
2# not use this file except in compliance with the License. You may obtain
3# a copy of the License at
4#
5# http://www.apache.org/licenses/LICENSE-2.0
6#
7# Unless required by applicable law or agreed to in writing, software
8# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
9# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
10# License for the specific language governing permissions and limitations
11# under the License.
12
13from nova.notifications.objects import base
14from nova.objects import base as nova_base
15from nova.objects import fields
16
17
18@nova_base.NovaObjectRegistry.register_notification
19class KeypairPayload(base.NotificationPayloadBase):
20 SCHEMA = {
21 'user_id': ('keypair', 'user_id'),
22 'name': ('keypair', 'name'),
23 'public_key': ('keypair', 'public_key'),
24 'fingerprint': ('keypair', 'fingerprint'),
25 'type': ('keypair', 'type')
26 }
27 # Version 1.0: Initial version
28 VERSION = '1.0'
29 fields = {
30 'user_id': fields.StringField(nullable=True),
31 'name': fields.StringField(nullable=False),
32 'fingerprint': fields.StringField(nullable=True),
33 'public_key': fields.StringField(nullable=True),
34 'type': fields.StringField(nullable=False),
35 }
36
37 def __init__(self, keypair, **kwargs):
38 super(KeypairPayload, self).__init__(**kwargs)
39 self.populate_schema(keypair=keypair)
40
41
42@base.notification_sample('keypair-create-start.json')
43@base.notification_sample('keypair-create-end.json')
44@nova_base.NovaObjectRegistry.register_notification
45class KeypairNotification(base.NotificationBase):
46 # Version 1.0: Initial version
47 VERSION = '1.0'
48
49 fields = {
50 'payload': fields.ObjectField('KeypairPayload')
51 }
diff --git a/nova/tests/functional/api/client.py b/nova/tests/functional/api/client.py
index 1abe500..c5414bd 100644
--- a/nova/tests/functional/api/client.py
+++ b/nova/tests/functional/api/client.py
@@ -217,7 +217,7 @@ class TestOpenStackClient(object):
217 headers['Content-Type'] = 'application/json' 217 headers['Content-Type'] = 'application/json'
218 kwargs['body'] = jsonutils.dumps(body) 218 kwargs['body'] = jsonutils.dumps(body)
219 219
220 kwargs.setdefault('check_response_status', [200, 202]) 220 kwargs.setdefault('check_response_status', [200, 201, 202])
221 return APIResponse(self.api_request(relative_uri, **kwargs)) 221 return APIResponse(self.api_request(relative_uri, **kwargs))
222 222
223 def api_put(self, relative_uri, body, **kwargs): 223 def api_put(self, relative_uri, body, **kwargs):
@@ -423,3 +423,6 @@ class TestOpenStackClient(object):
423 423
424 def get_services(self): 424 def get_services(self):
425 return self.api_get('/os-services').body['services'] 425 return self.api_get('/os-services').body['services']
426
427 def post_keypair(self, keypair):
428 return self.api_post('/os-keypairs', keypair).body['keypair']
diff --git a/nova/tests/functional/notification_sample_tests/test_keypair.py b/nova/tests/functional/notification_sample_tests/test_keypair.py
new file mode 100644
index 0000000..195e4b7
--- /dev/null
+++ b/nova/tests/functional/notification_sample_tests/test_keypair.py
@@ -0,0 +1,40 @@
1# Licensed under the Apache License, Version 2.0 (the "License"); you may
2# not use this file except in compliance with the License. You may obtain
3# a copy of the License at
4#
5# http://www.apache.org/licenses/LICENSE-2.0
6#
7# Unless required by applicable law or agreed to in writing, software
8# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
9# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
10# License for the specific language governing permissions and limitations
11# under the License.
12from nova.tests.functional.notification_sample_tests \
13 import notification_sample_base
14from nova.tests.unit import fake_notifier
15
16
17class TestKeypairNotificationSample(
18 notification_sample_base.NotificationSampleTestBase):
19
20 def test_keypair_create(self):
21 keypair_req = {
22 "keypair": {
23 "name": "my-key",
24 "user_id": "fake",
25 "type": "ssh"
26 }}
27 keypair = self.api.post_keypair(keypair_req)
28
29 self.assertEqual(2, len(fake_notifier.VERSIONED_NOTIFICATIONS))
30 self._verify_notification(
31 'keypair-create-start',
32 replacements={},
33 actual=fake_notifier.VERSIONED_NOTIFICATIONS[0])
34 self._verify_notification(
35 'keypair-create-end',
36 replacements={
37 "fingerprint": keypair['fingerprint'],
38 "public_key": keypair['public_key']
39 },
40 actual=fake_notifier.VERSIONED_NOTIFICATIONS[1])
diff --git a/nova/tests/unit/compute/test_keypairs.py b/nova/tests/unit/compute/test_keypairs.py
index 9bdf44f..48c5e81 100644
--- a/nova/tests/unit/compute/test_keypairs.py
+++ b/nova/tests/unit/compute/test_keypairs.py
@@ -14,6 +14,7 @@
14# under the License. 14# under the License.
15"""Tests for keypair API.""" 15"""Tests for keypair API."""
16 16
17import mock
17from oslo_concurrency import processutils 18from oslo_concurrency import processutils
18from oslo_config import cfg 19from oslo_config import cfg
19import six 20import six
@@ -162,11 +163,17 @@ class CreateImportSharedTestMixIn(object):
162class CreateKeypairTestCase(KeypairAPITestCase, CreateImportSharedTestMixIn): 163class CreateKeypairTestCase(KeypairAPITestCase, CreateImportSharedTestMixIn):
163 func_name = 'create_key_pair' 164 func_name = 'create_key_pair'
164 165
165 def _check_success(self): 166 @mock.patch('nova.compute.utils.notify_about_keypair_action')
167 def _check_success(self, mock_notify):
166 keypair, private_key = self.keypair_api.create_key_pair( 168 keypair, private_key = self.keypair_api.create_key_pair(
167 self.ctxt, self.ctxt.user_id, 'foo', key_type=self.keypair_type) 169 self.ctxt, self.ctxt.user_id, 'foo', key_type=self.keypair_type)
168 self.assertEqual('foo', keypair['name']) 170 self.assertEqual('foo', keypair['name'])
169 self.assertEqual(self.keypair_type, keypair['type']) 171 self.assertEqual(self.keypair_type, keypair['type'])
172 mock_notify.assert_has_calls([
173 mock.call(context=self.ctxt, keypair=keypair,
174 action='create', phase='start'),
175 mock.call(context=self.ctxt, keypair=keypair,
176 action='create', phase='end')])
170 self._check_notifications() 177 self._check_notifications()
171 178
172 def test_success_ssh(self): 179 def test_success_ssh(self):
diff --git a/nova/tests/unit/notifications/objects/test_notification.py b/nova/tests/unit/notifications/objects/test_notification.py
index 52a6ff3..3d75391 100644
--- a/nova/tests/unit/notifications/objects/test_notification.py
+++ b/nova/tests/unit/notifications/objects/test_notification.py
@@ -386,6 +386,8 @@ notification_object_data = {
386 'InstanceUpdateNotification': '1.0-a73147b93b520ff0061865849d3dfa56', 386 'InstanceUpdateNotification': '1.0-a73147b93b520ff0061865849d3dfa56',
387 'InstanceUpdatePayload': '1.3-5bf5f18ed1232b1d8884fa784b77728f', 387 'InstanceUpdatePayload': '1.3-5bf5f18ed1232b1d8884fa784b77728f',
388 'IpPayload': '1.0-8ecf567a99e516d4af094439a7632d34', 388 'IpPayload': '1.0-8ecf567a99e516d4af094439a7632d34',
389 'KeypairNotification': '1.0-a73147b93b520ff0061865849d3dfa56',
390 'KeypairPayload': '1.0-6daebbbde0e1bf35c1556b1ecd9385c1',
389 'NotificationPublisher': '1.0-bbbc1402fb0e443a3eb227cc52b61545', 391 'NotificationPublisher': '1.0-bbbc1402fb0e443a3eb227cc52b61545',
390 'ServiceStatusNotification': '1.0-a73147b93b520ff0061865849d3dfa56', 392 'ServiceStatusNotification': '1.0-a73147b93b520ff0061865849d3dfa56',
391 'ServiceStatusPayload': '1.1-7b6856bd879db7f3ecbcd0ca9f35f92f', 393 'ServiceStatusPayload': '1.1-7b6856bd879db7f3ecbcd0ca9f35f92f',