class SecurityGroupList(base.ObjectListBase, base.NovaObject): # Version 1.0: Initial version # SecurityGroup <= version 1.1 VERSION = '1.0' fields = { 'objects': fields.ListOfObjectsField('SecurityGroup'), } child_versions = { '1.0': '1.1', # NOTE(danms): SecurityGroup was at 1.1 before we added this } def __init__(self, *args, **kwargs): super(SecurityGroupList, self).__init__(*args, **kwargs) self.objects = [] self.obj_reset_changes() @base.remotable_classmethod def get_all(cls, context): groups = db.security_group_get_all(context) return base.obj_make_list(context, cls(context), objects.SecurityGroup, groups) @base.remotable_classmethod def get_by_project(cls, context, project_id): groups = db.security_group_get_by_project(context, project_id) return base.obj_make_list(context, cls(context), objects.SecurityGroup, groups) @base.remotable_classmethod def get_by_instance(cls, context, instance): groups = db.security_group_get_by_instance(context, instance.uuid) return base.obj_make_list(context, cls(context), objects.SecurityGroup, groups)
class InstanceMappingList(base.ObjectListBase, base.NovaObject): # Version 1.0: Initial version VERSION = '1.0' fields = { 'objects': fields.ListOfObjectsField('InstanceMapping'), } child_versions = { '1.0': '1.0', } @staticmethod def _get_by_project_id_from_db(context, project_id): session = db_api.get_api_session() with session.begin(): db_mappings = session.query(api_models.InstanceMapping).filter_by( project_id=project_id).all() return db_mappings @base.remotable_classmethod def get_by_project_id(cls, context, project_id): db_mappings = cls._get_by_project_id_from_db(context, project_id) return base.obj_make_list(context, cls(), objects.InstanceMapping, db_mappings)
class KeyPairList(base.ObjectListBase, base.NovaObject): # Version 1.0: Initial version # KeyPair <= version 1.1 # Version 1.1: KeyPair <= version 1.2 # Version 1.2: KeyPair <= version 1.3 VERSION = '1.2' fields = { 'objects': fields.ListOfObjectsField('KeyPair'), } child_versions = { '1.0': '1.1', # NOTE(danms): KeyPair was at 1.1 before we added this '1.1': '1.2', '1.2': '1.3', } @base.remotable_classmethod def get_by_user(cls, context, user_id): db_keypairs = db.key_pair_get_all_by_user(context, user_id) return base.obj_make_list(context, cls(context), objects.KeyPair, db_keypairs) @base.remotable_classmethod def get_count_by_user(cls, context, user_id): return db.key_pair_count_by_user(context, user_id)
class FlavorList(base.ObjectListBase, base.NovaObject): VERSION = '1.1' fields = { 'objects': fields.ListOfObjectsField('Flavor'), } child_versions = { '1.0': '1.0', '1.1': '1.1', } @base.remotable_classmethod def get_all(cls, context, inactive=False, filters=None, sort_key='flavorid', sort_dir='asc', limit=None, marker=None): db_flavors = db.flavor_get_all(context, inactive=inactive, filters=filters, sort_key=sort_key, sort_dir=sort_dir, limit=limit, marker=marker) return base.obj_make_list(context, cls(context), objects.Flavor, db_flavors, expected_attrs=['extra_specs'])
class ServiceList(base.ObjectListBase, base.NovaObject): # Version 1.0: Initial version # Service <= version 1.2 # Version 1.1 Service version 1.3 # Version 1.2: Service version 1.4 # Version 1.3: Service version 1.5 # Version 1.4: Service version 1.6 # Version 1.5: Service version 1.7 # Version 1.6: Service version 1.8 # Version 1.7: Service version 1.9 # Version 1.8: Service version 1.10 # Version 1.9: Added get_by_binary() and Service version 1.11 # Version 1.10: Service version 1.12 VERSION = '1.10' fields = { 'objects': fields.ListOfObjectsField('Service'), } child_versions = { '1.0': '1.2', # NOTE(danms): Service was at 1.2 before we added this '1.1': '1.3', '1.2': '1.4', '1.3': '1.5', '1.4': '1.6', '1.5': '1.7', '1.6': '1.8', '1.7': '1.9', '1.8': '1.10', '1.9': '1.11', '1.10': '1.12', } @base.remotable_classmethod def get_by_topic(cls, context, topic): db_services = db.service_get_all_by_topic(context, topic) return base.obj_make_list(context, cls(context), objects.Service, db_services) @base.remotable_classmethod def get_by_binary(cls, context, binary): db_services = db.service_get_all_by_binary(context, binary) return base.obj_make_list(context, cls(context), objects.Service, db_services) @base.remotable_classmethod def get_by_host(cls, context, host): db_services = db.service_get_all_by_host(context, host) return base.obj_make_list(context, cls(context), objects.Service, db_services) @base.remotable_classmethod def get_all(cls, context, disabled=None, set_zones=False): db_services = db.service_get_all(context, disabled=disabled) if set_zones: db_services = availability_zones.set_availability_zones( context, db_services) return base.obj_make_list(context, cls(context), objects.Service, db_services)
class AgentList(base.ObjectListBase, base.NovaObject): VERSION = '1.0' fields = { 'objects': fields.ListOfObjectsField('Agent'), } child_versions = { '1.0': '1.0', } @base.remotable_classmethod def get_all(cls, context, hypervisor=None): db_agents = db.agent_build_get_all(context, hypervisor=hypervisor) return base.obj_make_list(context, cls(), objects.Agent, db_agents)
class InstanceActionEventList(base.ObjectListBase, base.NovaObject): fields = { 'objects': fields.ListOfObjectsField('InstanceActionEvent'), } child_versions = { '1.0': '1.0', '1.1': '1.1', } @base.remotable_classmethod def get_by_action(cls, context, action_id): db_events = db.action_events_get(context, action_id) return base.obj_make_list(context, cls(context), objects.InstanceActionEvent, db_events)
class DNSDomainList(base.ObjectListBase, base.NovaObject): # Version 1.0: Initial version VERSION = '1.0' fields = { 'objects': fields.ListOfObjectsField('DNSDomain'), } child_versions = { '1.0': '1.0', } @base.remotable_classmethod def get_all(cls, context): db_domains = db.dnsdomain_get_all(context) return base.obj_make_list(context, cls(context), objects.DNSDomain, db_domains)
class AggregateList(base.ObjectListBase, base.NovaObject): # Version 1.0: Initial version # Version 1.1: Added key argument to get_by_host() # Aggregate <= version 1.1 # Version 1.2: Added get_by_metadata_key VERSION = '1.2' fields = { 'objects': fields.ListOfObjectsField('Aggregate'), } child_versions = { '1.0': '1.1', '1.1': '1.1', # NOTE(danms): Aggregate was at 1.1 before we added this '1.2': '1.1', } @classmethod def _filter_db_aggregates(cls, db_aggregates, hosts): if not isinstance(hosts, set): hosts = set(hosts) filtered_aggregates = [] for db_aggregate in db_aggregates: for host in db_aggregate['hosts']: if host in hosts: filtered_aggregates.append(db_aggregate) break return filtered_aggregates @base.remotable_classmethod def get_all(cls, context): db_aggregates = db.aggregate_get_all(context) return base.obj_make_list(context, cls(context), objects.Aggregate, db_aggregates) @base.remotable_classmethod def get_by_host(cls, context, host, key=None): db_aggregates = db.aggregate_get_by_host(context, host, key=key) return base.obj_make_list(context, cls(context), objects.Aggregate, db_aggregates) @base.remotable_classmethod def get_by_metadata_key(cls, context, key, hosts=None): db_aggregates = db.aggregate_get_by_metadata_key(context, key=key) if hosts: db_aggregates = cls._filter_db_aggregates(db_aggregates, hosts) return base.obj_make_list(context, cls(context), objects.Aggregate, db_aggregates)
class InstanceActionList(base.ObjectListBase, base.NovaObject): # Version 1.0: Initial version # InstanceAction <= version 1.1 VERSION = '1.0' fields = { 'objects': fields.ListOfObjectsField('InstanceAction'), } child_versions = { '1.0': '1.1', # NOTE(danms): InstanceAction was at 1.1 before we added this } @base.remotable_classmethod def get_by_instance_uuid(cls, context, instance_uuid): db_actions = db.actions_get(context, instance_uuid) return base.obj_make_list(context, cls(), InstanceAction, db_actions)
class NUMATopology(base.NovaObject, base.NovaObjectDictCompat): # Version 1.0: Initial version # Version 1.1: Update NUMACell to 1.1 # Version 1.2: Update NUMACell to 1.2 VERSION = '1.2' fields = { 'cells': fields.ListOfObjectsField('NUMACell'), } obj_relationships = { 'cells': [('1.0', '1.0'), ('1.1', '1.1'), ('1.2', '1.2')] } @classmethod def obj_from_primitive(cls, primitive): if 'patron_object.name' in primitive: obj_topology = super(NUMATopology, cls).obj_from_primitive(primitive) else: # NOTE(sahid): This compatibility code needs to stay until we can # guarantee that there are no cases of the old format stored in # the database (or forever, if we can never guarantee that). obj_topology = NUMATopology._from_dict(primitive) return obj_topology def _to_json(self): return jsonutils.dumps(self.obj_to_primitive()) @classmethod def obj_from_db_obj(cls, db_obj): return cls.obj_from_primitive(jsonutils.loads(db_obj)) def __len__(self): """Defined so that boolean testing works the same as for lists.""" return len(self.cells) def _to_dict(self): # TODO(sahid): needs to be removed. return {'cells': [cell._to_dict() for cell in self.cells]} @classmethod def _from_dict(cls, data_dict): return cls(cells=[ NUMACell._from_dict(cell_dict) for cell_dict in data_dict.get('cells', []) ])
class NetworkRequestList(obj_base.ObjectListBase, obj_base.NovaObject): fields = { 'objects': fields.ListOfObjectsField('NetworkRequest'), } child_versions = { '1.0': '1.0', '1.1': '1.1', } VERSION = '1.1' def as_tuples(self): return [x.to_tuple() for x in self.objects] @property def is_single_unspecified(self): return ((len(self.objects) == 1) and (self.objects[0].to_tuple() == NetworkRequest().to_tuple()))
class VirtCPUModel(base.NovaObject): # Version 1.0: Initial version VERSION = '1.0' fields = { 'arch': fields.EnumField(nullable=True, valid_values=arch.ALL), 'vendor': fields.StringField(nullable=True), 'topology': fields.ObjectField('VirtCPUTopology', nullable=True), 'features': fields.ListOfObjectsField("VirtCPUFeature", default=[]), 'mode': fields.EnumField(nullable=True, valid_values=cpumodel.ALL_CPUMODES), 'model': fields.StringField(nullable=True), 'match': fields.EnumField(nullable=True, valid_values=cpumodel.ALL_MATCHES), } obj_relationships = { 'topology': [('1.0', '1.0')], 'features': [('1.0', '1.0')], } def obj_load_attr(self, attrname): setattr(self, attrname, None) def to_json(self): return jsonutils.dumps(self.obj_to_primitive()) @classmethod def from_json(cls, jsonstr): return cls.obj_from_primitive(jsonutils.loads(jsonstr)) @base.remotable_classmethod def get_by_instance_uuid(cls, context, instance_uuid): db_extra = db.instance_extra_get_by_instance_uuid( context, instance_uuid, columns=['vcpu_model']) if not db_extra or not db_extra['vcpu_model']: return None return cls.obj_from_primitive(jsonutils.loads(db_extra['vcpu_model']))
class NetworkList(obj_base.ObjectListBase, obj_base.NovaObject): # Version 1.0: Initial version # Version 1.1: Added get_by_project() # Version 1.2: Network <= version 1.2 VERSION = '1.2' fields = { 'objects': fields.ListOfObjectsField('Network'), } child_versions = { '1.0': '1.0', '1.1': '1.1', '1.2': '1.2', } @obj_base.remotable_classmethod def get_all(cls, context, project_only='allow_none'): db_networks = db.network_get_all(context, project_only) return obj_base.obj_make_list(context, cls(context), objects.Network, db_networks) @obj_base.remotable_classmethod def get_by_uuids(cls, context, network_uuids, project_only='allow_none'): db_networks = db.network_get_all_by_uuids(context, network_uuids, project_only) return obj_base.obj_make_list(context, cls(context), objects.Network, db_networks) @obj_base.remotable_classmethod def get_by_host(cls, context, host): db_networks = db.network_get_all_by_host(context, host) return obj_base.obj_make_list(context, cls(context), objects.Network, db_networks) @obj_base.remotable_classmethod def get_by_project(cls, context, project_id, associate=True): db_networks = db.project_get_networks(context, project_id, associate=associate) return obj_base.obj_make_list(context, cls(context), objects.Network, db_networks)
class SecurityGroupRuleList(base.ObjectListBase, base.NovaObject): fields = { 'objects': fields.ListOfObjectsField('SecurityGroupRule'), } VERSION = '1.1' child_versions = { '1.0': '1.0', '1.1': '1.1', } @base.remotable_classmethod def get_by_security_group_id(cls, context, secgroup_id): db_rules = db.security_group_rule_get_by_security_group( context, secgroup_id, columns_to_join=['grantee_group']) return base.obj_make_list(context, cls(context), objects.SecurityGroupRule, db_rules, expected_attrs=['grantee_group']) @classmethod def get_by_security_group(cls, context, security_group): return cls.get_by_security_group_id(context, security_group.id)
class BandwidthUsageList(base.ObjectListBase, base.NovaObject): # Version 1.0: Initial version # Version 1.1: Add use_slave to get_by_uuids # Version 1.2: BandwidthUsage <= version 1.2 VERSION = '1.2' fields = { 'objects': fields.ListOfObjectsField('BandwidthUsage'), } child_versions = { '1.0': '1.0', '1.1': '1.1', '1.2': '1.2', } @base.serialize_args @base.remotable_classmethod def get_by_uuids(cls, context, uuids, start_period=None, use_slave=False): db_bw_usages = db.bw_usage_get_by_uuids(context, uuids=uuids, start_period=start_period, use_slave=use_slave) return base.obj_make_list(context, cls(), BandwidthUsage, db_bw_usages)
class InstanceFaultList(base.ObjectListBase, base.NovaObject): # Version 1.0: Initial version # InstanceFault <= version 1.1 # Version 1.1: InstanceFault version 1.2 VERSION = '1.1' fields = { 'objects': fields.ListOfObjectsField('InstanceFault'), } child_versions = { '1.0': '1.1', # NOTE(danms): InstanceFault was at 1.1 before we added this '1.1': '1.2', } @base.remotable_classmethod def get_by_instance_uuids(cls, context, instance_uuids): db_faultdict = db.instance_fault_get_by_instance_uuids( context, instance_uuids) db_faultlist = itertools.chain(*db_faultdict.values()) return base.obj_make_list(context, cls(context), objects.InstanceFault, db_faultlist)
class MigrationList(base.ObjectListBase, base.NovaObject): # Version 1.0: Initial version # Migration <= 1.1 # Version 1.1: Added use_slave to get_unconfirmed_by_dest_compute VERSION = '1.1' fields = { 'objects': fields.ListOfObjectsField('Migration'), } child_versions = { '1.0': '1.1', # NOTE(danms): Migration was at 1.1 before we added this '1.1': '1.1', } @base.remotable_classmethod def get_unconfirmed_by_dest_compute(cls, context, confirm_window, dest_compute, use_slave=False): db_migrations = db.migration_get_unconfirmed_by_dest_compute( context, confirm_window, dest_compute, use_slave=use_slave) return base.obj_make_list(context, cls(context), objects.Migration, db_migrations) @base.remotable_classmethod def get_in_progress_by_host_and_node(cls, context, host, node): db_migrations = db.migration_get_in_progress_by_host_and_node( context, host, node) return base.obj_make_list(context, cls(context), objects.Migration, db_migrations) @base.remotable_classmethod def get_by_filters(cls, context, filters): db_migrations = db.migration_get_all_by_filters(context, filters) return base.obj_make_list(context, cls(context), objects.Migration, db_migrations)
class VirtualInterfaceList(base.ObjectListBase, base.NovaObject): # Version 1.0: Initial version VERSION = '1.0' fields = { 'objects': fields.ListOfObjectsField('VirtualInterface'), } child_versions = { '1.0': '1.0', } @base.remotable_classmethod def get_all(cls, context): db_vifs = db.virtual_interface_get_all(context) return base.obj_make_list(context, cls(context), objects.VirtualInterface, db_vifs) @base.remotable_classmethod def get_by_instance_uuid(cls, context, instance_uuid, use_slave=False): db_vifs = db.virtual_interface_get_by_instance(context, instance_uuid, use_slave=use_slave) return base.obj_make_list(context, cls(context), objects.VirtualInterface, db_vifs)
class InstanceGroupList(base.ObjectListBase, base.NovaObject): # Version 1.0: Initial version # InstanceGroup <= version 1.3 # Version 1.1: InstanceGroup <= version 1.4 # Version 1.2: InstanceGroup <= version 1.5 # Version 1.3: InstanceGroup <= version 1.6 # Version 1.4: InstanceGroup <= version 1.7 # Version 1.5: InstanceGroup <= version 1.8 # Version 1.6: InstanceGroup <= version 1.9 VERSION = '1.6' fields = { 'objects': fields.ListOfObjectsField('InstanceGroup'), } child_versions = { '1.0': '1.3', # NOTE(danms): InstanceGroup was at 1.3 before we added this '1.1': '1.4', '1.2': '1.5', '1.3': '1.6', '1.4': '1.7', '1.5': '1.8', '1.6': '1.9', } @base.remotable_classmethod def get_by_project_id(cls, context, project_id): groups = db.instance_group_get_all_by_project_id(context, project_id) return base.obj_make_list(context, cls(context), objects.InstanceGroup, groups) @base.remotable_classmethod def get_all(cls, context): groups = db.instance_group_get_all(context) return base.obj_make_list(context, cls(context), objects.InstanceGroup, groups)
class TagList(base.ObjectListBase, base.NovaObject): # Version 1.0: Initial version VERSION = '1.0' fields = { 'objects': fields.ListOfObjectsField('Tag'), } child_versions = { '1.0': '1.0', } @base.remotable_classmethod def get_by_resource_id(cls, context, resource_id): db_tags = db.instance_tag_get_by_instance_uuid(context, resource_id) return base.obj_make_list(context, cls(), objects.Tag, db_tags) @base.remotable_classmethod def create(cls, context, resource_id, tags): db_tags = db.instance_tag_set(context, resource_id, tags) return base.obj_make_list(context, cls(), objects.Tag, db_tags) @base.remotable_classmethod def destroy(cls, context, resource_id): db.instance_tag_delete_all(context, resource_id)
class InstanceNUMATopology(base.NovaObject, base.NovaObjectDictCompat): # Version 1.0: Initial version # Version 1.1: Takes into account pagesize VERSION = '1.1' fields = { # NOTE(danms): The 'id' field is no longer used and should be # removed in the future when convenient 'id': obj_fields.IntegerField(), 'instance_uuid': obj_fields.UUIDField(), 'cells': obj_fields.ListOfObjectsField('InstanceNUMACell'), } obj_relationships = { 'cells': [('1.0', '1.0')], } @classmethod def obj_from_primitive(cls, primitive): if 'patron_object.name' in primitive: obj_topology = super(InstanceNUMATopology, cls).obj_from_primitive(primitive) else: # NOTE(sahid): This compatibility code needs to stay until we can # guarantee that there are no cases of the old format stored in # the database (or forever, if we can never guarantee that). obj_topology = InstanceNUMATopology._from_dict(primitive) obj_topology.id = 0 return obj_topology @classmethod def obj_from_db_obj(cls, instance_uuid, db_obj): primitive = jsonutils.loads(db_obj) obj_topology = cls.obj_from_primitive(primitive) if 'patron_object.name' not in db_obj: obj_topology.instance_uuid = instance_uuid # No benefit to store a list of changed fields obj_topology.obj_reset_changes() return obj_topology # TODO(ndipanov) Remove this method on the major version bump to 2.0 @base.remotable def create(self): self._save() # NOTE(ndipanov): We can't rename create and want to avoid version bump # as this needs to be backported to stable so this is not a @remotable # That's OK since we only call it from inside Instance.save() which is. def _save(self): values = {'numa_topology': self._to_json()} db.instance_extra_update_by_uuid(self._context, self.instance_uuid, values) self.obj_reset_changes() # NOTE(ndipanov): We want to avoid version bump # as this needs to be backported to stable so this is not a @remotable # That's OK since we only call it from inside Instance.save() which is. @classmethod def delete_by_instance_uuid(cls, context, instance_uuid): values = {'numa_topology': None} db.instance_extra_update_by_uuid(context, instance_uuid, values) @base.remotable_classmethod def get_by_instance_uuid(cls, context, instance_uuid): db_extra = db.instance_extra_get_by_instance_uuid( context, instance_uuid, columns=['numa_topology']) if not db_extra: raise exception.NumaTopologyNotFound(instance_uuid=instance_uuid) if db_extra['numa_topology'] is None: return None return cls.obj_from_db_obj(instance_uuid, db_extra['numa_topology']) def _to_json(self): return jsonutils.dumps(self.obj_to_primitive()) def __len__(self): """Defined so that boolean testing works the same as for lists.""" return len(self.cells) def _to_dict(self): # NOTE(sahid): Used as legacy, could be renamed in _legacy_to_dict_ # in the future to avoid confusing. return {'cells': [cell._to_dict() for cell in self.cells]} @classmethod def _from_dict(cls, data_dict): # NOTE(sahid): Used as legacy, could be renamed in _legacy_from_dict_ # in the future to avoid confusing. return cls(cells=[ InstanceNUMACell._from_dict(cell_dict) for cell_dict in data_dict.get('cells', []) ]) @property def cpu_pinning_requested(self): return all(cell.cpu_pinning_requested for cell in self.cells)
class ComputeNodeList(base.ObjectListBase, base.NovaObject): # Version 1.0: Initial version # ComputeNode <= version 1.2 # Version 1.1 ComputeNode version 1.3 # Version 1.2 Add get_by_service() # Version 1.3 ComputeNode version 1.4 # Version 1.4 ComputeNode version 1.5 # Version 1.5 Add use_slave to get_by_service # Version 1.6 ComputeNode version 1.6 # Version 1.7 ComputeNode version 1.7 # Version 1.8 ComputeNode version 1.8 + add get_all_by_host() # Version 1.9 ComputeNode version 1.9 # Version 1.10 ComputeNode version 1.10 # Version 1.11 ComputeNode version 1.11 VERSION = '1.11' fields = { 'objects': fields.ListOfObjectsField('ComputeNode'), } child_versions = { '1.0': '1.2', # NOTE(danms): ComputeNode was at 1.2 before we added this '1.1': '1.3', '1.2': '1.3', '1.3': '1.4', '1.4': '1.5', '1.5': '1.5', '1.6': '1.6', '1.7': '1.7', '1.8': '1.8', '1.9': '1.9', '1.10': '1.10', '1.11': '1.11', } @base.remotable_classmethod def get_all(cls, context): db_computes = db.compute_node_get_all(context) return base.obj_make_list(context, cls(context), objects.ComputeNode, db_computes) @base.remotable_classmethod def get_by_hypervisor(cls, context, hypervisor_match): db_computes = db.compute_node_search_by_hypervisor( context, hypervisor_match) return base.obj_make_list(context, cls(context), objects.ComputeNode, db_computes) @base.remotable_classmethod def _get_by_service(cls, context, service_id, use_slave=False): try: db_computes = db.compute_nodes_get_by_service_id( context, service_id) except exception.ServiceNotFound: # NOTE(sbauza): Previous behaviour was returning an empty list # if the service was created with no computes, we need to keep it. db_computes = [] return base.obj_make_list(context, cls(context), objects.ComputeNode, db_computes) @classmethod def get_by_service(cls, context, service, use_slave=False): return cls._get_by_service(context, service.id, use_slave=use_slave) @base.remotable_classmethod def get_all_by_host(cls, context, host, use_slave=False): try: db_computes = db.compute_node_get_all_by_host( context, host, use_slave) except exception.ComputeHostNotFound: # FIXME(sbauza): Some old computes can still have no host record # We need to provide compatibility by using the old service_id # record. # We assume the compatibility as an extra penalty of one more DB # call but that's necessary until all nodes are upgraded. try: service = objects.Service.get_by_compute_host( context, host, use_slave) db_computes = db.compute_nodes_get_by_service_id( context, service.id) except exception.ServiceNotFound: # We need to provide the same exception upstream raise exception.ComputeHostNotFound(host=host) # We can avoid an extra call to Service object in _from_db_object for db_compute in db_computes: db_compute['host'] = service.host return base.obj_make_list(context, cls(context), objects.ComputeNode, db_computes)
class FixedIPList(obj_base.ObjectListBase, obj_base.NovaObject): # Version 1.0: Initial version # Version 1.1: Added get_by_network() # Version 1.2: FixedIP <= version 1.2 # Version 1.3: FixedIP <= version 1.3 # Version 1.4: FixedIP <= version 1.4 # Version 1.5: FixedIP <= version 1.5, added expected attrs to gets # Version 1.6: FixedIP <= version 1.6 # Version 1.7: FixedIP <= version 1.7 # Version 1.8: FixedIP <= version 1.8 # Version 1.8: FixedIP <= version 1.9 VERSION = '1.9' fields = { 'objects': fields.ListOfObjectsField('FixedIP'), } child_versions = { '1.0': '1.0', '1.1': '1.1', '1.2': '1.2', '1.3': '1.3', '1.4': '1.4', '1.5': '1.5', '1.6': '1.6', '1.7': '1.7', '1.8': '1.8', '1.9': '1.9', } @obj_base.remotable_classmethod def get_all(cls, context): db_fixedips = db.fixed_ip_get_all(context) return obj_base.obj_make_list(context, cls(context), objects.FixedIP, db_fixedips) @obj_base.remotable_classmethod def get_by_instance_uuid(cls, context, instance_uuid): expected_attrs = ['network', 'virtual_interface', 'floating_ips'] db_fixedips = db.fixed_ip_get_by_instance(context, instance_uuid) return obj_base.obj_make_list(context, cls(context), objects.FixedIP, db_fixedips, expected_attrs=expected_attrs) @obj_base.remotable_classmethod def get_by_host(cls, context, host): db_fixedips = db.fixed_ip_get_by_host(context, host) return obj_base.obj_make_list(context, cls(context), objects.FixedIP, db_fixedips) @obj_base.remotable_classmethod def get_by_virtual_interface_id(cls, context, vif_id): expected_attrs = ['network', 'floating_ips'] db_fixedips = db.fixed_ips_by_virtual_interface(context, vif_id) return obj_base.obj_make_list(context, cls(context), objects.FixedIP, db_fixedips, expected_attrs=expected_attrs) @obj_base.remotable_classmethod def get_by_network(cls, context, network, host=None): ipinfo = db.network_get_associated_fixed_ips(context, network['id'], host=host) if not ipinfo: return [] fips = cls(context=context, objects=[]) for info in ipinfo: inst = objects.Instance(context=context, uuid=info['instance_uuid'], hostname=info['instance_hostname'], created_at=info['instance_created'], updated_at=info['instance_updated']) vif = objects.VirtualInterface(context=context, id=info['vif_id'], address=info['vif_address']) fip = objects.FixedIP(context=context, address=info['address'], instance_uuid=info['instance_uuid'], network_id=info['network_id'], virtual_interface_id=info['vif_id'], allocated=info['allocated'], leased=info['leased'], default_route=info['default_route'], instance=inst, virtual_interface=vif) fips.objects.append(fip) fips.obj_reset_changes() return fips @obj_base.remotable_classmethod 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)
class NUMACell(base.NovaObject, base.NovaObjectDictCompat): # Version 1.0: Initial version # Version 1.1: Added pinned_cpus and siblings fields # Version 1.2: Added mempages field VERSION = '1.2' fields = { 'id': fields.IntegerField(read_only=True), 'cpuset': fields.SetOfIntegersField(), 'memory': fields.IntegerField(), 'cpu_usage': fields.IntegerField(default=0), 'memory_usage': fields.IntegerField(default=0), 'pinned_cpus': fields.SetOfIntegersField(), 'siblings': fields.ListOfSetsOfIntegersField(), 'mempages': fields.ListOfObjectsField('NUMAPagesTopology'), } obj_relationships = {'mempages': [('1.2', '1.0')]} def __eq__(self, other): return all_things_equal(self, other) def __ne__(self, other): return not (self == other) @property def free_cpus(self): return self.cpuset - self.pinned_cpus or set() @property def free_siblings(self): return [sibling_set & self.free_cpus for sibling_set in self.siblings] @property def avail_cpus(self): return len(self.free_cpus) @property def avail_memory(self): return self.memory - self.memory_usage def pin_cpus(self, cpus): if self.pinned_cpus & cpus: raise exception.CPUPinningInvalid(requested=list(cpus), pinned=list(self.pinned_cpus)) self.pinned_cpus |= cpus def unpin_cpus(self, cpus): if (self.pinned_cpus & cpus) != cpus: raise exception.CPUPinningInvalid(requested=list(cpus), pinned=list(self.pinned_cpus)) self.pinned_cpus -= cpus def _to_dict(self): return { 'id': self.id, 'cpus': hardware.format_cpu_spec(self.cpuset, allow_ranges=False), 'mem': { 'total': self.memory, 'used': self.memory_usage }, 'cpu_usage': self.cpu_usage } @classmethod def _from_dict(cls, data_dict): cpuset = hardware.parse_cpu_spec(data_dict.get('cpus', '')) cpu_usage = data_dict.get('cpu_usage', 0) memory = data_dict.get('mem', {}).get('total', 0) memory_usage = data_dict.get('mem', {}).get('used', 0) cell_id = data_dict.get('id') return cls(id=cell_id, cpuset=cpuset, memory=memory, cpu_usage=cpu_usage, memory_usage=memory_usage, mempages=[], pinned_cpus=set([]), siblings=[]) def can_fit_hugepages(self, pagesize, memory): """Returns whether memory can fit into hugepages size :param pagesize: a page size in KibB :param memory: a memory size asked to fit in KiB :returns: whether memory can fit in hugepages :raises: MemoryPageSizeNotSupported if page size not supported """ for pages in self.mempages: if pages.size_kb == pagesize: return (memory <= pages.free_kb and (memory % pages.size_kb) == 0) raise exception.MemoryPageSizeNotSupported(pagesize=pagesize)
class ComputeNode(base.NovaPersistentObject, base.NovaObject, base.NovaObjectDictCompat): # Version 1.0: Initial version # Version 1.1: Added get_by_service_id() # Version 1.2: String attributes updated to support unicode # Version 1.3: Added stats field # Version 1.4: Added host ip field # Version 1.5: Added numa_topology field # Version 1.6: Added supported_hv_specs # Version 1.7: Added host field # Version 1.8: Added get_by_host_and_nodename() # Version 1.9: Added pci_device_pools # Version 1.10: Added get_first_node_by_host_for_old_compat() # Version 1.11: PciDevicePoolList version 1.1 VERSION = '1.11' fields = { 'id': fields.IntegerField(read_only=True), 'service_id': fields.IntegerField(), 'host': fields.StringField(nullable=True), 'vcpus': fields.IntegerField(), 'memory_mb': fields.IntegerField(), 'local_gb': fields.IntegerField(), 'vcpus_used': fields.IntegerField(), 'memory_mb_used': fields.IntegerField(), 'local_gb_used': fields.IntegerField(), 'hypervisor_type': fields.StringField(), 'hypervisor_version': fields.IntegerField(), 'hypervisor_hostname': fields.StringField(nullable=True), 'free_ram_mb': fields.IntegerField(nullable=True), 'free_disk_gb': fields.IntegerField(nullable=True), 'current_workload': fields.IntegerField(nullable=True), 'running_vms': fields.IntegerField(nullable=True), 'cpu_info': fields.StringField(nullable=True), 'disk_available_least': fields.IntegerField(nullable=True), 'metrics': fields.StringField(nullable=True), 'stats': fields.DictOfNullableStringsField(nullable=True), 'host_ip': fields.IPAddressField(nullable=True), 'numa_topology': fields.StringField(nullable=True), # NOTE(pmurray): the supported_hv_specs field maps to the # supported_instances field in the database 'supported_hv_specs': fields.ListOfObjectsField('HVSpec'), # NOTE(pmurray): the pci_device_pools field maps to the # pci_stats field in the database 'pci_device_pools': fields.ObjectField('PciDevicePoolList', nullable=True), } obj_relationships = { 'pci_device_pools': [('1.9', '1.0'), ('1.11', '1.1')], 'supported_hv_specs': [('1.6', '1.0')], } def obj_make_compatible(self, primitive, target_version): super(ComputeNode, self).obj_make_compatible(primitive, target_version) target_version = utils.convert_version_to_tuple(target_version) if target_version < (1, 7) and 'host' in primitive: del primitive['host'] if target_version < (1, 5) and 'numa_topology' in primitive: del primitive['numa_topology'] if target_version < (1, 4) and 'host_ip' in primitive: del primitive['host_ip'] if target_version < (1, 3) and 'stats' in primitive: # pre 1.3 version does not have a stats field del primitive['stats'] @staticmethod def _host_from_db_object(compute, db_compute): if (('host' not in db_compute or db_compute['host'] is None) and 'service_id' in db_compute and db_compute['service_id'] is not None): # FIXME(sbauza) : Unconverted compute record, provide compatibility # This has to stay until we can be sure that any/all compute nodes # in the database have been converted to use the host field # Service field of ComputeNode could be deprecated in a next patch, # so let's use directly the Service object try: service = objects.Service.get_by_id(compute._context, db_compute['service_id']) except exception.ServiceNotFound: compute['host'] = None return try: compute['host'] = service.host except (AttributeError, exception.OrphanedObjectError): # Host can be nullable in Service compute['host'] = None elif 'host' in db_compute and db_compute['host'] is not None: # New-style DB having host as a field compute['host'] = db_compute['host'] else: # We assume it should not happen but in case, let's set it to None compute['host'] = None @staticmethod def _from_db_object(context, compute, db_compute): special_cases = set([ 'stats', 'supported_hv_specs', 'host', 'pci_device_pools', ]) fields = set(compute.fields) - special_cases for key in fields: compute[key] = db_compute[key] stats = db_compute['stats'] if stats: compute['stats'] = jsonutils.loads(stats) sup_insts = db_compute.get('supported_instances') if sup_insts: hv_specs = jsonutils.loads(sup_insts) hv_specs = [ objects.HVSpec.from_list(hv_spec) for hv_spec in hv_specs ] compute['supported_hv_specs'] = hv_specs pci_stats = db_compute.get('pci_stats') compute.pci_device_pools = pci_device_pool.from_pci_stats(pci_stats) compute._context = context # Make sure that we correctly set the host field depending on either # host column is present in the table or not compute._host_from_db_object(compute, db_compute) compute.obj_reset_changes() return compute @base.remotable_classmethod def get_by_id(cls, context, compute_id): db_compute = db.compute_node_get(context, compute_id) return cls._from_db_object(context, cls(), db_compute) @base.remotable_classmethod def get_by_service_id(cls, context, service_id): db_computes = db.compute_nodes_get_by_service_id(context, service_id) # NOTE(sbauza): Old version was returning an item, we need to keep this # behaviour for backwards compatibility db_compute = db_computes[0] return cls._from_db_object(context, cls(), db_compute) @base.remotable_classmethod def get_by_host_and_nodename(cls, context, host, nodename): try: db_compute = db.compute_node_get_by_host_and_nodename( context, host, nodename) except exception.ComputeHostNotFound: # FIXME(sbauza): Some old computes can still have no host record # We need to provide compatibility by using the old service_id # record. # We assume the compatibility as an extra penalty of one more DB # call but that's necessary until all nodes are upgraded. try: service = objects.Service.get_by_compute_host(context, host) db_computes = db.compute_nodes_get_by_service_id( context, service.id) except exception.ServiceNotFound: # We need to provide the same exception upstream raise exception.ComputeHostNotFound(host=host) db_compute = None for compute in db_computes: if compute['hypervisor_hostname'] == nodename: db_compute = compute # We can avoid an extra call to Service object in # _from_db_object db_compute['host'] = service.host break if not db_compute: raise exception.ComputeHostNotFound(host=host) return cls._from_db_object(context, cls(), db_compute) @base.remotable_classmethod def get_first_node_by_host_for_old_compat(cls, context, host, use_slave=False): computes = ComputeNodeList.get_all_by_host(context, host, use_slave) # FIXME(sbauza): Some hypervisors (VMware, Ironic) can return multiple # nodes per host, we should return all the nodes and modify the callers # instead. # Arbitrarily returning the first node. return computes[0] @staticmethod def _convert_stats_to_db_format(updates): stats = updates.pop('stats', None) if stats is not None: updates['stats'] = jsonutils.dumps(stats) @staticmethod def _convert_host_ip_to_db_format(updates): host_ip = updates.pop('host_ip', None) if host_ip: updates['host_ip'] = str(host_ip) @staticmethod def _convert_supported_instances_to_db_format(updates): hv_specs = updates.pop('supported_hv_specs', None) if hv_specs is not None: hv_specs = [hv_spec.to_list() for hv_spec in hv_specs] updates['supported_instances'] = jsonutils.dumps(hv_specs) @staticmethod def _convert_pci_stats_to_db_format(updates): pools = updates.pop('pci_device_pools', None) if pools: updates['pci_stats'] = jsonutils.dumps(pools.obj_to_primitive()) @base.remotable def create(self): if self.obj_attr_is_set('id'): raise exception.ObjectActionError(action='create', reason='already created') updates = self.obj_get_changes() self._convert_stats_to_db_format(updates) self._convert_host_ip_to_db_format(updates) self._convert_supported_instances_to_db_format(updates) self._convert_pci_stats_to_db_format(updates) db_compute = db.compute_node_create(self._context, updates) self._from_db_object(self._context, self, db_compute) @base.remotable def save(self, prune_stats=False): # NOTE(belliott) ignore prune_stats param, no longer relevant updates = self.obj_get_changes() updates.pop('id', None) self._convert_stats_to_db_format(updates) self._convert_host_ip_to_db_format(updates) self._convert_supported_instances_to_db_format(updates) self._convert_pci_stats_to_db_format(updates) db_compute = db.compute_node_update(self._context, self.id, updates) self._from_db_object(self._context, self, db_compute) @base.remotable def destroy(self): db.compute_node_delete(self._context, self.id) @property def service(self): if not hasattr(self, '_cached_service'): self._cached_service = objects.Service.get_by_id( self._context, self.service_id) return self._cached_service
class ObjectListBase(object): """Mixin class for lists of objects. This mixin class can be added as a base class for an object that is implementing a list of objects. It adds a single field of 'objects', which is the list store, and behaves like a list itself. It supports serialization of the list of objects automatically. """ fields = { 'objects': obj_fields.ListOfObjectsField('NovaObject'), } # This is a dictionary of my_version:child_version mappings so that # we can support backleveling our contents based on the version # requested of the list object. child_versions = {} def __init__(self, *args, **kwargs): super(ObjectListBase, self).__init__(*args, **kwargs) if 'objects' not in kwargs: self.objects = [] self._changed_fields.discard('objects') def __iter__(self): """List iterator interface.""" return iter(self.objects) def __len__(self): """List length.""" return len(self.objects) def __getitem__(self, index): """List index access.""" if isinstance(index, slice): new_obj = self.__class__() new_obj.objects = self.objects[index] # NOTE(danms): We must be mixed in with a NovaObject! new_obj.obj_reset_changes() new_obj._context = self._context return new_obj return self.objects[index] def __contains__(self, value): """List membership test.""" return value in self.objects def count(self, value): """List count of value occurrences.""" return self.objects.count(value) def index(self, value): """List index of value.""" return self.objects.index(value) def sort(self, cmp=None, key=None, reverse=False): self.objects.sort(cmp=cmp, key=key, reverse=reverse) def obj_make_compatible(self, primitive, target_version): primitives = primitive['objects'] child_target_version = self.child_versions.get(target_version, '1.0') for index, item in enumerate(self.objects): self.objects[index].obj_make_compatible( primitives[index]['patron_object.data'], child_target_version) primitives[index]['patron_object.version'] = child_target_version def obj_what_changed(self): changes = set(self._changed_fields) for child in self.objects: if child.obj_what_changed(): changes.add('objects') return changes
class BlockDeviceMappingList(base.ObjectListBase, base.NovaObject): # Version 1.0: Initial version # Version 1.1: BlockDeviceMapping <= version 1.1 # Version 1.2: Added use_slave to get_by_instance_uuid # Version 1.3: BlockDeviceMapping <= version 1.2 # Version 1.4: BlockDeviceMapping <= version 1.3 # Version 1.5: BlockDeviceMapping <= version 1.4 # Version 1.6: BlockDeviceMapping <= version 1.5 # Version 1.7: BlockDeviceMapping <= version 1.6 # Version 1.8: BlockDeviceMapping <= version 1.7 # Version 1.9: BlockDeviceMapping <= version 1.8 VERSION = '1.9' fields = { 'objects': fields.ListOfObjectsField('BlockDeviceMapping'), } child_versions = { '1.0': '1.0', '1.1': '1.1', '1.2': '1.1', '1.3': '1.2', '1.4': '1.3', '1.5': '1.4', '1.6': '1.5', '1.7': '1.6', '1.8': '1.7', '1.9': '1.8', } @base.remotable_classmethod def get_by_instance_uuid(cls, context, instance_uuid, use_slave=False): db_bdms = db.block_device_mapping_get_all_by_instance( context, instance_uuid, use_slave=use_slave) return base.obj_make_list(context, cls(), objects.BlockDeviceMapping, db_bdms or []) def root_bdm(self): try: return (bdm_obj for bdm_obj in self if bdm_obj.is_root).next() except StopIteration: return def root_metadata(self, context, image_api, volume_api): root_bdm = self.root_bdm() if not root_bdm: return {} if root_bdm.is_volume: try: volume = volume_api.get(context, root_bdm.volume_id) return volume.get('volume_image_metadata', {}) except Exception: raise exception.InvalidBDMVolume(id=root_bdm.id) elif root_bdm.is_image: try: image_meta = image_api.show(context, root_bdm.image_id) return image_meta.get('properties', {}) except Exception: raise exception.InvalidBDMImage(id=root_bdm.id) else: return {}