Beispiel #1
0
class AggregateList(object_base.ObjectListBase, base.MoganObject,
                    object_base.VersionedObjectDictCompat):
    # Version 1.0: Initial version

    VERSION = '1.0'

    dbapi = dbapi.get_instance()

    fields = {'objects': object_fields.ListOfObjectsField('Aggregate')}

    @classmethod
    def get_all(cls, context):
        db_aggregates = cls.dbapi.aggregate_get_all(context)
        return object_base.obj_make_list(context, cls(context), Aggregate,
                                         db_aggregates)

    @classmethod
    def get_by_metadata_key(cls, context, key):
        db_aggregates = cls.dbapi.aggregate_get_by_metadata_key(context, key)
        return object_base.obj_make_list(context, cls(context), Aggregate,
                                         db_aggregates)

    @classmethod
    def get_by_metadata(cls, context, key, value):
        db_aggregates = cls.dbapi.aggregate_get_by_metadata(
            context, key, value)
        return object_base.obj_make_list(context, cls(context), Aggregate,
                                         db_aggregates)
Beispiel #2
0
class ServerGroup(base.MoganObject, object_base.VersionedObjectDictCompat):
    # Version 1.0: Initial version
    VERSION = '1.0'

    dbapi = dbapi.get_instance()

    fields = {
        'id': object_fields.IntegerField(),
        'user_id': object_fields.StringField(nullable=True),
        'project_id': object_fields.StringField(nullable=True),
        'uuid': object_fields.UUIDField(),
        'name': object_fields.StringField(nullable=True),
        'policies': object_fields.ListOfStringsField(nullable=True),
        'members': object_fields.ListOfStringsField(nullable=True),
    }

    @staticmethod
    def _from_db_object(context, server_group, db_server):
        """Method to help with migration to objects.

        Converts a database entity to a formal object.
        """
        for field in server_group.fields:
            server_group[field] = db_server[field]
        server_group._context = context
        server_group.obj_reset_changes()
        return server_group

    def create(self):
        values = self.obj_get_changes()
        policies = values.pop('policies', None)
        members = values.pop('members', None)
        db_group = self.dbapi.server_group_create(self._context,
                                                  values,
                                                  policies=policies,
                                                  members=members)
        self._from_db_object(self._context, self, db_group)

    @classmethod
    def get_by_uuid(cls, context, uuid):
        db_group = cls.dbapi.server_group_get(context, uuid)
        return cls._from_db_object(context, cls(), db_group)

    def destroy(self):
        self.dbapi.server_group_delete(self._context, self.uuid)
        self.obj_reset_changes()

    @classmethod
    def add_members(cls, context, group_uuid, members):
        cls.dbapi.server_group_members_add(context, group_uuid, members)

    def save(self, context=None):
        updates = self.obj_get_changes()
        self.dbapi.server_group_update(context, self.uuid, updates)
        self.obj_reset_changes()
Beispiel #3
0
class ComputePort(base.MoganObject, object_base.VersionedObjectDictCompat):
    # Version 1.0: Initial version
    VERSION = '1.0'

    dbapi = dbapi.get_instance()

    fields = {
        'id': object_fields.IntegerField(read_only=True),
        'address': object_fields.MACAddressField(nullable=False),
        'port_uuid': object_fields.UUIDField(read_only=True),
        'node_uuid': object_fields.UUIDField(read_only=True),
        'extra_specs': object_fields.FlexibleDictField(nullable=True),
    }

    @classmethod
    def list(cls, context):
        """Return a list of ComputePort objects."""
        db_compute_ports = cls.dbapi.compute_port_get_all(context)
        return cls._from_db_object_list(context, db_compute_ports)

    @classmethod
    def get(cls, context, port_uuid):
        """Find a compute port and return a ComputePort object."""
        db_compute_port = cls.dbapi.compute_port_get(context, port_uuid)
        compute_port = cls._from_db_object(context, cls(context),
                                           db_compute_port)
        return compute_port

    def create(self, context=None):
        """Create a ComputePort record in the DB."""
        values = self.obj_get_changes()
        db_compute_port = self.dbapi.compute_port_create(context, values)
        self._from_db_object(context, self, db_compute_port)

    def destroy(self, context=None):
        """Delete the ComputePort from the DB."""
        self.dbapi.compute_port_destroy(context, self.port_uuid)
        self.obj_reset_changes()

    def save(self, context=None):
        """Save updates to this ComputePort."""
        updates = self.obj_get_changes()
        self.dbapi.compute_port_update(context, self.port_uuid, updates)
        self.obj_reset_changes()

    def refresh(self, context=None):
        """Refresh the object by re-fetching from the DB."""
        current = self.__class__.get(context, self.port_uuid)
        self.obj_refresh(current)

    def update_from_driver(self, port):
        keys = ["address", "port_uuid", "node_uuid", "extra_specs"]
        for key in keys:
            if key in port:
                setattr(self, key, port[key])
Beispiel #4
0
 def test_quota_usage_reserve(self):
     utils.create_test_quota()
     dbapi = db_api.get_instance()
     r = dbapi.quota_reserve(self.context,
                             self.resources, {'servers': 10},
                             {'servers': 1},
                             datetime.datetime(2099, 1, 1, 0, 0),
                             CONF.quota.until_refresh,
                             CONF.quota.max_age,
                             project_id=self.project_id)
     self.assertEqual('servers', r[0].resource_name)
Beispiel #5
0
    def setUp(self):
        super(DbTestCase, self).setUp()

        self.dbapi = dbapi.get_instance()

        global _DB_CACHE
        if not _DB_CACHE:
            engine = enginefacade.get_legacy_facade().get_engine()
            _DB_CACHE = Database(engine,
                                 migration,
                                 sql_connection=CONF.database.connection)
        self.useFixture(_DB_CACHE)
Beispiel #6
0
class KeyPair(base.MoganObject):
    # Version 1.0: Initial version
    VERSION = '1.0'

    dbapi = dbapi.get_instance()

    fields = {
        'id': fields.IntegerField(),
        'name': fields.StringField(nullable=False),
        'user_id': fields.StringField(nullable=True),
        'project_id': fields.StringField(nullable=True),
        'fingerprint': fields.StringField(nullable=True),
        'public_key': fields.StringField(nullable=True),
        'type': fields.StringField(nullable=False),
    }

    @staticmethod
    def _from_db_object(context, keypair, db_keypair):
        ignore = {'deleted': False, 'deleted_at': None}
        for key in keypair.fields:
            if key in ignore and not hasattr(db_keypair, key):
                setattr(keypair, key, ignore[key])
            else:
                setattr(keypair, key, db_keypair[key])
        keypair._context = context
        keypair.obj_reset_changes()
        return keypair

    @classmethod
    def get_by_name(cls, context, user_id, name):
        db_keypair = cls.dbapi.key_pair_get(context, user_id, name)
        return cls._from_db_object(context, cls(), db_keypair)

    @classmethod
    def destroy_by_name(cls, context, user_id, name):
        cls.dbapi.key_pair_destroy(context, user_id, name)

    def create(self):
        if self.obj_attr_is_set('id'):
            raise exception.ObjectActionError(action='create',
                                              reason='already created')
        try:
            self.dbapi.key_pair_get(self._context, self.user_id, self.name)
            raise exception.KeypairExists(key_name=self.name)
        except exception.KeypairNotFound:
            pass
        updates = self.obj_get_changes()
        db_keypair = self.dbapi.key_pair_create(self._context, updates)
        self._from_db_object(self._context, self, db_keypair)

    def destroy(self):
        self.dbapi.key_pair_destroy(self._context, self.user_id, self.name)
Beispiel #7
0
def create_test_aggregate_metadata(context={}, **kw):
    """Create test aggregate metadata entry in DB and return the DB object.

        Function to be used to create test Aggregate metadata objects in the
        database.

        :param context: The request context, for access checks.
        :param kw: kwargs with overriding values for metadata's attributes.
        :returns: metadata dict object.
    """
    agg_meta = get_test_aggregate_metadata(**kw)
    dbapi = db_api.get_instance()
    return dbapi.aggregate_metadata_update_or_create(context, **agg_meta)
Beispiel #8
0
def create_test_server_tag(context, **kw):
    """Create test node tag entry in DB and return NodeTag DB object.

    Function to be used to create test NodeTag objects in the database.

    :param context: Request context
    :param kw: kwargs with overriding values for tag's attributes.
    :returns: Test NodeTag DB object.

    """
    tag = get_test_server_tag(**kw)
    dbapi = db_api.get_instance()
    return dbapi.add_server_tag(context, tag['server_id'], tag['tag'])
Beispiel #9
0
def create_test_server_fault(context={}, **kw):
    """Create test server fault entry in DB and return the DB object.

    Function to be used to create test Server Fault objects in the database.

    :param context: The request context, for access checks.
    :param kw: kwargs with overriding values for server fault's attributes.
    :returns: Test Server Fault DB object.

    """
    server_fault = get_test_server_fault(**kw)
    dbapi = db_api.get_instance()

    return dbapi.server_fault_create(context, server_fault)
Beispiel #10
0
class ServerNic(base.MoganObject, object_base.VersionedObjectDictCompat):
    # Version 1.0: Initial version
    VERSION = '1.0'

    dbapi = dbapi.get_instance()

    fields = {
        'port_id': object_fields.UUIDField(nullable=False),
        'server_uuid': object_fields.UUIDField(nullable=True),
        'mac_address': object_fields.MACAddressField(nullable=True),
        'network_id': object_fields.UUIDField(nullable=True),
        'fixed_ips':
        object_fields.ListOfDictOfNullableStringsField(nullable=True),
        'floating_ip': object_fields.StringField(nullable=True),
        'preserve_on_delete': object_fields.BooleanField(),
    }

    @staticmethod
    def _from_db_object(context, obj, db_object, server_uuid=None):
        if server_uuid:
            db_object = copy.deepcopy(db_object)
            db_object.update(server_uuid=server_uuid)
        if not isinstance(db_object, dict):
            db_object_dict = db_object.as_dict()
        else:
            db_object_dict = db_object
        obj = ServerNic(context)
        obj.update(db_object_dict)
        obj.obj_reset_changes()
        return obj

    @classmethod
    def delete_by_port_id(cls, context, port_id):
        cls.dbapi.server_nic_delete(context, port_id)

    @classmethod
    def get_by_port_id(cls, context, port_id):
        return cls.dbapi.server_nic_get(context, port_id)

    def save(self, context):
        updates = self.obj_get_changes()
        self.dbapi.server_nic_update_or_create(context, self.port_id, updates)

    def create(self, context):
        values = self.obj_to_primitive()['mogan_object.data']
        self.dbapi.server_nic_update_or_create(context, self.port_id, values)

    def delete(self, context):
        self.dbapi.server_nic_delete(context, self.port_id)
Beispiel #11
0
class ComputePortList(object_base.ObjectListBase, base.MoganObject,
                      object_base.VersionedObjectDictCompat):
    # Version 1.0: Initial version

    VERSION = '1.0'

    dbapi = dbapi.get_instance()

    fields = {'objects': object_fields.ListOfObjectsField('ComputePort')}

    @classmethod
    def get_by_node_uuid(cls, context, node_uuid):
        db_ports = cls.dbapi.compute_port_get_by_node_uuid(context, node_uuid)
        return object_base.obj_make_list(context, cls(context), ComputePort,
                                         db_ports)
Beispiel #12
0
class ServerFault(base.MoganObject, object_base.VersionedObjectDictCompat):
    # Version 1.0: Initial version
    VERSION = '1.0'

    dbapi = dbapi.get_instance()

    fields = {
        'id': object_fields.IntegerField(),
        'server_uuid': object_fields.UUIDField(),
        'code': object_fields.IntegerField(),
        'message': object_fields.StringField(nullable=True),
        'detail': object_fields.StringField(nullable=True),
    }

    def return_dict(self):
        return dict((k, getattr(self, k))
                    for k in ['code', 'message', 'detail']
                    if hasattr(self, k))

    @staticmethod
    def _from_db_object(context, fault, db_fault):
        for key in fault.fields:
            fault[key] = db_fault[key]
        fault._context = context
        fault.obj_reset_changes()
        return fault

    @classmethod
    def get_latest_for_server(cls, context, server_uuid):
        db_faults = cls.dbapi.server_fault_get_by_server_uuids(
            context, [server_uuid])
        if server_uuid in db_faults and db_faults[server_uuid]:
            return cls._from_db_object(context, cls(),
                                       db_faults[server_uuid][0])

    def create(self):
        if self.obj_attr_is_set('id'):
            raise exception.ObjectActionError(action='create',
                                              reason='already created')
        values = {
            'server_uuid': self.server_uuid,
            'code': self.code,
            'message': self.message,
            'detail': self.detail,
        }
        db_fault = self.dbapi.server_fault_create(self._context, values)
        self._from_db_object(self._context, self, db_fault)
        self.obj_reset_changes()
Beispiel #13
0
    def init_host(self):
        """Initialize the engine host.

        :param admin_context: the admin context to pass to periodic tasks.
        :raises RuntimeError: when engine is already running.
        """
        if self._started:
            raise RuntimeError(_('Attempt to start an already running '
                                 'engine manager'))

        self.dbapi = dbapi.get_instance()

        self._worker_pool = greenpool.GreenPool(
            size=CONF.engine.workers_pool_size)

        self._started = True
Beispiel #14
0
class ServerFaultList(base.MoganObject, object_base.VersionedObjectDictCompat):
    # Version 1.0: Initial version

    VERSION = '1.0'

    dbapi = dbapi.get_instance()

    fields = {'objects': object_fields.ListOfObjectsField('ServerFault')}

    @classmethod
    def get_by_server_uuids(cls, context, server_uuids):
        db_faultdict = cls.dbapi.server_fault_get_by_server_uuids(
            context, server_uuids)
        db_faultlist = itertools.chain(*db_faultdict.values())
        return object_base.obj_make_list(context, cls(context),
                                         objects.ServerFault, db_faultlist)
Beispiel #15
0
 def test_reserve_rollback(self):
     utils.create_test_quota()
     dbapi = db_api.get_instance()
     rs = dbapi.quota_reserve(self.context,
                              self.resources, {'servers': 10},
                              {'servers': 1},
                              datetime.datetime(2099, 1, 1, 0, 0),
                              CONF.quota.until_refresh,
                              CONF.quota.max_age,
                              project_id=self.project_id)
     r = dbapi.quota_usage_get_all_by_project(self.context, self.project_id)
     before_in_use = r['servers']['in_use']
     dbapi.reservation_rollback(self.context, rs, self.project_id)
     r = dbapi.quota_usage_get_all_by_project(self.context, self.project_id)
     after_in_use = r['servers']['in_use']
     self.assertEqual(before_in_use, after_in_use)
Beispiel #16
0
def create_test_aggregate(context={}, **kw):
    """Create test aggregate entry in DB and return the DB object.

    Function to be used to create test Aggregate objects in the database.

    :param context: The request context, for access checks.
    :param kw: kwargs with overriding values for aggregate's attributes.
    :returns: Test Aggregate DB object.

    """
    agg = get_test_aggregate(**kw)
    # Let DB generate ID if it isn't specified explicitly
    if 'id' not in kw:
        del agg['id']
    dbapi = db_api.get_instance()

    return dbapi.aggregate_create(context, agg)
Beispiel #17
0
def create_test_server(context={}, **kw):
    """Create test server entry in DB and return Server DB object.

    Function to be used to create test Server objects in the database.

    :param context: The request context, for access checks.
    :param kw: kwargs with overriding values for server's attributes.
    :returns: Test Server DB object.

    """
    server = get_test_server(**kw)
    # Let DB generate ID if it isn't specified explicitly
    if 'id' not in kw:
        del server['id']
    dbapi = db_api.get_instance()

    return dbapi.server_create(context, server)
Beispiel #18
0
class KeyPairList(object_base.ObjectListBase, base.MoganObject):
    # Version 1.0: Initial version
    VERSION = '1.0'

    dbapi = dbapi.get_instance()

    fields = {
        'objects': fields.ListOfObjectsField('KeyPair'),
    }

    @classmethod
    def get_count_from_db(cls, context, user_id):
        return cls.dbapi.key_pair_count_by_user(context, user_id)

    @classmethod
    def get_by_user(cls, context, user_id):
        db_keypairs = cls.dbapi.key_pair_get_all_by_user(context, user_id)

        return object_base.obj_make_list(context, cls(context),
                                         objects.KeyPair, db_keypairs)
Beispiel #19
0
def create_test_server_group(context={}, **kw):
    """Create test server fault entry in DB and return the DB object.

    Function to be used to create test Server Fault objects in the database.

    :param context: The request context, for access checks.
    :param kw: kwargs with overriding values for server fault's attributes.
    :returns: Test Server Fault DB object.

    """
    server_fault = get_test_server_group(**kw)
    # Let DB generate ID if it isn't specified explicitly
    if 'id' not in kw:
        del server_fault['id']
    dbapi = db_api.get_instance()
    members = server_fault.pop('members')
    policies = server_fault.pop('policies')
    return dbapi.server_group_create(context,
                                     server_fault,
                                     policies=policies,
                                     members=members)
Beispiel #20
0
class ServerNics(object_base.ObjectListBase, base.MoganObject,
                 object_base.VersionedObjectDictCompat):
    # Version 1.0: Initial version

    VERSION = '1.0'

    dbapi = dbapi.get_instance()

    fields = {
        'objects': object_fields.ListOfObjectsField('ServerNic')}

    def __init__(self, context=None, **kwargs):

        super(ServerNics, self).__init__(context=context, **kwargs)

    @classmethod
    def get_by_server_uuid(cls, context, server_uuid):
        nics = cls.dbapi.server_nics_get_by_server_uuid(
            context, server_uuid)
        return object_base.obj_make_list(context, cls(context), ServerNic,
                                         nics)

    def create(self, context):
        for nic_obj in self:
            nic_obj.create(context)

    def as_list_of_dict(self):
        return [obj.obj_to_primitive()['mogan_object.data'] for obj in self]

    def get_port_ids(self):
        return [x.port_id for x in self]

    def delete(self, context):
        for nic_obj in self:
            try:
                nic_obj.delete(context)
            except exception.PortNotFound as e:
                LOG.warning("For server %(uuid)s: %(reason)s",
                            {"uuid": nic_obj.server_uuid,
                             "reason": six.text_type(e)})
Beispiel #21
0
class ServerGroupList(object_base.ObjectListBase, base.MoganObject,
                      object_base.VersionedObjectDictCompat):
    # Version 1.0: Initial version
    VERSION = '1.0'

    dbapi = dbapi.get_instance()

    fields = {
        'objects': object_fields.ListOfObjectsField('ServerGroup'),
    }

    @classmethod
    def get_all(cls, context):
        db_groups = cls.dbapi.server_group_get_all(context)
        return object_base.obj_make_list(context, cls(context), ServerGroup,
                                         db_groups)

    @classmethod
    def get_by_project_id(cls, context, project_id):
        project_server_groups = cls.dbapi.server_group_get_all(
            context, project_id)
        return object_base.obj_make_list(context, cls(context), ServerGroup,
                                         project_server_groups)
Beispiel #22
0
class Server(base.MoganObject, object_base.VersionedObjectDictCompat):
    # Version 1.0: Initial version
    VERSION = '1.0'

    dbapi = dbapi.get_instance()

    fields = {
        'id': object_fields.IntegerField(),
        'uuid': object_fields.UUIDField(nullable=True),
        'name': object_fields.StringField(nullable=True),
        'description': object_fields.StringField(nullable=True),
        'project_id': object_fields.UUIDField(nullable=True),
        'user_id': object_fields.UUIDField(nullable=True),
        'status': object_fields.StringField(nullable=True),
        'power_state': object_fields.StringField(nullable=True),
        'flavor_uuid': object_fields.UUIDField(nullable=True),
        'availability_zone': object_fields.StringField(nullable=True),
        'image_uuid': object_fields.UUIDField(nullable=True),
        'nics': object_fields.ObjectField('ServerNics', nullable=True),
        'fault': object_fields.ObjectField('ServerFault', nullable=True),
        'node_uuid': object_fields.UUIDField(nullable=True),
        'launched_at': object_fields.DateTimeField(nullable=True),
        'metadata': object_fields.FlexibleDictField(nullable=True),
        'locked': object_fields.BooleanField(default=False),
        'locked_by': object_fields.StringField(nullable=True),
    }

    def __init__(self, context=None, **kwargs):
        server_nics = kwargs.pop('nics', None)
        if server_nics and isinstance(server_nics, list):
            nics_obj = objects.ServerNics(context)
            for nic in server_nics:
                nic_obj = objects.ServerNic(context,
                                            server_uuid=kwargs['uuid'],
                                            **nic)
                nics_obj.objects.append(nic_obj)
            kwargs['nics'] = nics_obj
        super(Server, self).__init__(context=context, **kwargs)

    @staticmethod
    def _from_db_object(server, db_server, expected_attrs=None):
        """Method to help with migration to objects.

        Converts a database entity to a formal object.

        :param server: An object of the Server class.
        :param db_server: A DB Server model of the object
        :return: The object of the class with the database entity added
        """
        for field in set(server.fields) - set(OPTIONAL_ATTRS):
            if field == 'metadata':
                server[field] = db_server['extra']
            else:
                server[field] = db_server[field]

        if expected_attrs is None:
            expected_attrs = []
        if 'nics' in expected_attrs:
            server._load_server_nics(server._context, server.uuid)
        else:
            server.nics = None
        if 'fault' in expected_attrs:
            server._load_fault(server._context, server.uuid)

        server.obj_reset_changes()
        return server

    def _load_server_nics(self, context, server_uuid):
        self.nics = objects.ServerNics.get_by_server_uuid(
            context=context, server_uuid=server_uuid)

    @staticmethod
    def _from_db_object_list(db_objects, cls, context):
        """Converts a list of database entities to a list of formal objects."""
        servers = []
        for obj in db_objects:
            expected_attrs = ['nics', 'fault']
            servers.append(
                Server._from_db_object(cls(context), obj, expected_attrs))
        return servers

    def _load_fault(self, context, server_uuid):
        self.fault = objects.ServerFault.get_latest_for_server(
            context=context, server_uuid=server_uuid)

    def _save_nics(self, context):
        for nic_obj in self.nics or []:
            nic_obj.save(context)

    def as_dict(self):
        data = dict(self.items())
        if 'nics' in data:
            data.update(nics=data['nics'].as_list_of_dict())
        return data

    @classmethod
    def list(cls, context, project_only=False, filters=None):
        """Return a list of Server objects."""
        db_servers = cls.dbapi.server_get_all(context,
                                              project_only=project_only,
                                              filters=filters)
        return Server._from_db_object_list(db_servers, cls, context)

    @classmethod
    def get(cls, context, uuid):
        """Find a server and return a Server object."""
        expected_attrs = ['nics', 'fault']
        db_server = cls.dbapi.server_get(context, uuid)
        server = Server._from_db_object(cls(context), db_server,
                                        expected_attrs)
        return server

    def create(self, context=None):
        """Create a Server record in the DB."""
        values = self.obj_get_changes()
        metadata = values.pop('metadata', None)
        if metadata is not None:
            values['extra'] = metadata
        server_nics = values.pop('nics', None)
        if server_nics:
            values['nics'] = server_nics.as_list_of_dict()
        db_server = self.dbapi.server_create(context, values)
        expected_attrs = None
        if server_nics:
            expected_attrs = ['nics']
        self._from_db_object(self, db_server, expected_attrs)

    def destroy(self, context=None):
        """Delete the Server from the DB."""
        self.dbapi.server_destroy(context, self.uuid)
        self.obj_reset_changes()

    def save(self, context=None):
        """Save updates to this Server."""
        updates = self.obj_get_changes()
        for field in list(updates):
            if (self.obj_attr_is_set(field) and isinstance(
                    self.fields[field], object_fields.ObjectField)
                    and getattr(self, field, None) is not None):
                try:
                    getattr(self, '_save_%s' % field)(context)
                except AttributeError:
                    LOG.exception('No save handler for %s', field, server=self)
                except db_exc.DBReferenceError as exp:
                    if exp.key != 'server_uuid':
                        raise
                updates.pop(field)

        metadata = updates.pop('metadata', None)
        if metadata is not None:
            updates['extra'] = metadata
        self.dbapi.server_update(context, self.uuid, updates)
        self.obj_reset_changes()

    def refresh(self, context=None):
        """Refresh the object by re-fetching from the DB."""
        current = self.__class__.get(context, self.uuid)
        self.obj_refresh(current)
        self.obj_reset_changes()
Beispiel #23
0
class Aggregate(base.MoganObject, object_base.VersionedObjectDictCompat):
    # Version 1.0: Initial version
    VERSION = '1.0'

    dbapi = dbapi.get_instance()

    fields = {
        'id': object_fields.IntegerField(read_only=True),
        'uuid': object_fields.UUIDField(read_only=True),
        'name': object_fields.StringField(),
        'metadata': object_fields.FlexibleDictField(nullable=True),
    }

    def __init__(self, *args, **kwargs):
        super(Aggregate, self).__init__(*args, **kwargs)
        self._orig_metadata = {}

    @staticmethod
    def _from_db_object(context, aggregate, db_aggregate):
        """Converts a database entity to a formal object."""
        for field in aggregate.fields:
            if field == 'metadata':
                aggregate[field] = db_aggregate['metadetails']
            else:
                aggregate[field] = db_aggregate[field]
        aggregate.obj_reset_changes()
        return aggregate

    def obj_reset_changes(self, fields=None, recursive=False):
        super(Aggregate, self).obj_reset_changes(fields=fields,
                                                 recursive=recursive)
        if fields is None or 'metadata' in fields:
            self._orig_metadata = (dict(self.metadata)
                                   if self.obj_attr_is_set('metadata') else {})

    def obj_what_changed(self):
        changes = super(Aggregate, self).obj_what_changed()
        if ('metadata' in self and self.metadata != self._orig_metadata):
            changes.add('metadata')
        return changes

    @classmethod
    def get(cls, context, aggregate_id):
        """Find an aggregate and return an Aggregate object."""
        db_aggregate = cls.dbapi.aggregate_get(context, aggregate_id)
        aggregate = cls._from_db_object(context, cls(context), db_aggregate)
        return aggregate

    def create(self, context=None):
        """Create an Aggregate record in the DB."""
        values = self.obj_get_changes()
        db_aggregate = self.dbapi.aggregate_create(context, values)
        self._from_db_object(context, self, db_aggregate)

    def destroy(self, context=None):
        """Delete the Aggregate from the DB."""
        self.dbapi.aggregate_destroy(context, self.id)
        self.obj_reset_changes()

    def save(self, context=None):
        """Save updates to this Aggregate."""
        updates = self.obj_get_changes()
        metadata = updates.pop('metadata', None)

        # metadata
        if metadata is not None:
            deleted_keys = (set(self._orig_metadata.keys()) -
                            set(metadata.keys()))
            added_keys = self.metadata
        else:
            added_keys = deleted_keys = None
        if added_keys or deleted_keys:
            self.save_metadata(context, self.metadata, deleted_keys)

        self.dbapi.aggregate_update(context, self.id, updates)
        self.obj_reset_changes()

    def save_metadata(self, context, to_add=None, to_delete=None):
        """Add or delete metadata.

        :param:to_add: A dict of new keys to add/update
        :param:to_delete: A list of keys to remove
        """
        ident = self.id

        to_add = to_add if to_add is not None else {}
        to_delete = to_delete if to_delete is not None else []

        if to_add:
            self.dbapi.aggregate_metadata_update_or_create(
                context, ident, to_add)

        for key in to_delete:
            self.dbapi.aggregate_metadata_delete(context, ident, key)
        self.obj_reset_changes(['metadata'])
Beispiel #24
0
class Flavor(base.MoganObject, object_base.VersionedObjectDictCompat):
    # Version 1.0: Initial version
    VERSION = '1.0'

    dbapi = dbapi.get_instance()

    fields = {
        'uuid': object_fields.UUIDField(nullable=True),
        'name': object_fields.StringField(nullable=True),
        'description': object_fields.StringField(nullable=True),
        'is_public': object_fields.BooleanField(),
        'disabled': object_fields.BooleanField(),
        'resources': object_fields.FlexibleDictField(nullable=True),
        'resource_traits': object_fields.FlexibleDictField(nullable=True),
        'projects': object_fields.ListOfStringsField(),
    }

    def __init__(self, *args, **kwargs):
        super(Flavor, self).__init__(*args, **kwargs)
        self._orig_projects = {}

    @staticmethod
    def _from_db_object(context, flavor, db_flavor, expected_attrs=None):
        if expected_attrs is None:
            expected_attrs = []

        for name, field in flavor.fields.items():
            if name in OPTIONAL_FIELDS:
                continue
            value = db_flavor[name]
            if isinstance(field, object_fields.IntegerField):
                value = value if value is not None else 0
            flavor[name] = value

        if 'projects' in expected_attrs:
            flavor._load_projects(context)

        flavor.obj_reset_changes()
        return flavor

    def _load_projects(self, context):
        self.projects = [x['project_id'] for x in
                         self.dbapi.flavor_access_get(context, self.uuid)]
        self.obj_reset_changes(['projects'])

    def obj_reset_changes(self, fields=None, recursive=False):
        super(Flavor, self).obj_reset_changes(fields=fields,
                                              recursive=recursive)
        if fields is None or 'projects' in fields:
            self._orig_projects = (list(self.projects)
                                   if self.obj_attr_is_set('projects')
                                   else [])

    def obj_what_changed(self):
        changes = super(Flavor, self).obj_what_changed()
        if 'projects' in self and self.projects != self._orig_projects:
            changes.add('projects')
        return changes

    @staticmethod
    def _from_db_object_list(db_objects, cls, context):
        """Converts a list of database entities to a list of formal objects."""
        return [Flavor._from_db_object(context, cls(context), obj)
                for obj in db_objects]

    @classmethod
    def list(cls, context):
        """Return a list of Flavor objects."""
        db_flavors = cls.dbapi.flavor_get_all(context)
        return Flavor._from_db_object_list(db_flavors, cls, context)

    @classmethod
    def get(cls, context, flavor_uuid):
        """Find a Flavor and return a Flavor object."""
        db_flavor = cls.dbapi.flavor_get(context, flavor_uuid)
        flavor = Flavor._from_db_object(
            context, cls(context), db_flavor,
            expected_attrs=['projects'])
        return flavor

    def create(self, context=None):
        """Create a Flavor record in the DB."""
        values = self.obj_get_changes()
        db_flavor = self.dbapi.flavor_create(context, values)
        self._from_db_object(context, self, db_flavor)

    def destroy(self, context=None):
        """Delete the Flavor from the DB."""
        self.dbapi.flavor_destroy(context, self.uuid)
        self.obj_reset_changes()

    def save(self, context=None):
        updates = self.obj_get_changes()
        projects = updates.pop('projects', None)

        # access projects
        if projects is not None:
            deleted_projects = set(self._orig_projects) - set(projects)
            added_projects = set(projects) - set(self._orig_projects)
        else:
            added_projects = deleted_projects = None

        if added_projects or deleted_projects:
            self.save_projects(context, added_projects, deleted_projects)

        self.dbapi.flavor_update(context, self.uuid, updates)

    def save_projects(self, context, to_add=None, to_delete=None):
        """Add or delete projects.

        :param:to_add: A list of projects to add
        :param:to_delete: A list of projects to remove
        """
        ident = self.uuid

        to_add = to_add if to_add is not None else []
        to_delete = to_delete if to_delete is not None else []

        for project_id in to_add:
            self.dbapi.flavor_access_add(context, ident, project_id)

        for project_id in to_delete:
            self.dbapi.flavor_access_remove(context, ident, project_id)
        self.obj_reset_changes(['projects'])
Beispiel #25
0
class DbQuotaDriver(object):
    """Driver to perform check to enforcement of quotas.

    Also allows to obtain quota information.
    The default driver utilizes the local database.
    """

    dbapi = dbapi.get_instance()

    def get_project_quotas(self, context, resources, project_id, usages=True):
        """Retrieve quotas for a project.

        Given a list of resources, retrieve the quotas for the given
        project.

        :param context: The request context, for access checks.
        :param resources: A dictionary of the registered resources.
        :param project_id: The ID of the project to return quotas for.
        :param usages: If True, the current in_use, reserved and allocated
                       counts will also be returned.
        """

        quotas = {}
        project_quotas = {}
        res = self.dbapi.quota_get_all_by_project(context, project_id)
        for p_quota in res:
            project_quotas[p_quota.resource_name] = p_quota.hard_limit
        if project_quotas == {}:
            self.dbapi.quota_create(
                context, {
                    'resource_name': 'servers',
                    'project_id': project_id,
                    'hard_limit': 10,
                    'allocated': 0
                })
            project_quotas['servers'] = 10
        allocated_quotas = None
        if usages:
            project_usages = self.dbapi.quota_usage_get_all_by_project(
                context, project_id)
            allocated_quotas = self.dbapi.quota_allocated_get_all_by_project(
                context, project_id)
            allocated_quotas.pop('project_id')

        for resource in resources.values():
            if resource.name not in project_quotas:
                continue

            quota_val = project_quotas.get(resource.name)
            if quota_val is None:
                raise exception.QuotaNotFound(quota_name=resource.name)
            quotas[resource.name] = {'limit': quota_val}

            # Include usages if desired.  This is optional because one
            # internal consumer of this interface wants to access the
            # usages directly from inside a transaction.
            if usages:
                usage = project_usages.get(resource.name, {})
                quotas[resource.name].update(
                    in_use=usage.get('in_use', 0),
                    reserved=usage.get('reserved', 0),
                )
            if allocated_quotas:
                quotas[resource.name].update(allocated=allocated_quotas.get(
                    resource.name, 0), )
        return quotas

    def _get_quotas(self, context, resources, keys, has_sync, project_id=None):
        """A helper method which retrieves the quotas for specific resources.

        This specific resource is identified by keys, and which apply to the
        current context.

        :param context: The request context, for access checks.
        :param resources: A dictionary of the registered resources.
        :param keys: A list of the desired quotas to retrieve.
        :param has_sync: If True, indicates that the resource must
                         have a sync attribute; if False, indicates
                         that the resource must NOT have a sync
                         attribute.
        :param project_id: Specify the project_id if current context
                           is admin and admin wants to impact on
                           common user's tenant.
        """

        # Filter resources
        if has_sync:
            sync_filt = lambda x: hasattr(x, 'sync')
        else:
            sync_filt = lambda x: not hasattr(x, 'sync')
        desired = set(keys)
        sub_resources = {
            k: v
            for k, v in resources.items() if k in desired and sync_filt(v)
        }

        # Make sure we accounted for all of them...
        if len(keys) != len(sub_resources):
            unknown = desired - set(sub_resources.keys())
            raise exception.QuotaResourceUnknown(unknown=sorted(unknown))

        # Grab and return the quotas (without usages)
        quotas = self.get_project_quotas(context,
                                         sub_resources,
                                         project_id,
                                         usages=False)

        return {k: v['limit'] for k, v in quotas.items()}

    def reserve(self,
                context,
                resources,
                deltas,
                expire=None,
                project_id=None):
        """Check quotas and reserve resources.

        For counting quotas--those quotas for which there is a usage
        synchronization function--this method checks quotas against
        current usage and the desired deltas.

        This method will raise a QuotaResourceUnknown exception if a
        given resource is unknown or if it does not have a usage
        synchronization function.

        If any of the proposed values is over the defined quota, an
        OverQuota exception will be raised with the sorted list of the
        resources which are too high.  Otherwise, the method returns a
        list of reservation UUIDs which were created.

        :param context: The request context, for access checks.
        :param resources: A dictionary of the registered resources.
        :param deltas: A dictionary of the proposed delta changes.
        :param expire: An optional parameter specifying an expiration
                       time for the reservations.  If it is a simple
                       number, it is interpreted as a number of
                       seconds and added to the current time; if it is
                       a datetime.timedelta object, it will also be
                       added to the current time.  A datetime.datetime
                       object will be interpreted as the absolute
                       expiration time.  If None is specified, the
                       default expiration time set by
                       --default-reservation-expire will be used (this
                       value will be treated as a number of seconds).
        :param project_id: Specify the project_id if current context
                           is admin and admin wants to impact on
                           common user's tenant.
        """

        # Set up the reservation expiration
        if expire is None:
            expire = CONF.quota.reservation_expire
        if isinstance(expire, six.integer_types):
            expire = datetime.timedelta(seconds=expire)
        if isinstance(expire, datetime.timedelta):
            expire = timeutils.utcnow() + expire
        if not isinstance(expire, datetime.datetime):
            raise exception.InvalidReservationExpiration(expire=expire)

        # If project_id is None, then we use the project_id in context
        if project_id is None:
            project_id = context.tenant

        # Get the applicable quotas.
        quotas = self._get_quotas(context,
                                  resources,
                                  deltas.keys(),
                                  has_sync=True,
                                  project_id=project_id)

        return self._reserve(context, resources, quotas, deltas, expire,
                             project_id)

    def _reserve(self, context, resources, quotas, deltas, expire, project_id):
        return self.dbapi.quota_reserve(context, resources, quotas, deltas,
                                        expire, CONF.quota.until_refresh,
                                        CONF.quota.max_age, project_id)

    def commit(self, context, reservations, project_id=None):
        """Commit reservations.

        :param context: The request context, for access checks.
        :param reservations: A list of the reservation UUIDs, as
                             returned by the reserve() method.
        :param project_id: Specify the project_id if current context
                           is admin and admin wants to impact on
                           common user's tenant.
        """
        # If project_id is None, then we use the project_id in context
        if project_id is None:
            project_id = context.tenant

        self.dbapi.reservation_commit(context,
                                      reservations,
                                      project_id=project_id)

    def rollback(self, context, reservations, project_id=None):
        """Roll back reservations.

        :param context: The request context, for access checks.
        :param reservations: A list of the reservation UUIDs, as
                             returned by the reserve() method.
        :param project_id: Specify the project_id if current context
                           is admin and admin wants to impact on
                           common user's tenant.
        """
        # If project_id is None, then we use the project_id in context
        if project_id is None:
            project_id = context.tenant

        self.dbapi.reservation_rollback(context,
                                        reservations,
                                        project_id=project_id)

    def expire(self, context):
        """Expire reservations.

        Explores all currently existing reservations and rolls back
        any that have expired.

        :param context: The request context, for access checks.
        """

        self.dbapi.reservation_expire(context)
Beispiel #26
0
class Quota(base.MoganObject, object_base.VersionedObjectDictCompat):
    # Version 1.0: Initial version
    VERSION = '1.0'

    dbapi = dbapi.get_instance()

    fields = {
        'id': object_fields.IntegerField(),
        'project_id': object_fields.UUIDField(nullable=True),
        'resource_name': object_fields.StringField(nullable=True),
        'hard_limit': object_fields.IntegerField(nullable=True),
        'allocated': object_fields.IntegerField(default=0),
    }

    def __init__(self, *args, **kwargs):
        super(Quota, self).__init__(*args, **kwargs)
        self.quota_driver = driver.DriverManager('mogan.quota.backend_driver',
                                                 CONF.quota.quota_driver,
                                                 invoke_on_load=True).driver
        self._resources = {}

    @property
    def resources(self):
        return self._resources

    @staticmethod
    def _from_db_object_list(db_objects, cls, context):
        """Converts a list of database entities to a list of formal objects."""
        return [Quota._from_db_object(cls(context), obj) for obj in db_objects]

    @classmethod
    def list(cls, context, project_only=False):
        """Return a list of Quota objects."""
        db_quotas = cls.dbapi.quota_get_all(context, project_only=project_only)
        return Quota._from_db_object_list(db_quotas, cls, context)

    @classmethod
    def get(cls, context, project_id, resource_name):
        """Find a quota of resource and return a Quota object."""
        db_quota = cls.dbapi.quota_get(context, project_id, resource_name)
        quota = Quota._from_db_object(cls(context), db_quota)
        return quota

    def create(self, context):
        """Create a Quota record in the DB."""
        values = self.obj_get_changes()
        # Since we need to avoid passing False down to the DB layer
        # (which uses an integer), we can always default it to zero here.
        values['deleted'] = 0

        db_quota = self.dbapi.quota_create(context, values)
        self._from_db_object(self, db_quota)

    def destroy(self, context, project_id, resource_name):
        """Delete the Quota from the DB."""
        self.dbapi.quota_destroy(context, project_id, resource_name)
        self.obj_reset_changes()

    def save(self, context, project_id, resource_name):
        """Save updates to this Quota."""
        updates = self.obj_get_changes()
        self.dbapi.quota_update(context, project_id, resource_name, updates)
        self.obj_reset_changes()

    def refresh(self, context, project_id, resource_name):
        """Refresh the object by re-fetching from the DB."""
        current = self.__class__.get(context, project_id, resource_name)
        self.obj_refresh(current)
        self.obj_reset_changes()

    def reserve(self, context, expire=None, project_id=None, **deltas):
        """reserve the Quota."""
        return self.quota_driver.reserve(context,
                                         self.resources,
                                         deltas,
                                         expire=expire,
                                         project_id=project_id)

    def commit(self, context, reservations, project_id=None):
        self.quota_driver.commit(context, reservations, project_id=project_id)

    def rollback(self, context, reservations, project_id=None):
        self.quota_driver.rollback(context,
                                   reservations,
                                   project_id=project_id)

    def expire(self, context):
        return self.quota_driver.expire(context)

    def count(self, context, resource, *args, **kwargs):
        """Count a resource.

        For countable resources, invokes the count() function and
        returns its result.  Arguments following the context and
        resource are passed directly to the count function declared by
        the resource.

        :param context: The request context, for access checks.
        :param resource: The name of the resource, as a string.
        """

        # Get the resource
        res = self.resources.get(resource)
        if not res or not hasattr(res, 'count'):
            raise exception.QuotaResourceUnknown(unknown=[resource])

        return res.count(context, *args, **kwargs)

    def register_resource(self, resource):
        """Register a resource."""

        self._resources[resource.name] = resource

    def register_resources(self, resources):
        """Register a list of resources."""

        for resource in resources:
            self.register_resource(resource)

    def get_quota_limit_and_usage(self, context, resources, project_id):
        return self.quota_driver.get_project_quotas(context,
                                                    resources,
                                                    project_id,
                                                    usages=True)
Beispiel #27
0
 def before(self, state):
     state.request.dbapi = dbapi.get_instance()