c4266d89df
Change-Id: Ide9368fd57d3322476d59c7d4cbb83d59736f664 Closes-Bug: #1308924
192 lines
6.9 KiB
Python
192 lines
6.9 KiB
Python
# 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.
|
|
|
|
import types
|
|
|
|
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 muranoapi.dsl.helpers.generate_id()
|
|
self.__type = murano_class
|
|
self.__properties = {}
|
|
self.__object_store = object_store
|
|
self.__parents = {}
|
|
self.__context = context
|
|
self.__defaults = defaults or {}
|
|
known_classes[murano_class.name] = self
|
|
for parent_class in murano_class.parents:
|
|
name = parent_class.name
|
|
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]
|
|
|
|
def initialize(self, **kwargs):
|
|
used_names = set()
|
|
for i in xrange(2):
|
|
for property_name in self.__type.properties:
|
|
spec = self.__type.get_property(property_name)
|
|
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, type_scheme.NoValue)
|
|
self.set_property(property_name, property_value)
|
|
for parent in self.__parents.values():
|
|
parent.initialize(**kwargs)
|
|
|
|
@property
|
|
def object_id(self):
|
|
return self.__object_id
|
|
|
|
@property
|
|
def type(self):
|
|
return self.__type
|
|
|
|
@property
|
|
def parent(self):
|
|
return self.__parent_obj
|
|
|
|
def __getattr__(self, item):
|
|
if item.startswith('__'):
|
|
raise AttributeError('Access to internal attributes is '
|
|
'restricted')
|
|
return self.get_property(item)
|
|
|
|
def get_property(self, item, caller_class=None):
|
|
try:
|
|
return self.__get_property(item, caller_class)
|
|
except AttributeError:
|
|
if not caller_class:
|
|
raise AttributeError(item)
|
|
try:
|
|
obj = self.cast(caller_class)
|
|
return obj.__properties[item]
|
|
except KeyError:
|
|
raise AttributeError(item)
|
|
except TypeError:
|
|
raise AttributeError(item)
|
|
|
|
def __get_property(self, item, caller_class=None):
|
|
if item in self.__properties:
|
|
return self.__properties[item]
|
|
i = 0
|
|
result = None
|
|
for parent in self.__parents.values():
|
|
try:
|
|
result = parent.__get_property(item, caller_class)
|
|
i += 1
|
|
if i > 1:
|
|
raise LookupError()
|
|
except AttributeError:
|
|
continue
|
|
if not i:
|
|
raise AttributeError()
|
|
return result
|
|
|
|
def set_property(self, key, value, caller_class=None):
|
|
try:
|
|
self.__set_property(key, value, caller_class)
|
|
except AttributeError as e:
|
|
if not caller_class:
|
|
raise e
|
|
try:
|
|
obj = self.cast(caller_class)
|
|
obj.__properties[key] = value
|
|
except TypeError:
|
|
raise AttributeError(key)
|
|
|
|
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 (spec.usage not in typespec.PropertyUsages.Writable
|
|
or not caller_class.is_compatible(self)):
|
|
raise exceptions.NoWriteAccess(key)
|
|
|
|
default = self.__defaults.get(key, spec.default)
|
|
child_context = yaql.context.Context(parent_context=self.__context)
|
|
child_context.set_data(self)
|
|
default = muranoapi.dsl.helpers.evaluate(default, child_context, 1)
|
|
|
|
self.__properties[key] = spec.validate(
|
|
value, self, self.__context, self.__object_store, default)
|
|
else:
|
|
for parent in self.__parents.values():
|
|
try:
|
|
parent.__set_property(key, value, caller_class)
|
|
return
|
|
except AttributeError:
|
|
continue
|
|
raise AttributeError(key)
|
|
|
|
def cast(self, type):
|
|
if self.type == type:
|
|
return self
|
|
for parent in self.__parents.values():
|
|
try:
|
|
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.usage != typespec.PropertyUsages.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
|