diff options
Diffstat (limited to 'nova/tests')
4 files changed, 270 insertions, 30 deletions
diff --git a/nova/tests/functional/notification_sample_tests/notification_sample_base.py b/nova/tests/functional/notification_sample_tests/notification_sample_base.py index 8106404ddd..5f4d0b13e8 100644 --- a/nova/tests/functional/notification_sample_tests/notification_sample_base.py +++ b/nova/tests/functional/notification_sample_tests/notification_sample_base.py @@ -77,7 +77,7 @@ class NotificationSampleTestBase(test.TestCase, self.start_service('conductor', manager=CONF.conductor.manager) self.start_service('scheduler') self.start_service('network') - self.start_service('compute') + self.compute = self.start_service('compute') def _get_notification_sample(self, sample): sample_dir = os.path.dirname(os.path.abspath(__file__)) @@ -177,3 +177,8 @@ class NotificationSampleTestBase(test.TestCase, self.fail('Server failed to delete.') except api_client.OpenStackApiNotFoundException: return + + def _get_notifications(self, event_type): + return [notification for notification + in fake_notifier.VERSIONED_NOTIFICATIONS + if notification['event_type'] == event_type] diff --git a/nova/tests/functional/notification_sample_tests/test_instance.py b/nova/tests/functional/notification_sample_tests/test_instance.py index 4d19bdba5a..17b4f3c953 100644 --- a/nova/tests/functional/notification_sample_tests/test_instance.py +++ b/nova/tests/functional/notification_sample_tests/test_instance.py @@ -9,6 +9,7 @@ # 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 import context from nova.tests import fixtures from nova.tests.functional.notification_sample_tests \ import notification_sample_base @@ -47,3 +48,145 @@ class TestInstanceNotificationSample( notification_sample_base.NotificationSampleTestBase.ANY, 'uuid': server['id']}, actual=fake_notifier.VERSIONED_NOTIFICATIONS[1]) + + def _verify_instance_update_steps(self, steps, notifications, + initial=None): + replacements = {} + if initial: + replacements = initial + for i, step in enumerate(steps): + replacements.update(step) + self._verify_notification( + 'instance-update', + replacements=replacements, + actual=notifications[i]) + return replacements + + def test_create_delete_server_with_instance_update(self): + self.flags(notify_on_state_change='vm_and_task_state') + + server = self._boot_a_server( + extra_params={'networks': [{'port': self.neutron.port_1['id']}]}) + + instance_updates = self._get_notifications('instance.update') + + # The first notification comes from the nova-api the rest is from the + # nova-compute. To keep the test simpler assert this fact and then + # modify the publisher_id of the first notification to match the + # template + self.assertEqual('nova-api:fake-mini', + instance_updates[0]['publisher_id']) + instance_updates[0]['publisher_id'] = 'nova-compute:fake-mini' + + self.assertEqual(7, len(instance_updates)) + create_steps = [ + # nothing -> scheduling + {'reservation_id': + notification_sample_base.NotificationSampleTestBase.ANY, + 'uuid': server['id'], + 'host': None, + 'node': None, + 'state_update.new_task_state': 'scheduling', + 'state_update.old_task_state': 'scheduling', + 'state_update.state': 'building', + 'state_update.old_state': 'building', + 'state': 'building'}, + + # scheduling -> building + { + 'state_update.new_task_state': None, + 'state_update.old_task_state': 'scheduling', + 'task_state': None}, + + # scheduled + {'host': 'compute', + 'node': 'fake-mini', + 'state_update.old_task_state': None}, + + # building -> networking + {'state_update.new_task_state': 'networking', + 'state_update.old_task_state': 'networking', + 'task_state': 'networking'}, + + # networking -> block_device_mapping + {'state_update.new_task_state': 'block_device_mapping', + 'state_update.old_task_state': 'networking', + 'task_state': 'block_device_mapping', + }, + + # block_device_mapping -> spawning + {'state_update.new_task_state': 'spawning', + 'state_update.old_task_state': 'block_device_mapping', + 'task_state': 'spawning', + 'ip_addresses': [{ + "nova_object.name": "IpPayload", + "nova_object.namespace": "nova", + "nova_object.version": "1.0", + "nova_object.data": { + "mac": "fa:16:3e:4c:2c:30", + "address": "192.168.1.3", + "port_uuid": "ce531f90-199f-48c0-816c-13e38010b442", + "meta": {}, + "version": 4, + "label": "private-network", + "device_name": "tapce531f90-19" + }}] + }, + + # spawning -> active + {'state_update.new_task_state': None, + 'state_update.old_task_state': 'spawning', + 'state_update.state': 'active', + 'launched_at': '2012-10-29T13:42:11Z', + 'state': 'active', + 'task_state': None, + 'power_state': 'running'}, + ] + + replacements = self._verify_instance_update_steps( + create_steps, instance_updates) + + fake_notifier.reset() + + # Let's generate some bandwidth usage data. + # Just call the periodic task directly for simplicity + self.compute.manager._poll_bandwidth_usage(context.get_admin_context()) + + self.api.delete_server(server['id']) + self._wait_until_deleted(server) + + instance_updates = self._get_notifications('instance.update') + self.assertEqual(2, len(instance_updates)) + + delete_steps = [ + # active -> deleting + {'state_update.new_task_state': 'deleting', + 'state_update.old_task_state': 'deleting', + 'state_update.old_state': 'active', + 'state': 'active', + 'task_state': 'deleting', + 'bandwidth': [ + {'nova_object.namespace': 'nova', + 'nova_object.name': 'BandwidthPayload', + 'nova_object.data': + {'network_name': 'private-network', + 'out_bytes': 0, + 'in_bytes': 0}, + 'nova_object.version': '1.0'}] + }, + + # deleting -> deleted + {'state_update.new_task_state': None, + 'state_update.old_task_state': 'deleting', + 'state_update.old_state': 'active', + 'state_update.state': 'deleted', + 'state': 'deleted', + 'task_state': None, + 'terminated_at': '2012-10-29T13:42:11Z', + 'ip_addresses': [], + 'power_state': 'pending', + 'bandwidth': []}, + ] + + self._verify_instance_update_steps(delete_steps, instance_updates, + initial=replacements) diff --git a/nova/tests/unit/notifications/objects/test_notification.py b/nova/tests/unit/notifications/objects/test_notification.py index a698e9ab16..2f9e2afced 100644 --- a/nova/tests/unit/notifications/objects/test_notification.py +++ b/nova/tests/unit/notifications/objects/test_notification.py @@ -255,6 +255,8 @@ class TestNotificationBase(test.NoDBTestCase): notification_object_data = { + 'AuditPeriodPayload': '1.0-28345f72ca9d805eeb61b2c2385805dd', + 'BandwidthPayload': '1.0-49278639296f9939ff2c8947b2078a82', 'EventType': '1.3-6ef678bfe9a4ebfd669c96d2d2c124a5', 'ExceptionNotification': '1.0-a73147b93b520ff0061865849d3dfa56', 'ExceptionPayload': '1.0-4516ae282a55fe2fd5c754967ee6248b', @@ -262,6 +264,9 @@ notification_object_data = { 'InstanceActionNotification': '1.0-a73147b93b520ff0061865849d3dfa56', 'InstanceActionPayload': '1.0-aa6a322cf1a3a19d090259fee65d1094', 'InstancePayload': '1.0-878bbc5a7a20bdeac7c6570f438a53aa', + 'InstanceStateUpdatePayload': '1.0-a934d04e1b314318e42e8062647edd11', + 'InstanceUpdateNotification': '1.0-a73147b93b520ff0061865849d3dfa56', + 'InstanceUpdatePayload': '1.0-c69e17e00400455bfe602e5573a61f0b', 'IpPayload': '1.0-26b40117c41ed95a61ae104f0fcb5fdc', 'NotificationPublisher': '1.0-bbbc1402fb0e443a3eb227cc52b61545', 'ServiceStatusNotification': '1.0-a73147b93b520ff0061865849d3dfa56', diff --git a/nova/tests/unit/test_notifications.py b/nova/tests/unit/test_notifications.py index 97d8fe02a9..a99fc25dfb 100644 --- a/nova/tests/unit/test_notifications.py +++ b/nova/tests/unit/test_notifications.py @@ -200,6 +200,7 @@ class NotificationsTestCase(test.TestCase): notifications.send_update(self.context, old, self.instance) self.assertEqual(0, len(fake_notifier.NOTIFICATIONS)) + self.assertEqual(0, len(fake_notifier.VERSIONED_NOTIFICATIONS)) def test_task_notif(self): @@ -220,12 +221,18 @@ class NotificationsTestCase(test.TestCase): verify_states=True) self.assertEqual(0, len(fake_notifier.NOTIFICATIONS)) + self.assertEqual(0, len(fake_notifier.VERSIONED_NOTIFICATIONS)) # ok now enable task state notifications and re-try self.flags(notify_on_state_change="vm_and_task_state") notifications.send_update(self.context, old, self.instance) self.assertEqual(1, len(fake_notifier.NOTIFICATIONS)) + self.assertEqual(1, len(fake_notifier.VERSIONED_NOTIFICATIONS)) + + self.assertEqual( + 'instance.update', + fake_notifier.VERSIONED_NOTIFICATIONS[0]['event_type']) def test_send_no_notif(self): @@ -240,6 +247,7 @@ class NotificationsTestCase(test.TestCase): service="compute", host=None, verify_states=True) self.assertEqual(0, len(fake_notifier.NOTIFICATIONS)) + self.assertEqual(0, len(fake_notifier.VERSIONED_NOTIFICATIONS)) def test_send_on_vm_change(self): old = obj_base.obj_to_primitive(self.instance) @@ -253,6 +261,14 @@ class NotificationsTestCase(test.TestCase): notif = fake_notifier.NOTIFICATIONS[0] self.assertEqual('compute.testhost', notif.publisher_id) + self.assertEqual(1, len(fake_notifier.VERSIONED_NOTIFICATIONS)) + self.assertEqual( + 'nova-compute:testhost', + fake_notifier.VERSIONED_NOTIFICATIONS[0]['publisher_id']) + self.assertEqual( + 'instance.update', + fake_notifier.VERSIONED_NOTIFICATIONS[0]['event_type']) + def test_send_on_task_change(self): old = obj_base.obj_to_primitive(self.instance) @@ -262,6 +278,10 @@ class NotificationsTestCase(test.TestCase): notifications.send_update(self.context, old, self.instance) self.assertEqual(1, len(fake_notifier.NOTIFICATIONS)) + self.assertEqual(1, len(fake_notifier.VERSIONED_NOTIFICATIONS)) + self.assertEqual( + 'instance.update', + fake_notifier.VERSIONED_NOTIFICATIONS[0]['event_type']) def test_no_update_with_states(self): @@ -269,84 +289,146 @@ class NotificationsTestCase(test.TestCase): vm_states.BUILDING, vm_states.BUILDING, task_states.SPAWNING, task_states.SPAWNING, verify_states=True) self.assertEqual(0, len(fake_notifier.NOTIFICATIONS)) - - def test_vm_update_with_states(self): + self.assertEqual(0, len(fake_notifier.VERSIONED_NOTIFICATIONS)) + + def get_fake_bandwidth(self): + usage = objects.BandwidthUsage(context=self.context) + usage.create( + self.instance.uuid, + mac='DE:AD:BE:EF:00:01', + bw_in=1, + bw_out=2, + last_ctr_in=0, + last_ctr_out=0, + start_period='2012-10-29T13:42:11Z') + return usage + + @mock.patch.object(objects.BandwidthUsageList, 'get_by_uuids') + def test_vm_update_with_states(self, mock_bandwidth_list): + mock_bandwidth_list.return_value = [self.get_fake_bandwidth()] + fake_net_info = fake_network.fake_get_instance_nw_info(self, 1, 1) + self.instance.info_cache.network_info = fake_net_info notifications.send_update_with_states(self.context, self.instance, vm_states.BUILDING, vm_states.ACTIVE, task_states.SPAWNING, task_states.SPAWNING, verify_states=True) + + self._verify_notification() + + def _verify_notification(self, expected_state=vm_states.ACTIVE, + expected_new_task_state=task_states.SPAWNING): self.assertEqual(1, len(fake_notifier.NOTIFICATIONS)) - notif = fake_notifier.NOTIFICATIONS[0] - payload = notif.payload + self.assertEqual(1, len(fake_notifier.VERSIONED_NOTIFICATIONS)) + self.assertEqual( + 'instance.update', + fake_notifier.VERSIONED_NOTIFICATIONS[0]['event_type']) access_ip_v4 = str(self.instance.access_ip_v4) access_ip_v6 = str(self.instance.access_ip_v6) display_name = self.instance.display_name hostname = self.instance.hostname node = self.instance.node - + payload = fake_notifier.NOTIFICATIONS[0].payload self.assertEqual(vm_states.BUILDING, payload["old_state"]) - self.assertEqual(vm_states.ACTIVE, payload["state"]) + self.assertEqual(expected_state, payload["state"]) self.assertEqual(task_states.SPAWNING, payload["old_task_state"]) - self.assertEqual(task_states.SPAWNING, payload["new_task_state"]) + self.assertEqual(expected_new_task_state, payload["new_task_state"]) self.assertEqual(payload["access_ip_v4"], access_ip_v4) self.assertEqual(payload["access_ip_v6"], access_ip_v6) self.assertEqual(payload["display_name"], display_name) self.assertEqual(payload["hostname"], hostname) self.assertEqual(payload["node"], node) - - def test_task_update_with_states(self): + payload = fake_notifier.VERSIONED_NOTIFICATIONS[0][ + 'payload']['nova_object.data'] + state_update = payload['state_update']['nova_object.data'] + self.assertEqual(vm_states.BUILDING, state_update['old_state']) + self.assertEqual(expected_state, state_update["state"]) + self.assertEqual(task_states.SPAWNING, state_update["old_task_state"]) + self.assertEqual(expected_new_task_state, + state_update["new_task_state"]) + self.assertEqual(payload["display_name"], display_name) + self.assertEqual(payload["host_name"], hostname) + self.assertEqual(payload["node"], node) + flavor = payload['flavor']['nova_object.data'] + self.assertEqual(flavor['flavorid'], '1') + self.assertEqual(payload['image_uuid'], uuids.image_ref) + + net_info = self.instance.info_cache.network_info + vif = net_info[0] + ip_addresses = payload['ip_addresses'] + + self.assertEqual(len(ip_addresses), 2) + for actual_ip, expected_ip in zip(ip_addresses, vif.fixed_ips()): + actual_ip = actual_ip['nova_object.data'] + self.assertEqual(actual_ip['label'], vif['network']['label']) + self.assertEqual(actual_ip['mac'], vif['address'].lower()) + self.assertEqual(actual_ip['port_uuid'], vif['id']) + self.assertEqual(actual_ip['device_name'], vif['devname']) + self.assertEqual(actual_ip['version'], expected_ip['version']) + self.assertEqual(actual_ip['address'], expected_ip['address']) + + bandwidth = payload['bandwidth'] + self.assertEqual(len(bandwidth), 1) + bandwidth = bandwidth[0]['nova_object.data'] + self.assertEqual(bandwidth['in_bytes'], 1) + self.assertEqual(bandwidth['out_bytes'], 2) + self.assertEqual(bandwidth['network_name'], 'test1') + + @mock.patch.object(objects.BandwidthUsageList, 'get_by_uuids') + def test_task_update_with_states(self, mock_bandwidth_list): self.flags(notify_on_state_change="vm_and_task_state") + mock_bandwidth_list.return_value = [self.get_fake_bandwidth()] + fake_net_info = fake_network.fake_get_instance_nw_info(self, 1, 1) + self.instance.info_cache.network_info = fake_net_info notifications.send_update_with_states(self.context, self.instance, vm_states.BUILDING, vm_states.BUILDING, task_states.SPAWNING, None, verify_states=True) - self.assertEqual(1, len(fake_notifier.NOTIFICATIONS)) - notif = fake_notifier.NOTIFICATIONS[0] - payload = notif.payload - access_ip_v4 = str(self.instance.access_ip_v4) - access_ip_v6 = str(self.instance.access_ip_v6) - display_name = self.instance.display_name - hostname = self.instance.hostname - - self.assertEqual(vm_states.BUILDING, payload["old_state"]) - self.assertEqual(vm_states.BUILDING, payload["state"]) - self.assertEqual(task_states.SPAWNING, payload["old_task_state"]) - self.assertIsNone(payload["new_task_state"]) - self.assertEqual(payload["access_ip_v4"], access_ip_v4) - self.assertEqual(payload["access_ip_v6"], access_ip_v6) - self.assertEqual(payload["display_name"], display_name) - self.assertEqual(payload["hostname"], hostname) + self._verify_notification(expected_state=vm_states.BUILDING, + expected_new_task_state=None) def test_update_no_service_name(self): notifications.send_update_with_states(self.context, self.instance, vm_states.BUILDING, vm_states.BUILDING, task_states.SPAWNING, None) self.assertEqual(1, len(fake_notifier.NOTIFICATIONS)) + self.assertEqual(1, len(fake_notifier.VERSIONED_NOTIFICATIONS)) # service name should default to 'compute' notif = fake_notifier.NOTIFICATIONS[0] self.assertEqual('compute.testhost', notif.publisher_id) + # in the versioned notification it defaults to nova-compute + notif = fake_notifier.VERSIONED_NOTIFICATIONS[0] + self.assertEqual('nova-compute:testhost', notif['publisher_id']) + def test_update_with_service_name(self): notifications.send_update_with_states(self.context, self.instance, vm_states.BUILDING, vm_states.BUILDING, task_states.SPAWNING, None, service="testservice") self.assertEqual(1, len(fake_notifier.NOTIFICATIONS)) + self.assertEqual(1, len(fake_notifier.VERSIONED_NOTIFICATIONS)) # service name should default to 'compute' notif = fake_notifier.NOTIFICATIONS[0] self.assertEqual('testservice.testhost', notif.publisher_id) + notif = fake_notifier.VERSIONED_NOTIFICATIONS[0] + self.assertEqual('testservice:testhost', notif['publisher_id']) + def test_update_with_host_name(self): notifications.send_update_with_states(self.context, self.instance, vm_states.BUILDING, vm_states.BUILDING, task_states.SPAWNING, None, host="someotherhost") self.assertEqual(1, len(fake_notifier.NOTIFICATIONS)) + self.assertEqual(1, len(fake_notifier.VERSIONED_NOTIFICATIONS)) # service name should default to 'compute' notif = fake_notifier.NOTIFICATIONS[0] self.assertEqual('compute.someotherhost', notif.publisher_id) + notif = fake_notifier.VERSIONED_NOTIFICATIONS[0] + self.assertEqual('nova-compute:someotherhost', notif['publisher_id']) + def test_payload_has_fixed_ip_labels(self): info = notifications.info_from_instance(self.context, self.instance, self.net_info, None) @@ -404,13 +486,18 @@ class NotificationsTestCase(test.TestCase): new_name_inst = self._wrapped_create(params=param) notifications.send_update(self.context, self.instance, new_name_inst) self.assertEqual(1, len(fake_notifier.NOTIFICATIONS)) - notif = fake_notifier.NOTIFICATIONS[0] - payload = notif.payload + self.assertEqual(1, len(fake_notifier.VERSIONED_NOTIFICATIONS)) + old_display_name = self.instance.display_name new_display_name = new_name_inst.display_name - self.assertEqual(payload["old_display_name"], old_display_name) - self.assertEqual(payload["display_name"], new_display_name) + for payload in [ + fake_notifier.NOTIFICATIONS[0].payload, + fake_notifier.VERSIONED_NOTIFICATIONS[0][ + 'payload']['nova_object.data']]: + + self.assertEqual(payload["old_display_name"], old_display_name) + self.assertEqual(payload["display_name"], new_display_name) def test_send_no_state_change(self): called = [False] |