deb-murano/murano/dsl/dsl.py
Alexander Tivelkov 81eebd12ad Ability to retrieve current/owner user/project
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
2016-11-24 02:07:34 -08:00

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)