Resolve issues with circular dependency

* Resolved issues with circular dependencies
 * Updated objects namespaces to the new io.murano.* namespace
 * Resolved a few issues related to not included code from PoC
 * Renamed objects to more pythonic name (back to original actually)

Closes-bug: #1297146
Change-Id: I34641eca33c70908bd44b50f0956abda9d8dbfa7
This commit is contained in:
Serg Melikyan
2014-03-28 20:07:39 +04:00
parent 3621c57404
commit 5958cced52
37 changed files with 545 additions and 500 deletions

View File

@@ -1,3 +1,3 @@
Namespaces:
=: org.openstack.murano
=: io.murano
Name: Application

View File

@@ -1,6 +1,6 @@
Namespaces:
=: org.openstack.murano
sys: org.openstack.murano.system
=: io.murano
sys: io.murano.system
Name: Environment

View File

@@ -1,5 +1,5 @@
Namespaces:
=: org.openstack.murano
=: io.murano
Name: Object
Workflow:

View File

@@ -22,13 +22,13 @@ from oslo.messaging import target
from muranoapi.common import config
from muranoapi.common.helpers import token_sanitizer
from muranoapi.common import rpc
from muranoapi.dsl import executor
from muranoapi.dsl import results_serializer
from muranoapi.engine import environment
from muranoapi.engine import executor
from muranoapi.engine import results_serializer
from muranoapi.engine import system
from muranoapi.engine import simple_cloader
import muranoapi.engine.system.system_objects as system_objects
from muranoapi.openstack.common.gettextutils import _ # noqa
from muranoapi.openstack.common import log as logging
from muranoapi import simple_cloader
RPC_SERVICE = None
@@ -46,7 +46,7 @@ class TaskProcessingEndpoint(object):
env.tenant_id = task['Objects']['?']['tenant_id']
cl = simple_cloader.SimpleClassLoader(config.CONF.metadata_dir)
system.register(cl, config.CONF.metadata_dir)
system_objects.register(cl, config.CONF.metadata_dir)
exc = executor.MuranoDslExecutor(cl, env)
obj = exc.load(task)

View File

View File

@@ -12,7 +12,7 @@
# License for the specific language governing permissions and limitations
# under the License.
from muranoapi.engine import objects
import muranoapi.dsl.murano_object as murano_object
class AttributeStore(object):
@@ -20,7 +20,7 @@ class AttributeStore(object):
self._attributes = {}
def set(self, tagged_object, owner_type, name, value):
if isinstance(value, objects.MuranoObject):
if isinstance(value, murano_object.MuranoObject):
value = value.object_id
key = (tagged_object.object_id, owner_type.name, name)

View File

@@ -18,13 +18,13 @@ import types
import yaql
import yaql.context
from muranoapi.engine import classes
from muranoapi.engine import exceptions
from muranoapi.engine import helpers
from muranoapi.engine import namespaces
from muranoapi.engine import objects
from muranoapi.engine import principal_objects
from muranoapi.engine import typespec
import muranoapi.dsl.exceptions as exceptions
import muranoapi.dsl.helpers as helpers
import muranoapi.dsl.murano_class as murano_class
import muranoapi.dsl.murano_object as murano_object
import muranoapi.dsl.namespace_resolver as namespace_resolver
import muranoapi.dsl.principal_objects as principal_objects
import muranoapi.dsl.typespec as typespec
class MuranoClassLoader(object):
@@ -43,22 +43,23 @@ class MuranoClassLoader(object):
else:
raise exceptions.NoClassFound(name)
namespace_resolver = namespaces.NamespaceResolver(
data.get('Namespaces', {}))
namespaces = data.get('Namespaces', {})
ns_resolver = namespace_resolver.NamespaceResolver(namespaces)
class_parents = data.get('Extends')
if class_parents:
if not isinstance(class_parents, types.ListType):
class_parents = [class_parents]
for i, parent in enumerate(class_parents):
class_parents[i] = self.get_class(
namespace_resolver.resolve_name(parent))
type_obj = classes.MuranoClass(self, namespace_resolver, name,
class_parents)
for i, parent_name in enumerate(class_parents):
full_name = ns_resolver.resolve_name(parent_name)
class_parents[i] = self.get_class(full_name)
p_iter = data.get('Properties', {}).iteritems()
for property_name, property_spec in p_iter:
spec = typespec.PropertySpec(property_spec, namespace_resolver)
type_obj = murano_class.MuranoClass(self, ns_resolver, name,
class_parents)
properties = data.get('Properties', {})
for property_name, property_spec in properties.iteritems():
spec = typespec.PropertySpec(property_spec, ns_resolver)
type_obj.add_property(property_name, spec)
for method_name, payload in data.get('Workflow', {}).iteritems():
@@ -96,16 +97,16 @@ class MuranoClassLoader(object):
else:
name = cls.__class__._murano_class_name
murano_class = self.get_class(name, create_missing=True)
m_class = self.get_class(name, create_missing=True)
if inspect.isclass(cls):
if issubclass(cls, objects.MuranoObject):
murano_class.object_class = cls
if issubclass(cls, murano_object.MuranoObject):
m_class.object_class = cls
else:
murano_class.object_class = type(
'mpc' + helpers.generate_id(),
(cls, objects.MuranoObject), {})
mpc_name = 'mpc' + helpers.generate_id()
bases = (cls, murano_object.MuranoObject)
m_class.object_class = type(mpc_name, bases, {})
for item in dir(cls):
method = getattr(cls, item)
if callable(method) and not item.startswith('_'):
murano_class.add_method(item, method)
m_class.add_method(item, method)

View File

@@ -18,23 +18,23 @@ import types
import uuid
import eventlet
from eventlet import event as e_event
from yaql import context as y_context
import eventlet.event
import yaql.context
from muranoapi.engine import attribute_store as attr_store
from muranoapi.engine import exceptions
from muranoapi.engine import expressions
from muranoapi.engine import helpers
from muranoapi.engine import object_store
from muranoapi.engine import objects
from muranoapi.engine import yaql_functions
import muranoapi.dsl.attribute_store as attribute_store
import muranoapi.dsl.exceptions as exceptions
import muranoapi.dsl.expressions as expressions
import muranoapi.dsl.helpers as helpers
import muranoapi.dsl.murano_object as murano_object
import muranoapi.dsl.object_store as object_store
import muranoapi.dsl.yaql_functions as yaql_functions
class MuranoDslExecutor(object):
def __init__(self, class_loader, environment=None):
self._class_loader = class_loader
self._object_store = object_store.ObjectStore(class_loader)
self._attribute_store = attr_store.AttributeStore()
self._attribute_store = attribute_store.AttributeStore()
self._root_context = class_loader.create_root_context()
self._root_context.set_data(self, '?executor')
self._root_context.set_data(self._class_loader, '?classLoader')
@@ -43,7 +43,7 @@ class MuranoDslExecutor(object):
self._root_context.set_data(self._attribute_store, '?attributeStore')
self._locks = {}
yaql_functions.register(self._root_context)
self._root_context = y_context.Context(self._root_context)
self._root_context = yaql.context.Context(self._root_context)
@property
def object_store(self):
@@ -80,7 +80,6 @@ class MuranoDslExecutor(object):
params = self._evaluate_parameters(
arguments_scheme, context, this, *args)
except Exception:
# TODO(slagun): print exception
params = self._evaluate_parameters(
arguments_scheme, context, this, *args)
delegates.append(functools.partial(
@@ -118,7 +117,7 @@ class MuranoDslExecutor(object):
body, this, params, murano_class, context)
event.wait()
event = e_event.Event()
event = eventlet.event.Event()
self._locks[(method_id, this_id)] = (event, thread_marker)
gt = eventlet.spawn(self._invoke_method_implementation_gt, body,
this, params, murano_class, context,
@@ -191,13 +190,13 @@ class MuranoDslExecutor(object):
new_context.set_data(murano_class, '?type')
new_context.set_data(context, '?callerContext')
@y_context.EvalArg('obj', arg_type=objects.MuranoObject)
@y_context.EvalArg('property_name', arg_type=str)
@yaql.context.EvalArg('obj', arg_type=murano_object.MuranoObject)
@yaql.context.EvalArg('property_name', arg_type=str)
def obj_attribution(obj, property_name):
return obj.get_property(property_name, murano_class)
@y_context.EvalArg('prefix', str)
@y_context.EvalArg('name', str)
@yaql.context.EvalArg('prefix', str)
@yaql.context.EvalArg('name', str)
def validate(prefix, name):
return murano_class.namespace_resolver.resolve_name(
'%s:%s' % (prefix, name))

View File

@@ -14,10 +14,9 @@
import types
from muranoapi.engine import helpers
from muranoapi.engine import lhs_expression as lhs
from muranoapi.engine import yaql_expression
import muranoapi.dsl.helpers as helpers
import muranoapi.dsl.lhs_expression as lhs_expression
import muranoapi.dsl.yaql_expression as yaql_expression
_macros = []
@@ -44,7 +43,7 @@ class Statement(DslExpression):
else:
raise SyntaxError()
self._destination = None if not key else lhs.LhsExpression(key)
self._destination = lhs_expression.LhsExpression(key) if key else None
self._expression = value
@property

View File

@@ -14,105 +14,39 @@
import collections
import re
import sys
import types
import uuid
import deep
from eventlet import greenpool
import yaql
import eventlet.greenpool
import yaql.expressions
from muranoapi.engine import consts
from muranoapi.engine import yaql_expression
import muranoapi.dsl.murano_object
import muranoapi.dsl.yaql_expression as yaql_expression
def merge_lists(list1, list2):
result = []
for item in list1 + list2:
exists = False
for old_item in result:
if deep.diff(item, old_item) is None:
exists = True
break
if not exists:
result.append(item)
return result
def serialize(value, memo=None):
if memo is None:
memo = set()
if isinstance(value, types.DictionaryType):
result = {}
for d_key, d_value in value.iteritems():
result[d_key] = serialize(d_value, memo)
return result
elif isinstance(value, muranoapi.dsl.murano_object.MuranoObject):
if not value.object_id in memo:
memo.add(value.object_id)
return serialize(value.to_dictionary(), memo)
else:
return value.object_id
elif isinstance(value, types.ListType):
return [serialize(t, memo) for t in value]
else:
return value
def merge_dicts(dict1, dict2, max_levels=0):
result = {}
for key, value in dict1.items():
result[key] = value
if key in dict2:
other_value = dict2[key]
if type(other_value) != type(value):
raise TypeError()
if max_levels != 1 and isinstance(
other_value, types.DictionaryType):
result[key] = merge_dicts(
value, other_value,
0 if max_levels == 0 else max_levels - 1)
elif max_levels != 1 and isinstance(
other_value, types.ListType):
result[key] = merge_lists(value, other_value)
else:
result[key] = other_value
for key, value in dict2.items():
if key not in result:
result[key] = value
return result
def parallel_select(collection, func):
gp = greenpool.GreenPool()
return list(gp.imap(func, collection))
def to_python_codestyle(name):
s1 = re.sub('(.)([A-Z][a-z]+)', r'\1_\2', name)
return re.sub('([a-z0-9])([A-Z])', r'\1_\2', s1).lower()
def enum(**enums):
return type('Enum', (), enums)
def get_executor(context):
return context.get_data('$?executor')
def get_class_loader(context):
return context.get_data('$?classLoader')
def get_type(context):
return context.get_data('$?type')
def get_environment(context):
return context.get_data('$?environment')
def get_object_store(context):
return context.get_data('$?objectStore')
def get_this(context):
return context.get_data('$?this')
def get_caller_context(context):
return context.get_data('$?callerContext')
def get_attribute_store(context):
return context.get_data('$?attributeStore')
def generate_id():
return uuid.uuid4().hex
def evaluate(value, context, max_depth=consts.EVALUATION_MAX_DEPTH):
def evaluate(value, context, max_depth=sys.maxint):
if isinstance(value, (yaql_expression.YaqlExpression,
yaql.expressions.Expression)):
func = lambda: evaluate(value.evaluate(context), context, 1)
@@ -156,3 +90,90 @@ def needs_evaluation(value):
if needs_evaluation(t):
return True
return False
def merge_lists(list1, list2):
result = []
for item in list1 + list2:
exists = False
for old_item in result:
if deep.diff(item, old_item) is None:
exists = True
break
if not exists:
result.append(item)
return result
def merge_dicts(dict1, dict2, max_levels=0):
result = {}
for key, value in dict1.items():
result[key] = value
if key in dict2:
other_value = dict2[key]
if type(other_value) != type(value):
raise TypeError()
if max_levels != 1 and isinstance(
other_value, types.DictionaryType):
result[key] = merge_dicts(
value, other_value,
0 if max_levels == 0 else max_levels - 1)
elif max_levels != 1 and isinstance(
other_value, types.ListType):
result[key] = merge_lists(value, other_value)
else:
result[key] = other_value
for key, value in dict2.items():
if key not in result:
result[key] = value
return result
def generate_id():
return uuid.uuid4().hex
def parallel_select(collection, func):
gpool = eventlet.greenpool.GreenPool()
return list(gpool.imap(func, collection))
def to_python_codestyle(name):
s1 = re.sub('(.)([A-Z][a-z]+)', r'\1_\2', name)
return re.sub('([a-z0-9])([A-Z])', r'\1_\2', s1).lower()
def enum(**enums):
return type('Enum', (), enums)
def get_executor(context):
return context.get_data('$?executor')
def get_class_loader(context):
return context.get_data('$?classLoader')
def get_type(context):
return context.get_data('$?type')
def get_environment(context):
return context.get_data('$?environment')
def get_object_store(context):
return context.get_data('$?objectStore')
def get_this(context):
return context.get_data('$?this')
def get_caller_context(context):
return context.get_data('$?callerContext')
def get_attribute_store(context):
return context.get_data('$?attributeStore')

View File

@@ -15,12 +15,12 @@
import types
import yaql
from yaql import context as y_context
import yaql.context
import yaql.expressions
from muranoapi.engine import objects
from muranoapi.engine import type_scheme
from muranoapi.engine import yaql_expression as y_expression
import muranoapi.dsl.murano_object as murano_object
import muranoapi.dsl.type_scheme as type_scheme
import muranoapi.dsl.yaql_expression as yaql_expression
class LhsExpression(object):
@@ -36,7 +36,7 @@ class LhsExpression(object):
self._setter(value)
def __init__(self, expression):
if isinstance(expression, (y_expression.YaqlExpression,
if isinstance(expression, (yaql_expression.YaqlExpression,
yaql.expressions.Expression)):
self._expression = expression
else:
@@ -51,7 +51,7 @@ class LhsExpression(object):
elif isinstance(src, types.ListType) and isinstance(
key, types.IntType):
return src[key]
elif isinstance(src, objects.MuranoObject) and isinstance(
elif isinstance(src, murano_object.MuranoObject) and isinstance(
key, types.StringTypes):
self._current_obj = src
self._current_obj_name = key
@@ -89,7 +89,7 @@ class LhsExpression(object):
src[key] = old_value
raise e
elif isinstance(src, objects.MuranoObject) and isinstance(
elif isinstance(src, murano_object.MuranoObject) and isinstance(
key, types.StringTypes):
self._current_spec = src.type.find_property(key)
src.set_property(key, value, murano_class)
@@ -107,20 +107,20 @@ class LhsExpression(object):
return LhsExpression.Property(
lambda: root_context.get_data(path), set_data)
@y_context.EvalArg('this', arg_type=LhsExpression.Property)
@yaql.context.EvalArg('this', arg_type=LhsExpression.Property)
def attribution(this, arg_name):
arg_name = arg_name()
return LhsExpression.Property(
lambda: _get_value(this.get(), arg_name),
lambda value: _set_value(this.get(), arg_name, value))
@y_context.EvalArg("this", LhsExpression.Property)
@yaql.context.EvalArg("this", LhsExpression.Property)
def indexation(this, index):
return LhsExpression.Property(
lambda: _get_value(this.get(), index()),
lambda value: _set_value(this.get(), index(), value))
context = y_context.Context()
context = yaql.context.Context()
context.register_function(get_context_data, '#get_context_data')
context.register_function(attribution, '#operator_.')
context.register_function(indexation, "where")

View File

@@ -14,13 +14,13 @@
import types
from eventlet import greenpool
from yaql import context as y_context
import eventlet.greenpool as greenpool
import yaql.context
from muranoapi.engine import exceptions
from muranoapi.engine import expressions
from muranoapi.engine import helpers
from muranoapi.engine import yaql_expression
import muranoapi.dsl.exceptions as exceptions
import muranoapi.dsl.expressions as expressions
import muranoapi.dsl.helpers as helpers
import muranoapi.dsl.yaql_expression as yaql_expression
class CodeBlock(expressions.DslExpression):
@@ -81,10 +81,10 @@ class ParallelMacro(CodeBlock):
def execute(self, context, murano_class):
if not self.code_block:
return
gp = greenpool.GreenPool(helpers.evaluate(self._limit, context))
gpool = greenpool.GreenPool(helpers.evaluate(self._limit, context))
for expr in self.code_block:
gp.spawn_n(expr.execute, context, murano_class)
gp.waitall()
gpool.spawn_n(expr.execute, context, murano_class)
gpool.waitall()
class IfMacro(expressions.DslExpression):
@@ -136,7 +136,7 @@ class ForMacro(expressions.DslExpression):
def execute(self, context, murano_class):
collection = helpers.evaluate(self._collection, context)
child_context = y_context.Context(context)
child_context = yaql.context.Context(context)
for t in collection:
child_context.set_data(t, self._var)
try:
@@ -189,16 +189,15 @@ class SwitchMacro(expressions.DslExpression):
def execute(self, context, murano_class):
matched = False
for key, value in self._switch.iteritems():
if not isinstance(key,
(yaql_expression.YaqlExpression,
types.BooleanType)):
if not isinstance(key, (yaql_expression.YaqlExpression,
types.BooleanType)):
raise SyntaxError()
res = helpers.evaluate(key, context)
if not isinstance(res, types.BooleanType):
raise TypeError()
if res:
matched = True
child_context = y_context.Context(context)
child_context = yaql.context.Context(context)
CodeBlock(value).execute(child_context, murano_class)
if self._default is not None and not matched:
@@ -210,7 +209,7 @@ class DoMacro(expressions.DslExpression):
self._code = CodeBlock(Do)
def execute(self, context, murano_class):
child_context = y_context.Context(context)
child_context = yaql.context.Context(context)
self._code.execute(child_context, murano_class)

View File

@@ -15,10 +15,10 @@
import collections
import inspect
from muranoapi.engine import helpers
from muranoapi.engine import methods as engine_methods
from muranoapi.engine import objects
from muranoapi.engine import typespec
import muranoapi.dsl.helpers as helpers
import muranoapi.dsl.murano_method as murano_method
import muranoapi.dsl.murano_object as murano_object
import muranoapi.dsl.typespec as typespec
def classname(name):
@@ -35,16 +35,17 @@ class MuranoClass(object):
self._namespace_resolver = namespace_resolver
self._name = namespace_resolver.resolve_name(name)
self._properties = {}
if self._name == 'org.openstack.murano.Object':
if self._name == 'io.murano.Object':
self._parents = []
else:
self._parents = parents if parents is not None else [
class_loader.get_class('org.openstack.murano.Object')]
self.object_class = type(
'mc' + helpers.generate_id(),
tuple([p.object_class for p in self._parents]) or (
objects.MuranoObject,),
{})
self._parents = parents or [
class_loader.get_class('io.murano.Object')]
class_name = 'mc' + helpers.generate_id()
parents_class = [p.object_class for p in self._parents]
bases = tuple(parents_class) or (murano_object.MuranoObject,)
self.object_class = type(class_name, bases, {})
@property
def name(self):
@@ -58,6 +59,19 @@ class MuranoClass(object):
def parents(self):
return self._parents
@property
def methods(self):
return self._methods
def get_method(self, name):
return self._methods.get(name)
def add_method(self, name, payload):
method = murano_method.MuranoMethod(self._namespace_resolver,
self, name, payload)
self._methods[name] = method
return method
@property
def properties(self):
return self._properties.keys()
@@ -71,6 +85,7 @@ class MuranoClass(object):
return self._properties[name]
def find_method(self, name):
#resolved_name = self._namespace_resolver.resolve_name(name, self.name)
if name in self._methods:
return [(self, name)]
if not self._parents:
@@ -88,27 +103,12 @@ class MuranoClass(object):
types.extend(mc.parents)
return None
@property
def methods(self):
return self._methods
def get_method(self, name):
return self._methods.get(name)
def add_method(self, name, payload):
#name = self._namespace_resolver.resolve_name(name, self.name)
method = engine_methods.MuranoMethod(
self._namespace_resolver,
self, name, payload)
self._methods[name] = method
return method
def invoke(self, name, executor, this, parameters):
args = executor.to_yaql_args(parameters)
return executor.invoke_method(name, this, None, self, *args)
def is_compatible(self, obj):
if isinstance(obj, objects.MuranoObject):
if isinstance(obj, murano_object.MuranoObject):
return self.is_compatible(obj.type)
if obj is self:
return True

View File

@@ -13,13 +13,16 @@
# under the License.
import inspect
import ordereddict
import types
import muranoapi.dsl.macros as macros
import muranoapi.dsl.typespec as typespec
import muranoapi.dsl.yaql_expression as yaql_expression
from muranoapi.engine import macros
from muranoapi.engine import typespec
from muranoapi.engine import yaql_expression
try:
from collections import OrderedDict # noqa
except ImportError: # python2.6
from ordereddict import OrderedDict # noqa
class MuranoMethod(object):
@@ -38,11 +41,11 @@ class MuranoMethod(object):
if isinstance(arguments_scheme, types.DictionaryType):
arguments_scheme = [{key: value} for key, value in
arguments_scheme.iteritems()]
self._arguments_scheme = ordereddict.OrderedDict()
self._arguments_scheme = OrderedDict()
for record in arguments_scheme:
if not isinstance(record, types.DictionaryType) \
or len(record) > 1:
raise ValueError()
raise ValueError()
name = record.keys()[0]
self._arguments_scheme[name] = typespec.ArgumentSpec(
record[name], self._namespace_resolver)
@@ -74,7 +77,7 @@ class MuranoMethod(object):
defaults = func_info.defaults or tuple()
for i in xrange(len(defaults)):
data[i + len(data) - len(defaults)][1]['Default'] = defaults[i]
result = ordereddict.OrderedDict([
result = OrderedDict([
(name, typespec.ArgumentSpec(
declaration, self._namespace_resolver))
for name, declaration in data])

View File

@@ -12,20 +12,25 @@
# License for the specific language governing permissions and limitations
# under the License.
from yaql import context
import types
from muranoapi.engine import consts
from muranoapi.engine import exceptions
from muranoapi.engine import helpers
import yaml
import yaql.context
import muranoapi.dsl.exceptions as exceptions
import muranoapi.dsl.helpers
import muranoapi.dsl.type_scheme as type_scheme
import muranoapi.dsl.typespec as typespec
class MuranoObject(object):
def __init__(self, murano_class, parent_obj, object_store, context,
object_id=None, known_classes=None, defaults=None):
if known_classes is None:
known_classes = {}
self.__parent_obj = parent_obj
self.__object_id = object_id or helpers.generate_id()
self.__object_id = object_id or muranoapi.dsl.helpers.generate_id()
self.__type = murano_class
self.__properties = {}
self.__object_store = object_store
@@ -35,13 +40,13 @@ class MuranoObject(object):
known_classes[murano_class.name] = self
for parent_class in murano_class.parents:
name = parent_class.name
if not name in known_classes:
obj = parent_class.new(
parent_obj, object_store, context, None,
object_id=self.__object_id,
known_classes=known_classes,
defaults=defaults)
known_classes[name] = self.__parents[name] = obj
if name not in known_classes:
obj = parent_class.new(parent_obj, object_store, context,
None, object_id=self.__object_id,
known_classes=known_classes,
defaults=defaults)
self.__parents[name] = known_classes[name] = obj
else:
self.__parents[name] = known_classes[name]
@@ -50,11 +55,12 @@ class MuranoObject(object):
for i in xrange(2):
for property_name in self.__type.properties:
spec = self.__type.get_property(property_name)
if i == 0 and helpers.needs_evaluation(spec.default) \
or i == 1 and property_name in used_names:
needs_evaluation = muranoapi.dsl.helpers.needs_evaluation
if i == 0 and needs_evaluation(spec.default) or i == 1\
and property_name in used_names:
continue
used_names.add(property_name)
property_value = kwargs.get(property_name, consts.NoValue)
property_value = kwargs.get(property_name, type_scheme.NoValue)
self.set_property(property_name, property_value)
for parent in self.__parents.values():
parent.initialize(**kwargs)
@@ -123,14 +129,15 @@ class MuranoObject(object):
def __set_property(self, key, value, caller_class=None):
if key in self.__type.properties:
spec = self.__type.get_property(key)
if (caller_class is not None and
not caller_class.is_compatible(self)):
if caller_class is not None \
and (spec.type not in typespec.PropertyTypes.Writable
or not caller_class.is_compatible(self)):
raise exceptions.NoWriteAccess(key)
default = self.__defaults.get(key, spec.default)
child_context = context.Context(parent_context=self.__context)
child_context = yaql.context.Context(parent_context=self.__context)
child_context.set_data(self)
default = helpers.evaluate(default, child_context, 1)
default = muranoapi.dsl.helpers.evaluate(default, child_context, 1)
self.__properties[key] = spec.validate(
value, self, self.__context, self.__object_store, default)
@@ -143,12 +150,42 @@ class MuranoObject(object):
continue
raise AttributeError(key)
def cast(self, _type):
if self.type == _type:
def cast(self, type):
if self.type == type:
return self
for parent in self.__parents.values():
try:
return parent.cast(_type)
return parent.cast(type)
except TypeError:
continue
raise TypeError('Cannot cast')
def __repr__(self):
return yaml.safe_dump(muranoapi.dsl.helpers.serialize(self))
def to_dictionary(self, include_hidden=False):
result = {}
for parent in self.__parents.values():
result.update(parent.to_dictionary(include_hidden))
result.update({'?': {'type': self.type.name, 'id': self.object_id}})
if include_hidden:
result.update(self.__properties)
else:
for property_name in self.type.properties:
if property_name in self.__properties:
spec = self.type.get_property(property_name)
if spec.type != typespec.PropertyTypes.Runtime:
result[property_name] = \
self.__properties[property_name]
return result
def __merge_default(self, src, defaults):
if src is None:
return
if type(src) != type(defaults):
raise ValueError()
if isinstance(defaults, types.DictionaryType):
for key, value in defaults.iteritems():
src_value = src.get(key)
if src_value is None:
continue

View File

@@ -14,7 +14,7 @@
import inspect
from muranoapi.engine import helpers
import muranoapi.dsl.helpers as helpers
class ObjectStore(object):
@@ -48,7 +48,6 @@ class ObjectStore(object):
if '?' not in value or 'type' not in value['?']:
raise ValueError()
system_key = value['?']
#del value['?']
object_id = system_key['id']
obj_type = system_key['type']
class_obj = self._class_loader.get_class(obj_type)
@@ -83,5 +82,4 @@ class ObjectStore(object):
methods = obj.type.find_method('initialize')
for cls, method in methods:
cls.invoke(method, executor, obj, {})
# self._store.update(tmp_store._store)
return obj

View File

@@ -0,0 +1,6 @@
import muranoapi.dsl.principal_objects.sys_object
def register(class_loader):
sys_object = muranoapi.dsl.principal_objects.sys_object
class_loader.import_class(sys_object.SysObject)

View File

@@ -12,16 +12,16 @@
# License for the specific language governing permissions and limitations
# under the License.
from muranoapi.engine import classes
from muranoapi.engine import helpers
import muranoapi.dsl.helpers as helpers
import muranoapi.dsl.murano_class as murano_class
@classes.classname('org.openstack.murano.Object')
@murano_class.classname('io.murano.Object')
class SysObject(object):
def setAttr(self, _context, name, value, owner=None):
if owner is None:
owner = helpers.get_type(helpers.get_caller_context(_context))
if not isinstance(owner, classes.MuranoClass):
if not isinstance(owner, murano_class.MuranoClass):
raise TypeError()
attribute_store = helpers.get_attribute_store(_context)
@@ -30,7 +30,7 @@ class SysObject(object):
def getAttr(self, _context, name, owner=None):
if owner is None:
owner = helpers.get_type(helpers.get_caller_context(_context))
if not isinstance(owner, classes.MuranoClass):
if not isinstance(owner, murano_class.MuranoClass):
raise TypeError()
attribute_store = helpers.get_attribute_store(_context)

View File

@@ -14,7 +14,7 @@
import types
from muranoapi.engine import objects
import muranoapi.dsl.murano_object as murano_object
class ObjRef(object):
@@ -45,7 +45,7 @@ def _pass1_serialize(value, parent, serialized_objects):
if isinstance(value, (types.StringTypes, types.IntType, types.FloatType,
types.BooleanType, types.NoneType)):
return value
elif isinstance(value, objects.MuranoObject):
elif isinstance(value, murano_object.MuranoObject):
if not _cmp_objects(value.parent, parent) \
or value.object_id in serialized_objects:
return ObjRef(value)

View File

@@ -16,12 +16,14 @@ import sys
import types
import uuid
from yaql import context as y_context
import yaql.context
from muranoapi.engine import consts
from muranoapi.engine import helpers
from muranoapi.engine import objects
from muranoapi.engine import yaql_expression
import muranoapi.dsl.helpers
import muranoapi.dsl.murano_object
import muranoapi.dsl.yaql_expression as yaql_expression
NoValue = object()
class TypeScheme(object):
@@ -37,7 +39,7 @@ class TypeScheme(object):
namespace_resolver, default):
def _int(value):
value = value()
if value is consts.NoValue:
if value is NoValue:
value = default
if value is None:
return None
@@ -48,7 +50,7 @@ class TypeScheme(object):
def _string(value):
value = value()
if value is consts.NoValue:
if value is NoValue:
value = default
if value is None:
return None
@@ -59,7 +61,7 @@ class TypeScheme(object):
def _bool(value):
value = value()
if value is consts.NoValue:
if value is NoValue:
value = default
if value is None:
return None
@@ -85,8 +87,11 @@ class TypeScheme(object):
else:
raise TypeError(value)
@y_context.EvalArg('obj', arg_type=(objects.MuranoObject,
TypeScheme.ObjRef, types.NoneType))
@yaql.context.EvalArg('obj', arg_type=(
muranoapi.dsl.murano_object.MuranoObject,
TypeScheme.ObjRef,
types.NoneType
))
def _owned(obj):
if isinstance(obj, TypeScheme.ObjRef):
return obj
@@ -98,8 +103,11 @@ class TypeScheme(object):
else:
raise TypeError()
@y_context.EvalArg('obj', arg_type=(objects.MuranoObject,
TypeScheme.ObjRef, types.NoneType))
@yaql.context.EvalArg('obj', arg_type=(
muranoapi.dsl.murano_object.MuranoObject,
TypeScheme.ObjRef,
types.NoneType
))
def _not_owned(obj):
if isinstance(obj, TypeScheme.ObjRef):
return obj
@@ -111,12 +119,12 @@ class TypeScheme(object):
else:
return obj
@y_context.EvalArg('name', arg_type=str)
@yaql.context.EvalArg('name', arg_type=str)
def _class(value, name):
return _class2(value, name, None)
@y_context.EvalArg('name', arg_type=str)
@y_context.EvalArg('default_name', arg_type=(str, types.NoneType))
@yaql.context.EvalArg('name', arg_type=str)
@yaql.context.EvalArg('default_name', arg_type=(str, types.NoneType))
def _class2(value, name, default_name):
name = namespace_resolver.resolve_name(name)
if not default_name:
@@ -124,20 +132,20 @@ class TypeScheme(object):
else:
default_name = namespace_resolver.resolve_name(default_name)
value = value()
if value is consts.NoValue:
if value is NoValue:
value = default
if isinstance(default, types.DictionaryType):
value = {'?': {
'id': uuid.uuid4().hex,
'type': default_name
}}
class_loader = helpers.get_class_loader(root_context)
class_loader = muranoapi.dsl.helpers.get_class_loader(root_context)
murano_class = class_loader.get_class(name)
if not murano_class:
raise TypeError()
if value is None:
return None
if isinstance(value, objects.MuranoObject):
if isinstance(value, muranoapi.dsl.murano_object.MuranoObject):
obj = value
elif isinstance(value, types.DictionaryType):
obj = object_store.load(value, this, root_context,
@@ -155,13 +163,13 @@ class TypeScheme(object):
raise TypeError()
return obj
@y_context.EvalArg('prefix', str)
@y_context.EvalArg('name', str)
@yaql.context.EvalArg('prefix', str)
@yaql.context.EvalArg('name', str)
def _validate(prefix, name):
return namespace_resolver.resolve_name(
'%s:%s' % (prefix, name))
context = y_context.Context(parent_context=root_context)
context = yaql.context.Context(parent_context=root_context)
context.register_function(_validate, '#validate')
context.register_function(_int, 'int')
context.register_function(_string, 'string')
@@ -176,7 +184,7 @@ class TypeScheme(object):
return context
def _map_dict(self, data, spec, context):
if data is None or data is consts.NoValue:
if data is None or data is NoValue:
data = {}
if not isinstance(data, types.DictionaryType):
raise TypeError()
@@ -205,7 +213,7 @@ class TypeScheme(object):
def _map_list(self, data, spec, context):
if not isinstance(data, types.ListType):
if data is None or data is consts.NoValue:
if data is None or data is NoValue:
data = []
else:
data = [data]
@@ -239,7 +247,7 @@ class TypeScheme(object):
return data
def _map(self, data, spec, context):
child_context = y_context.Context(parent_context=context)
child_context = yaql.context.Context(parent_context=context)
if isinstance(spec, yaql_expression.YaqlExpression):
child_context.set_data(data)
return spec.evaluate(context=child_context)
@@ -258,6 +266,6 @@ class TypeScheme(object):
context, this, object_store, namespace_resolver,
default)
result = self._map(data, self._spec, context)
if result is consts.NoValue:
if result is NoValue:
raise TypeError('No type specified')
return result

View File

@@ -12,7 +12,7 @@
# License for the specific language governing permissions and limitations
# under the License.
from muranoapi.engine import type_scheme
import muranoapi.dsl.type_scheme as type_scheme
class PropertyTypes(object):

View File

@@ -12,21 +12,21 @@
# License for the specific language governing permissions and limitations
# under the License.
import eventlet
import itertools
import types
from yaql import context as y_context
import eventlet
import yaql.context
import yaql.exceptions
from muranoapi.engine import exceptions
from muranoapi.engine import helpers
from muranoapi.engine import objects
import muranoapi.dsl.exceptions as exceptions
import muranoapi.dsl.helpers as helpers
import muranoapi.dsl.murano_object as murano_object
def _resolve(name, obj):
@y_context.EvalArg('this', objects.MuranoObject)
@y_context.ContextAware()
@yaql.context.EvalArg('this', murano_object.MuranoObject)
@yaql.context.ContextAware()
def invoke(context, this, *args):
try:
executor = helpers.get_executor(context)
@@ -38,20 +38,20 @@ def _resolve(name, obj):
except exceptions.AmbiguousMethodName:
raise yaql.exceptions.YaqlExecutionException()
if not isinstance(obj, objects.MuranoObject):
if not isinstance(obj, murano_object.MuranoObject):
return None
return invoke
@y_context.EvalArg('value', objects.MuranoObject)
@yaql.context.EvalArg('value', murano_object.MuranoObject)
def _id(value):
return value.object_id
@y_context.EvalArg('value', objects.MuranoObject)
@y_context.EvalArg('type', str)
@y_context.ContextAware()
@yaql.context.EvalArg('value', murano_object.MuranoObject)
@yaql.context.EvalArg('type', str)
@yaql.context.ContextAware()
def _cast(context, value, type):
if not '.' in type:
murano_class = context.get_data('$?type')
@@ -60,8 +60,8 @@ def _cast(context, value, type):
return value.cast(class_loader.get_class(type))
@y_context.EvalArg('name', str)
@y_context.ContextAware()
@yaql.context.EvalArg('name', str)
@yaql.context.ContextAware()
def _new(context, name, *args):
murano_class = helpers.get_type(context)
name = murano_class.namespace_resolver.resolve_name(name)
@@ -79,38 +79,38 @@ def _new(context, name, *args):
object_store = helpers.get_object_store(context)
class_loader = helpers.get_class_loader(context)
new_context = y_context.Context(parent_context=context)
new_context = yaql.context.Context(parent_context=context)
for key, value in parameters.iteritems():
new_context.set_data(value, key)
return class_loader.get_class(name).new(
None, object_store, new_context, parameters=parameters)
@y_context.EvalArg('value', objects.MuranoObject)
@yaql.context.EvalArg('value', murano_object.MuranoObject)
def _super(value):
return [value.cast(type) for type in value.type.parents]
@y_context.EvalArg('value', objects.MuranoObject)
@yaql.context.EvalArg('value', murano_object.MuranoObject)
def _super2(value, func):
return itertools.imap(func, _super(value))
@y_context.EvalArg('value', objects.MuranoObject)
@yaql.context.EvalArg('value', murano_object.MuranoObject)
def _psuper2(value, func):
helpers.parallel_select(_super(value), func)
@y_context.EvalArg('value', object)
@yaql.context.EvalArg('value', object)
def _require(value):
if value is None:
raise ValueError()
return value
@y_context.EvalArg('obj', objects.MuranoObject)
@y_context.EvalArg('class_name', str)
@y_context.ContextAware()
@yaql.context.EvalArg('obj', murano_object.MuranoObject)
@yaql.context.EvalArg('class_name', str)
@yaql.context.ContextAware()
def _get_container(context, obj, class_name):
namespace_resolver = helpers.get_type(context).namespace_resolver
class_loader = helpers.get_class_loader(context)
@@ -124,7 +124,7 @@ def _get_container(context, obj, class_name):
return None
@y_context.EvalArg('seconds', (int, float))
@yaql.context.EvalArg('seconds', (int, float))
def _sleep(seconds):
eventlet.sleep(seconds)

View File

@@ -1,18 +0,0 @@
# Copyright (c) 2014 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.
NoValue = object()
EVALUATION_MAX_DEPTH = 100

View File

@@ -1,19 +0,0 @@
# Copyright (c) 2014 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 muranoapi.engine.principal_objects import sys_object
def register(class_loader):
class_loader.import_class(sys_object.SysObject)

View File

@@ -17,9 +17,9 @@ import os.path
import yaml
from muranoapi.engine import class_loader
from muranoapi.engine.system import yaql_functions
from muranoapi.engine import yaql_expression
import muranoapi.dsl.class_loader as class_loader
import muranoapi.dsl.yaql_expression as yaql_expression
import muranoapi.engine.system.yaql_functions as yaql_functions
def yaql_constructor(loader, node):

View File

@@ -1,48 +0,0 @@
# Copyright (c) 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.
import inspect
from muranoapi.engine import classes
from muranoapi.engine.system import agent
from muranoapi.engine.system import agent_listener
from muranoapi.engine.system import heat_stack
from muranoapi.engine.system import resource_manager
def _auto_register(class_loader):
globs = globals().copy()
for module_name, value in globs.iteritems():
if inspect.ismodule(value):
for class_name in dir(value):
class_def = getattr(value, class_name)
if inspect.isclass(class_def) and hasattr(
class_def, '_murano_class_name'):
class_loader.import_class(class_def)
def register(class_loader, path):
_auto_register(class_loader)
@classes.classname('org.openstack.murano.system.Resources')
class ResourceManagerWrapper(resource_manager.ResourceManager):
def initialize(self, _context, _class=None):
super(ResourceManagerWrapper, self).initialize(
path, _context, _class)
class_loader.import_class(agent.Agent)
class_loader.import_class(agent_listener.AgentListener)
class_loader.import_class(heat_stack.HeatStack)
class_loader.import_class(ResourceManagerWrapper)

View File

@@ -20,11 +20,11 @@ import uuid
import eventlet.event
from muranoapi.common import messaging
from muranoapi.engine import classes
from muranoapi.engine import objects
from muranoapi.engine.system import common
from muranoapi.engine import yaql_expression
import muranoapi.common.messaging as messaging
import muranoapi.dsl.murano_class as murano_class
import muranoapi.dsl.murano_object as murano_object
import muranoapi.dsl.yaql_expression as yaql_expression
import muranoapi.engine.system.common as common
class AgentException(Exception):
@@ -32,11 +32,11 @@ class AgentException(Exception):
self.message_info = message_info
@classes.classname('org.openstack.murano.system.Agent')
class Agent(objects.MuranoObject):
@murano_class.classname('io.murano.system.Agent')
class Agent(murano_object.MuranoObject):
def initialize(self, _context, host):
environment = yaql_expression.YaqlExpression(
"$host.find('org.openstack.murano.Environment').require()"
"$host.find('io.murano.Environment').require()"
).evaluate(_context)
self._queue = str('e%s-h%s' % (

View File

@@ -15,13 +15,13 @@
import eventlet
from muranoapi.engine import classes
from muranoapi.engine import objects
from muranoapi.engine.system import common
import muranoapi.dsl.murano_class as murano_class
import muranoapi.dsl.murano_object as murano_object
import muranoapi.engine.system.common as common
@classes.classname('org.openstack.murano.system.AgentListener')
class AgentListener(objects.MuranoObject):
@murano_class.classname('io.murano.system.AgentListener')
class AgentListener(murano_object.MuranoObject):
def initialize(self, _context, name):
self._results_queue = str('-execution-results-%s' % name.lower())
self._subscriptions = {}

View File

@@ -13,8 +13,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
from muranoapi.common import config
from muranoapi.common import messaging
import muranoapi.common.config as config
import muranoapi.common.messaging as messaging
def create_rmq_client():

View File

@@ -14,21 +14,23 @@
# limitations under the License.
import eventlet
from heatclient import client as hclient
from heatclient import exc as heat_exc
from keystoneclient.v2_0 import client as ksclient
import heatclient.client as hclient
import heatclient.exc as heat_exc
import keystoneclient.v2_0.client as ksclient
from muranoapi.common import config
from muranoapi.engine import classes
from muranoapi.engine import helpers
from muranoapi.engine import objects
from muranoapi.openstack.common import log as logging
import muranoapi.common.config as config
import muranoapi.dsl.helpers as helpers
import muranoapi.dsl.murano_class as murano_class
import muranoapi.dsl.murano_object as murano_object
import muranoapi.openstack.common.log as logging
log = logging.getLogger(__name__)
@classes.classname('org.openstack.murano.system.HeatStack')
class HeatStack(objects.MuranoObject):
@murano_class.classname('io.murano.system.HeatStack')
class HeatStack(murano_object.MuranoObject):
def initialize(self, _context, name):
self._name = name
self._template = None

View File

@@ -17,10 +17,10 @@ import json as jsonlib
import os.path
import yaml as yamllib
from muranoapi.engine import objects
import muranoapi.dsl.murano_object as murano_object
class ResourceManager(objects.MuranoObject):
class ResourceManager(murano_object.MuranoObject):
def initialize(self, base_path, _context, _class):
if _class is None:
_class = _context.get_data('$')

View File

@@ -0,0 +1,48 @@
# Copyright (c) 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.
import inspect
import muranoapi.dsl.murano_class as murano_class
import muranoapi.engine.system.agent as agent
import muranoapi.engine.system.agent_listener as agent_listener
import muranoapi.engine.system.heat_stack as heat_stack
import muranoapi.engine.system.resource_manager as resource_manager
def _auto_register(class_loader):
globs = globals().copy()
for module_name, value in globs.iteritems():
if inspect.ismodule(value):
for class_name in dir(value):
class_def = getattr(value, class_name)
if inspect.isclass(class_def) and hasattr(
class_def, '_murano_class_name'):
class_loader.import_class(class_def)
def register(class_loader, path):
_auto_register(class_loader)
@murano_class.classname('io.murano.system.Resources')
class ResourceManagerWrapper(resource_manager.ResourceManager):
def initialize(self, _context, _class=None):
super(ResourceManagerWrapper, self).initialize(
path, _context, _class)
class_loader.import_class(agent.Agent)
class_loader.import_class(agent_listener.AgentListener)
class_loader.import_class(heat_stack.HeatStack)
class_loader.import_class(ResourceManagerWrapper)

View File

@@ -17,10 +17,10 @@ import base64
import re
import types
from yaql import context
import yaql.context
from muranoapi.common import config as cfg
from muranoapi.engine import helpers
import muranoapi.common.config as cfg
import muranoapi.dsl.helpers as helpers
def _transform_json(json, mappings):
@@ -62,20 +62,20 @@ def _convert_macro_parameter(macro, mappings):
return mappings[macro]
@context.EvalArg('format', types.StringTypes)
@yaql.context.EvalArg('format', types.StringTypes)
def _format(format, *args):
return format.format(*[t() for t in args])
@context.EvalArg('src', types.StringTypes)
@context.EvalArg('substring', types.StringTypes)
@context.EvalArg('value', types.StringTypes)
@yaql.context.EvalArg('src', types.StringTypes)
@yaql.context.EvalArg('substring', types.StringTypes)
@yaql.context.EvalArg('value', types.StringTypes)
def _replace_str(src, substring, value):
return src.replace(substring, value)
@context.EvalArg('src', types.StringTypes)
@context.EvalArg('replacements', dict)
@yaql.context.EvalArg('src', types.StringTypes)
@yaql.context.EvalArg('replacements', dict)
def _replace_dict(src, replacements):
for key, value in replacements.iteritems():
if isinstance(src, str):
@@ -97,74 +97,74 @@ def _coalesce(*args):
return None
@context.EvalArg('value', types.StringTypes)
@yaql.context.EvalArg('value', types.StringTypes)
def _base64encode(value):
return base64.b64encode(value)
@context.EvalArg('value', types.StringTypes)
@yaql.context.EvalArg('value', types.StringTypes)
def _base64decode(value):
return base64.b64decode(value)
@context.EvalArg('group', types.StringTypes)
@context.EvalArg('setting', types.StringTypes)
@yaql.context.EvalArg('group', types.StringTypes)
@yaql.context.EvalArg('setting', types.StringTypes)
def _config(group, setting):
return cfg.CONF[group][setting]
@context.EvalArg('setting', types.StringTypes)
@yaql.context.EvalArg('setting', types.StringTypes)
def _config_default(setting):
return cfg.CONF[setting]
@context.EvalArg('value', types.StringTypes)
@yaql.context.EvalArg('value', types.StringTypes)
def _upper(value):
return value.upper()
@context.EvalArg('value', types.StringTypes)
@yaql.context.EvalArg('value', types.StringTypes)
def _lower(value):
return value.lower()
@context.EvalArg('separator', types.StringTypes)
@yaql.context.EvalArg('separator', types.StringTypes)
def _join(separator, *args):
return separator.join([t() for t in args])
@context.EvalArg('value', types.StringTypes)
@context.EvalArg('separator', types.StringTypes)
@yaql.context.EvalArg('value', types.StringTypes)
@yaql.context.EvalArg('separator', types.StringTypes)
def _split(value, separator):
return value.split(separator)
@context.EvalArg('value', types.StringTypes)
@context.EvalArg('prefix', types.StringTypes)
@yaql.context.EvalArg('value', types.StringTypes)
@yaql.context.EvalArg('prefix', types.StringTypes)
def _startswith(value, prefix):
return value.startswith(prefix)
@context.EvalArg('value', types.StringTypes)
@context.EvalArg('suffix', types.StringTypes)
@yaql.context.EvalArg('value', types.StringTypes)
@yaql.context.EvalArg('suffix', types.StringTypes)
def _endswith(value, suffix):
return value.endswith(suffix)
@context.EvalArg('value', types.StringTypes)
@yaql.context.EvalArg('value', types.StringTypes)
def _trim(value):
return value.strip()
@context.EvalArg('value', types.StringTypes)
@context.EvalArg('pattern', types.StringTypes)
@yaql.context.EvalArg('value', types.StringTypes)
@yaql.context.EvalArg('pattern', types.StringTypes)
def _mathces(value, pattern):
return re.match(pattern, value) is not None
@context.EvalArg('value', types.StringTypes)
@context.EvalArg('index', int)
@context.EvalArg('length', int)
@yaql.context.EvalArg('value', types.StringTypes)
@yaql.context.EvalArg('index', int)
@yaql.context.EvalArg('length', int)
def _substr(value, index=0, length=-1):
if length < 0:
return value[index:]

View File

@@ -19,44 +19,44 @@ import mock
import unittest2 as unittest
import yaql
from muranoapi.engine import classes
from muranoapi.engine import exceptions
from muranoapi.engine import helpers
from muranoapi.engine import namespaces
from muranoapi.engine import objects
from muranoapi.engine import typespec
from muranoapi.engine import yaql_expression
import muranoapi.dsl.exceptions as exceptions
import muranoapi.dsl.helpers as helpers
import muranoapi.dsl.murano_class as murano_class
import muranoapi.dsl.murano_object as murano_object
import muranoapi.dsl.namespace_resolver as ns_resolver
import muranoapi.dsl.typespec as typespec
import muranoapi.dsl.yaql_expression as yaql_expression
ROOT_CLASS = 'org.openstack.murano.Object'
ROOT_CLASS = 'io.murano.Object'
class TestNamespaceResolving(unittest.TestCase):
def test_fails_w_empty_name(self):
resolver = namespaces.NamespaceResolver({'=': 'com.example.murano'})
resolver = ns_resolver.NamespaceResolver({'=': 'com.example.murano'})
self.assertRaises(ValueError, resolver.resolve_name, None)
def test_fails_w_unknown_prefix(self):
resolver = namespaces.NamespaceResolver({'=': 'com.example.murano'})
resolver = ns_resolver.NamespaceResolver({'=': 'com.example.murano'})
name = 'unknown_prefix:example.murano'
self.assertRaises(KeyError, resolver.resolve_name, name)
def test_fails_w_prefix_wo_name(self):
resolver = namespaces.NamespaceResolver({'=': 'com.example.murano'})
resolver = ns_resolver.NamespaceResolver({'=': 'com.example.murano'})
name = 'sys:'
self.assertRaises(NameError, resolver.resolve_name, name)
def test_fails_w_excessive_prefix(self):
ns = {'sys': 'com.example.murano.system'}
resolver = namespaces.NamespaceResolver(ns)
resolver = ns_resolver.NamespaceResolver(ns)
invalid_name = 'sys:excessive_ns:muranoResource'
self.assertRaises(NameError, resolver.resolve_name, invalid_name)
def test_cuts_empty_prefix(self):
resolver = namespaces.NamespaceResolver({'=': 'com.example.murano'})
resolver = ns_resolver.NamespaceResolver({'=': 'com.example.murano'})
# name without prefix delimiter
name = 'some.arbitrary.name'
@@ -66,7 +66,7 @@ class TestNamespaceResolving(unittest.TestCase):
def test_resolves_specified_ns_prefix(self):
ns = {'sys': 'com.example.murano.system'}
resolver = namespaces.NamespaceResolver(ns)
resolver = ns_resolver.NamespaceResolver(ns)
short_name, full_name = 'sys:File', 'com.example.murano.system.File'
resolved_name = resolver.resolve_name(short_name)
@@ -74,7 +74,7 @@ class TestNamespaceResolving(unittest.TestCase):
self.assertEqual(full_name, resolved_name)
def test_resolves_current_ns(self):
resolver = namespaces.NamespaceResolver({'=': 'com.example.murano'})
resolver = ns_resolver.NamespaceResolver({'=': 'com.example.murano'})
short_name, full_name = 'Resource', 'com.example.murano.Resource'
resolved_name = resolver.resolve_name(short_name)
@@ -82,21 +82,21 @@ class TestNamespaceResolving(unittest.TestCase):
self.assertEqual(full_name, resolved_name)
def test_resolves_explicit_base(self):
resolver = namespaces.NamespaceResolver({'=': 'com.example.murano'})
resolver = ns_resolver.NamespaceResolver({'=': 'com.example.murano'})
resolved_name = resolver.resolve_name('Resource', relative='com.base')
self.assertEqual('com.base.Resource', resolved_name)
def test_resolves_explicit_base_w_empty_namespaces(self):
resolver = namespaces.NamespaceResolver({})
resolver = ns_resolver.NamespaceResolver({})
resolved_name = resolver.resolve_name('File', 'com.base')
self.assertEqual('com.base.File', resolved_name)
def test_resolves_w_empty_namespaces(self):
resolver = namespaces.NamespaceResolver({})
resolver = ns_resolver.NamespaceResolver({})
resolved_name = resolver.resolve_name('Resource')
@@ -114,38 +114,38 @@ class TestClassesManipulation(unittest.TestCase):
resolver = mock.Mock(resolve_name=lambda name: name)
def test_class_name(self):
cls = classes.MuranoClass(None, self.resolver, ROOT_CLASS)
cls = murano_class.MuranoClass(None, self.resolver, ROOT_CLASS)
self.assertEqual(ROOT_CLASS, cls.name)
def test_class_namespace_resolver(self):
resolver = namespaces.NamespaceResolver({})
cls = classes.MuranoClass(None, resolver, ROOT_CLASS)
resolver = ns_resolver.NamespaceResolver({})
cls = murano_class.MuranoClass(None, resolver, ROOT_CLASS)
self.assertEqual(resolver, cls.namespace_resolver)
def test_root_class_has_no_parents(self):
root_class = classes.MuranoClass(
root_class = murano_class.MuranoClass(
None, self.resolver, ROOT_CLASS, ['You should not see me!'])
self.assertEqual([], root_class.parents)
def test_non_root_class_resolves_parents(self):
root_cls = classes.MuranoClass(None, self.resolver, ROOT_CLASS)
root_cls = murano_class.MuranoClass(None, self.resolver, ROOT_CLASS)
class_loader = mock.Mock(get_class=lambda name: root_cls)
desc_cls1 = classes.MuranoClass(class_loader, self.resolver, 'Obj')
desc_cls2 = classes.MuranoClass(
desc_cl1 = murano_class.MuranoClass(class_loader, self.resolver, 'Obj')
desc_cl2 = murano_class.MuranoClass(
class_loader, self.resolver, 'Obj', [root_cls])
self.assertEqual([root_cls], desc_cls1.parents)
self.assertEqual([root_cls], desc_cls2.parents)
self.assertEqual([root_cls], desc_cl1.parents)
self.assertEqual([root_cls], desc_cl2.parents)
def test_class_initial_properties(self):
cls = classes.MuranoClass(None, self.resolver, ROOT_CLASS)
cls = murano_class.MuranoClass(None, self.resolver, ROOT_CLASS)
self.assertEqual([], cls.properties)
def test_fails_add_incompatible_property_to_class(self):
cls = classes.MuranoClass(None, self.resolver, ROOT_CLASS)
cls = murano_class.MuranoClass(None, self.resolver, ROOT_CLASS)
kwargs = {'name': 'sampleProperty', 'property_typespec': {}}
self.assertRaises(TypeError, cls.add_property, **kwargs)
@@ -153,7 +153,7 @@ class TestClassesManipulation(unittest.TestCase):
@unittest.skip
def test_add_property_to_class(self):
prop = typespec.PropertySpec({'Default': 1}, self.resolver)
cls = classes.MuranoClass(None, self.resolver, ROOT_CLASS)
cls = murano_class.MuranoClass(None, self.resolver, ROOT_CLASS)
cls.add_property('firstPrime', prop)
class_properties = cls.properties
@@ -171,10 +171,12 @@ class TestClassesManipulation(unittest.TestCase):
self.resolver)
child_prop = typespec.PropertySpec({'Default': 'Child'},
self.resolver)
root = classes.MuranoClass(None, self.resolver, ROOT_CLASS)
mother = classes.MuranoClass(None, self.resolver, 'Mother', [root])
father = classes.MuranoClass(None, self.resolver, 'Father', [root])
child = classes.MuranoClass(
root = murano_class.MuranoClass(None, self.resolver, ROOT_CLASS)
mother = murano_class.MuranoClass(None, self.resolver,
'Mother', [root])
father = murano_class.MuranoClass(None, self.resolver,
'Father', [root])
child = murano_class.MuranoClass(
None, self.resolver, 'Child', [mother, father])
root.add_property('Void', void_prop)
@@ -188,11 +190,11 @@ class TestClassesManipulation(unittest.TestCase):
self.assertEqual(void_prop, child.find_property('Void'))
def test_class_is_compatible(self):
cls = classes.MuranoClass(None, self.resolver, ROOT_CLASS)
descendant_cls = classes.MuranoClass(
cls = murano_class.MuranoClass(None, self.resolver, ROOT_CLASS)
descendant_cls = murano_class.MuranoClass(
None, self.resolver, 'DescendantCls', [cls])
obj = mock.Mock(spec=objects.MuranoObject)
descendant_obj = mock.Mock(spec=objects.MuranoObject)
obj = mock.Mock(spec=murano_object.MuranoObject)
descendant_obj = mock.Mock(spec=murano_object.MuranoObject)
obj.type = cls
descendant_obj.type = descendant_cls
descendant_obj.parents = [obj]
@@ -202,7 +204,7 @@ class TestClassesManipulation(unittest.TestCase):
self.assertFalse(descendant_cls.is_compatible(obj))
def test_new_method_calls_initialize(self):
cls = classes.MuranoClass(None, self.resolver, ROOT_CLASS)
cls = murano_class.MuranoClass(None, self.resolver, ROOT_CLASS)
cls.object_class = mock.Mock()
with mock.patch('inspect.getargspec') as spec_mock:
@@ -212,7 +214,7 @@ class TestClassesManipulation(unittest.TestCase):
self.assertTrue(obj.initialize.called)
def test_new_method_not_calls_initialize(self):
cls = classes.MuranoClass(None, self.resolver, ROOT_CLASS)
cls = murano_class.MuranoClass(None, self.resolver, ROOT_CLASS)
cls.object_class = mock.Mock()
obj = cls.new(None, None, None)
@@ -228,7 +230,7 @@ class TestObjectsManipulation(unittest.TestCase):
self.cls.parents = []
def test_object_valid_type_instantiation(self):
obj = objects.MuranoObject(self.cls, None, None, None)
obj = murano_object.MuranoObject(self.cls, None, None, None)
self.assertEqual(self.cls, obj.type)
@@ -239,11 +241,12 @@ class TestObjectsManipulation(unittest.TestCase):
pass
def test_object_parent_properties_initialization(self):
root = classes.MuranoClass(None, self.resolver, ROOT_CLASS)
cls = classes.MuranoClass(None, self.resolver, 'SomeClass', [root])
root = murano_class.MuranoClass(None, self.resolver, ROOT_CLASS)
cls = murano_class.MuranoClass(None, self.resolver,
'SomeClass', [root])
root.new = mock.Mock()
init_kwargs = {'theArg': 0}
obj = objects.MuranoObject(cls, None, None, None)
obj = murano_object.MuranoObject(cls, None, None, None)
expected_calls = [mock.call().initialize(**init_kwargs)]
obj.initialize(**init_kwargs)
@@ -253,35 +256,36 @@ class TestObjectsManipulation(unittest.TestCase):
def test_object_id(self):
_id = 'some_id'
patch_at = 'muranoapi.engine.objects.helpers.generate_id'
patch_at = 'muranoapi.dsl.helpers.generate_id'
obj = objects.MuranoObject(self.cls, None, None, None, object_id=_id)
obj = murano_object.MuranoObject(self.cls, None, None, None,
object_id=_id)
with mock.patch(patch_at) as gen_id_mock:
gen_id_mock.return_value = _id
obj1 = objects.MuranoObject(self.cls, None, None, None)
obj1 = murano_object.MuranoObject(self.cls, None, None, None)
self.assertEqual(_id, obj.object_id)
self.assertEqual(_id, obj1.object_id)
def test_parent_obj(self):
parent = mock.Mock()
obj = objects.MuranoObject(self.cls, parent, None, None)
obj = murano_object.MuranoObject(self.cls, parent, None, None)
self.assertEqual(parent, obj.parent)
@unittest.skip
def test_fails_internal_property_access(self):
cls = classes.MuranoClass(None, self.resolver, ROOT_CLASS)
cls = murano_class.MuranoClass(None, self.resolver, ROOT_CLASS)
cls.add_property('__hidden',
typespec.PropertySpec({'Default': 10}, self.resolver))
obj = objects.MuranoObject(cls, None, None, None)
obj = murano_object.MuranoObject(cls, None, None, None)
self.assertRaises(AttributeError, lambda: obj.__hidden)
@unittest.skip
def test_proper_property_access(self):
cls = classes.MuranoClass(None, self.resolver, ROOT_CLASS)
cls = murano_class.MuranoClass(None, self.resolver, ROOT_CLASS)
cls.add_property('someProperty',
typespec.PropertySpec({'Default': 0}, self.resolver))
@@ -291,8 +295,9 @@ class TestObjectsManipulation(unittest.TestCase):
@unittest.skip
def test_parent_class_property_access(self):
cls = classes.MuranoClass(None, self.resolver, ROOT_CLASS)
child_cls = classes.MuranoClass(None, self.resolver, 'Child', [cls])
cls = murano_class.MuranoClass(None, self.resolver, ROOT_CLASS)
child_cls = murano_class.MuranoClass(None, self.resolver,
'Child', [cls])
cls.add_property('anotherProperty',
typespec.PropertySpec({'Default': 0}, self.resolver))
@@ -302,10 +307,12 @@ class TestObjectsManipulation(unittest.TestCase):
@unittest.skip
def test_fails_on_parents_property_collision(self):
root = classes.MuranoClass(None, self.resolver, ROOT_CLASS)
mother = classes.MuranoClass(None, self.resolver, 'Mother', [root])
father = classes.MuranoClass(None, self.resolver, 'Father', [root])
child = classes.MuranoClass(
root = murano_class.MuranoClass(None, self.resolver, ROOT_CLASS)
mother = murano_class.MuranoClass(None, self.resolver,
'Mother', [root])
father = murano_class.MuranoClass(None, self.resolver,
'Father', [root])
child = murano_class.MuranoClass(
None, self.resolver, 'Child', [mother, father])
mother.add_property(
@@ -319,13 +326,13 @@ class TestObjectsManipulation(unittest.TestCase):
self.assertRaises(LookupError, lambda: obj.conflictProp)
def test_fails_setting_undeclared_property(self):
cls = classes.MuranoClass(None, self.resolver, ROOT_CLASS)
cls = murano_class.MuranoClass(None, self.resolver, ROOT_CLASS)
obj = cls.new(None, None, None, {})
self.assertRaises(AttributeError, obj.set_property, 'newOne', 10)
def test_set_undeclared_property_as_internal(self):
cls = classes.MuranoClass(None, self.resolver, ROOT_CLASS)
cls = murano_class.MuranoClass(None, self.resolver, ROOT_CLASS)
obj = cls.new(None, None, None, {})
obj.cast = mock.Mock(return_value=obj)
prop_value = 10
@@ -337,7 +344,7 @@ class TestObjectsManipulation(unittest.TestCase):
@unittest.skip
def test_fails_forbidden_set_property(self):
cls = classes.MuranoClass(None, self.resolver, ROOT_CLASS)
cls = murano_class.MuranoClass(None, self.resolver, ROOT_CLASS)
cls.add_property('someProperty',
typespec.PropertySpec({'Default': 0}, self.resolver))
cls.is_compatible = mock.Mock(return_value=False)
@@ -348,7 +355,7 @@ class TestObjectsManipulation(unittest.TestCase):
@unittest.skip
def test_set_property(self):
cls = classes.MuranoClass(None, self.resolver, ROOT_CLASS)
cls = murano_class.MuranoClass(None, self.resolver, ROOT_CLASS)
cls.add_property('someProperty',
typespec.PropertySpec({'Default': 0}, self.resolver))
obj = cls.new(None, None, None, {})
@@ -362,8 +369,9 @@ class TestObjectsManipulation(unittest.TestCase):
@unittest.skip
def test_set_parent_property(self):
root = classes.MuranoClass(None, self.resolver, ROOT_CLASS)
cls = classes.MuranoClass(None, self.resolver, 'SomeClass', [root])
root = murano_class.MuranoClass(None, self.resolver, ROOT_CLASS)
cls = murano_class.MuranoClass(None, self.resolver,
'SomeClass', [root])
root.add_property('rootProperty',
typespec.PropertySpec({'Default': 0}, self.resolver))
obj = cls.new(None, None, None, {})
@@ -375,10 +383,11 @@ class TestObjectsManipulation(unittest.TestCase):
self.assertEqual(20, obj.rootProperty)
@unittest.skip
def test_object_up_cast(self):
root = classes.MuranoClass(None, self.resolver, ROOT_CLASS)
root_alt = classes.MuranoClass(None, self.resolver, 'RootAlt', [])
cls = classes.MuranoClass(
root = murano_class.MuranoClass(None, self.resolver, ROOT_CLASS)
root_alt = murano_class.MuranoClass(None, self.resolver, 'RootAlt', [])
cls = murano_class.MuranoClass(
None, self.resolver, 'SomeClass', [root, root_alt])
root_obj = root.new(None, None, None)
cls_obj = cls.new(None, None, None)
@@ -394,8 +403,8 @@ class TestObjectsManipulation(unittest.TestCase):
self.assertEqual(root_alt, cls_obj_casted2root_alt.type)
def test_fails_object_down_cast(self):
root = classes.MuranoClass(None, self.resolver, ROOT_CLASS)
cls = classes.MuranoClass(
root = murano_class.MuranoClass(None, self.resolver, ROOT_CLASS)
cls = murano_class.MuranoClass(
None, self.resolver, 'SomeClass', [root])
root_obj = root.new(None, None, None)