barbican/barbican/objects/base.py

206 lines
7.5 KiB
Python

# Copyright 2018 Fujitsu.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
"""Barbican common internal objects model"""
from oslo_versionedobjects import base as object_base
from barbican.model import repositories as repos
from barbican.objects import fields
class States(object):
PENDING = 'PENDING'
ACTIVE = 'ACTIVE'
ERROR = 'ERROR'
@classmethod
def is_valid(cls, state_to_test):
"""Tests if a state is a valid one."""
return state_to_test in cls.__dict__
class BarbicanPersistentObject(object):
fields = {
'id': fields.StringField(nullable=True, default=None),
'created_at': fields.DateTimeField(nullable=True, tzinfo_aware=False),
'updated_at': fields.DateTimeField(nullable=True, tzinfo_aware=False),
'deleted_at': fields.DateTimeField(nullable=True, tzinfo_aware=False),
'deleted': fields.BooleanField(nullable=True),
'status': fields.StringField(nullable=True, default=States.PENDING)
}
class BarbicanObject(object_base.VersionedObject):
# Version 1.0: Initial version
VERSION = '1.0'
OBJ_PROJECT_NAMESPACE = 'barbican'
synthetic_fields = []
# NOTE(namnh): The db_model, db_repo class variable should be inherited
# by sub-classes.
# For example, in the Secret object has to have "db_model = models.Secret"
# and "db_repo = repo.get_secret_repository()".
db_model = None
db_repo = repos.BaseRepo()
def __init__(self, context=None, **kwargs):
super(BarbicanObject, self).__init__(context=context, **kwargs)
self.dict_fields = None
self.obj_set_defaults()
def set_attribute(self, name_attr, value_attr=None):
setattr(self, name_attr, value_attr)
def _get_db_entity(self):
return self.db_model()
def _get_changed_persistent_fields(self):
change_fields = self.obj_get_changes()
for field in self.synthetic_fields:
if field in change_fields:
del change_fields[field]
return change_fields
def _validate_fields(self, change_fields):
"""Validate fields before creating model
In order to verify fields before saving a model to database. It should
be inherited by sub-class in case the class need to verify.
"""
pass
def _from_db_object(self, db_entity):
if db_entity is None:
return None
for field in self.fields:
if field not in self.synthetic_fields:
self.set_attribute(field, db_entity[field])
self.load_synthetic_db_fields(db_entity=db_entity)
self.dict_fields = db_entity.to_dict_fields()
self.obj_reset_changes()
return self
def to_dict_fields(self):
return self.dict_fields
def register_value(self, data=None, **kwargs):
data = data or dict()
data.update(kwargs)
for key, value in data.items():
setattr(self, key, value)
@classmethod
def is_synthetic(cls, field):
return field in cls.synthetic_fields
@classmethod
def load_object(cls, db_entity):
obj = cls()
obj._from_db_object(db_entity=db_entity)
return obj
def load_synthetic_db_fields(self, db_entity):
"""Load synthetic database field.
:param db_entity: Database model
:return: None
"""
for field in self.synthetic_fields:
objclasses = object_base.VersionedObjectRegistry.obj_classes(
).get(self.fields[field].objname)
objclass = objclasses[0]
synth_db_objs = db_entity.get(field, None)
# NOTE(namnh): synth_db_objs can be list, dict, empty list
if isinstance(self.fields[field], fields.DictOfObjectsField):
dict_entity_object = {key: objclass.load_object(value)
for key, value in synth_db_objs.items()}
setattr(self, field, dict_entity_object)
elif isinstance(self.fields[field], fields.ListOfObjectsField):
entities_object = [objclass.load_object(entity)
for entity in synth_db_objs]
setattr(self, field, entities_object)
else:
# At this moment, this field is an ObjectField.
entity_object = objclass.load_object(synth_db_objs)
setattr(self, field, entity_object)
self.obj_reset_changes([fields])
def create(self, session=None):
change_fields = self._get_changed_persistent_fields()
self._validate_fields(change_fields)
db_entity = self._get_db_entity()
db_entity.update(change_fields)
db_entity = self.db_repo.create_from(db_entity, session=session)
self._from_db_object(db_entity)
def save(self, session=None):
"""To update new values to a row in database."""
change_fields = self._get_changed_persistent_fields()
self.db_repo.update_from(self.db_model, self.id,
change_fields, session=session)
self.obj_reset_changes()
def delete(self, session):
raise NotImplementedError()
@classmethod
def get(cls, entity_id, external_project_id=None,
force_show_deleted=False,
suppress_exception=False, session=None):
"""Get an entity or raise if it does not exist"""
db_entity = cls.db_repo.get(
entity_id, external_project_id=external_project_id,
force_show_deleted=force_show_deleted,
suppress_exception=suppress_exception, session=session)
if db_entity:
return cls()._from_db_object(db_entity)
else:
return None
@classmethod
def get_session(cls, session=None):
return cls.db_repo.get_session(session)
@classmethod
def delete_entity_by_id(cls, entity_id, external_project_id,
session=None):
cls.db_repo.delete_entity_by_id(
entity_id, external_project_id, session=session)
@classmethod
def get_project_entities(cls, project_id, session=None):
"""Gets entities associated with a given project."""
entities_db = cls.db_repo.get_project_entities(project_id,
session=session)
entities_object = [cls()._from_db_object(entity_db)
for entity_db in entities_db] if entities_db else []
return entities_object
@classmethod
def get_count(cls, project_id, session=None):
"""Gets count of entities associated with a given project"""
return cls.db_repo.get_count(project_id, session=session)
@classmethod
def delete_project_entities(cls, project_id,
suppress_exception=False,
session=None):
"""Deletes entities for a given project."""
cls.db_repo.delete_project_entities(
project_id, suppress_exception=suppress_exception, session=session)