Add order plugin metadata entity and logic
To support certificate plugin workflows, plugins needs a means to persist their state in between method invocations by Barbican core. This CR adds that persistence feature, by adding a new SQLAlchemy model and migration file, and a new repository. Change-Id: Ic0f74d49ab8c97e5b15c61fbc8c64d00bd9c8b5e Implements: blueprint add-ssl-ca-support
This commit is contained in:
parent
b293d11c56
commit
78dfbc6463
@ -0,0 +1,39 @@
|
||||
"""Add orders plugin metadata table and relationships
|
||||
|
||||
Revision ID: 4070806f6972
|
||||
Revises: 47b69e523451
|
||||
Create Date: 2014-08-21 14:06:48.237701
|
||||
|
||||
"""
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = '4070806f6972'
|
||||
down_revision = '47b69e523451'
|
||||
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
|
||||
|
||||
def upgrade():
|
||||
ctx = op.get_context()
|
||||
con = op.get_bind()
|
||||
table_exists = ctx.dialect.has_table(con.engine, 'order_plugin_metadata')
|
||||
if not table_exists:
|
||||
op.create_table(
|
||||
'order_plugin_metadata',
|
||||
sa.Column('id', sa.String(length=36), nullable=False),
|
||||
sa.Column('created_at', sa.DateTime(), nullable=False),
|
||||
sa.Column('updated_at', sa.DateTime(), nullable=False),
|
||||
sa.Column('deleted_at', sa.DateTime(), nullable=True),
|
||||
sa.Column('deleted', sa.Boolean(), nullable=False),
|
||||
sa.Column('status', sa.String(length=20), nullable=False),
|
||||
sa.Column('order_id', sa.String(length=36), nullable=False),
|
||||
sa.Column('key', sa.String(length=255), nullable=False),
|
||||
sa.Column('value', sa.String(length=255), nullable=False),
|
||||
sa.ForeignKeyConstraint(['order_id'], ['orders.id'],),
|
||||
sa.PrimaryKeyConstraint('id'),
|
||||
)
|
||||
|
||||
|
||||
def downgrade():
|
||||
op.drop_table('order_plugin_metadata')
|
@ -43,10 +43,9 @@ CONF.register_opts(db_opts)
|
||||
def init_config(sql_url=None):
|
||||
"""Initialize and return the Alembic configuration."""
|
||||
sqlalchemy_url = sql_url or CONF.sql_connection
|
||||
if 'sqlite' in sqlalchemy_url:
|
||||
LOG.warn('!!! No support for migrating sqlite databases...'
|
||||
'skipping migration processing !!!')
|
||||
return None
|
||||
if sqlalchemy_url and 'sqlite' in sqlalchemy_url:
|
||||
LOG.warn('!!! Limited support for migration commands using sqlite'
|
||||
' databases; This operation may not succeed.')
|
||||
|
||||
config = alembic_config.Config(
|
||||
os.path.join(os.path.dirname(__file__), 'alembic.ini')
|
||||
|
@ -268,11 +268,11 @@ class Secret(BASE, ModelBase):
|
||||
# Eager load this relationship via 'lazy=False'.
|
||||
encrypted_data = orm.relationship("EncryptedDatum", lazy=False)
|
||||
|
||||
secret_store_metadata = orm.\
|
||||
relationship("SecretStoreMetadatum",
|
||||
collection_class=col.attribute_mapped_collection('key'),
|
||||
backref="secret",
|
||||
cascade="all, delete-orphan")
|
||||
secret_store_metadata = orm.relationship(
|
||||
"SecretStoreMetadatum",
|
||||
collection_class=col.attribute_mapped_collection('key'),
|
||||
backref="secret",
|
||||
cascade="all, delete-orphan")
|
||||
|
||||
def __init__(self, parsed_request=None):
|
||||
"""Creates secret from a dict."""
|
||||
@ -453,6 +453,17 @@ class Order(BASE, ModelBase):
|
||||
container_id = sa.Column(sa.String(36), sa.ForeignKey('containers.id'),
|
||||
nullable=True)
|
||||
|
||||
order_plugin_metadata = orm.relationship(
|
||||
"OrderPluginMetadatum",
|
||||
collection_class=col.attribute_mapped_collection('key'),
|
||||
backref="order",
|
||||
cascade="all, delete-orphan")
|
||||
|
||||
def _do_delete_children(self, session):
|
||||
"""Sub-class hook: delete children relationships."""
|
||||
for k, v in self.order_plugin_metadata.items():
|
||||
v.delete(session)
|
||||
|
||||
def _do_extra_dict_fields(self):
|
||||
"""Sub-class hook method: return dict of fields."""
|
||||
ret = {'secret': {'name': self.secret_name or self.secret_id,
|
||||
@ -478,6 +489,40 @@ class Order(BASE, ModelBase):
|
||||
return ret
|
||||
|
||||
|
||||
class OrderPluginMetadatum(BASE, ModelBase):
|
||||
"""Represents Order plugin metadatum for a single key-value pair.
|
||||
|
||||
This entity is used to store plugin-specific metadata on behalf of an
|
||||
Order instance.
|
||||
"""
|
||||
|
||||
__tablename__ = "order_plugin_metadata"
|
||||
|
||||
order_id = sa.Column(sa.String(36), sa.ForeignKey('orders.id'),
|
||||
nullable=False)
|
||||
key = sa.Column(sa.String(255), nullable=False)
|
||||
value = sa.Column(sa.String(255), nullable=False)
|
||||
|
||||
def __init__(self, key, value):
|
||||
super(OrderPluginMetadatum, self).__init__()
|
||||
|
||||
msg = ("Must supply non-None {0} argument "
|
||||
"for OrderPluginMetadatum entry.")
|
||||
|
||||
if key is None:
|
||||
raise exception.MissingArgumentError(msg.format("key"))
|
||||
self.key = key
|
||||
|
||||
if value is None:
|
||||
raise exception.MissingArgumentError(msg.format("value"))
|
||||
self.value = value
|
||||
|
||||
def _do_extra_dict_fields(self):
|
||||
"""Sub-class hook method: return dict of fields."""
|
||||
return {'key': self.key,
|
||||
'value': self.value}
|
||||
|
||||
|
||||
class Container(BASE, ModelBase):
|
||||
"""Represents a Container for Secrets in the datastore.
|
||||
|
||||
@ -622,7 +667,7 @@ class TransportKey(BASE, ModelBase):
|
||||
# Keep this tuple synchronized with the models in the file
|
||||
MODELS = [TenantSecret, Tenant, Secret, EncryptedDatum, Order, Container,
|
||||
ContainerConsumerMetadatum, ContainerSecret, TransportKey,
|
||||
SecretStoreMetadatum, KEKDatum]
|
||||
SecretStoreMetadatum, OrderPluginMetadatum, KEKDatum]
|
||||
|
||||
|
||||
def register_models(engine):
|
||||
|
@ -264,6 +264,8 @@ class Repositories(object):
|
||||
self._set_repo('secret_meta_repo', SecretStoreMetadatumRepo,
|
||||
kwargs)
|
||||
self._set_repo('order_repo', OrderRepo, kwargs)
|
||||
self._set_repo('order_plugin_meta_repo', OrderPluginMetadatumRepo,
|
||||
kwargs)
|
||||
self._set_repo('transport_key_repo', TransportKeyRepo, kwargs)
|
||||
|
||||
def _set_repo(self, repo_name, repo_cls, specs):
|
||||
@ -803,6 +805,42 @@ class OrderRepo(BaseRepo):
|
||||
pass
|
||||
|
||||
|
||||
class OrderPluginMetadatumRepo(BaseRepo):
|
||||
"""Repository for the OrderPluginMetadatum entity (that stores key/value
|
||||
plugin information on behalf of a Order).
|
||||
"""
|
||||
|
||||
def save(self, metadata, order_model):
|
||||
"""Saves the the specified metadata for the order.
|
||||
|
||||
:raises NotFound if entity does not exist.
|
||||
"""
|
||||
now = timeutils.utcnow()
|
||||
session = get_session()
|
||||
with session.begin():
|
||||
for k, v in metadata.items():
|
||||
meta_model = models.OrderPluginMetadatum(k, v)
|
||||
meta_model.updated_at = now
|
||||
meta_model.order = order_model
|
||||
meta_model.save(session=session)
|
||||
|
||||
def _do_entity_name(self):
|
||||
"""Sub-class hook: return entity name, such as for debugging."""
|
||||
return "OrderPluginMetadatum"
|
||||
|
||||
def _do_create_instance(self):
|
||||
return models.OrderPluginMetadatum()
|
||||
|
||||
def _do_build_get_query(self, entity_id, keystone_id, session):
|
||||
"""Sub-class hook: build a retrieve query."""
|
||||
query = session.query(models.OrderPluginMetadatum)
|
||||
return query.filter_by(id=entity_id)
|
||||
|
||||
def _do_validate(self, values):
|
||||
"""Sub-class hook: validate values."""
|
||||
pass
|
||||
|
||||
|
||||
class ContainerRepo(BaseRepo):
|
||||
"""Repository for the Container entity."""
|
||||
|
||||
|
@ -53,7 +53,7 @@ def issue_certificate_request(order_model, repos):
|
||||
def _get_plugin_meta(order_model):
|
||||
if order_model:
|
||||
meta_dict = dict((k, v.value) for (k, v) in
|
||||
order_model.order_plugin_meta.items())
|
||||
order_model.order_plugin_metadata.items())
|
||||
return meta_dict
|
||||
else:
|
||||
return dict()
|
||||
|
@ -97,8 +97,11 @@ def main():
|
||||
LOG = log.getLogger(__name__)
|
||||
LOG.debug("Performing database schema migration...")
|
||||
|
||||
dm = DatabaseManager()
|
||||
dm.execute()
|
||||
try:
|
||||
dm = DatabaseManager()
|
||||
dm.execute()
|
||||
except:
|
||||
LOG.exception('Problem trying to execute Alembic commands')
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
Loading…
Reference in New Issue
Block a user