Ejemplo n.º 1
0
class NovaTimestampObject(object):
    """Mixin class for db backed objects with timestamp fields.

    Sqlalchemy models that inherit from the oslo_db TimestampMixin will include
    these fields and the corresponding objects will benefit from this mixin.
    """
    fields = {
        'created_at': obj_fields.DateTimeField(nullable=True),
        'updated_at': obj_fields.DateTimeField(nullable=True),
    }
Ejemplo n.º 2
0
class NovaPersistentObject(object):
    """Mixin class for Persistent objects.

    This adds the fields that we use in common for most persistent objects.
    """
    fields = {
        'created_at': obj_fields.DateTimeField(nullable=True),
        'updated_at': obj_fields.DateTimeField(nullable=True),
        'deleted_at': obj_fields.DateTimeField(nullable=True),
        'deleted': obj_fields.BooleanField(default=False),
    }
Ejemplo n.º 3
0
class ServiceStatusPayload(notification.NotificationPayloadBase):
    SCHEMA = {
        'host': ('service', 'host'),
        'binary': ('service', 'binary'),
        'topic': ('service', 'topic'),
        'report_count': ('service', 'report_count'),
        'disabled': ('service', 'disabled'),
        'disabled_reason': ('service', 'disabled_reason'),
        'availability_zone': ('service', 'availability_zone'),
        'last_seen_up': ('service', 'last_seen_up'),
        'forced_down': ('service', 'forced_down'),
        'version': ('service', 'version')
    }
    # Version 1.0: Initial version
    VERSION = '1.0'
    fields = {
        'host': fields.StringField(nullable=True),
        'binary': fields.StringField(nullable=True),
        'topic': fields.StringField(nullable=True),
        'report_count': fields.IntegerField(),
        'disabled': fields.BooleanField(),
        'disabled_reason': fields.StringField(nullable=True),
        'availability_zone': fields.StringField(nullable=True),
        'last_seen_up': fields.DateTimeField(nullable=True),
        'forced_down': fields.BooleanField(),
        'version': fields.IntegerField(),
    }

    def __init__(self, service):
        super(ServiceStatusPayload, self).__init__()
        self.populate_schema(service=service)
Ejemplo n.º 4
0
class VolumeUsage(base.NovaPersistentObject, base.NovaObject):
    # Version 1.0: Initial version
    VERSION = '1.0'

    fields = {
        'id': fields.IntegerField(read_only=True),
        'volume_id': fields.UUIDField(),
        'instance_uuid': fields.UUIDField(nullable=True),
        'project_id': fields.StringField(nullable=True),
        'user_id': fields.StringField(nullable=True),
        'availability_zone': fields.StringField(nullable=True),
        'tot_last_refreshed': fields.DateTimeField(nullable=True,
                                                   read_only=True),
        'tot_reads': fields.IntegerField(read_only=True),
        'tot_read_bytes': fields.IntegerField(read_only=True),
        'tot_writes': fields.IntegerField(read_only=True),
        'tot_write_bytes': fields.IntegerField(read_only=True),
        'curr_last_refreshed': fields.DateTimeField(nullable=True,
                                                    read_only=True),
        'curr_reads': fields.IntegerField(),
        'curr_read_bytes': fields.IntegerField(),
        'curr_writes': fields.IntegerField(),
        'curr_write_bytes': fields.IntegerField()
    }

    @staticmethod
    def _from_db_object(context, vol_usage, db_vol_usage):
        for field in vol_usage.fields:
            setattr(vol_usage, field, db_vol_usage[field])
        vol_usage._context = context
        vol_usage.obj_reset_changes()
        return vol_usage

    @base.remotable
    def save(self, update_totals=False):
        db_vol_usage = db.vol_usage_update(
            self._context, self.volume_id, self.curr_reads,
            self.curr_read_bytes, self.curr_writes, self.curr_write_bytes,
            self.instance_uuid, self.project_id, self.user_id,
            self.availability_zone, update_totals=update_totals)
        self._from_db_object(self._context, self, db_vol_usage)
Ejemplo n.º 5
0
class MonitorMetric(base.NovaObject):
    # Version 1.0: Initial version
    # Version 1.1: Added NUMA support

    VERSION = '1.1'

    fields = {
        'name': fields.MonitorMetricTypeField(nullable=False),
        'value': fields.IntegerField(nullable=False),
        'numa_membw_values': fields.DictOfIntegersField(nullable=True),
        'timestamp': fields.DateTimeField(nullable=False),
        # This will be the stevedore extension full class name
        # for the plugin from which the metric originates.
        'source': fields.StringField(nullable=False),
    }

    def obj_make_compatible(self, primitive, target_version):
        super(MonitorMetric, self).obj_make_compatible(primitive,
                                                       target_version)
        target_version = versionutils.convert_version_to_tuple(target_version)
        if target_version < (1, 1) and 'numa_nodes_values' in primitive:
            del primitive['numa_membw_values']

    # NOTE(jaypipes): This method exists to convert the object to the
    # format expected by the RPC notifier for metrics events.
    def to_dict(self):
        dict_to_return = {
            'name': self.name,
            # NOTE(jaypipes): This is what jsonutils.dumps() does to
            # datetime.datetime objects, which is what timestamp is in
            # this object as well as the original simple dict metrics
            'timestamp': utils.strtime(self.timestamp),
            'source': self.source,
        }

        if self.obj_attr_is_set('value'):
            if self.name in FIELDS_REQUIRING_CONVERSION:
                dict_to_return['value'] = self.value / 100.0
            else:
                dict_to_return['value'] = self.value
        elif self.obj_attr_is_set('numa_membw_values'):
            dict_to_return['numa_membw_values'] = self.numa_membw_values

        return dict_to_return
Ejemplo n.º 6
0
class ImageMeta(base.NovaObject):
    # Version 1.0: Initial version
    # Version 1.1: updated ImageMetaProps
    # Version 1.2: ImageMetaProps version 1.2
    # Version 1.3: ImageMetaProps version 1.3
    # Version 1.4: ImageMetaProps version 1.4
    # Version 1.5: ImageMetaProps version 1.5
    # Version 1.6: ImageMetaProps version 1.6
    # Version 1.7: ImageMetaProps version 1.7
    # Version 1.8: ImageMetaProps version 1.8
    VERSION = '1.8'

    # These are driven by what the image client API returns
    # to Nova from Glance. This is defined in the glance
    # code glance/api/v2/images.py get_base_properties()
    # method. A few things are currently left out:
    # self, file, schema - Nova does not appear to ever use
    # these field; locations - modelling the arbitrary
    # data in the 'metadata' subfield is non-trivial as
    # there's no clear spec.
    #
    # TODO(ft): In version 2.0, these fields should be nullable:
    # name, checksum, owner, size, virtual_size, container_format, disk_format
    #
    fields = {
        'id': fields.UUIDField(),
        'name': fields.StringField(),
        'status': fields.StringField(),
        'visibility': fields.StringField(),
        'protected': fields.FlexibleBooleanField(),
        'checksum': fields.StringField(),
        'owner': fields.StringField(),
        'size': fields.IntegerField(),
        'virtual_size': fields.IntegerField(),
        'container_format': fields.StringField(),
        'disk_format': fields.StringField(),
        'created_at': fields.DateTimeField(nullable=True),
        'updated_at': fields.DateTimeField(nullable=True),
        'tags': fields.ListOfStringsField(),
        'direct_url': fields.StringField(),
        'min_ram': fields.IntegerField(),
        'min_disk': fields.IntegerField(),
        'properties': fields.ObjectField('ImageMetaProps'),
    }

    @classmethod
    def from_dict(cls, image_meta):
        """Create instance from image metadata dict

        :param image_meta: image metadata dictionary

        Creates a new object instance, initializing from the
        properties associated with the image metadata instance

        :returns: an ImageMeta instance
        """
        if image_meta is None:
            image_meta = {}

        # We must turn 'properties' key dict into an object
        # so copy image_meta to avoid changing original
        image_meta = copy.deepcopy(image_meta)
        image_meta["properties"] = \
            objects.ImageMetaProps.from_dict(
                image_meta.get("properties", {}))

        # Some fields are nullable in Glance DB schema, but was not marked that
        # in ImageMeta initially by mistake. To keep compatibility with compute
        # nodes which are run with previous versions these fields are still
        # not nullable in ImageMeta, but the code below converts None to
        # approppriate empty values.
        for fld in NULLABLE_STRING_FIELDS:
            if fld in image_meta and image_meta[fld] is None:
                image_meta[fld] = ''
        for fld in NULLABLE_INTEGER_FIELDS:
            if fld in image_meta and image_meta[fld] is None:
                image_meta[fld] = 0

        return cls(**image_meta)

    @classmethod
    def from_instance(cls, instance):
        """Create instance from instance system metadata

        :param instance: Instance object

        Creates a new object instance, initializing from the
        system metadata "image_*" properties associated with
        instance

        :returns: an ImageMeta instance
        """
        sysmeta = utils.instance_sys_meta(instance)
        image_meta = utils.get_image_from_system_metadata(sysmeta)
        return cls.from_dict(image_meta)

    @classmethod
    def from_image_ref(cls, context, image_api, image_ref):
        """Create instance from glance image

        :param context: the request context
        :param image_api: the glance client API
        :param image_ref: the glance image identifier

        Creates a new object instance, initializing from the
        properties associated with a glance image

        :returns: an ImageMeta instance
        """

        image_meta = image_api.get(context, image_ref)
        image = cls.from_dict(image_meta)
        setattr(image, "id", image_ref)
        return image
Ejemplo n.º 7
0
class Service(base.NovaPersistentObject, base.NovaObject,
              base.NovaObjectDictCompat):
    # Version 1.0: Initial version
    # Version 1.1: Added compute_node nested object
    # Version 1.2: String attributes updated to support unicode
    # Version 1.3: ComputeNode version 1.5
    # Version 1.4: Added use_slave to get_by_compute_host
    # Version 1.5: ComputeNode version 1.6
    # Version 1.6: ComputeNode version 1.7
    # Version 1.7: ComputeNode version 1.8
    # Version 1.8: ComputeNode version 1.9
    # Version 1.9: ComputeNode version 1.10
    # Version 1.10: Changes behaviour of loading compute_node
    # Version 1.11: Added get_by_host_and_binary
    # Version 1.12: ComputeNode version 1.11
    # Version 1.13: Added last_seen_up
    # Version 1.14: Added forced_down
    # Version 1.15: ComputeNode version 1.12
    # Version 1.16: Added version
    # Version 1.17: ComputeNode version 1.13
    # Version 1.18: ComputeNode version 1.14
    # Version 1.19: Added get_minimum_version()
    VERSION = '1.19'

    fields = {
        'id': fields.IntegerField(read_only=True),
        'host': fields.StringField(nullable=True),
        'binary': fields.StringField(nullable=True),
        'topic': fields.StringField(nullable=True),
        'report_count': fields.IntegerField(),
        'disabled': fields.BooleanField(),
        'disabled_reason': fields.StringField(nullable=True),
        'availability_zone': fields.StringField(nullable=True),
        'compute_node': fields.ObjectField('ComputeNode'),
        'last_seen_up': fields.DateTimeField(nullable=True),
        'forced_down': fields.BooleanField(),
        'version': fields.IntegerField(),
        'rpc_current_version': fields.StringField(nullable=True),
        'object_current_version': fields.StringField(nullable=True),
    }

    _MIN_VERSION_CACHE = {}
    _SERVICE_VERSION_CACHING = False

    def __init__(self, *args, **kwargs):
        # NOTE(danms): We're going against the rules here and overriding
        # init. The reason is that we want to *ensure* that we're always
        # setting the current service version on our objects, overriding
        # whatever else might be set in the database, or otherwise (which
        # is the normal reason not to override init).
        #
        # We also need to do this here so that it's set on the client side
        # all the time, such that create() and save() operations will
        # include the current service version.
        if 'version' in kwargs:
            raise exception.ObjectActionError(
                action='init',
                reason='Version field is immutable')

        super(Service, self).__init__(*args, **kwargs)
        self.version = SERVICE_VERSION

    def obj_make_compatible_from_manifest(self, primitive, target_version,
                                          version_manifest):
        super(Service, self).obj_make_compatible_from_manifest(
            primitive, target_version, version_manifest)
        _target_version = versionutils.convert_version_to_tuple(target_version)
        if _target_version < (1, 16) and 'version' in primitive:
            del primitive['version']
        if _target_version < (1, 14) and 'forced_down' in primitive:
            del primitive['forced_down']
        if _target_version < (1, 13) and 'last_seen_up' in primitive:
            del primitive['last_seen_up']
        if _target_version < (1, 10):
            # service.compute_node was not lazy-loaded, we need to provide it
            # when called
            self._do_compute_node(self._context, primitive,
                                  version_manifest)

    def _do_compute_node(self, context, primitive, version_manifest):
        try:
            target_version = version_manifest['ComputeNode']
            # NOTE(sbauza): Some drivers (VMware, Ironic) can have multiple
            # nodes for the same service, but for keeping same behaviour,
            # returning only the first elem of the list
            compute = objects.ComputeNodeList.get_all_by_host(
                context, primitive['host'])[0]
        except Exception:
            return
        primitive['compute_node'] = compute.obj_to_primitive(
            target_version=target_version,
            version_manifest=version_manifest)

    @staticmethod
    def _from_db_object(context, service, db_service):
        allow_missing = ('availability_zone',)
        for key in service.fields:
            if key in allow_missing and key not in db_service:
                continue
            if key == 'compute_node':
                #  NOTE(sbauza); We want to only lazy-load compute_node
                continue
            elif key == 'version':
                # NOTE(danms): Special handling of the version field, since
                # it is read_only and set in our init.
                setattr(service, base.get_attrname(key), db_service[key])
            else:
                service[key] = db_service[key]
        service._context = context
        service.obj_reset_changes()
        return service

    def obj_load_attr(self, attrname):
        if not self._context:
            raise exception.OrphanedObjectError(method='obj_load_attr',
                                                objtype=self.obj_name())

        LOG.debug("Lazy-loading '%(attr)s' on %(name)s id %(id)s",
                  {'attr': attrname,
                   'name': self.obj_name(),
                   'id': self.id,
                   })
        if attrname != 'compute_node':
            raise exception.ObjectActionError(
                action='obj_load_attr',
                reason='attribute %s not lazy-loadable' % attrname)
        if self.binary == 'nova-compute':
            # Only n-cpu services have attached compute_node(s)
            compute_nodes = objects.ComputeNodeList.get_all_by_host(
                self._context, self.host)
        else:
            # NOTE(sbauza); Previous behaviour was raising a ServiceNotFound,
            # we keep it for backwards compatibility
            raise exception.ServiceNotFound(service_id=self.id)
        # NOTE(sbauza): Some drivers (VMware, Ironic) can have multiple nodes
        # for the same service, but for keeping same behaviour, returning only
        # the first elem of the list
        self.compute_node = compute_nodes[0]

    @base.remotable_classmethod
    def get_by_id(cls, context, service_id):
        db_service = db.service_get(context, service_id)
        return cls._from_db_object(context, cls(), db_service)

    @base.remotable_classmethod
    def get_by_host_and_topic(cls, context, host, topic):
        db_service = db.service_get_by_host_and_topic(context, host, topic)
        return cls._from_db_object(context, cls(), db_service)

    @base.remotable_classmethod
    def get_by_host_and_binary(cls, context, host, binary):
        try:
            db_service = db.service_get_by_host_and_binary(context,
                                                           host, binary)
        except exception.HostBinaryNotFound:
            return
        return cls._from_db_object(context, cls(), db_service)

    @staticmethod
    @db.select_db_reader_mode
    def _db_service_get_by_compute_host(context, host, use_slave=False):
        return db.service_get_by_compute_host(context, host)

    @base.remotable_classmethod
    def get_by_compute_host(cls, context, host, use_slave=False):
        db_service = cls._db_service_get_by_compute_host(context, host,
                                                         use_slave=use_slave)
        return cls._from_db_object(context, cls(), db_service)

    # NOTE(ndipanov): This is deprecated and should be removed on the next
    # major version bump
    @base.remotable_classmethod
    def get_by_args(cls, context, host, binary):
        db_service = db.service_get_by_host_and_binary(context, host, binary)
        return cls._from_db_object(context, cls(), db_service)

    def _check_minimum_version(self):
        """Enforce that we are not older that the minimum version.

        This is a loose check to avoid creating or updating our service
        record if we would do so with a version that is older that the current
        minimum of all services. This could happen if we were started with
        older code by accident, either due to a rollback or an old and
        un-updated node suddenly coming back onto the network.

        There is technically a race here between the check and the update,
        but since the minimum version should always roll forward and never
        backwards, we don't need to worry about doing it atomically. Further,
        the consequence for getting this wrong is minor, in that we'll just
        fail to send messages that other services understand.
        """
        if not self.obj_attr_is_set('version'):
            return
        if not self.obj_attr_is_set('binary'):
            return
        minver = self.get_minimum_version(self._context, self.binary)
        if minver > self.version:
            raise exception.ServiceTooOld(thisver=self.version,
                                          minver=minver)

    @base.remotable
    def create(self):
        if self.obj_attr_is_set('id'):
            raise exception.ObjectActionError(action='create',
                                              reason='already created')
        self._check_minimum_version()
        updates = self.obj_get_changes()
        db_service = db.service_create(self._context, updates)
        self._from_db_object(self._context, self, db_service)

    @base.remotable
    def save(self):
        updates = self.obj_get_changes()
        updates.pop('id', None)
        if list(updates.keys()) == ['version']:
            # NOTE(danms): Since we set/dirty version in init, don't
            # do a save if that's all that has changed. This keeps the
            # "save is a no-op if nothing has changed" behavior.
            return
        self._check_minimum_version()
        db_service = db.service_update(self._context, self.id, updates)
        self._from_db_object(self._context, self, db_service)

        self._send_status_update_notification(updates)

    def _send_status_update_notification(self, updates):
        # Note(gibi): We do not trigger notification on version as that field
        # is always dirty, which would cause that compute sends notification on
        # every other field change. See the comment in save() too.
        if set(updates.keys()).intersection(
                {'disabled', 'disabled_reason', 'forced_down'}):
            payload = ServiceStatusPayload(self)
            ServiceStatusNotification(
                publisher=notification.NotificationPublisher.from_service_obj(
                    self),
                event_type=notification.EventType(
                    object='service',
                    action=fields.NotificationAction.UPDATE),
                priority=fields.NotificationPriority.INFO,
                payload=payload).emit(self._context)

    @base.remotable
    def destroy(self):
        db.service_destroy(self._context, self.id)

    @classmethod
    def enable_min_version_cache(cls):
        cls.clear_min_version_cache()
        cls._SERVICE_VERSION_CACHING = True

    @classmethod
    def clear_min_version_cache(cls):
        cls._MIN_VERSION_CACHE = {}

    @staticmethod
    @db.select_db_reader_mode
    def _db_service_get_minimum_version(context, binary, use_slave=False):
        return db.service_get_minimum_version(context, binary)

    @base.remotable_classmethod
    def get_minimum_version(cls, context, binary, use_slave=False):
        if not binary.startswith('nova-') and not binary.startswith('jacket-'):
            LOG.warning(_LW('get_minimum_version called with likely-incorrect '
                            'binary `%s\''), binary)
            raise exception.ObjectActionError(action='get_minimum_version',
                                              reason='Invalid binary prefix')

        if cls._SERVICE_VERSION_CACHING:
            cached_version = cls._MIN_VERSION_CACHE.get(binary)
            if cached_version:
                return cached_version
        version = cls._db_service_get_minimum_version(context, binary,
                                                      use_slave=use_slave)
        if version is None:
            return 0
        # NOTE(danms): Since our return value is not controlled by object
        # schema, be explicit here.
        version = int(version)
        cls._MIN_VERSION_CACHE[binary] = version

        return version

    @classmethod
    def _get_minimum_version(cls, attribute, context, binary):
        services = ServiceList.get_by_binary(context, binary)
        min_ver = None
        min_ver_str = None
        for s in services:
            ver_str = getattr(s, attribute)
            if ver_str is None:
                # FIXME(dulek) None in *_current_version means that this
                # service is in Liberty version, so we must assume this is the
                # lowest one. We use handy and easy to remember token to
                # indicate that. This may go away as soon as we drop
                # compatibility with Liberty, possibly in early N.
                return 'liberty'
            ver = versionutils.convert_version_to_int(ver_str)
            if min_ver is None or ver < min_ver:
                min_ver = ver
                min_ver_str = ver_str

        return min_ver_str


    @base.remotable_classmethod
    def get_minimum_rpc_version(cls, context, binary):
        return cls._get_minimum_version('rpc_current_version', context, binary)


    @base.remotable_classmethod
    def get_minimum_obj_version(cls, context, binary):
        return cls._get_minimum_version('object_current_version', context,
                                        binary)
Ejemplo n.º 8
0
class InstanceAction(base.NovaPersistentObject, base.NovaObject,
                     base.NovaObjectDictCompat):
    # Version 1.0: Initial version
    # Version 1.1: String attributes updated to support unicode
    VERSION = '1.1'

    fields = {
        'id': fields.IntegerField(),
        'action': fields.StringField(nullable=True),
        'instance_uuid': fields.UUIDField(nullable=True),
        'request_id': fields.StringField(nullable=True),
        'user_id': fields.StringField(nullable=True),
        'project_id': fields.StringField(nullable=True),
        'start_time': fields.DateTimeField(nullable=True),
        'finish_time': fields.DateTimeField(nullable=True),
        'message': fields.StringField(nullable=True),
        }

    @staticmethod
    def _from_db_object(context, action, db_action):
        for field in action.fields:
            action[field] = db_action[field]
        action._context = context
        action.obj_reset_changes()
        return action

    @staticmethod
    def pack_action_start(context, instance_uuid, action_name):
        values = {'request_id': context.request_id,
                  'instance_uuid': instance_uuid,
                  'user_id': context.user_id,
                  'project_id': context.project_id,
                  'action': action_name,
                  'start_time': context.timestamp}
        return values

    @staticmethod
    def pack_action_finish(context, instance_uuid):
        values = {'request_id': context.request_id,
                  'instance_uuid': instance_uuid,
                  'finish_time': timeutils.utcnow()}
        return values

    @base.remotable_classmethod
    def get_by_request_id(cls, context, instance_uuid, request_id):
        db_action = db.action_get_by_request_id(context, instance_uuid,
                                                request_id)
        if db_action:
            return cls._from_db_object(context, cls(), db_action)

    @base.remotable_classmethod
    def action_start(cls, context, instance_uuid, action_name,
                     want_result=True):
        values = cls.pack_action_start(context, instance_uuid, action_name)
        db_action = db.action_start(context, values)
        if want_result:
            return cls._from_db_object(context, cls(), db_action)

    @base.remotable_classmethod
    def action_finish(cls, context, instance_uuid, want_result=True):
        values = cls.pack_action_finish(context, instance_uuid)
        db_action = db.action_finish(context, values)
        if want_result:
            return cls._from_db_object(context, cls(), db_action)

    @base.remotable
    def finish(self):
        values = self.pack_action_finish(self._context, self.instance_uuid)
        db_action = db.action_finish(self._context, values)
        self._from_db_object(self._context, self, db_action)
Ejemplo n.º 9
0
class InstanceActionEvent(base.NovaPersistentObject, base.NovaObject,
                          base.NovaObjectDictCompat):
    # Version 1.0: Initial version
    # Version 1.1: event_finish_with_failure decorated with serialize_args
    VERSION = '1.1'
    fields = {
        'id': fields.IntegerField(),
        'event': fields.StringField(nullable=True),
        'action_id': fields.IntegerField(nullable=True),
        'start_time': fields.DateTimeField(nullable=True),
        'finish_time': fields.DateTimeField(nullable=True),
        'result': fields.StringField(nullable=True),
        'traceback': fields.StringField(nullable=True),
        }

    @staticmethod
    def _from_db_object(context, event, db_event):
        for field in event.fields:
            event[field] = db_event[field]
        event._context = context
        event.obj_reset_changes()
        return event

    @staticmethod
    def pack_action_event_start(context, instance_uuid, event_name):
        values = {'event': event_name,
                  'instance_uuid': instance_uuid,
                  'request_id': context.request_id,
                  'start_time': timeutils.utcnow()}
        return values

    @staticmethod
    def pack_action_event_finish(context, instance_uuid, event_name,
                                 exc_val=None, exc_tb=None):
        values = {'event': event_name,
                  'instance_uuid': instance_uuid,
                  'request_id': context.request_id,
                  'finish_time': timeutils.utcnow()}
        if exc_tb is None:
            values['result'] = 'Success'
        else:
            values['result'] = 'Error'
            values['message'] = exc_val
            values['traceback'] = exc_tb
        return values

    @base.remotable_classmethod
    def get_by_id(cls, context, action_id, event_id):
        db_event = db.action_event_get_by_id(context, action_id, event_id)
        return cls._from_db_object(context, cls(), db_event)

    @base.remotable_classmethod
    def event_start(cls, context, instance_uuid, event_name, want_result=True):
        values = cls.pack_action_event_start(context, instance_uuid,
                                             event_name)
        db_event = db.action_event_start(context, values)
        if want_result:
            return cls._from_db_object(context, cls(), db_event)

    @base.serialize_args
    @base.remotable_classmethod
    def event_finish_with_failure(cls, context, instance_uuid, event_name,
                                  exc_val=None, exc_tb=None, want_result=None):
        values = cls.pack_action_event_finish(context, instance_uuid,
                                              event_name, exc_val=exc_val,
                                              exc_tb=exc_tb)
        db_event = db.action_event_finish(context, values)
        if want_result:
            return cls._from_db_object(context, cls(), db_event)

    @base.remotable_classmethod
    def event_finish(cls, context, instance_uuid, event_name,
                     want_result=True):
        return cls.event_finish_with_failure(context, instance_uuid,
                                             event_name, exc_val=None,
                                             exc_tb=None,
                                             want_result=want_result)

    @base.remotable
    def finish_with_failure(self, exc_val, exc_tb):
        values = self.pack_action_event_finish(self._context,
                                               self.instance_uuid,
                                               self.event, exc_val=exc_val,
                                               exc_tb=exc_tb)
        db_event = db.action_event_finish(self._context, values)
        self._from_db_object(self._context, self, db_event)

    @base.remotable
    def finish(self):
        self.finish_with_failure(self._context, exc_val=None, exc_tb=None)
Ejemplo n.º 10
0
class BandwidthUsage(base.NovaPersistentObject, base.NovaObject,
                     base.NovaObjectDictCompat):
    # Version 1.0: Initial version
    # Version 1.1: Add use_slave to get_by_instance_uuid_and_mac
    # Version 1.2: Add update_cells to create
    VERSION = '1.2'

    fields = {
        'instance_uuid': fields.UUIDField(),
        'mac': fields.StringField(),
        'start_period': fields.DateTimeField(),
        'last_refreshed': fields.DateTimeField(),
        'bw_in': fields.IntegerField(),
        'bw_out': fields.IntegerField(),
        'last_ctr_in': fields.IntegerField(),
        'last_ctr_out': fields.IntegerField()
    }

    @staticmethod
    def _from_db_object(context, bw_usage, db_bw_usage):
        for field in bw_usage.fields:
            if field == 'instance_uuid':
                bw_usage[field] = db_bw_usage['uuid']
            else:
                bw_usage[field] = db_bw_usage[field]
        bw_usage._context = context
        bw_usage.obj_reset_changes()
        return bw_usage

    @staticmethod
    @db.select_db_reader_mode
    def _db_bw_usage_get(context, uuid, start_period, mac, use_slave=False):
        return db.bw_usage_get(context,
                               uuid=uuid,
                               start_period=start_period,
                               mac=mac)

    @base.serialize_args
    @base.remotable_classmethod
    def get_by_instance_uuid_and_mac(cls,
                                     context,
                                     instance_uuid,
                                     mac,
                                     start_period=None,
                                     use_slave=False):
        db_bw_usage = cls._db_bw_usage_get(context,
                                           uuid=instance_uuid,
                                           start_period=start_period,
                                           mac=mac,
                                           use_slave=use_slave)
        if db_bw_usage:
            return cls._from_db_object(context, cls(), db_bw_usage)

    @base.serialize_args
    @base.remotable
    def create(self,
               uuid,
               mac,
               bw_in,
               bw_out,
               last_ctr_in,
               last_ctr_out,
               start_period=None,
               last_refreshed=None,
               update_cells=True):
        db_bw_usage = db.bw_usage_update(self._context,
                                         uuid,
                                         mac,
                                         start_period,
                                         bw_in,
                                         bw_out,
                                         last_ctr_in,
                                         last_ctr_out,
                                         last_refreshed=last_refreshed,
                                         update_cells=update_cells)

        self._from_db_object(self._context, self, db_bw_usage)
Ejemplo n.º 11
0
class TaskLog(base.NovaPersistentObject, base.NovaObject):
    # Version 1.0: Initial version
    VERSION = '1.0'

    fields = {
        'id': fields.IntegerField(read_only=True),
        'task_name': fields.StringField(),
        'state': fields.StringField(read_only=True),
        'host': fields.StringField(),
        'period_beginning': fields.DateTimeField(),
        'period_ending': fields.DateTimeField(),
        'message': fields.StringField(),
        'task_items': fields.IntegerField(),
        'errors': fields.IntegerField(),
    }

    @staticmethod
    def _from_db_object(context, task_log, db_task_log):
        for field in task_log.fields:
            setattr(task_log, field, db_task_log[field])
        task_log._context = context
        task_log.obj_reset_changes()
        return task_log

    @base.serialize_args
    @base.remotable_classmethod
    def get(cls,
            context,
            task_name,
            period_beginning,
            period_ending,
            host,
            state=None):
        db_task_log = db.task_log_get(context,
                                      task_name,
                                      period_beginning,
                                      period_ending,
                                      host,
                                      state=state)
        if db_task_log:
            return cls._from_db_object(context, cls(context), db_task_log)

    @base.remotable
    def begin_task(self):
        db.task_log_begin_task(self._context,
                               self.task_name,
                               self.period_beginning,
                               self.period_ending,
                               self.host,
                               task_items=self.task_items,
                               message=self.message)

    @base.remotable
    def end_task(self):
        db.task_log_end_task(self._context,
                             self.task_name,
                             self.period_beginning,
                             self.period_ending,
                             self.host,
                             errors=self.errors,
                             message=self.message)
Ejemplo n.º 12
0
class BuildRequest(base.NovaObject):
    # Version 1.0: Initial version
    VERSION = '1.0'

    fields = {
        'id': fields.IntegerField(),
        'project_id': fields.StringField(),
        'user_id': fields.StringField(),
        'display_name': fields.StringField(nullable=True),
        'instance_metadata': fields.DictOfStringsField(nullable=True),
        'progress': fields.IntegerField(nullable=True),
        'vm_state': fields.StringField(nullable=True),
        'task_state': fields.StringField(nullable=True),
        'image_ref': fields.StringField(nullable=True),
        'access_ip_v4': fields.IPV4AddressField(nullable=True),
        'access_ip_v6': fields.IPV6AddressField(nullable=True),
        'info_cache': fields.ObjectField('InstanceInfoCache', nullable=True),
        'security_groups': fields.ObjectField('SecurityGroupList'),
        'config_drive': fields.BooleanField(default=False),
        'key_name': fields.StringField(nullable=True),
        'locked_by': fields.EnumField(['owner', 'admin'], nullable=True),
        'request_spec': fields.ObjectField('RequestSpec'),
        # NOTE(alaski): Normally these would come from the NovaPersistentObject
        # mixin but they're being set explicitly because we only need
        # created_at/updated_at. There is no soft delete for this object.
        # These fields should be carried over to the instance when it is
        # scheduled and created in a cell database.
        'created_at': fields.DateTimeField(nullable=True),
        'updated_at': fields.DateTimeField(nullable=True),
    }

    def _load_request_spec(self, db_spec):
        self.request_spec = objects.RequestSpec._from_db_object(self._context,
                objects.RequestSpec(), db_spec)

    def _load_info_cache(self, db_info_cache):
        self.info_cache = objects.InstanceInfoCache.obj_from_primitive(
                jsonutils.loads(db_info_cache))

    def _load_security_groups(self, db_sec_group):
        self.security_groups = objects.SecurityGroupList.obj_from_primitive(
                jsonutils.loads(db_sec_group))

    @staticmethod
    def _from_db_object(context, req, db_req):
        for key in req.fields:
            if isinstance(req.fields[key], fields.ObjectField):
                try:
                    getattr(req, '_load_%s' % key)(db_req[key])
                except AttributeError:
                    LOG.exception(_LE('No load handler for %s'), key)
            elif key in JSON_FIELDS and db_req[key] is not None:
                setattr(req, key, jsonutils.loads(db_req[key]))
            else:
                setattr(req, key, db_req[key])
        req.obj_reset_changes()
        req._context = context
        return req

    @staticmethod
    @db.api_context_manager.reader
    def _get_by_instance_uuid_from_db(context, instance_uuid):
        db_req = (context.session.query(api_models.BuildRequest)
                .join(api_models.RequestSpec)
                .with_entities(api_models.BuildRequest,
                               api_models.RequestSpec)
                .filter(
                    api_models.RequestSpec.instance_uuid == instance_uuid)
                ).first()
        if not db_req:
            raise exception.BuildRequestNotFound(uuid=instance_uuid)
        # db_req is a tuple (api_models.BuildRequest, api_models.RequestSpect)
        build_req = db_req[0]
        build_req['request_spec'] = db_req[1]
        return build_req

    @base.remotable_classmethod
    def get_by_instance_uuid(cls, context, instance_uuid):
        db_req = cls._get_by_instance_uuid_from_db(context, instance_uuid)
        return cls._from_db_object(context, cls(), db_req)

    @staticmethod
    @db.api_context_manager.writer
    def _create_in_db(context, updates):
        db_req = api_models.BuildRequest()
        db_req.update(updates)
        db_req.save(context.session)
        # NOTE: This is done because a later access will trigger a lazy load
        # outside of the db session so it will fail. We don't lazy load
        # request_spec on the object later because we never need a BuildRequest
        # without the RequestSpec.
        db_req.request_spec
        return db_req

    def _get_update_primitives(self):
        updates = self.obj_get_changes()
        for key, value in six.iteritems(updates):
            if key in OBJECT_FIELDS and value is not None:
                updates[key] = jsonutils.dumps(value.obj_to_primitive())
            elif key in JSON_FIELDS and value is not None:
                updates[key] = jsonutils.dumps(value)
            elif key in IP_FIELDS and value is not None:
                # These are stored as a string in the db and must be converted
                updates[key] = str(value)
        req_spec_obj = updates.pop('request_spec', None)
        if req_spec_obj:
            updates['request_spec_id'] = req_spec_obj.id
        return updates

    @base.remotable
    def create(self):
        if self.obj_attr_is_set('id'):
            raise exception.ObjectActionError(action='create',
                                              reason='already created')

        updates = self._get_update_primitives()
        db_req = self._create_in_db(self._context, updates)
        self._from_db_object(self._context, self, db_req)

    @staticmethod
    @db.api_context_manager.writer
    def _destroy_in_db(context, id):
        context.session.query(api_models.BuildRequest).filter_by(
                id=id).delete()

    @base.remotable
    def destroy(self):
        self._destroy_in_db(self._context, self.id)