Merge "Refactor context usage in profile"

This commit is contained in:
Jenkins 2015-06-26 08:29:30 +00:00 committed by Gerrit Code Review
commit d5acef3fc1
14 changed files with 97 additions and 78 deletions

View File

@ -287,7 +287,7 @@ class List(Schema):
# We have a child schema specified for list elements
# Fake a dict of array elements, since we have only one schema
schema_arr = dict((k, sub_schema[k]) for k in keys)
subspec = Spec(schema_arr, dict(values), context)
subspec = Spec(schema_arr, dict(values))
subspec.validate()
return ((k, subspec[k]) for k in keys)
@ -327,7 +327,7 @@ class Map(Schema):
sub_schema = self.schema
if sub_schema is not None:
# sub_schema shoud be a dict here
subspec = Spec(sub_schema, dict(values), context)
subspec = Spec(sub_schema, dict(values))
subspec.validate()
return ((k, subspec[k]) for k in sub_schema)
@ -351,10 +351,9 @@ class Map(Schema):
class Spec(collections.Mapping):
'''A class that contains all spec items.'''
def __init__(self, schema, data, context):
def __init__(self, schema, data):
self._schema = schema
self._data = data
self.context = context
def validate(self):
'''Validate the schema.'''

View File

@ -209,7 +209,7 @@ class EngineService(service.Service):
'permission': perm,
'metadata': metadata,
}
profile = plugin(context, profile_type, name, **kwargs)
profile = plugin(profile_type, name, **kwargs)
profile.validate()
profile.store(context)
return profile.to_dict()
@ -251,7 +251,7 @@ class EngineService(service.Service):
}
new_name = name or db_profile.name
profile = plugin(context, db_profile.type, new_name, **kwargs)
profile = plugin(db_profile.type, new_name, **kwargs)
profile.validate()
profile.store(context)
return profile.to_dict()

View File

@ -52,7 +52,7 @@ class Policy(object):
self.updated_time = kwargs.get('updated_time', None)
self.deleted_time = kwargs.get('deleted_time', None)
self.spec_data = schema.Spec(self.spec_schema, self.spec, self.context)
self.spec_data = schema.Spec(self.spec_schema, self.spec)
@classmethod
def _from_db_record(cls, context, record):

View File

@ -25,9 +25,8 @@ class LaunchConfigProfile(base.Profile):
'''
spec_schema = {}
def __init__(self, ctx, name, type_name=__type_name__, **kwargs):
super(LaunchConfigProfile, self).__init__(ctx, name, type_name,
**kwargs)
def __init__(self, type_name, name, **kwargs):
super(LaunchConfigProfile, self).__init__(type_name, name, **kwargs)
self.ImageId = kwargs.get('ImageId')
self.InstanceType = kwargs.get('InstanceType')

View File

@ -10,11 +10,11 @@
# License for the specific language governing permissions and limitations
# under the License.
import copy
import datetime
from oslo_log import log as logging
from senlin.common import context
from senlin.common import exception
from senlin.common import schema
from senlin.db import api as db_api
@ -27,7 +27,7 @@ LOG = logging.getLogger(__name__)
class Profile(object):
'''Base class for profiles.'''
def __new__(cls, ctx, type_name, name, **kwargs):
def __new__(cls, type_name, name, **kwargs):
'''Create a new profile of the appropriate class.'''
if cls != Profile:
@ -37,16 +37,19 @@ class Profile(object):
return super(Profile, cls).__new__(ProfileClass)
def __init__(self, ctx, type_name, name, **kwargs):
'''Initialize the profile with given parameters and a JSON object.'''
def __init__(self, type_name, name, **kwargs):
'''Initialize the profile with given parameters and a JSON object.
:param type_name: a string containing valid profile type name;
:param name: a string that specifies the name for the profile.
'''
self.id = kwargs.get('id', None)
self.name = name
self.type = type_name
self.id = kwargs.get('id', None)
self.context = ctx
self.spec = kwargs.get('spec', None)
self.spec_data = schema.Spec(self.spec_schema, self.spec, self.context)
self.spec_data = schema.Spec(self.spec_schema, self.spec)
self.permission = kwargs.get('permission', '')
self.metadata = kwargs.get('metadata', {})
@ -54,15 +57,21 @@ class Profile(object):
self.updated_time = kwargs.get('updated_time', None)
self.deleted_time = kwargs.get('deleted_time', None)
if not self.id:
# new object needs a context dict
self.context = self._init_context()
else:
self.context = kwargs.get('context')
@classmethod
def from_db_record(cls, record):
'''Construct a profile object from database record.
:param context: the context used for DB operations.
:param record: a DB Profle object that contains all required fields.
'''
kwargs = {
'id': record.id,
'context': record.context,
'spec': record.spec,
'permission': record.permission,
'metadata': record.meta_data,
@ -71,25 +80,24 @@ class Profile(object):
'deleted_time': record.deleted_time,
}
ctx = context.RequestContext.from_dict(record.context)
return cls(ctx, record.type, record.name, **kwargs)
return cls(record.type, record.name, **kwargs)
@classmethod
def load(cls, context, profile_id=None, profile=None):
def load(cls, ctx, profile_id=None, profile=None):
'''Retrieve a profile object from database.'''
if profile is None:
profile = db_api.profile_get(context, profile_id)
profile = db_api.profile_get(ctx, profile_id)
if profile is None:
raise exception.ProfileNotFound(profile=profile_id)
return cls.from_db_record(profile)
@classmethod
def load_all(cls, context, limit=None, sort_keys=None, marker=None,
def load_all(cls, ctx, limit=None, sort_keys=None, marker=None,
sort_dir=None, filters=None, show_deleted=False):
'''Retrieve all profiles from database.'''
records = db_api.profile_get_all(context, limit=limit, marker=marker,
records = db_api.profile_get_all(ctx, limit=limit, marker=marker,
sort_keys=sort_keys,
sort_dir=sort_dir,
filters=filters,
@ -99,17 +107,17 @@ class Profile(object):
yield cls.from_db_record(record)
@classmethod
def delete(cls, context, profile_id):
db_api.profile_delete(context, profile_id)
def delete(cls, ctx, profile_id):
db_api.profile_delete(ctx, profile_id)
def store(self, context):
def store(self, ctx):
'''Store the profile into database and return its ID.'''
timestamp = datetime.datetime.utcnow()
values = {
'name': self.name,
'type': self.type,
'context': self.context.to_dict(),
'context': self.context,
'spec': self.spec,
'permission': self.permission,
'meta_data': self.metadata,
@ -118,70 +126,79 @@ class Profile(object):
if self.id:
self.updated_time = timestamp
values['updated_time'] = timestamp
db_api.profile_update(self.context, self.id, values)
db_api.profile_update(ctx, self.id, values)
else:
self.created_time = timestamp
values['created_time'] = timestamp
profile = db_api.profile_create(self.context, values)
profile = db_api.profile_create(ctx, values)
self.id = profile.id
return self.id
@classmethod
def create_object(cls, context, obj):
profile = cls.load(context, obj.profile_id)
def create_object(cls, ctx, obj):
profile = cls.load(ctx, obj.profile_id)
return profile.do_create(obj)
@classmethod
def delete_object(cls, context, obj):
profile = cls.load(context, obj.profile_id)
def delete_object(cls, ctx, obj):
profile = cls.load(ctx, obj.profile_id)
return profile.do_delete(obj)
@classmethod
def update_object(cls, context, obj, new_profile_id):
profile = cls.load(context, obj.profile_id)
new_profile = cls.load(context, new_profile_id)
def update_object(cls, ctx, obj, new_profile_id):
profile = cls.load(ctx, obj.profile_id)
new_profile = cls.load(ctx, new_profile_id)
return profile.do_update(obj, new_profile)
@classmethod
def get_details(cls, context, obj):
profile = cls.load(context, obj.profile_id)
def get_details(cls, ctx, obj):
profile = cls.load(ctx, obj.profile_id)
return profile.do_get_details(obj)
@classmethod
def join_cluster(cls, context, obj, cluster_id):
profile = cls.load(context, obj.profile_id)
def join_cluster(cls, ctx, obj, cluster_id):
profile = cls.load(ctx, obj.profile_id)
return profile.do_join(obj, cluster_id)
@classmethod
def leave_cluster(cls, context, obj):
profile = cls.load(context, obj.profile_id)
def leave_cluster(cls, ctx, obj):
profile = cls.load(ctx, obj.profile_id)
return profile.do_leave(obj)
def validate(self):
'''Validate the schema and the data provided.'''
self.spec_data.validate()
def _get_connection_params(self, obj):
cred = db_api.cred_get(self.context, obj.user, obj.project)
def _init_context(self):
cred = keystoneclient.get_service_credentials()
cntx = {
'auth_url': cred['auth_url'],
'user_name': cred['user_name'],
'user_domain_name': cred['user_domain_name'],
'password': cred['password'],
}
if self.CONTEXT in self.spec_data:
profile_context = self.spec_data[self.CONTEXT]
if profile_context:
# TODO(Anyone): need to check the contents in self.CONTEXT
cntx.update(profile_context)
return cntx
def _get_connection_params(self, ctx, obj):
cred = db_api.cred_get(ctx, obj.user, obj.project)
if cred is None:
# TODO(Anyone): this exception type makes no sense to end user,
# need to translate it at a higher layer
raise exception.TrustNotFound(trustor=obj.user)
trust_id = cred.cred['openstack']['trust']
ctx = keystoneclient.get_service_credentials()
params = {
'auth_url': ctx['auth_url'],
'user_name': ctx['user_name'],
'user_domain_name': ctx['user_domain_name'],
'password': ctx['password'],
'project_id': obj.project,
'trusts': trust_id,
}
profile_context = self.spec_data[self.CONTEXT]
if profile_context is not None and len(profile_context) > 0:
# We don't know what will happen, it is completely left to users.
params.update(profile_context)
params = copy.deepcopy(self.context)
params['project_id'] = obj.project,
params['trusts'] = trust_id,
return params
def do_create(self, obj):

View File

@ -24,8 +24,8 @@ class ResourceProfile(base.Profile):
'''
spec_schema = {}
def __init__(self, ctx, name, type_name=__type_name__, **kwargs):
super(ResourceProfile, self).__init__(ctx, name, type_name, **kwargs)
def __init__(self, type_name, name, **kwargs):
super(ResourceProfile, self).__init__(type_name, name, **kwargs)
def do_create(self):
return {}

View File

@ -12,6 +12,7 @@
import six
from oslo_context import context
from oslo_log import log as logging
from senlin.common import exception
@ -73,8 +74,8 @@ class StackProfile(base.Profile):
)
}
def __init__(self, ctx, type_name, name, **kwargs):
super(StackProfile, self).__init__(ctx, type_name, name, **kwargs)
def __init__(self, type_name, name, **kwargs):
super(StackProfile, self).__init__(type_name, name, **kwargs)
self.hc = None
self.stack_id = None
@ -84,7 +85,7 @@ class StackProfile(base.Profile):
if self.hc:
return self.hc
params = self._get_connection_params(obj)
params = self._get_connection_params(context.get_current(), obj)
self.hc = heatclient.HeatClient(params)
return self.hc

View File

@ -10,6 +10,7 @@
# License for the specific language governing permissions and limitations
# under the License.
from oslo_context import context
from oslo_log import log as logging
import six
@ -159,8 +160,8 @@ class ServerProfile(base.Profile):
),
}
def __init__(self, ctx, type_name, name, **kwargs):
super(ServerProfile, self).__init__(ctx, type_name, name, **kwargs)
def __init__(self, type_name, name, **kwargs):
super(ServerProfile, self).__init__(type_name, name, **kwargs)
self._nc = None
self.server_id = None
@ -175,7 +176,7 @@ class ServerProfile(base.Profile):
if self._nc is not None:
return self._nc
params = self._get_connection_params(obj)
params = self._get_connection_params(context.get_current(), obj)
self._nc = novaclient.NovaClient(params)
return self._nc

View File

@ -87,11 +87,11 @@ class EngineClient(object):
sort_dir=sort_dir, filters=filters,
show_deleted=show_deleted))
def profile_create(self, ctxt, name, type, spec, perm, metadata):
def profile_create(self, ctxt, name, profile_type, spec, perm, metadata):
return self.call(ctxt,
self.make_msg('profile_create', name=name,
type=type, spec=spec, perm=perm,
metadata=metadata))
profile_type=profile_type, spec=spec,
perm=perm, metadata=metadata))
def profile_get(self, ctxt, identity):
return self.call(ctxt,
@ -127,10 +127,10 @@ class EngineClient(object):
sort_dir=sort_dir, filters=filters,
show_deleted=show_deleted))
def policy_create(self, ctxt, name, type, spec, level, cooldown):
def policy_create(self, ctxt, name, policy_type, spec, level, cooldown):
return self.call(ctxt,
self.make_msg('policy_create',
name=name, type=type, spec=spec,
self.make_msg('policy_create', name=name,
policy_type=policy_type, spec=spec,
level=level, cooldown=cooldown))
def policy_get(self, ctxt, identity):

View File

@ -253,7 +253,7 @@ class PolicyControllerTest(shared.ControllerTest, base.SenlinTestCase):
req.context,
('policy_create', {
'name': 'test_policy',
'type': 'test_policy_type',
'policy_type': 'test_policy_type',
'spec': {'param_1': 'value1', 'param_2': 2},
'level': 30,
'cooldown': 60

View File

@ -251,7 +251,7 @@ class ProfileControllerTest(shared.ControllerTest, base.SenlinTestCase):
req.context,
('profile_create', {
'name': 'test_profile',
'type': 'test_profile_type',
'profile_type': 'test_profile_type',
'spec': {'param_1': 'value1', 'param_2': 2},
'perm': None,
'metadata': {},

View File

@ -50,6 +50,7 @@ class ProfileTest(base.SenlinTestCase):
'LIST': ['v1', 'v2'],
'MAP': {'KEY1': 1, 'KEY2': 'v2'},
}
result = self.eng.profile_create(self.ctx, 'p-1', 'TestProfile', spec)
self.assertEqual(spec, result['spec'])

View File

@ -20,6 +20,7 @@ from senlin.profiles import base as profile_base
class TestProfile(profile_base.Profile):
CONTEXT = 'context'
spec_schema = {
'INT': schema.Integer('int property', default=0),
'STR': schema.String('string property', default='a string'),
@ -36,8 +37,8 @@ class TestProfile(profile_base.Profile):
),
}
def __init__(self, ctx, name, type_name='TestProfile', **kwargs):
super(TestProfile, self).__init__(ctx, name, type_name, **kwargs)
def __init__(self, type_name, name, **kwargs):
super(TestProfile, self).__init__(type_name, name, **kwargs)
def do_create(self):
return {}

View File

@ -118,7 +118,7 @@ class EngineRpcAPITestCase(base.SenlinTestCase):
def test_profile_create(self):
default_args = {
'name': mock.ANY,
'type': mock.ANY,
'profile_type': mock.ANY,
'spec': mock.ANY,
'perm': mock.ANY,
'metadata': mock.ANY,
@ -165,7 +165,7 @@ class EngineRpcAPITestCase(base.SenlinTestCase):
def test_policy_create(self):
default_args = {
'name': mock.ANY,
'type': mock.ANY,
'policy_type': mock.ANY,
'spec': mock.ANY,
'level': mock.ANY,
'cooldown': mock.ANY,