Merge "Transform keypair.create notification"

This commit is contained in:
Jenkins 2017-06-16 11:07:41 +00:00 committed by Gerrit Code Review
commit 8238e8aaa0
10 changed files with 180 additions and 7 deletions

View File

@ -30,6 +30,7 @@ from nova.objects import base
from nova.notifications.objects import exception
from nova.notifications.objects import flavor
from nova.notifications.objects import instance
from nova.notifications.objects import keypair
from nova.notifications.objects import service

View File

@ -0,0 +1,17 @@
{
"priority": "INFO",
"payload": {
"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"
}
},
"event_type": "keypair.create.end",
"publisher_id": "nova-api:fake-mini"
}

View File

@ -0,0 +1,17 @@
{
"priority": "INFO",
"payload": {
"nova_object.version": "1.0",
"nova_object.namespace": "nova",
"nova_object.name": "KeypairPayload",
"nova_object.data": {
"user_id": "fake",
"name": "my-key",
"fingerprint": null,
"public_key": null,
"type": "ssh"
}
},
"event_type": "keypair.create.start",
"publisher_id": "nova-api:fake-mini"
}

View File

@ -4952,18 +4952,31 @@ class KeypairAPI(base.Base):
"""Create a new key pair."""
self._validate_new_key_pair(context, user_id, key_name, key_type)
self._notify(context, 'create.start', key_name)
private_key, public_key, fingerprint = self._generate_key_pair(
user_id, key_type)
keypair = objects.KeyPair(context)
keypair.user_id = user_id
keypair.name = key_name
keypair.type = key_type
keypair.fingerprint = None
keypair.public_key = None
self._notify(context, 'create.start', key_name)
compute_utils.notify_about_keypair_action(
context=context,
keypair=keypair,
action=fields_obj.NotificationAction.CREATE,
phase=fields_obj.NotificationPhase.START)
private_key, public_key, fingerprint = self._generate_key_pair(
user_id, key_type)
keypair.fingerprint = fingerprint
keypair.public_key = public_key
keypair.create()
compute_utils.notify_about_keypair_action(
context=context,
keypair=keypair,
action=fields_obj.NotificationAction.CREATE,
phase=fields_obj.NotificationPhase.END)
self._notify(context, 'create.end', key_name)

View File

@ -35,6 +35,7 @@ from nova.notifications.objects import aggregate as aggregate_notification
from nova.notifications.objects import base as notification_base
from nova.notifications.objects import exception as notification_exception
from nova.notifications.objects import instance as instance_notification
from nova.notifications.objects import keypair as keypair_notification
from nova import objects
from nova.objects import fields
from nova import rpc
@ -394,6 +395,27 @@ def notify_about_volume_attach_detach(context, instance, host, action, phase,
notification.emit(context)
def notify_about_keypair_action(context, keypair, action, phase):
"""Send versioned notification about the keypair action on the instance
:param context: the request context
:param keypair: the keypair which the action performed on
:param action: the name of the action
:param phase: the phase of the action
"""
payload = keypair_notification.KeypairPayload(keypair=keypair)
notification = keypair_notification.KeypairNotification(
priority=fields.NotificationPriority.INFO,
publisher=notification_base.NotificationPublisher(
host=CONF.host, binary='nova-api'),
event_type=notification_base.EventType(
object='keypair',
action=action,
phase=phase),
payload=payload)
notification.emit(context)
def notify_about_volume_swap(context, instance, host, action, phase,
old_volume_id, new_volume_id, exception=None):
"""Send versioned notification about the volume swap action

View File

@ -0,0 +1,51 @@
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from nova.notifications.objects import base
from nova.objects import base as nova_base
from nova.objects import fields
@nova_base.NovaObjectRegistry.register_notification
class KeypairPayload(base.NotificationPayloadBase):
SCHEMA = {
'user_id': ('keypair', 'user_id'),
'name': ('keypair', 'name'),
'public_key': ('keypair', 'public_key'),
'fingerprint': ('keypair', 'fingerprint'),
'type': ('keypair', 'type')
}
# Version 1.0: Initial version
VERSION = '1.0'
fields = {
'user_id': fields.StringField(nullable=True),
'name': fields.StringField(nullable=False),
'fingerprint': fields.StringField(nullable=True),
'public_key': fields.StringField(nullable=True),
'type': fields.StringField(nullable=False),
}
def __init__(self, keypair, **kwargs):
super(KeypairPayload, self).__init__(**kwargs)
self.populate_schema(keypair=keypair)
@base.notification_sample('keypair-create-start.json')
@base.notification_sample('keypair-create-end.json')
@nova_base.NovaObjectRegistry.register_notification
class KeypairNotification(base.NotificationBase):
# Version 1.0: Initial version
VERSION = '1.0'
fields = {
'payload': fields.ObjectField('KeypairPayload')
}

View File

@ -217,7 +217,7 @@ class TestOpenStackClient(object):
headers['Content-Type'] = 'application/json'
kwargs['body'] = jsonutils.dumps(body)
kwargs.setdefault('check_response_status', [200, 202])
kwargs.setdefault('check_response_status', [200, 201, 202])
return APIResponse(self.api_request(relative_uri, **kwargs))
def api_put(self, relative_uri, body, **kwargs):
@ -423,3 +423,6 @@ class TestOpenStackClient(object):
def get_services(self):
return self.api_get('/os-services').body['services']
def post_keypair(self, keypair):
return self.api_post('/os-keypairs', keypair).body['keypair']

View File

@ -0,0 +1,40 @@
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from nova.tests.functional.notification_sample_tests \
import notification_sample_base
from nova.tests.unit import fake_notifier
class TestKeypairNotificationSample(
notification_sample_base.NotificationSampleTestBase):
def test_keypair_create(self):
keypair_req = {
"keypair": {
"name": "my-key",
"user_id": "fake",
"type": "ssh"
}}
keypair = self.api.post_keypair(keypair_req)
self.assertEqual(2, len(fake_notifier.VERSIONED_NOTIFICATIONS))
self._verify_notification(
'keypair-create-start',
replacements={},
actual=fake_notifier.VERSIONED_NOTIFICATIONS[0])
self._verify_notification(
'keypair-create-end',
replacements={
"fingerprint": keypair['fingerprint'],
"public_key": keypair['public_key']
},
actual=fake_notifier.VERSIONED_NOTIFICATIONS[1])

View File

@ -14,6 +14,7 @@
# under the License.
"""Tests for keypair API."""
import mock
from oslo_concurrency import processutils
from oslo_config import cfg
import six
@ -162,11 +163,17 @@ class CreateImportSharedTestMixIn(object):
class CreateKeypairTestCase(KeypairAPITestCase, CreateImportSharedTestMixIn):
func_name = 'create_key_pair'
def _check_success(self):
@mock.patch('nova.compute.utils.notify_about_keypair_action')
def _check_success(self, mock_notify):
keypair, private_key = self.keypair_api.create_key_pair(
self.ctxt, self.ctxt.user_id, 'foo', key_type=self.keypair_type)
self.assertEqual('foo', keypair['name'])
self.assertEqual(self.keypair_type, keypair['type'])
mock_notify.assert_has_calls([
mock.call(context=self.ctxt, keypair=keypair,
action='create', phase='start'),
mock.call(context=self.ctxt, keypair=keypair,
action='create', phase='end')])
self._check_notifications()
def test_success_ssh(self):

View File

@ -386,6 +386,8 @@ notification_object_data = {
'InstanceUpdateNotification': '1.0-a73147b93b520ff0061865849d3dfa56',
'InstanceUpdatePayload': '1.3-5bf5f18ed1232b1d8884fa784b77728f',
'IpPayload': '1.0-8ecf567a99e516d4af094439a7632d34',
'KeypairNotification': '1.0-a73147b93b520ff0061865849d3dfa56',
'KeypairPayload': '1.0-6daebbbde0e1bf35c1556b1ecd9385c1',
'NotificationPublisher': '1.0-bbbc1402fb0e443a3eb227cc52b61545',
'ServiceStatusNotification': '1.0-a73147b93b520ff0061865849d3dfa56',
'ServiceStatusPayload': '1.1-7b6856bd879db7f3ecbcd0ca9f35f92f',