Add security service DB model and API.

Add support for managing security services information.

User will be able to create description for services
such as ldap, kerberos and active directory.
Security service record will contain type of service
(kerberos, ldap or ad), ip address of dns server, security
service server hostname or ip, domain, sid (security identifier)
and other auxiliary data.

Partially implements bp: join-tenant-network

Change-Id: I50e1f96496a40840aad97b77024a11302a1dd997
This commit is contained in:
Aleks Chirko 2013-12-18 17:34:00 +02:00
parent 32b69b5ba4
commit 55f42ea27c
8 changed files with 368 additions and 0 deletions

View File

@ -0,0 +1,22 @@
# Copyright 2013 Openstack 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.
STATUS_NEW = 'NEW'
STATUS_CREATING = 'CREATING'
STATUS_DELETING = 'DELETING'
STATUS_DELETED = 'DELETED'
STATUS_ERROR = 'ERROR'
STATUS_ACTIVE = 'ACTIVE'
STATUS_INACTIVE = 'INACTIVE'

View File

@ -429,6 +429,37 @@ def share_snapshot_data_get_for_project(context, project_id, session=None):
session=None)
###################
def security_service_create(context, values):
""" Create security service DB record."""
return IMPL.security_service_create(context, values)
def security_service_delete(context, id):
""" Delete security service DB record."""
return IMPL.security_service_delete(context, id)
def security_service_update(context, id, values):
""" Update security service DB record."""
return IMPL.security_service_update(context, id, values)
def security_service_get(context, id):
""" Get security service DB record."""
return IMPL.security_service_get(context, id)
def security_service_get_all(context):
""" Get all security service DB records."""
return IMPL.security_service_get_all(context)
def security_service_get_all_by_project(context, project_id):
""" Get all security service DB records for the given project."""
return IMPL.security_service_get_all_by_project(context, project_id)
####################

View File

@ -39,6 +39,7 @@ from manila.db.sqlalchemy.session import get_session
from manila import exception
from manila.openstack.common import log as logging
from manila.openstack.common import timeutils
from manila.openstack.common import uuidutils
CONF = cfg.CONF
@ -252,6 +253,7 @@ QUOTA_SYNC_FUNCTIONS = {
'_sync_gigabytes': _sync_gigabytes,
}
###################
@ -1414,3 +1416,67 @@ def _share_metadata_get_item(context, share_id, key, session=None):
raise exception.ShareMetadataNotFound(metadata_key=key,
share_id=share_id)
return result
@require_context
def security_service_create(context, values):
if not values.get('id'):
values['id'] = uuidutils.generate_uuid()
security_service_ref = models.SecurityService()
security_service_ref.update(values)
session = get_session()
with session.begin():
security_service_ref.save(session=session)
return security_service_ref
@require_context
def security_service_delete(context, id):
session = get_session()
with session.begin():
security_service_ref = security_service_get(context,
id,
session=session)
security_service_ref.delete(session=session)
@require_context
def security_service_update(context, id, values):
session = get_session()
with session.begin():
security_service_ref = security_service_get(context,
id,
session=session)
security_service_ref.update(values)
security_service_ref.save(session=session)
return security_service_ref
@require_context
def security_service_get(context, id, session=None):
result = _security_service_get_query(context, session=session).\
filter_by(id=id).first()
if result is None:
raise exception.SecurityServiceNotFound(security_service_id=id)
return result
@require_context
def security_service_get_all(context):
return _security_service_get_query(context).all()
@require_context
def security_service_get_all_by_project(context, project_id):
return _security_service_get_query(context).\
filter_by(project_id=project_id).all()
def _security_service_get_query(context, session=None):
if session is None:
session = get_session()
return model_query(context, models.SecurityService, session=session)

View File

@ -0,0 +1,61 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2013 Mirantis Inc.
#
# 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 sqlalchemy import Boolean, Column, DateTime
from sqlalchemy import MetaData, String, Table
from manila.openstack.common.gettextutils import _
from manila.openstack.common import log as logging
LOG = logging.getLogger(__name__)
def upgrade(migrate_engine):
meta = MetaData()
meta.bind = migrate_engine
security_services = Table(
'security_services', meta,
Column('created_at', DateTime),
Column('updated_at', DateTime),
Column('deleted_at', DateTime),
Column('deleted', Boolean, default=False),
Column('id', String(length=36), primary_key=True, nullable=False),
Column('project_id', String(length=36), nullable=False),
Column('type', String(length=32), nullable=False),
Column('dns_ip', String(length=64), nullable=True),
Column('server', String(length=255), nullable=True),
Column('domain', String(length=255), nullable=True),
Column('sid', String(length=255), nullable=True),
Column('name', String(length=255), nullable=True),
Column('description', String(length=255), nullable=True),
Column('status', String(length=16)),
mysql_engine='InnoDB',
mysql_charset='utf8',
)
try:
security_services.create()
except Exception:
LOG.exception(_("Exception while creating table"))
raise
def downgrade(migrate_engine):
meta = MetaData()
meta.bind = migrate_engine
security_services = Table('security_services', meta, autoload=True)
security_services.drop()

View File

@ -27,6 +27,7 @@ from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import ForeignKey, DateTime, Boolean, Enum
from sqlalchemy.orm import relationship, backref, object_mapper
from manila.common import constants
from manila.db.sqlalchemy.session import get_session
from manila import exception
@ -320,6 +321,24 @@ class ShareSnapshot(BASE, ManilaBase):
'ShareSnapshot.deleted == False)')
class SecurityService(BASE, ManilaBase):
"""Security service information for manila shares"""
__tablename__ = 'security_services'
id = Column(String(36), primary_key=True)
project_id = Column(String(36), nullable=False)
type = Column(String(32), nullable=False)
dns_ip = Column(String(64), nullable=True)
server = Column(String(255), nullable=True)
domain = Column(String(255), nullable=True)
sid = Column(String(255), nullable=True)
name = Column(String(255), nullable=True)
description = Column(String(255), nullable=True)
status = Column(Enum(constants.STATUS_NEW, constants.STATUS_ACTIVE,
constants.STATUS_ERROR),
default=constants.STATUS_NEW)
def register_models():
"""Register Models and create metadata.

View File

@ -491,3 +491,7 @@ class InvalidShareMetadata(Invalid):
class InvalidShareMetadataSize(Invalid):
message = _("Invalid metadata size")
class SecurityServiceNotFound(NotFound):
message = _("Security service %(security_service_id)s could not be found.")

View File

View File

@ -0,0 +1,165 @@
# Copyright 2013 OpenStack 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.
from manila.common import constants
from manila import context
from manila.db import api as db_api
from manila import exception
from manila import test
security_service_dict = {'id': 'fake id',
'project_id': 'fake project',
'type': 'ldap',
'dns_ip': 'fake dns',
'server': 'fake ldap server',
'domain': 'fake ldap domain',
'sid': 'fake sid',
'name': 'whatever',
'description': 'nevermind',
'status': constants.STATUS_NEW}
class SecurityServiceDBTest(test.TestCase):
def __init__(self, *args, **kwargs):
super(SecurityServiceDBTest, self).__init__(*args, **kwargs)
self.fake_context = context.RequestContext(user_id='fake user',
project_id='fake project',
is_admin=False)
def _check_expected_fields(self, result, expected):
for key in expected:
self.assertEqual(result[key], expected[key])
def test_create(self):
result = db_api.security_service_create(self.fake_context,
security_service_dict)
self._check_expected_fields(result, security_service_dict)
def test_get(self):
db_api.security_service_create(self.fake_context,
security_service_dict)
result = db_api.security_service_get(self.fake_context,
security_service_dict['id'])
self._check_expected_fields(result, security_service_dict)
def test_get_not_found(self):
self.assertRaises(exception.SecurityServiceNotFound,
db_api.security_service_get,
self.fake_context,
'wrong id')
def test_delete(self):
db_api.security_service_create(self.fake_context,
security_service_dict)
db_api.security_service_delete(self.fake_context,
security_service_dict['id'])
self.assertRaises(exception.SecurityServiceNotFound,
db_api.security_service_get,
self.fake_context,
security_service_dict['id'])
def test_update(self):
update_dict = {'dns_ip': 'new dns',
'server': 'new ldap server',
'domain': 'new ldap domain',
'sid': 'new sid',
'name': 'new whatever',
'description': 'new nevermind',
'status': constants.STATUS_ERROR}
db_api.security_service_create(self.fake_context,
security_service_dict)
result = db_api.security_service_update(self.fake_context,
security_service_dict['id'],
update_dict)
self._check_expected_fields(result, update_dict)
def test_update_no_updates(self):
db_api.security_service_create(self.fake_context,
security_service_dict)
result = db_api.security_service_update(self.fake_context,
security_service_dict['id'],
{})
self._check_expected_fields(result, security_service_dict)
def test_update_not_found(self):
self.assertRaises(exception.SecurityServiceNotFound,
db_api.security_service_update,
self.fake_context,
'wrong id',
{})
def test_get_all_no_records(self):
result = db_api.security_service_get_all(self.fake_context)
self.assertEqual(len(result), 0)
def test_get_all_one_record(self):
db_api.security_service_create(self.fake_context,
security_service_dict)
result = db_api.security_service_get_all(self.fake_context)
self.assertEqual(len(result), 1)
self._check_expected_fields(result[0], security_service_dict)
def test_get_all_two_records(self):
dict1 = security_service_dict
dict2 = security_service_dict.copy()
dict2['id'] = 'fake id 2'
db_api.security_service_create(self.fake_context,
dict1)
db_api.security_service_create(self.fake_context,
dict2)
result = db_api.security_service_get_all(self.fake_context)
self.assertEqual(len(result), 2)
def test_get_all_by_project(self):
dict1 = security_service_dict
dict2 = security_service_dict.copy()
dict2['id'] = 'fake id 2'
dict2['project_id'] = 'fake project 2'
db_api.security_service_create(self.fake_context,
dict1)
db_api.security_service_create(self.fake_context,
dict2)
result1 = db_api.security_service_get_all_by_project(
self.fake_context,
dict1['project_id'])
self.assertEqual(len(result1), 1)
self._check_expected_fields(result1[0], dict1)
result2 = db_api.security_service_get_all_by_project(
self.fake_context,
dict2['project_id'])
self.assertEqual(len(result2), 1)
self._check_expected_fields(result2[0], dict2)