summaryrefslogtreecommitdiffstats
path: root/azure/aria/aria-extension-cloudify/adapters/context_adapter.py
diff options
context:
space:
mode:
Diffstat (limited to 'azure/aria/aria-extension-cloudify/adapters/context_adapter.py')
-rw-r--r--azure/aria/aria-extension-cloudify/adapters/context_adapter.py461
1 files changed, 461 insertions, 0 deletions
diff --git a/azure/aria/aria-extension-cloudify/adapters/context_adapter.py b/azure/aria/aria-extension-cloudify/adapters/context_adapter.py
new file mode 100644
index 0000000..9e540ae
--- /dev/null
+++ b/azure/aria/aria-extension-cloudify/adapters/context_adapter.py
@@ -0,0 +1,461 @@
+#
+# Copyright (c) 2017 GigaSpaces Technologies Ltd. All rights reserved.
+#
+# 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 os
+import tempfile
+
+from aria.orchestrator.context import operation
+
+
+DEPLOYMENT = 'deployment'
+NODE_INSTANCE = 'node-instance'
+RELATIONSHIP_INSTANCE = 'relationship-instance'
+
+
+class CloudifyContextAdapter(object):
+
+ def __init__(self, ctx):
+ self._ctx = ctx
+ self._blueprint = BlueprintAdapter(ctx)
+ self._deployment = DeploymentAdapter(ctx)
+ self._operation = OperationAdapter(ctx)
+ self._bootstrap_context = BootstrapAdapter(ctx)
+ self._plugin = PluginAdapter(ctx)
+ self._agent = CloudifyAgentAdapter()
+ self._node = None
+ self._node_instance = None
+ self._source = None
+ self._target = None
+ if isinstance(ctx, operation.NodeOperationContext):
+ self._node = NodeAdapter(ctx, ctx.node_template, ctx.node)
+ self._instance = NodeInstanceAdapter(ctx, ctx.node, True)
+ elif isinstance(ctx, operation.RelationshipOperationContext):
+ self._source = RelationshipTargetAdapter(
+ ctx,
+ ctx.source_node_template,
+ ctx.source_node,
+ True
+ )
+ self._target = RelationshipTargetAdapter(
+ ctx,
+ ctx.target_node_template,
+ ctx.target_node,
+ True
+ )
+
+ def __getattr__(self, item):
+ try:
+ return getattr(self._ctx, item)
+ except AttributeError:
+ return super(CloudifyContextAdapter, self).__getattribute__(item)
+
+ @property
+ def blueprint(self):
+ return self._blueprint
+
+ @property
+ def deployment(self):
+ return self._deployment
+
+ @property
+ def operation(self):
+ return self._operation
+
+ @property
+ def bootstrap_context(self):
+ return self._bootstrap_context
+
+ @property
+ def plugin(self):
+ return self._plugin
+
+ @property
+ def agent(self):
+ return self._agent
+
+ @property
+ def type(self):
+ if self._source:
+ return RELATIONSHIP_INSTANCE
+ elif self._instance:
+ return NODE_INSTANCE
+ else:
+ return DEPLOYMENT
+
+ @property
+ def instance(self):
+ self._verify_in_node_operation()
+ return self._instance
+
+ @property
+ def node(self):
+ self._verify_in_node_operation()
+ return self._node
+
+ @property
+ def source(self):
+ self._verify_in_relationship_operation()
+ return self._source
+
+ @property
+ def target(self):
+ self._verify_in_relationship_operation()
+ return self._target
+
+ @property
+ def execution_id(self):
+ return self._ctx.task.execution.id
+
+ @property
+ def workflow_id(self):
+ return self._ctx.task.execution.workflow_name
+
+ @property
+ def rest_token(self):
+ return None
+
+ @property
+ def task_id(self):
+ return self._ctx.task.id
+
+ @property
+ def task_name(self):
+ return self._ctx.task.function
+
+ @property
+ def task_target(self):
+ return None
+
+ @property
+ def task_queue(self):
+ return None
+
+ @property
+ def logger(self):
+
+
+ def getChild( self, name ):
+ loggertype = type(self)
+
+ childlogger = self._logger.getChild(name)
+ finallogger = loggertype(childlogger, self._task_id)
+ return finallogger
+
+
+ loggertype = type(self._ctx.logger)
+
+ childloggertype = type(self._ctx.logger.getChild("test"))
+ if loggertype != childloggertype:
+ loggertype.getChild = getChild
+
+ return self._ctx.logger
+
+ def send_event(self, event):
+ self.logger.info(event)
+
+ @property
+ def provider_context(self):
+ return {}
+
+ def get_resource(self, resource_path):
+ return self._ctx.get_resource(resource_path)
+
+ def get_resource_and_render(self, resource_path, template_variables=None):
+ return self._ctx.get_resource_and_render(resource_path, variables=template_variables)
+
+ def download_resource(self, resource_path, target_path=None):
+ target_path = self._get_target_path(target_path, resource_path)
+ self._ctx.download_resource(
+ destination=target_path,
+ path=resource_path
+ )
+ return target_path
+
+ def download_resource_and_render(self,
+ resource_path,
+ target_path=None,
+ template_variables=None):
+ target_path = self._get_target_path(target_path, resource_path)
+ self._ctx.download_resource_and_render(
+ destination=target_path,
+ path=resource_path,
+ variables=template_variables
+ )
+ return target_path
+
+ @staticmethod
+ def _get_target_path(target_path, resource_path):
+ if target_path:
+ return target_path
+ fd, target_path = tempfile.mkstemp(suffix=os.path.basename(resource_path))
+ os.close(fd)
+ return target_path
+
+ def _verify_in_node_operation(self):
+ if self.type != NODE_INSTANCE:
+ self._ctx.task.abort(
+ 'ctx.node/ctx.instance can only be used in a {0} context but '
+ 'used in a {1} context.'.format(NODE_INSTANCE, self.type)
+ )
+
+ def _verify_in_relationship_operation(self):
+ if self.type != RELATIONSHIP_INSTANCE:
+ self._ctx.task.abort(
+ 'ctx.source/ctx.target can only be used in a {0} context but '
+ 'used in a {1} context.'.format(RELATIONSHIP_INSTANCE,
+ self.type)
+ )
+
+
+class BlueprintAdapter(object):
+
+ def __init__(self, ctx):
+ self._ctx = ctx
+
+ @property
+ def id(self):
+ return self._ctx.service_template.id
+
+
+class DeploymentAdapter(object):
+
+ def __init__(self, ctx):
+ self._ctx = ctx
+
+ @property
+ def id(self):
+ return self._ctx.service.id
+
+
+class NodeAdapter(object):
+
+ def __init__(self, ctx, node_template, node):
+ self._ctx = ctx
+ self._node_template = node_template
+ self._node = node
+
+ @property
+ def id(self):
+ return self._node_template.id
+
+ @property
+ def name(self):
+ return self._node_template.name
+
+ @property
+ def properties(self):
+ # Cloudify Azure plugin will request the resource_config and merge it with new configurations.
+ # This creates an problem when the resource_config is None. Fix this by replacing an empty
+ # resource_config with an empth dict.
+ if 'resource_config' in self._node.properties and self._node.properties.get('resource_config') == None:
+ self._node.properties['resource_config']={}
+ return self._node.properties
+
+ @property
+ def type(self):
+ return self._node_template.type.name
+
+ @property
+ def type_hierarchy(self):
+ # We needed to modify the type hierarchy to be a list of strings that include the word
+ # 'cloudify' in each one of them instead of 'aria', since in the Cloudify AWS plugin, that
+ # we currently wish to support, if we want to attach an ElasticIP to a node, this node's
+ # type_hierarchy property must be a list of strings only, and it must contain either the
+ # string 'cloudify.aws.nodes.Instance', or the string 'cloudify.aws.nodes.Interface'.
+ # In any other case, we won't be able to attach an ElasticIP to a node using the Cloudify
+ # AWS plugin.
+ type_hierarchy_names = [type_.name for type_ in self._node_template.type.hierarchy
+ if type_.name is not None]
+ return [type_name.replace('aria', 'cloudify') for type_name in type_hierarchy_names]
+
+
+class NodeInstanceAdapter(object):
+
+ def __init__(self, ctx, node, modifiable):
+ self._ctx = ctx
+ self._node = node
+ self._modifiable = modifiable
+
+ @property
+ def id(self):
+ return self._node.id
+
+ @property
+ def runtime_properties(self):
+ return self._node.attributes
+
+ @runtime_properties.setter
+ def runtime_properties(self, value):
+ self._node.attributes = value
+
+ def update(self, on_conflict=None):
+ self._ctx.model.node.update(self._node)
+
+ def refresh(self, force=False):
+ self._ctx.model.node.refresh(self._node)
+
+ @property
+ def host_ip(self):
+ return self._node.host_address
+
+ @property
+ def relationships(self):
+ return [RelationshipAdapter(self._ctx, relationship=relationship) for
+ relationship in self._node.outbound_relationships]
+
+ #def __getattr__(self, item):
+ # print "requsting "
+ # print self._node.attributes
+ # print dir(self._ctx)
+ # return getattr(self._ctx.instance, item)
+
+
+class RelationshipAdapter(object):
+
+ def __init__(self, ctx, relationship):
+ self._ctx = ctx
+ self._relationship = relationship
+ node = relationship.target_node
+ node_template = node.node_template
+ self.target = RelationshipTargetAdapter(ctx, node_template, node, False)
+
+ @property
+ def type(self):
+ return self._relationship.type.name
+
+ #@property
+ #def type_hierarchy(self):
+ # return self._relationship.type.hierarchy
+
+
+
+ @property
+ def type_hierarchy(self):
+ # We needed to modify the type hierarchy to be a list of strings that include the word
+ # 'cloudify' in each one of them instead of 'aria', since in the Cloudify AWS plugin, that
+ # we currently wish to support, if we want to attach an ElasticIP to a node, this node's
+ # type_hierarchy property must be a list of strings only, and it must contain either the
+ # string 'cloudify.aws.nodes.Instance', or the string 'cloudify.aws.nodes.Interface'.
+ # In any other case, we won't be able to attach an ElasticIP to a node using the Cloudify
+ # AWS plugin.
+ type_hierarchy_names = [type_.name for type_ in self._relationship.type.hierarchy
+ if type_.name is not None]
+ return [type_name.replace('aria', 'cloudify') for type_name in type_hierarchy_names]
+
+
+
+
+
+
+
+
+
+
+
+class RelationshipTargetAdapter(object):
+
+ def __init__(self, ctx, node_template, node, modifiable):
+ self._ctx = ctx
+ self.node = NodeAdapter(ctx, node_template=node_template, node=node)
+ self.instance = NodeInstanceAdapter(ctx, node=node, modifiable=modifiable)
+
+
+class OperationAdapter(object):
+
+ def __init__(self, ctx):
+ self._ctx = ctx
+
+ @property
+ def name(self):
+ # We needed to modify the operation's 'name' property in order to support the Cloudify AWS
+ # plugin. It can't use ARIA's operation naming convention, as any operation we want to run
+ # using the Cloudify AWS plugin must have its name in the format:
+ # '<something>.<operation_name>'.
+ aria_name = self._ctx.task.name
+ return aria_name.split('@')[0].replace(':', '.')
+
+ @property
+ def retry_number(self):
+ return self._ctx.task.attempts_count - 1
+
+ @property
+ def max_retries(self):
+ task = self._ctx.task
+ if task.max_attempts == task.INFINITE_RETRIES:
+ return task.INFINITE_RETRIES
+ else:
+ return task.max_attempts - 1 if task.max_attempts > 0 else 0
+
+ def retry(self, message=None, retry_after=None):
+ self._ctx.task.retry(message, retry_after)
+
+
+class BootstrapAdapter(object):
+
+ def __init__(self, ctx):
+ self._ctx = ctx
+ self.cloudify_agent = _Stub()
+ self.resources_prefix = ''
+
+ def broker_config(self, *args, **kwargs):
+ return {}
+
+
+class CloudifyAgentAdapter(object):
+
+ def init_script(self, *args, **kwargs):
+ return None
+
+
+class PluginAdapter(object):
+
+ def __init__(self, ctx):
+ self._ctx = ctx
+ self._plugin = None
+
+ @property
+ def name(self):
+ return self._ctx.task.plugin.name
+
+ @property
+ def package_name(self):
+ return self._plugin_attr('package_name')
+
+ @property
+ def package_version(self):
+ return self._plugin_attr('package_version')
+
+ @property
+ def prefix(self):
+ # TODO
+ return self._plugin_attr('prefix')
+
+ @property
+ def workdir(self):
+ return self._ctx.plugin_workdir
+
+ def _plugin_attr(self, attr):
+ if not self._plugin:
+ self._plugin = self._ctx.task.plugin
+ if not self._plugin:
+ return None
+ return getattr(self._plugin, attr, None)
+
+
+
+class _Stub(object):
+ def __getattr__(self, _):
+ return None