Added X509KeyPair object and data model.
This patch adds backend object and data model to handle x509keypair related operations. Partially-Implements: bp secure-kubernetes Change-Id: I862dcdd10d28b3d5e5f972c7c23bdab6c188a04d
This commit is contained in:
parent
9747777f62
commit
09d8ef4e04
|
@ -462,3 +462,11 @@ class KubernetesAPIFailed(MagnumException):
|
|||
def __init__(self, message=None, **kwargs):
|
||||
self.__class__.code = kwargs.get('code')
|
||||
super(KubernetesAPIFailed, self).__init__(message, **kwargs)
|
||||
|
||||
|
||||
class X509KeyPairNotFound(ResourceNotFound):
|
||||
message = _("A key pair %(keypair)s could not be found.")
|
||||
|
||||
|
||||
class X509KeyPairAlreadyExists(Conflict):
|
||||
message = _("A key pair with UUID %(uuid)s already exists.")
|
||||
|
|
|
@ -659,3 +659,86 @@ class Connection(object):
|
|||
:param rc_id: The id or uuid of a ReplicationController.
|
||||
:returns: A ReplicationController.
|
||||
"""
|
||||
|
||||
@abc.abstractmethod
|
||||
def create_x509keypair(self, values):
|
||||
"""Create a new x509keypair.
|
||||
|
||||
:param values: A dict containing several items used to identify
|
||||
and track the x509keypair, and several dicts which
|
||||
are passed into the Drivers when managing this
|
||||
x509keypair. For example:
|
||||
|
||||
::
|
||||
|
||||
{
|
||||
'uuid': utils.generate_uuid(),
|
||||
'name': 'example',
|
||||
'ca_cert': 'AAA...',
|
||||
'certificate': 'BBB...',
|
||||
'private_key': 'CCC...',
|
||||
}
|
||||
:returns: A X509KeyPair.
|
||||
"""
|
||||
|
||||
@abc.abstractmethod
|
||||
def get_x509keypair_by_id(self, context, x509keypair_id):
|
||||
"""Return a x509keypair.
|
||||
|
||||
:param context: The security context
|
||||
:param x509keypair_id: The id of a x509keypair.
|
||||
:returns: A x509keypair.
|
||||
"""
|
||||
|
||||
@abc.abstractmethod
|
||||
def get_x509keypair_by_uuid(self, context, x509keypair_uuid):
|
||||
"""Return a x509keypair.
|
||||
|
||||
:param context: The security context
|
||||
:param x509keypair_uuid: The uuid of a x509keypair.
|
||||
:returns: A x509keypair.
|
||||
"""
|
||||
|
||||
@abc.abstractmethod
|
||||
def get_x509keypair_by_name(self, context, x509keypair_name):
|
||||
"""Return a x509keypair.
|
||||
|
||||
:param context: The security context
|
||||
:param x509keypair_name: The name of a x509keypair.
|
||||
:returns: A x509keypair.
|
||||
"""
|
||||
|
||||
@abc.abstractmethod
|
||||
def destroy_x509keypair(self, x509keypair_id):
|
||||
"""Destroy a x509keypair.
|
||||
|
||||
:param x509keypair_id: The id or uuid of a x509keypair.
|
||||
"""
|
||||
|
||||
@abc.abstractmethod
|
||||
def update_x509keypair(self, x509keypair_id, values):
|
||||
"""Update properties of a X509KeyPair.
|
||||
|
||||
:param x509keypair_id: The id or uuid of a X509KeyPair.
|
||||
:returns: A X509KeyPair.
|
||||
"""
|
||||
|
||||
@abc.abstractmethod
|
||||
def get_x509keypair_list(self, context, filters=None, limit=None,
|
||||
marker=None, sort_key=None, sort_dir=None):
|
||||
"""Get matching x509keypairs.
|
||||
|
||||
Return a list of the specified columns for all x509keypairs
|
||||
that match the specified filters.
|
||||
|
||||
:param context: The security context
|
||||
:param filters: Filters to apply. Defaults to None.
|
||||
|
||||
:param limit: Maximum number of x509keypairs to return.
|
||||
:param marker: the last item of the previous page; we return the next
|
||||
result set.
|
||||
:param sort_key: Attribute by which results should be sorted.
|
||||
:param sort_dir: direction in which results should be sorted.
|
||||
(asc, desc)
|
||||
:returns: A list of tuples of the specified columns.
|
||||
"""
|
||||
|
|
|
@ -0,0 +1,50 @@
|
|||
# Copyright 2015 NEC Corporation. All rights reserved.
|
||||
#
|
||||
# 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.
|
||||
|
||||
"""create x509keypair table
|
||||
|
||||
Revision ID: 421102d1f2d2
|
||||
Revises: 14328d6a57e3
|
||||
Create Date: 2015-07-17 13:12:12.653241
|
||||
|
||||
"""
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = '421102d1f2d2'
|
||||
down_revision = '14328d6a57e3'
|
||||
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
|
||||
|
||||
def upgrade():
|
||||
op.create_table(
|
||||
'x509keypair',
|
||||
sa.Column('id', sa.Integer(), nullable=False),
|
||||
sa.Column('created_at', sa.DateTime(), nullable=True),
|
||||
sa.Column('updated_at', sa.DateTime(), nullable=True),
|
||||
sa.Column('name', sa.String(length=255), nullable=True),
|
||||
sa.Column('uuid', sa.String(length=36), nullable=True),
|
||||
sa.Column('bay_uuid', sa.String(length=36), nullable=True),
|
||||
sa.Column('ca_cert', sa.Text()),
|
||||
sa.Column('certificate', sa.Text()),
|
||||
sa.Column('private_key', sa.Text()),
|
||||
sa.Column('project_id', sa.String(length=255), nullable=True),
|
||||
sa.Column('user_id', sa.String(length=255), nullable=True),
|
||||
sa.PrimaryKeyConstraint('id'),
|
||||
mysql_ENGINE='InnoDB',
|
||||
mysql_DEFAULT_CHARSET='UTF8'
|
||||
)
|
||||
op.create_unique_constraint("uniq_x509keypair0uuid",
|
||||
"x509keypair", ["uuid"])
|
|
@ -933,3 +933,106 @@ class Connection(api.Connection):
|
|||
|
||||
ref.update(values)
|
||||
return ref
|
||||
|
||||
def create_x509keypair(self, values):
|
||||
# ensure defaults are present for new x509keypairs
|
||||
if not values.get('uuid'):
|
||||
values['uuid'] = utils.generate_uuid()
|
||||
|
||||
x509keypair = models.X509KeyPair()
|
||||
x509keypair.update(values)
|
||||
try:
|
||||
x509keypair.save()
|
||||
except db_exc.DBDuplicateEntry:
|
||||
raise exception.X509KeyPairAlreadyExists(uuid=values['uuid'])
|
||||
return x509keypair
|
||||
|
||||
def get_x509keypair_by_id(self, context, x509keypair_id):
|
||||
query = model_query(models.X509KeyPair)
|
||||
query = self._add_tenant_filters(context, query)
|
||||
query = query.filter_by(id=x509keypair_id)
|
||||
try:
|
||||
return query.one()
|
||||
except NoResultFound:
|
||||
raise exception.X509KeyPairNotFound(x509keypair=x509keypair_id)
|
||||
|
||||
def get_x509keypair_by_name(self, context, x509keypair_name):
|
||||
query = model_query(models.X509KeyPair)
|
||||
query = self._add_tenant_filters(context, query)
|
||||
query = query.filter_by(name=x509keypair_name)
|
||||
try:
|
||||
return query.one()
|
||||
except MultipleResultsFound:
|
||||
raise exception.Conflict('Multiple x509keypairs exist with '
|
||||
'same name. Please use the x509keypair '
|
||||
'uuid instead.')
|
||||
except NoResultFound:
|
||||
raise exception.X509KeyPairNotFound(x509keypair=x509keypair_name)
|
||||
|
||||
def get_x509keypair_by_uuid(self, context, x509keypair_uuid):
|
||||
query = model_query(models.X509KeyPair)
|
||||
query = self._add_tenant_filters(context, query)
|
||||
query = query.filter_by(uuid=x509keypair_uuid)
|
||||
try:
|
||||
return query.one()
|
||||
except NoResultFound:
|
||||
raise exception.X509KeyPairNotFound(x509keypair=x509keypair_uuid)
|
||||
|
||||
def destroy_x509keypair(self, x509keypair_id):
|
||||
session = get_session()
|
||||
with session.begin():
|
||||
query = model_query(models.X509KeyPair, session=session)
|
||||
query = add_identity_filter(query, x509keypair_id)
|
||||
count = query.delete()
|
||||
if count != 1:
|
||||
raise exception.X509KeyPairNotFound(x509keypair_id)
|
||||
|
||||
def update_x509keypair(self, x509keypair_id, values):
|
||||
# NOTE(dtantsur): this can lead to very strange errors
|
||||
if 'uuid' in values:
|
||||
msg = _("Cannot overwrite UUID for an existing X509KeyPair.")
|
||||
raise exception.InvalidParameterValue(err=msg)
|
||||
|
||||
return self._do_update_x509keypair(x509keypair_id, values)
|
||||
|
||||
def _do_update_x509keypair(self, x509keypair_id, values):
|
||||
session = get_session()
|
||||
with session.begin():
|
||||
query = model_query(models.X509KeyPair, session=session)
|
||||
query = add_identity_filter(query, x509keypair_id)
|
||||
try:
|
||||
ref = query.with_lockmode('update').one()
|
||||
except NoResultFound:
|
||||
raise exception.X509KeyPairNotFound(x509keypair=x509keypair_id)
|
||||
|
||||
if 'provision_state' in values:
|
||||
values['provision_updated_at'] = timeutils.utcnow()
|
||||
|
||||
ref.update(values)
|
||||
return ref
|
||||
|
||||
def _add_x509keypairs_filters(self, query, filters):
|
||||
if filters is None:
|
||||
filters = []
|
||||
|
||||
if 'bay_uuid' in filters:
|
||||
query = query.filter_by(bay_uuid=filters['bay_uuid'])
|
||||
if 'name' in filters:
|
||||
query = query.filter_by(name=filters['name'])
|
||||
if 'project_id' in filters:
|
||||
query = query.filter_by(project_id=filters['project_id'])
|
||||
if 'user_id' in filters:
|
||||
query = query.filter_by(user_id=filters['user_id'])
|
||||
|
||||
return query
|
||||
|
||||
def get_x509keypair_list(self, context, filters=None, limit=None,
|
||||
marker=None, sort_key=None, sort_dir=None,
|
||||
opts=None):
|
||||
if opts is None:
|
||||
opts = {}
|
||||
query = model_query(models.X509KeyPair)
|
||||
query = self._add_tenant_filters(context, query, opts=opts)
|
||||
query = self._add_x509keypairs_filters(query, filters)
|
||||
return _paginate_query(models.X509KeyPair, limit, marker,
|
||||
sort_key, sort_dir, query)
|
||||
|
|
|
@ -271,3 +271,22 @@ class ReplicationController(Base):
|
|||
replicas = Column(Integer())
|
||||
project_id = Column(String(255))
|
||||
user_id = Column(String(255))
|
||||
|
||||
|
||||
class X509KeyPair(Base):
|
||||
"""X509KeyPair"""
|
||||
__tablename__ = 'x509keypair'
|
||||
__table_args__ = (
|
||||
schema.UniqueConstraint('uuid',
|
||||
name='uniq_x509keypair0uuid'),
|
||||
table_args()
|
||||
)
|
||||
id = Column(Integer, primary_key=True)
|
||||
uuid = Column(String(36))
|
||||
name = Column(String(255))
|
||||
bay_uuid = Column(String(36))
|
||||
ca_cert = Column(Text())
|
||||
certificate = Column(Text())
|
||||
private_key = Column(Text())
|
||||
project_id = Column(String(255))
|
||||
user_id = Column(String(255))
|
||||
|
|
|
@ -20,6 +20,7 @@ from magnum.objects import node
|
|||
from magnum.objects import pod
|
||||
from magnum.objects import replicationcontroller as rc
|
||||
from magnum.objects import service
|
||||
from magnum.objects import x509keypair
|
||||
|
||||
|
||||
Container = container.Container
|
||||
|
@ -30,6 +31,7 @@ Node = node.Node
|
|||
Pod = pod.Pod
|
||||
ReplicationController = rc.ReplicationController
|
||||
Service = service.Service
|
||||
X509KeyPair = x509keypair.X509KeyPair
|
||||
|
||||
__all__ = (Bay,
|
||||
BayLock,
|
||||
|
@ -38,4 +40,5 @@ __all__ = (Bay,
|
|||
Node,
|
||||
Pod,
|
||||
ReplicationController,
|
||||
Service)
|
||||
Service,
|
||||
X509KeyPair)
|
||||
|
|
|
@ -0,0 +1,228 @@
|
|||
# coding=utf-8
|
||||
#
|
||||
#
|
||||
# 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.
|
||||
|
||||
from oslo_versionedobjects import fields
|
||||
|
||||
from magnum.common import exception
|
||||
from magnum.common import utils
|
||||
from magnum.db import api as dbapi
|
||||
from magnum.objects import base
|
||||
|
||||
|
||||
@base.MagnumObjectRegistry.register
|
||||
class X509KeyPair(base.MagnumPersistentObject, base.MagnumObject,
|
||||
base.MagnumObjectDictCompat):
|
||||
# Version 1.0: Initial version
|
||||
VERSION = '1.0'
|
||||
|
||||
dbapi = dbapi.get_instance()
|
||||
|
||||
fields = {
|
||||
'id': fields.IntegerField(),
|
||||
'uuid': fields.UUIDField(nullable=True),
|
||||
'name': fields.StringField(nullable=True),
|
||||
'bay_uuid': fields.StringField(nullable=True),
|
||||
'ca_cert': fields.StringField(nullable=True),
|
||||
'certificate': fields.StringField(nullable=True),
|
||||
'private_key': fields.StringField(nullable=True),
|
||||
'project_id': fields.StringField(nullable=True),
|
||||
'user_id': fields.StringField(nullable=True),
|
||||
}
|
||||
|
||||
@staticmethod
|
||||
def _from_db_object(x509keypair, db_x509keypair):
|
||||
"""Converts a database entity to a formal object."""
|
||||
for field in x509keypair.fields:
|
||||
x509keypair[field] = db_x509keypair[field]
|
||||
|
||||
x509keypair.obj_reset_changes()
|
||||
return x509keypair
|
||||
|
||||
@staticmethod
|
||||
def _from_db_object_list(db_objects, cls, context):
|
||||
"""Converts a list of database entities to a list of formal objects."""
|
||||
return [X509KeyPair._from_db_object(cls(context), obj)
|
||||
for obj in db_objects]
|
||||
|
||||
@base.remotable_classmethod
|
||||
def get(cls, context, x509keypair_id):
|
||||
"""Find a x509keypair_id based on its id or uuid and return a
|
||||
X509KeyPair object.
|
||||
|
||||
:param x509keypair_id: the id *or* uuid of a x509keypair.
|
||||
:returns: a :class:`X509KeyPair` object.
|
||||
"""
|
||||
if utils.is_int_like(x509keypair_id):
|
||||
return cls.get_by_id(context, x509keypair_id)
|
||||
elif utils.is_uuid_like(x509keypair_id):
|
||||
return cls.get_by_uuid(context, x509keypair_id)
|
||||
else:
|
||||
raise exception.InvalidIdentity(identity=x509keypair_id)
|
||||
|
||||
@base.remotable_classmethod
|
||||
def get_by_id(cls, context, x509keypair_id):
|
||||
"""Find a x509keypair based on its integer id and return a
|
||||
X509KeyPair object.
|
||||
|
||||
:param x509keypair_id: the id of a x509keypair.
|
||||
:returns: a :class:`X509KeyPair` object.
|
||||
"""
|
||||
db_x509keypair = cls.dbapi.get_x509keypair_by_id(context,
|
||||
x509keypair_id)
|
||||
x509keypair = X509KeyPair._from_db_object(cls(context), db_x509keypair)
|
||||
return x509keypair
|
||||
|
||||
@base.remotable_classmethod
|
||||
def get_by_uuid(cls, context, uuid):
|
||||
"""Find a x509keypair based on uuid and return a :class:`X509KeyPair` object.
|
||||
|
||||
:param uuid: the uuid of a x509keypair.
|
||||
:param context: Security context
|
||||
:returns: a :class:`X509KeyPair` object.
|
||||
"""
|
||||
db_x509keypair = cls.dbapi.get_x509keypair_by_uuid(context, uuid)
|
||||
x509keypair = X509KeyPair._from_db_object(cls(context), db_x509keypair)
|
||||
return x509keypair
|
||||
|
||||
@base.remotable_classmethod
|
||||
def get_by_name(cls, context, name):
|
||||
"""Find a x509keypair based on name and return a X509KeyPair object.
|
||||
|
||||
:param name: the logical name of a x509keypair.
|
||||
:param context: Security context
|
||||
:returns: a :class:`X509KeyPair` object.
|
||||
"""
|
||||
db_x509keypair = cls.dbapi.get_x509keypair_by_name(context, name)
|
||||
x509keypair = X509KeyPair._from_db_object(cls(context), db_x509keypair)
|
||||
return x509keypair
|
||||
|
||||
@base.remotable_classmethod
|
||||
def list(cls, context, limit=None, marker=None,
|
||||
sort_key=None, sort_dir=None, filters=None):
|
||||
"""Return a list of X509KeyPair objects.
|
||||
|
||||
:param context: Security context.
|
||||
:param limit: maximum number of resources to return in a single result.
|
||||
:param marker: pagination marker for large data sets.
|
||||
:param sort_key: column to sort results by.
|
||||
:param sort_dir: direction to sort. "asc" or "desc".
|
||||
:param filters: filter dict, can include 'x509keypairmodel_id', 'name',
|
||||
'node_count', 'stack_id', 'api_address',
|
||||
'node_addresses', 'project_id', 'user_id',
|
||||
'status'(should be a status list).
|
||||
:returns: a list of :class:`X509KeyPair` object.
|
||||
|
||||
"""
|
||||
db_x509keypairs = cls.dbapi.get_x509keypair_list(context, limit=limit,
|
||||
marker=marker,
|
||||
sort_key=sort_key,
|
||||
sort_dir=sort_dir,
|
||||
filters=filters)
|
||||
return X509KeyPair._from_db_object_list(db_x509keypairs, cls, context)
|
||||
|
||||
@base.remotable_classmethod
|
||||
def list_all(cls, context, limit=None, marker=None,
|
||||
sort_key=None, sort_dir=None, filters=None):
|
||||
"""Return all tenants of X509KeyPair objects.
|
||||
|
||||
:param context: Security context, should be an admin context.
|
||||
:param limit: maximum number of resources to return in a single result.
|
||||
:param marker: pagination marker for large data sets.
|
||||
:param sort_key: column to sort results by.
|
||||
:param sort_dir: direction to sort. "asc" or "desc".
|
||||
:param filters: filter dict, can include 'x509keypairmodel_id', 'name',
|
||||
'node_count', 'stack_id', 'api_address',
|
||||
'node_addresses', 'project_id', 'user_id',
|
||||
'status'(should be a status list).
|
||||
:returns: a list of :class:`X509KeyPair` object.
|
||||
|
||||
"""
|
||||
db_x509keypairs = cls.dbapi.get_x509keypair_list(
|
||||
context, limit=limit,
|
||||
marker=marker,
|
||||
sort_key=sort_key,
|
||||
sort_dir=sort_dir,
|
||||
filters=filters,
|
||||
opts={'get_all_tenants': True})
|
||||
return X509KeyPair._from_db_object_list(db_x509keypairs, cls, context)
|
||||
|
||||
@base.remotable
|
||||
def create(self, context=None):
|
||||
"""Create a X509KeyPair record in the DB.
|
||||
|
||||
:param context: Security context. NOTE: This should only
|
||||
be used internally by the indirection_api.
|
||||
Unfortunately, RPC requires context as the first
|
||||
argument, even though we don't use it.
|
||||
A context should be set when instantiating the
|
||||
object, e.g.: X509KeyPair(context)
|
||||
|
||||
"""
|
||||
values = self.obj_get_changes()
|
||||
db_x509keypair = self.dbapi.create_x509keypair(values)
|
||||
self._from_db_object(self, db_x509keypair)
|
||||
|
||||
@base.remotable
|
||||
def destroy(self, context=None):
|
||||
"""Delete the X509KeyPair from the DB.
|
||||
|
||||
:param context: Security context. NOTE: This should only
|
||||
be used internally by the indirection_api.
|
||||
Unfortunately, RPC requires context as the first
|
||||
argument, even though we don't use it.
|
||||
A context should be set when instantiating the
|
||||
object, e.g.: X509KeyPair(context)
|
||||
"""
|
||||
self.dbapi.destroy_x509keypair(self.uuid)
|
||||
self.obj_reset_changes()
|
||||
|
||||
@base.remotable
|
||||
def save(self, context=None):
|
||||
"""Save updates to this X509KeyPair.
|
||||
|
||||
Updates will be made column by column based on the result
|
||||
of self.what_changed().
|
||||
|
||||
:param context: Security context. NOTE: This should only
|
||||
be used internally by the indirection_api.
|
||||
Unfortunately, RPC requires context as the first
|
||||
argument, even though we don't use it.
|
||||
A context should be set when instantiating the
|
||||
object, e.g.: X509KeyPair(context)
|
||||
"""
|
||||
updates = self.obj_get_changes()
|
||||
self.dbapi.update_x509keypair(self.uuid, updates)
|
||||
|
||||
self.obj_reset_changes()
|
||||
|
||||
@base.remotable
|
||||
def refresh(self, context=None):
|
||||
"""Loads updates for this X509KeyPair.
|
||||
|
||||
Loads a x509keypair with the same uuid from the database and
|
||||
checks for updated attributes. Updates are applied from
|
||||
the loaded x509keypair column by column, if there are any updates.
|
||||
|
||||
:param context: Security context. NOTE: This should only
|
||||
be used internally by the indirection_api.
|
||||
Unfortunately, RPC requires context as the first
|
||||
argument, even though we don't use it.
|
||||
A context should be set when instantiating the
|
||||
object, e.g.: X509KeyPair(context)
|
||||
"""
|
||||
current = self.__class__.get_by_uuid(self._context, uuid=self.uuid)
|
||||
for field in self.fields:
|
||||
if self.obj_attr_is_set(field) and self[field] != current[field]:
|
||||
self[field] = current[field]
|
|
@ -0,0 +1,156 @@
|
|||
# Copyright 2015 NEC Foundation
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# 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.
|
||||
|
||||
"""Tests for manipulating X509KeyPairs via the DB API"""
|
||||
|
||||
import six
|
||||
|
||||
from magnum.common import context
|
||||
from magnum.common import exception
|
||||
from magnum.common import utils as magnum_utils
|
||||
from magnum.tests.unit.db import base
|
||||
from magnum.tests.unit.db import utils
|
||||
|
||||
|
||||
class DbX509KeyPairTestCase(base.DbTestCase):
|
||||
|
||||
def test_create_x509keypair(self):
|
||||
utils.create_test_x509keypair()
|
||||
|
||||
def test_create_x509keypair_nullable_bay_uuid(self):
|
||||
utils.create_test_x509keypair(bay_uuid=None)
|
||||
|
||||
def test_create_x509keypair_already_exists(self):
|
||||
utils.create_test_x509keypair()
|
||||
self.assertRaises(exception.X509KeyPairAlreadyExists,
|
||||
utils.create_test_x509keypair)
|
||||
|
||||
def test_get_x509keypair_by_id(self):
|
||||
x509keypair = utils.create_test_x509keypair()
|
||||
res = self.dbapi.get_x509keypair_by_id(self.context, x509keypair.id)
|
||||
self.assertEqual(x509keypair.id, res.id)
|
||||
self.assertEqual(x509keypair.uuid, res.uuid)
|
||||
|
||||
def test_get_x509keypair_by_name(self):
|
||||
x509keypair = utils.create_test_x509keypair()
|
||||
res = self.dbapi.get_x509keypair_by_name(self.context,
|
||||
x509keypair.name)
|
||||
self.assertEqual(x509keypair.name, res.name)
|
||||
self.assertEqual(x509keypair.uuid, res.uuid)
|
||||
|
||||
def test_get_x509keypair_by_uuid(self):
|
||||
x509keypair = utils.create_test_x509keypair()
|
||||
res = self.dbapi.get_x509keypair_by_uuid(self.context,
|
||||
x509keypair.uuid)
|
||||
self.assertEqual(x509keypair.id, res.id)
|
||||
self.assertEqual(x509keypair.uuid, res.uuid)
|
||||
|
||||
def test_get_x509keypair_that_does_not_exist(self):
|
||||
self.assertRaises(exception.X509KeyPairNotFound,
|
||||
self.dbapi.get_x509keypair_by_id,
|
||||
self.context, 999)
|
||||
self.assertRaises(exception.X509KeyPairNotFound,
|
||||
self.dbapi.get_x509keypair_by_uuid,
|
||||
self.context,
|
||||
'12345678-9999-0000-aaaa-123456789012')
|
||||
|
||||
def test_get_x509keypair_list(self):
|
||||
uuids = []
|
||||
for i in range(1, 6):
|
||||
x509keypair = utils.create_test_x509keypair(
|
||||
uuid=magnum_utils.generate_uuid())
|
||||
uuids.append(six.text_type(x509keypair['uuid']))
|
||||
res = self.dbapi.get_x509keypair_list(self.context)
|
||||
res_uuids = [r.uuid for r in res]
|
||||
self.assertEqual(sorted(uuids), sorted(res_uuids))
|
||||
|
||||
def test_get_x509keypair_list_with_filters(self):
|
||||
bay1 = utils.get_test_bay(id=1, uuid=magnum_utils.generate_uuid())
|
||||
bay2 = utils.get_test_bay(id=2, uuid=magnum_utils.generate_uuid())
|
||||
self.dbapi.create_bay(bay1)
|
||||
self.dbapi.create_bay(bay2)
|
||||
|
||||
x509keypair1 = utils.create_test_x509keypair(
|
||||
name='x509keypair-one',
|
||||
uuid=magnum_utils.generate_uuid(),
|
||||
bay_uuid=bay1['uuid'])
|
||||
x509keypair2 = utils.create_test_x509keypair(
|
||||
name='x509keypair-two',
|
||||
uuid=magnum_utils.generate_uuid(),
|
||||
bay_uuid=bay2['uuid'])
|
||||
x509keypair3 = utils.create_test_x509keypair(
|
||||
name='x509keypair-three',
|
||||
bay_uuid=bay2['uuid'])
|
||||
|
||||
res = self.dbapi.get_x509keypair_list(
|
||||
self.context, filters={'bay_uuid': bay1['uuid']})
|
||||
self.assertEqual([x509keypair1.id], [r.id for r in res])
|
||||
|
||||
res = self.dbapi.get_x509keypair_list(
|
||||
self.context, filters={'bay_uuid': bay2['uuid']})
|
||||
self.assertEqual([x509keypair2.id, x509keypair3.id],
|
||||
[r.id for r in res])
|
||||
|
||||
res = self.dbapi.get_x509keypair_list(
|
||||
self.context, filters={'name': 'x509keypair-one'})
|
||||
self.assertEqual([x509keypair1.id], [r.id for r in res])
|
||||
|
||||
res = self.dbapi.get_x509keypair_list(
|
||||
self.context, filters={'name': 'bad-x509keypair'})
|
||||
self.assertEqual([], [r.id for r in res])
|
||||
|
||||
def test_get_x509keypair_list_by_admin_all_tenants(self):
|
||||
uuids = []
|
||||
for i in range(1, 6):
|
||||
x509keypair = utils.create_test_x509keypair(
|
||||
uuid=magnum_utils.generate_uuid(),
|
||||
project_id=magnum_utils.generate_uuid(),
|
||||
user_id=magnum_utils.generate_uuid())
|
||||
uuids.append(six.text_type(x509keypair['uuid']))
|
||||
ctx = context.make_admin_context()
|
||||
res = self.dbapi.get_x509keypair_list(
|
||||
ctx, opts={'get_all_tenants': True})
|
||||
res_uuids = [r.uuid for r in res]
|
||||
self.assertEqual(sorted(uuids), sorted(res_uuids))
|
||||
|
||||
def test_get_x509keypair_list_bay_not_exist(self):
|
||||
utils.create_test_x509keypair()
|
||||
self.assertEqual(1, len(self.dbapi.get_x509keypair_list(self.context)))
|
||||
res = self.dbapi.get_x509keypair_list(self.context, filters={
|
||||
'bay_uuid': magnum_utils.generate_uuid()})
|
||||
self.assertEqual(0, len(res))
|
||||
|
||||
def test_destroy_x509keypair(self):
|
||||
x509keypair = utils.create_test_x509keypair()
|
||||
self.assertIsNotNone(self.dbapi.get_x509keypair_by_id(
|
||||
self.context, x509keypair.id))
|
||||
self.dbapi.destroy_x509keypair(x509keypair.id)
|
||||
self.assertRaises(exception.X509KeyPairNotFound,
|
||||
self.dbapi.get_x509keypair_by_id,
|
||||
self.context, x509keypair.id)
|
||||
|
||||
def test_destroy_x509keypair_by_uuid(self):
|
||||
x509keypair = utils.create_test_x509keypair()
|
||||
self.assertIsNotNone(self.dbapi.get_x509keypair_by_uuid(
|
||||
self.context, x509keypair.uuid))
|
||||
self.dbapi.destroy_x509keypair(x509keypair.uuid)
|
||||
self.assertRaises(exception.X509KeyPairNotFound,
|
||||
self.dbapi.get_x509keypair_by_uuid, self.context,
|
||||
x509keypair.uuid)
|
||||
|
||||
def test_destroy_x509keypair_that_does_not_exist(self):
|
||||
self.assertRaises(exception.X509KeyPairNotFound,
|
||||
self.dbapi.destroy_x509keypair,
|
||||
'12345678-9999-0000-aaaa-123456789012')
|
|
@ -260,3 +260,35 @@ def get_test_baylock(**kw):
|
|||
'conductor_id': kw.get('conductor_id',
|
||||
'72625085-c507-4410-9b28-cd7cf1fbf1ad'),
|
||||
}
|
||||
|
||||
|
||||
def get_test_x509keypair(**kw):
|
||||
return {
|
||||
'id': kw.get('id', 42),
|
||||
'uuid': kw.get('uuid', '72625085-c507-4410-9b28-cd7cf1fbf1ad'),
|
||||
'name': kw.get('name', 'x509keypair1'),
|
||||
'project_id': kw.get('project_id', 'fake_project'),
|
||||
'user_id': kw.get('user_id', 'fake_user'),
|
||||
'bay_uuid': kw.get('bay_uuid',
|
||||
'5d12f6fd-a196-4bf0-ae4c-1f639a523a52'),
|
||||
'ca_cert': kw.get('ca_cert', 'client_ca'),
|
||||
'certificate': kw.get('certificate',
|
||||
'certificate'),
|
||||
'private_key': kw.get('private_key', 'private_key'),
|
||||
'created_at': kw.get('created_at'),
|
||||
'updated_at': kw.get('updated_at'),
|
||||
}
|
||||
|
||||
|
||||
def create_test_x509keypair(**kw):
|
||||
"""Create test x509keypair entry in DB and return X509KeyPair DB object.
|
||||
Function to be used to create test X509KeyPair objects in the database.
|
||||
:param kw: kwargs with overriding values for x509keypair's attributes.
|
||||
:returns: Test X509KeyPair DB object.
|
||||
"""
|
||||
x509keypair = get_test_x509keypair(**kw)
|
||||
# Let DB generate ID if it isn't specified explicitly
|
||||
if 'id' not in kw:
|
||||
del x509keypair['id']
|
||||
dbapi = db_api.get_instance()
|
||||
return dbapi.create_x509keypair(x509keypair)
|
||||
|
|
|
@ -0,0 +1,163 @@
|
|||
# Copyright 2015 NEC Foundation
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# 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.
|
||||
|
||||
import mock
|
||||
from testtools.matchers import HasLength
|
||||
|
||||
from magnum.common import exception
|
||||
from magnum.common import utils as magnum_utils
|
||||
from magnum import objects
|
||||
from magnum.tests.unit.db import base
|
||||
from magnum.tests.unit.db import utils
|
||||
|
||||
|
||||
class TestX509KeyPairObject(base.DbTestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(TestX509KeyPairObject, self).setUp()
|
||||
self.fake_x509keypair = utils.get_test_x509keypair()
|
||||
|
||||
def test_get_by_id(self):
|
||||
x509keypair_id = self.fake_x509keypair['id']
|
||||
with mock.patch.object(self.dbapi, 'get_x509keypair_by_id',
|
||||
autospec=True) as mock_get_x509keypair:
|
||||
mock_get_x509keypair.return_value = self.fake_x509keypair
|
||||
x509keypair = objects.X509KeyPair.get(self.context, x509keypair_id)
|
||||
mock_get_x509keypair.assert_called_once_with(self.context,
|
||||
x509keypair_id)
|
||||
self.assertEqual(self.context, x509keypair._context)
|
||||
|
||||
def test_get_by_uuid(self):
|
||||
uuid = self.fake_x509keypair['uuid']
|
||||
with mock.patch.object(self.dbapi, 'get_x509keypair_by_uuid',
|
||||
autospec=True) as mock_get_x509keypair:
|
||||
mock_get_x509keypair.return_value = self.fake_x509keypair
|
||||
x509keypair = objects.X509KeyPair.get(self.context, uuid)
|
||||
mock_get_x509keypair.assert_called_once_with(self.context, uuid)
|
||||
self.assertEqual(self.context, x509keypair._context)
|
||||
|
||||
def test_get_by_name(self):
|
||||
name = self.fake_x509keypair['name']
|
||||
with mock.patch.object(self.dbapi, 'get_x509keypair_by_name',
|
||||
autospec=True) as mock_get_x509keypair:
|
||||
mock_get_x509keypair.return_value = self.fake_x509keypair
|
||||
x509keypair = objects.X509KeyPair.get_by_name(self.context, name)
|
||||
mock_get_x509keypair.assert_called_once_with(self.context, name)
|
||||
self.assertEqual(self.context, x509keypair._context)
|
||||
|
||||
def test_get_bad_id_and_uuid(self):
|
||||
self.assertRaises(exception.InvalidIdentity,
|
||||
objects.X509KeyPair.get, self.context, 'not-a-uuid')
|
||||
|
||||
def test_list(self):
|
||||
with mock.patch.object(self.dbapi, 'get_x509keypair_list',
|
||||
autospec=True) as mock_get_list:
|
||||
mock_get_list.return_value = [self.fake_x509keypair]
|
||||
x509keypairs = objects.X509KeyPair.list(self.context)
|
||||
self.assertEqual(mock_get_list.call_count, 1)
|
||||
self.assertThat(x509keypairs, HasLength(1))
|
||||
self.assertIsInstance(x509keypairs[0], objects.X509KeyPair)
|
||||
self.assertEqual(self.context, x509keypairs[0]._context)
|
||||
|
||||
def test_list_all(self):
|
||||
with mock.patch.object(self.dbapi, 'get_x509keypair_list',
|
||||
autospec=True) as mock_get_list:
|
||||
mock_get_list.return_value = [self.fake_x509keypair]
|
||||
x509keypairs = objects.X509KeyPair.list_all(self.context)
|
||||
mock_get_list.assert_called_once_with(
|
||||
self.context, limit=None, opts={'get_all_tenants': True},
|
||||
marker=None, filters=None, sort_dir=None, sort_key=None)
|
||||
self.assertEqual(mock_get_list.call_count, 1)
|
||||
self.assertThat(x509keypairs, HasLength(1))
|
||||
self.assertIsInstance(x509keypairs[0], objects.X509KeyPair)
|
||||
self.assertEqual(self.context, x509keypairs[0]._context)
|
||||
|
||||
def test_list_with_filters(self):
|
||||
with mock.patch.object(self.dbapi, 'get_x509keypair_list',
|
||||
autospec=True) as mock_get_list:
|
||||
mock_get_list.return_value = [self.fake_x509keypair]
|
||||
filters = {'name': 'x509keypair1'}
|
||||
x509keypairs = objects.X509KeyPair.list(self.context,
|
||||
filters=filters)
|
||||
|
||||
mock_get_list.assert_called_once_with(self.context, sort_key=None,
|
||||
sort_dir=None,
|
||||
filters=filters, limit=None,
|
||||
marker=None)
|
||||
self.assertEqual(mock_get_list.call_count, 1)
|
||||
self.assertThat(x509keypairs, HasLength(1))
|
||||
self.assertIsInstance(x509keypairs[0], objects.X509KeyPair)
|
||||
self.assertEqual(self.context, x509keypairs[0]._context)
|
||||
|
||||
def test_create(self):
|
||||
with mock.patch.object(self.dbapi, 'create_x509keypair',
|
||||
autospec=True) as mock_create_x509keypair:
|
||||
mock_create_x509keypair.return_value = self.fake_x509keypair
|
||||
x509keypair = objects.X509KeyPair(self.context,
|
||||
**self.fake_x509keypair)
|
||||
x509keypair.create()
|
||||
mock_create_x509keypair.assert_called_once_with(
|
||||
self.fake_x509keypair)
|
||||
self.assertEqual(self.context, x509keypair._context)
|
||||
|
||||
def test_destroy(self):
|
||||
uuid = self.fake_x509keypair['uuid']
|
||||
with mock.patch.object(self.dbapi, 'get_x509keypair_by_uuid',
|
||||
autospec=True) as mock_get_x509keypair:
|
||||
mock_get_x509keypair.return_value = self.fake_x509keypair
|
||||
with mock.patch.object(self.dbapi, 'destroy_x509keypair',
|
||||
autospec=True) as mock_destroy_x509keypair:
|
||||
x509keypair = objects.X509KeyPair.get_by_uuid(self.context,
|
||||
uuid)
|
||||
x509keypair.destroy()
|
||||
mock_get_x509keypair.assert_called_once_with(self.context,
|
||||
uuid)
|
||||
mock_destroy_x509keypair.assert_called_once_with(uuid)
|
||||
self.assertEqual(self.context, x509keypair._context)
|
||||
|
||||
def test_save(self):
|
||||
uuid = self.fake_x509keypair['uuid']
|
||||
with mock.patch.object(self.dbapi, 'get_x509keypair_by_uuid',
|
||||
autospec=True) as mock_get_x509keypair:
|
||||
mock_get_x509keypair.return_value = self.fake_x509keypair
|
||||
with mock.patch.object(self.dbapi, 'update_x509keypair',
|
||||
autospec=True) as mock_update_x509keypair:
|
||||
x509keypair = objects.X509KeyPair.get_by_uuid(self.context,
|
||||
uuid)
|
||||
x509keypair.certificate = 'new_certificate'
|
||||
x509keypair.save()
|
||||
|
||||
mock_get_x509keypair.assert_called_once_with(self.context,
|
||||
uuid)
|
||||
mock_update_x509keypair.assert_called_once_with(
|
||||
uuid, {'certificate': 'new_certificate'})
|
||||
self.assertEqual(self.context, x509keypair._context)
|
||||
|
||||
def test_refresh(self):
|
||||
uuid = self.fake_x509keypair['uuid']
|
||||
new_uuid = magnum_utils.generate_uuid()
|
||||
returns = [dict(self.fake_x509keypair, uuid=uuid),
|
||||
dict(self.fake_x509keypair, uuid=new_uuid)]
|
||||
expected = [mock.call(self.context, uuid),
|
||||
mock.call(self.context, uuid)]
|
||||
with mock.patch.object(self.dbapi, 'get_x509keypair_by_uuid',
|
||||
side_effect=returns,
|
||||
autospec=True) as mock_get_x509keypair:
|
||||
x509keypair = objects.X509KeyPair.get_by_uuid(self.context, uuid)
|
||||
self.assertEqual(uuid, x509keypair.uuid)
|
||||
x509keypair.refresh()
|
||||
self.assertEqual(new_uuid, x509keypair.uuid)
|
||||
self.assertEqual(expected, mock_get_x509keypair.call_args_list)
|
||||
self.assertEqual(self.context, x509keypair._context)
|
|
@ -178,3 +178,30 @@ def create_test_node(context, **kw):
|
|||
node = get_test_node(context, **kw)
|
||||
node.create()
|
||||
return node
|
||||
|
||||
|
||||
def get_test_x509keypair(context, **kw):
|
||||
"""Return a X509KeyPair object with appropriate attributes.
|
||||
|
||||
NOTE: The object leaves the attributes marked as changed, such
|
||||
that a create() could be used to commit it to the DB.
|
||||
"""
|
||||
db_x509keypair = db_utils.get_test_x509keypair(**kw)
|
||||
# Let DB generate ID if it isn't specified explicitly
|
||||
if 'id' not in kw:
|
||||
del db_x509keypair['id']
|
||||
x509keypair = objects.X509KeyPair(context)
|
||||
for key in db_x509keypair:
|
||||
setattr(x509keypair, key, db_x509keypair[key])
|
||||
return x509keypair
|
||||
|
||||
|
||||
def create_test_x509keypair(context, **kw):
|
||||
"""Create and return a test x509keypair object.
|
||||
|
||||
Create a x509keypair in the DB and return a X509KeyPair object with
|
||||
appropriate attributes.
|
||||
"""
|
||||
x509keypair = get_test_x509keypair(context, **kw)
|
||||
x509keypair.create()
|
||||
return x509keypair
|
||||
|
|
Loading…
Reference in New Issue