81eebd12ad
Added an ability to retrieve information about the current user, current project, environment owner (both user and project) from keystone. Appropriate information (including extra fields but excluding internal system data) is fetched from Keystone using the same service credentials that are used to validate tokens, create trusts etc. - io.murano.User and io.murano.Project classes were added. - Both classes have 2 static methods to get current and environment owner object of appropriate class - Object model now contains project_id/user_id of the user who created the environment - Deployment task contains project_id (renamed from tenant_id) and user_id of the user who initiated the deployment Change-Id: Ic7e24c1d2b669ed315851047bcdb27e075cfc56b
390 lines
12 KiB
Python
390 lines
12 KiB
Python
# Copyright (c) 2015 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.
|
|
|
|
import inspect
|
|
import os.path
|
|
|
|
import eventlet
|
|
import six
|
|
from yaql.language import expressions as yaql_expressions
|
|
from yaql.language import specs
|
|
from yaql.language import utils
|
|
from yaql.language import yaqltypes
|
|
from yaql import yaql_interface
|
|
|
|
from murano.dsl import constants
|
|
from murano.dsl import dsl_types
|
|
from murano.dsl import helpers
|
|
|
|
|
|
NO_VALUE = utils.create_marker('NO_VALUE')
|
|
|
|
|
|
def name(dsl_name):
|
|
def wrapper(cls):
|
|
cls.__murano_name = dsl_name
|
|
return cls
|
|
return wrapper
|
|
|
|
|
|
class MuranoObjectParameter(yaqltypes.PythonType):
|
|
def __init__(self, murano_class=None, nullable=False, version_spec=None,
|
|
decorate=True):
|
|
self.murano_class = murano_class
|
|
self.version_spec = version_spec
|
|
self.decorate = decorate
|
|
super(MuranoObjectParameter, self).__init__(
|
|
(dsl_types.MuranoObject, MuranoObjectInterface), nullable)
|
|
|
|
def check(self, value, context, *args, **kwargs):
|
|
if not super(MuranoObjectParameter, self).check(
|
|
value, context, *args, **kwargs):
|
|
return False
|
|
if value is None or isinstance(value, yaql_expressions.Expression):
|
|
return True
|
|
if isinstance(value, MuranoObjectInterface):
|
|
value = value.object
|
|
if not isinstance(value, dsl_types.MuranoObject):
|
|
return False
|
|
if self.murano_class:
|
|
murano_class = self.murano_class
|
|
if isinstance(murano_class, six.string_types):
|
|
return helpers.is_instance_of(
|
|
value, murano_class,
|
|
self.version_spec or helpers.get_type(context))
|
|
else:
|
|
return murano_class.is_compatible(value)
|
|
else:
|
|
return True
|
|
|
|
def convert(self, value, sender, context, function_spec, engine,
|
|
*args, **kwargs):
|
|
result = super(MuranoObjectParameter, self).convert(
|
|
value, sender, context, function_spec, engine, *args, **kwargs)
|
|
if self.decorate:
|
|
return MuranoObjectInterface.create(result)
|
|
else:
|
|
if isinstance(result, dsl_types.MuranoObject):
|
|
return result
|
|
return None if result is None else result.object
|
|
|
|
|
|
class ThisParameter(yaqltypes.HiddenParameterType, yaqltypes.SmartType):
|
|
def __init__(self):
|
|
super(ThisParameter, self).__init__(False)
|
|
|
|
def convert(self, value, sender, context, function_spec, engine,
|
|
*args, **kwargs):
|
|
return get_this(context)
|
|
|
|
|
|
class InterfacesParameter(yaqltypes.HiddenParameterType,
|
|
yaqltypes.SmartType):
|
|
def __init__(self):
|
|
super(InterfacesParameter, self).__init__(False)
|
|
|
|
def convert(self, value, sender, context, function_spec, engine,
|
|
*args, **kwargs):
|
|
this = helpers.get_this(context)
|
|
return Interfaces(this)
|
|
|
|
|
|
class MuranoTypeParameter(yaqltypes.PythonType):
|
|
def __init__(self, base_type=None, nullable=False, context=None,
|
|
resolve_strings=True, lazy=False):
|
|
self._context = context
|
|
self._base_type = base_type
|
|
self._resolve_strings = resolve_strings
|
|
self._lazy = lazy
|
|
super(MuranoTypeParameter, self).__init__(
|
|
(dsl_types.MuranoTypeReference,
|
|
six.string_types), nullable)
|
|
|
|
def check(self, value, context, *args, **kwargs):
|
|
if not super(MuranoTypeParameter, self).check(
|
|
value, context, *args, **kwargs):
|
|
return False
|
|
if isinstance(value, six.string_types):
|
|
if not self._resolve_strings:
|
|
return False
|
|
value = helpers.get_class(value, context).get_reference()
|
|
if isinstance(value, dsl_types.MuranoTypeReference):
|
|
if not self._base_type:
|
|
return True
|
|
return self._base_type.is_compatible(value)
|
|
return True
|
|
|
|
def convert(self, value, sender, context, function_spec, engine,
|
|
*args, **kwargs):
|
|
|
|
def implementation(ctx=None):
|
|
value2 = value
|
|
if ctx is None:
|
|
ctx = self._context or context
|
|
if isinstance(value2, yaql_expressions.Expression):
|
|
value2 = value2(utils.NO_VALUE, ctx, engine)
|
|
value2 = super(MuranoTypeParameter, self).convert(
|
|
value2, sender, ctx, function_spec, engine)
|
|
if isinstance(value2, six.string_types):
|
|
value2 = helpers.get_class(value2, ctx).get_reference()
|
|
if self._base_type and not self._base_type.is_compatible(value):
|
|
raise ValueError('Value must be subtype of {0}'.format(
|
|
self._base_type.name
|
|
))
|
|
return value2
|
|
|
|
if self._lazy:
|
|
return implementation
|
|
return implementation()
|
|
|
|
|
|
class MuranoObjectInterface(dsl_types.MuranoObjectInterface):
|
|
class DataInterface(object):
|
|
def __init__(self, object_interface):
|
|
object.__setattr__(self, '__object_interface', object_interface)
|
|
|
|
def __getattr__(self, item):
|
|
oi = getattr(self, '__object_interface')
|
|
return oi[item]
|
|
|
|
def __setattr__(self, key, value):
|
|
oi = getattr(self, '__object_interface')
|
|
oi[key] = value
|
|
|
|
class CallInterface(object):
|
|
def __init__(self, object_interface):
|
|
self.__object_interface = object_interface
|
|
|
|
def __getattr__(self, item):
|
|
def func(*args, **kwargs):
|
|
self._insert_instruction()
|
|
with helpers.with_object_store(
|
|
self.__object_interface._object_store):
|
|
context = helpers.get_context()
|
|
obj = self.__object_interface.object
|
|
return to_mutable(obj.type.invoke(
|
|
item, obj, args, kwargs,
|
|
context), helpers.get_yaql_engine(context))
|
|
return func
|
|
|
|
@staticmethod
|
|
def _insert_instruction():
|
|
context = helpers.get_context()
|
|
if context:
|
|
frame = inspect.stack()[2]
|
|
location = dsl_types.ExpressionFilePosition(
|
|
os.path.abspath(frame[1]), frame[2],
|
|
-1, frame[2], -1)
|
|
context[constants.CTX_CURRENT_INSTRUCTION] = NativeInstruction(
|
|
frame[4][0].strip(), location)
|
|
|
|
def __init__(self, mpl_object):
|
|
self._object = mpl_object
|
|
self._object_store = helpers.get_object_store()
|
|
|
|
@staticmethod
|
|
def create(mpl_object):
|
|
if mpl_object is None or isinstance(mpl_object, MuranoObjectInterface):
|
|
return mpl_object
|
|
return MuranoObjectInterface(mpl_object)
|
|
|
|
@property
|
|
def object(self):
|
|
return self._object
|
|
|
|
@property
|
|
def id(self):
|
|
return self.object.object_id
|
|
|
|
@property
|
|
def owner(self):
|
|
owner = self.object.owner
|
|
return MuranoObjectInterface.create(owner)
|
|
|
|
def find_owner(self, type, optional=False):
|
|
if isinstance(type, six.string_types):
|
|
type = helpers.get_class(type)
|
|
elif isinstance(type, dsl_types.MuranoTypeReference):
|
|
type = type.type
|
|
owner = helpers.find_object_owner(
|
|
self.object, lambda t: type.is_compatible(t))
|
|
if owner:
|
|
return MuranoObjectInterface(owner)
|
|
if not optional:
|
|
raise ValueError('Object is not owned by any instance of type '
|
|
'{0}'.format(type.name))
|
|
return None
|
|
|
|
@property
|
|
def type(self):
|
|
return self.object.type
|
|
|
|
@property
|
|
def package(self):
|
|
return self.type.package
|
|
|
|
@property
|
|
def properties(self):
|
|
return MuranoObjectInterface.DataInterface(self)
|
|
|
|
@property
|
|
def name(self):
|
|
return self.object.name
|
|
|
|
@property
|
|
def extension(self):
|
|
return self.object.extension
|
|
|
|
def cast(self, murano_class, version_spec=None):
|
|
return MuranoObjectInterface.create(
|
|
helpers.cast(
|
|
self.object, murano_class,
|
|
version_spec or helpers.get_type()))
|
|
|
|
def is_instance_of(self, murano_class, version_spec=None):
|
|
return helpers.is_instance_of(
|
|
self.object, murano_class,
|
|
version_spec or helpers.get_type())
|
|
|
|
def ancestors(self):
|
|
return self.type.ancestors()
|
|
|
|
def __getitem__(self, item):
|
|
context = helpers.get_context()
|
|
return to_mutable(
|
|
self.object.get_property(item, context),
|
|
helpers.get_yaql_engine(context))
|
|
|
|
def __setitem__(self, key, value):
|
|
context = helpers.get_context()
|
|
value = helpers.evaluate(value, context)
|
|
self.object.set_property(key, value, context)
|
|
|
|
def __call__(self):
|
|
return MuranoObjectInterface.CallInterface(self)
|
|
|
|
def __repr__(self):
|
|
return '<{0}>'.format(repr(self.object))
|
|
|
|
def __eq__(self, other):
|
|
if isinstance(other, MuranoObjectInterface):
|
|
return self.object == other.object
|
|
else:
|
|
return False
|
|
|
|
def __ne__(self, other):
|
|
return not (self == other)
|
|
|
|
def __hash__(self):
|
|
return hash(self.object)
|
|
|
|
|
|
class Interfaces(object):
|
|
def __init__(self, mpl_object):
|
|
self.__object = mpl_object
|
|
|
|
def yaql(self, receiver=utils.NO_VALUE):
|
|
return yaql_interface.YaqlInterface(
|
|
helpers.get_context(), helpers.get_yaql_engine(), receiver)
|
|
|
|
def this(self):
|
|
return self.methods(self.__object)
|
|
|
|
def methods(self, mpl_object):
|
|
return MuranoObjectInterface.create(mpl_object)
|
|
|
|
@property
|
|
def execution_session(self):
|
|
return helpers.get_execution_session()
|
|
|
|
@property
|
|
def caller(self):
|
|
caller_context = helpers.get_caller_context()
|
|
if caller_context is None:
|
|
return None
|
|
return get_this(caller_context)
|
|
|
|
@property
|
|
def attributes(self):
|
|
executor = helpers.get_executor()
|
|
return executor.attribute_store
|
|
|
|
@property
|
|
def class_config(self):
|
|
return self.__object.type.package.get_class_config(
|
|
self.__object.type.name)
|
|
|
|
@property
|
|
def package_loader(self):
|
|
return helpers.get_package_loader()
|
|
|
|
|
|
class NativeInstruction(object):
|
|
def __init__(self, instruction, location):
|
|
self.instruction = instruction
|
|
self.source_file_position = location
|
|
|
|
def __str__(self):
|
|
return self.instruction
|
|
|
|
|
|
def to_mutable(obj, yaql_engine=None):
|
|
if yaql_engine is None:
|
|
yaql_engine = helpers.get_yaql_engine()
|
|
|
|
def converter(value, limit_func, engine, rec):
|
|
if isinstance(value, dsl_types.MuranoObject):
|
|
return MuranoObjectInterface.create(value)
|
|
else:
|
|
return utils.convert_output_data(value, limit_func, engine, rec)
|
|
|
|
limiter = lambda it: utils.limit_iterable(it, constants.ITERATORS_LIMIT)
|
|
return converter(obj, limiter, yaql_engine, converter)
|
|
|
|
|
|
def meta(type_name, value):
|
|
def wrapper(func):
|
|
fd = specs.get_function_definition(func)
|
|
mpl_meta = fd.meta.get(constants.META_MPL_META, [])
|
|
mpl_meta.append({type_name: value})
|
|
specs.meta(type_name, mpl_meta)(func)
|
|
return wrapper
|
|
|
|
|
|
def get_this(context=None):
|
|
this = helpers.get_this(context)
|
|
return MuranoObjectInterface.create(this)
|
|
|
|
|
|
def get_execution_session():
|
|
return helpers.get_execution_session()
|
|
|
|
|
|
def spawn(func, *args, **kwargs):
|
|
context = helpers.get_context()
|
|
object_store = helpers.get_object_store()
|
|
|
|
def wrapper():
|
|
with helpers.with_object_store(object_store):
|
|
with helpers.contextual(context):
|
|
return func(*args, **kwargs)
|
|
|
|
return eventlet.spawn(wrapper)
|
|
|
|
|
|
def new(properties, owner=None, type=None):
|
|
context = helpers.get_context()
|
|
return helpers.get_object_store().load(
|
|
properties, owner, type or get_this(context).type, context=context)
|