def _get_usage_dict(self, object_or_dict, **updates): """Make a usage dict _update methods expect. Accepts a dict or an Instance or Flavor object, and a set of updates. Converts the object to a dict and applies the updates. :param object_or_dict: instance or flavor as an object or just a dict :param updates: key-value pairs to update the passed object. Currently only considers 'numa_topology', all other keys are ignored. :returns: a dict with all the information from object_or_dict updated with updates """ usage = {} if isinstance(object_or_dict, objects.Instance): usage = obj_base.obj_to_primitive(object_or_dict) elif isinstance(object_or_dict, objects.Flavor): usage = obj_base.obj_to_primitive(object_or_dict) else: usage.update(object_or_dict) for key in ('numa_topology', ): if key in updates: usage[key] = updates[key] return usage
def _get_usage_dict(self, object_or_dict, **updates): """Make a usage dict _update methods expect. Accepts a dict or an Instance or Flavor object, and a set of updates. Converts the object to a dict and applies the updates. :param object_or_dict: instance or flavor as an object or just a dict :param updates: key-value pairs to update the passed object. Currently only considers 'numa_topology', all other keys are ignored. :returns: a dict with all the information from object_or_dict updated with updates """ usage = {} if isinstance(object_or_dict, objects.Instance): usage = obj_base.obj_to_primitive(object_or_dict) elif isinstance(object_or_dict, objects.Flavor): usage = obj_base.obj_to_primitive(object_or_dict) else: usage.update(object_or_dict) for key in ('numa_topology',): if key in updates: usage[key] = updates[key] return usage
def build_instances(self, ctxt, **kwargs): """Build instances.""" build_inst_kwargs = kwargs instances = build_inst_kwargs['instances'] build_inst_kwargs['image'] = jsonutils.to_primitive( build_inst_kwargs['image']) version = '1.34' if self.client.can_send_version('1.34'): build_inst_kwargs.pop('legacy_bdm', None) else: bdm_p = objects_base.obj_to_primitive( build_inst_kwargs['block_device_mapping']) build_inst_kwargs['block_device_mapping'] = bdm_p version = '1.32' if not self.client.can_send_version('1.32'): instances_p = [jsonutils.to_primitive(inst) for inst in instances] build_inst_kwargs['instances'] = instances_p version = '1.30' if not self.client.can_send_version('1.30'): if 'filter_properties' in build_inst_kwargs: filter_properties = build_inst_kwargs['filter_properties'] flavor = filter_properties['instance_type'] flavor_p = objects_base.obj_to_primitive(flavor) filter_properties['instance_type'] = flavor_p version = '1.8' cctxt = self.client.prepare(version=version) cctxt.cast(ctxt, 'build_instances', build_inst_kwargs=build_inst_kwargs)
def migrate_server(self, context, instance, scheduler_hint, live, rebuild, flavor, block_migration, disk_over_commit, reservations=None, clean_shutdown=True, request_spec=None): kw = {'instance': instance, 'scheduler_hint': scheduler_hint, 'live': live, 'rebuild': rebuild, 'flavor': flavor, 'block_migration': block_migration, 'disk_over_commit': disk_over_commit, 'reservations': reservations, 'clean_shutdown': clean_shutdown, 'request_spec': request_spec, } version = '1.13' if not self.client.can_send_version(version): del kw['request_spec'] version = '1.11' if not self.client.can_send_version(version): del kw['clean_shutdown'] version = '1.10' if not self.client.can_send_version(version): kw['flavor'] = objects_base.obj_to_primitive(flavor) version = '1.6' if not self.client.can_send_version(version): kw['instance'] = jsonutils.to_primitive( objects_base.obj_to_primitive(instance)) version = '1.4' cctxt = self.client.prepare(version=version) return cctxt.call(context, 'migrate_server', **kw)
def build_instances(self, context, instances, image, filter_properties, admin_password, injected_files, requested_networks, security_groups, block_device_mapping, legacy_bdm=True): image_p = jsonutils.to_primitive(image) version = '1.10' if not self.client.can_send_version(version): version = '1.9' if 'instance_type' in filter_properties: flavor = filter_properties['instance_type'] flavor_p = objects_base.obj_to_primitive(flavor) filter_properties = dict(filter_properties, instance_type=flavor_p) kw = {'instances': instances, 'image': image_p, 'filter_properties': filter_properties, 'admin_password': admin_password, 'injected_files': injected_files, 'requested_networks': requested_networks, 'security_groups': security_groups} if not self.client.can_send_version(version): version = '1.8' kw['requested_networks'] = kw['requested_networks'].as_tuples() if not self.client.can_send_version('1.7'): version = '1.5' bdm_p = objects_base.obj_to_primitive(block_device_mapping) kw.update({'block_device_mapping': bdm_p, 'legacy_bdm': legacy_bdm}) cctxt = self.client.prepare(version=version) cctxt.cast(context, 'build_instances', **kw)
def _test_extract_flavor(self, prefix): instance_type = flavors.get_default_flavor() instance_type_p = obj_base.obj_to_primitive(instance_type) metadata = {} flavors.save_flavor_info(metadata, instance_type, prefix) instance = {'system_metadata': self._dict_to_metadata(metadata)} _instance_type = flavors.extract_flavor(instance, prefix) _instance_type_p = obj_base.obj_to_primitive(_instance_type) props = flavors.system_metadata_flavor_props.keys() for key in list(instance_type_p.keys()): if key not in props: del instance_type_p[key] self.assertEqual(instance_type_p, _instance_type_p)
def set_network_host(self, ctxt, network_ref): version = '1.15' if not self.client.can_send_version(version): version = '1.0' network_ref = objects_base.obj_to_primitive(network_ref) cctxt = self.client.prepare(version=version) return cctxt.call(ctxt, 'set_network_host', network_ref=network_ref)
def _update_usage_from_instance(self, context, instance, is_removed=False): """Update usage for a single instance.""" uuid = instance['uuid'] is_new_instance = uuid not in self.tracked_instances is_removed_instance = (is_removed or instance['vm_state'] in vm_states.ALLOW_RESOURCE_REMOVAL) if is_new_instance: self.tracked_instances[uuid] = obj_base.obj_to_primitive(instance) sign = 1 if is_removed_instance: self.tracked_instances.pop(uuid) sign = -1 self.stats.update_stats_for_instance(instance, is_removed_instance) # if it's a new or deleted instance: if is_new_instance or is_removed_instance: if self.pci_tracker: self.pci_tracker.update_pci_for_instance(context, instance, sign=sign) # new instance, update compute node resource usage: self._update_usage(instance, sign=sign) self.compute_node.current_workload = self.stats.calculate_workload() if self.pci_tracker: obj = self.pci_tracker.stats.to_device_pools_obj() self.compute_node.pci_device_pools = obj else: self.compute_node.pci_device_pools = objects.PciDevicePoolList()
def _update_usage_from_instance(self, context, instance, is_removed=False): """Update usage for a single instance.""" uuid = instance['uuid'] is_new_instance = uuid not in self.tracked_instances is_removed_instance = ( is_removed or instance['vm_state'] in vm_states.ALLOW_RESOURCE_REMOVAL) if is_new_instance: self.tracked_instances[uuid] = obj_base.obj_to_primitive(instance) sign = 1 if is_removed_instance: self.tracked_instances.pop(uuid) sign = -1 self.stats.update_stats_for_instance(instance, is_removed_instance) # if it's a new or deleted instance: if is_new_instance or is_removed_instance: if self.pci_tracker: self.pci_tracker.update_pci_for_instance(context, instance, sign=sign) # new instance, update compute node resource usage: self._update_usage(instance, sign=sign) self.compute_node.current_workload = self.stats.calculate_workload() if self.pci_tracker: obj = self.pci_tracker.stats.to_device_pools_obj() self.compute_node.pci_device_pools = obj else: self.compute_node.pci_device_pools = objects.PciDevicePoolList()
def instance_destroy_at_top(self, ctxt, instance): """Destroy instance at API level.""" version = '1.35' if not self.client.can_send_version('1.35'): instance = objects_base.obj_to_primitive(instance) version = '1.34' cctxt = self.client.prepare(version=version) cctxt.cast(ctxt, 'instance_destroy_at_top', instance=instance)
def test_send_on_task_change(self): old = obj_base.obj_to_primitive(self.instance) old['task_state'] = None # pretend we just transitioned to task SPAWNING: self.instance.task_state = task_states.SPAWNING notifications.send_update(self.context, old, self.instance) self.assertEqual(1, len(fake_notifier.NOTIFICATIONS))
def refresh_instance_security_rules(self, ctxt, host, instance): version = '4.4' if not self.client.can_send_version(version): version = '4.0' instance = objects_base.obj_to_primitive(instance) cctxt = self.client.prepare(server=_compute_host(None, instance), version=version) cctxt.cast(ctxt, 'refresh_instance_security_rules', instance=instance)
def bulk_create(self, context, fixed_ips): ips = [] for fixedip in fixed_ips: ip = obj_base.obj_to_primitive(fixedip) if 'id' in ip: raise exception.ObjectActionError(action='create', reason='already created') ips.append(ip) db.fixed_ip_bulk_create(context, ips)
def bulk_create(self, context, fixed_ips): ips = [] for fixedip in fixed_ips: ip = obj_base.obj_to_primitive(fixedip) if 'id' in ip: raise exception.ObjectActionError(action='create', reason='already created') ips.append(ip) db.fixed_ip_bulk_create(context, ips)
def instance_info_cache_update_at_top(self, ctxt, instance_info_cache): """Broadcast up that an instance's info_cache has changed.""" version = '1.35' instance = objects.Instance(uuid=instance_info_cache.instance_uuid, info_cache=instance_info_cache) if not self.client.can_send_version('1.35'): instance = objects_base.obj_to_primitive(instance) version = '1.34' cctxt = self.client.prepare(version=version) cctxt.cast(ctxt, 'instance_update_at_top', instance=instance)
def test_send_on_vm_change(self): old = obj_base.obj_to_primitive(self.instance) old['vm_state'] = None # pretend we just transitioned to ACTIVE: self.instance.vm_state = vm_states.ACTIVE notifications.send_update(self.context, old, self.instance) self.assertEqual(1, len(fake_notifier.NOTIFICATIONS)) # service name should default to 'compute' notif = fake_notifier.NOTIFICATIONS[0] self.assertEqual('compute.testhost', notif.publisher_id)
def build_request_spec(ctxt, image, instances, instance_type=None): """Build a request_spec for the scheduler. The request_spec assumes that all instances to be scheduled are the same type. """ instance = instances[0] if instance_type is None: if isinstance(instance, obj_instance.Instance): instance_type = instance.get_flavor() else: instance_type = flavors.extract_flavor(instance) if isinstance(instance, obj_instance.Instance): instance = obj_base.obj_to_primitive(instance) # obj_to_primitive doesn't copy this enough, so be sure # to detach our metadata blob because we modify it below. instance['system_metadata'] = dict(instance.get('system_metadata', {})) if isinstance(instance_type, objects.Flavor): instance_type = obj_base.obj_to_primitive(instance_type) # NOTE(danms): Replicate this old behavior because the # scheduler RPC interface technically expects it to be # there. Remove this when we bump the scheduler RPC API to # v5.0 try: flavors.save_flavor_info(instance.get('system_metadata', {}), instance_type) except KeyError: # If the flavor isn't complete (which is legit with a # flavor object, just don't put it in the request spec pass request_spec = { 'image': image or {}, 'instance_properties': instance, 'instance_type': instance_type, 'num_instances': len(instances)} return jsonutils.to_primitive(request_spec)
def resize_instance(self, ctxt, instance, migration, image, instance_type, reservations=None, clean_shutdown=True): msg_args = {'instance': instance, 'migration': migration, 'image': image, 'reservations': reservations, 'instance_type': instance_type, 'clean_shutdown': clean_shutdown, } version = '4.1' if not self.client.can_send_version(version): msg_args['instance_type'] = objects_base.obj_to_primitive( instance_type) version = '4.0' cctxt = self.client.prepare(server=_compute_host(None, instance), version=version) cctxt.cast(ctxt, 'resize_instance', **msg_args)
def bdm_update_or_create_at_top(self, ctxt, bdm, create=None): """Create or update a block device mapping in API cells. If create is True, only try to create. If create is None, try to update but fall back to create. If create is False, only attempt to update. This maps to compute-conductor's behavior. """ if self.client.can_send_version('1.28'): version = '1.28' else: version = '1.10' bdm = objects_base.obj_to_primitive(bdm) cctxt = self.client.prepare(version=version) try: cctxt.cast(ctxt, 'bdm_update_or_create_at_top', bdm=bdm, create=create) except Exception: LOG.exception(_LE("Failed to notify cells of BDM update/create."))
def setUp(self): super(MigrationTaskTestCase, self).setUp() self.user_id = 'fake' self.project_id = 'fake' self.context = FakeContext(self.user_id, self.project_id) inst = fake_instance.fake_db_instance(image_ref='image_ref') self.instance = compute.Instance._from_db_object( self.context, compute.Instance(), inst, []) self.instance.system_metadata = {'image_hw_disk_bus': 'scsi'} self.flavor = fake_flavor.fake_flavor_obj(self.context) self.flavor.extra_specs = {'extra_specs': 'fake'} self.request_spec = {'instance_type': obj_base.obj_to_primitive(self.flavor), 'instance_properties': {}, 'image': 'image'} self.hosts = [dict(host='host1', nodename=None, limits={})] self.filter_properties = {'limits': {}, 'retry': {'num_attempts': 1, 'hosts': [['host1', None]]}} self.reservations = [] self.clean_shutdown = True
def prep_resize(self, ctxt, image, instance, instance_type, host, reservations=None, request_spec=None, filter_properties=None, node=None, clean_shutdown=True): image_p = jsonutils.to_primitive(image) msg_args = {'instance': instance, 'instance_type': instance_type, 'image': image_p, 'reservations': reservations, 'request_spec': request_spec, 'filter_properties': filter_properties, 'node': node, 'clean_shutdown': clean_shutdown} version = '4.1' if not self.client.can_send_version(version): version = '4.0' msg_args['instance_type'] = objects_base.obj_to_primitive( instance_type) cctxt = self.client.prepare(server=host, version=version) cctxt.cast(ctxt, 'prep_resize', **msg_args)
def _build_instances(self, message, target_cells, instance_uuids, build_inst_kwargs): """Attempt to build instance(s) or send msg to child cell.""" ctxt = message.ctxt instance_properties = obj_base.obj_to_primitive( build_inst_kwargs['instances'][0]) filter_properties = build_inst_kwargs['filter_properties'] instance_type = filter_properties['instance_type'] image = build_inst_kwargs['image'] security_groups = build_inst_kwargs['security_groups'] block_device_mapping = build_inst_kwargs['block_device_mapping'] LOG.debug("Building instances with routing_path=%(routing_path)s", {'routing_path': message.routing_path}) for target_cell in target_cells: try: if target_cell.is_me: # Need to create instance DB entries as the conductor # expects that the instance(s) already exists. instances = self._create_instances_here( ctxt, instance_uuids, instance_properties, instance_type, image, security_groups, block_device_mapping) build_inst_kwargs['instances'] = instances # Need to record the create action in the db as the # conductor expects it to already exist. self._create_action_here(ctxt, instance_uuids) self.compute_task_api.build_instances( ctxt, **build_inst_kwargs) return self.msg_runner.build_instances(ctxt, target_cell, build_inst_kwargs) return except Exception: LOG.exception(_LE("Couldn't communicate with cell '%s'"), target_cell.name) # FIXME(comstud): Would be nice to kick this back up so that # the parent cell could retry, if we had a parent. LOG.error(_LE("Couldn't communicate with any cells")) raise exception.NoCellsAvailable()
def _output(self, req, migrations_obj, add_link=False): """Returns the desired output of the API from an object. From a MigrationsList's object this method returns a list of primitive objects with the only necessary fields. """ detail_keys = [ 'memory_total', 'memory_processed', 'memory_remaining', 'disk_total', 'disk_processed', 'disk_remaining' ] # TODO(Shaohe Feng) we should share the in-progress list. live_migration_in_progress = [ 'queued', 'preparing', 'running', 'post-migrating' ] # Note(Shaohe Feng): We need to leverage the oslo.versionedobjects. # Then we can pass the target version to it's obj_to_primitive. objects = obj_base.obj_to_primitive(migrations_obj) objects = [x for x in objects if not x['hidden']] for obj in objects: del obj['deleted'] del obj['deleted_at'] del obj['hidden'] if 'memory_total' in obj: for key in detail_keys: del obj[key] # NOTE(Shaohe Feng) above version 2.23, add migration_type for all # kinds of migration, but we only add links just for in-progress # live-migration. if add_link and obj['migration_type'] == "live-migration" and ( obj["status"] in live_migration_in_progress): obj["links"] = self._view_builder._get_links( req, obj["id"], self._collection_name % obj['instance_uuid']) elif add_link is False: del obj['migration_type'] return objects
def output(migrations_obj): """Returns the desired output of the API from an object. From a MigrationsList's object this method returns a list of primitive objects with the only necessary fields. """ detail_keys = ['memory_total', 'memory_processed', 'memory_remaining', 'disk_total', 'disk_processed', 'disk_remaining'] # Note(Shaohe Feng): We need to leverage the oslo.versionedobjects. # Then we can pass the target version to it's obj_to_primitive. objects = obj_base.obj_to_primitive(migrations_obj) objects = [x for x in objects if not x['hidden']] for obj in objects: del obj['deleted'] del obj['deleted_at'] del obj['migration_type'] del obj['hidden'] if 'memory_total' in obj: for key in detail_keys: del obj[key] return objects
def test_set_network_host_network_object_to_primitive(self): # Tests that the network object is converted to a primitive if it # can't send version 1.15. ctxt = context.RequestContext('fake_user', 'fake_project') network = fake_network.fake_network_obj(ctxt) network_dict = objects_base.obj_to_primitive(network) rpcapi = network_rpcapi.NetworkAPI() call_mock = mock.Mock() cctxt_mock = mock.Mock(call=call_mock) with test.nested( mock.patch.object(rpcapi.client, 'can_send_version', return_value=False), mock.patch.object(rpcapi.client, 'prepare', return_value=cctxt_mock) ) as ( can_send_mock, prepare_mock ): rpcapi.set_network_host(ctxt, network) # assert our mocks were called as expected can_send_mock.assert_called_once_with('1.15') prepare_mock.assert_called_once_with(version='1.0') call_mock.assert_called_once_with(ctxt, 'set_network_host', network_ref=network_dict)
def _output(self, req, migrations_obj, add_link=False): """Returns the desired output of the API from an object. From a MigrationsList's object this method returns a list of primitive objects with the only necessary fields. """ detail_keys = ['memory_total', 'memory_processed', 'memory_remaining', 'disk_total', 'disk_processed', 'disk_remaining'] # TODO(Shaohe Feng) we should share the in-progress list. live_migration_in_progress = ['queued', 'preparing', 'running', 'post-migrating'] # Note(Shaohe Feng): We need to leverage the oslo.versionedobjects. # Then we can pass the target version to it's obj_to_primitive. objects = obj_base.obj_to_primitive(migrations_obj) objects = [x for x in objects if not x['hidden']] for obj in objects: del obj['deleted'] del obj['deleted_at'] del obj['hidden'] if 'memory_total' in obj: for key in detail_keys: del obj[key] # NOTE(Shaohe Feng) above version 2.23, add migration_type for all # kinds of migration, but we only add links just for in-progress # live-migration. if add_link and obj['migration_type'] == "live-migration" and ( obj["status"] in live_migration_in_progress): obj["links"] = self._view_builder._get_links( req, obj["id"], self._collection_name % obj['instance_uuid']) elif add_link is False: del obj['migration_type'] return objects
def _to_legacy_image(self): return base.obj_to_primitive(self.image) if ( self.obj_attr_is_set('image') and self.image) else {}
def bdm_update_or_create_at_top(self, ctxt, bdm, create=None): """BDM was created/updated in this cell. Tell the API cells.""" # TODO(ndipanov): Move inter-cell RPC to use objects bdm = base_obj.obj_to_primitive(bdm) self.msg_runner.bdm_update_or_create_at_top(ctxt, bdm, create=create)
def to_dict(self): pci_pool = base.obj_to_primitive(self) tags = pci_pool.pop('tags', {}) for k, v in six.iteritems(tags): pci_pool[k] = v return pci_pool
def _to_legacy_image(self): return base.obj_to_primitive(self.image) if ( self.obj_attr_is_set('image') and self.image) else {}
def bdm_update_or_create_at_top(self, ctxt, bdm, create=None): """BDM was created/updated in this cell. Tell the API cells.""" # TODO(ndipanov): Move inter-cell RPC to use objects bdm = base_obj.obj_to_primitive(bdm) self.msg_runner.bdm_update_or_create_at_top(ctxt, bdm, create=create)