diff options
Diffstat (limited to 'azure/aria/aria-extension-cloudify/src/aria/aria/orchestrator/execution_plugin/instantiation.py')
-rw-r--r-- | azure/aria/aria-extension-cloudify/src/aria/aria/orchestrator/execution_plugin/instantiation.py | 217 |
1 files changed, 217 insertions, 0 deletions
diff --git a/azure/aria/aria-extension-cloudify/src/aria/aria/orchestrator/execution_plugin/instantiation.py b/azure/aria/aria-extension-cloudify/src/aria/aria/orchestrator/execution_plugin/instantiation.py new file mode 100644 index 0000000..8b52015 --- /dev/null +++ b/azure/aria/aria-extension-cloudify/src/aria/aria/orchestrator/execution_plugin/instantiation.py @@ -0,0 +1,217 @@ +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You 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. + +""" +Instantiation of :class:`~aria.modeling.models.Operation` models. +""" + +# TODO: this module will eventually be moved to a new "aria.instantiation" package +from ...modeling.functions import Function +from ... import utils + + +def configure_operation(operation, reporter): + host = None + interface = operation.interface + if interface.node is not None: + host = interface.node.host + elif interface.relationship is not None: + if operation.relationship_edge is True: + host = interface.relationship.target_node.host + else: # either False or None (None meaning that edge was not specified) + host = interface.relationship.source_node.host + + _configure_common(operation, reporter) + if host is None: + _configure_local(operation) + else: + _configure_remote(operation, reporter) + + # Any remaining un-handled configuration parameters will become extra arguments, available as + # kwargs in either "run_script_locally" or "run_script_with_ssh" + for key, value in operation.configurations.iteritems(): + if key not in ('process', 'ssh'): + operation.arguments[key] = value.instantiate(None) + + +def _configure_common(operation, reporter): + """ + Local and remote operations. + """ + + from ...modeling.models import Argument + operation.arguments['script_path'] = Argument.wrap('script_path', operation.implementation, + 'Relative path to the executable file.') + operation.arguments['process'] = Argument.wrap('process', _get_process(operation, reporter), + 'Sub-process configuration.') + + +def _configure_local(operation): + """ + Local operation. + """ + + from . import operations + operation.function = '{0}.{1}'.format(operations.__name__, + operations.run_script_locally.__name__) + + +def _configure_remote(operation, reporter): + """ + Remote SSH operation via Fabric. + """ + + from ...modeling.models import Argument + from . import operations + + ssh = _get_ssh(operation, reporter) + + # Defaults + # TODO: find a way to configure these generally in the service template + default_user = '' + default_password = '' + if 'user' not in ssh: + ssh['user'] = default_user + if ('password' not in ssh) and ('key' not in ssh) and ('key_filename' not in ssh): + ssh['password'] = default_password + + operation.arguments['use_sudo'] = Argument.wrap('use_sudo', ssh.get('use_sudo', False), + 'Whether to execute with sudo.') + + operation.arguments['hide_output'] = Argument.wrap('hide_output', ssh.get('hide_output', []), + 'Hide output of these Fabric groups.') + + fabric_env = {} + if 'warn_only' in ssh: + fabric_env['warn_only'] = ssh['warn_only'] + fabric_env['user'] = ssh.get('user') + fabric_env['password'] = ssh.get('password') + fabric_env['key'] = ssh.get('key') + fabric_env['key_filename'] = ssh.get('key_filename') + if 'address' in ssh: + fabric_env['host_string'] = ssh['address'] + + # Make sure we have a user + if fabric_env.get('user') is None: + reporter.report('must configure "ssh.user" for "{0}"'.format(operation.implementation), + level=reporter.Issue.BETWEEN_TYPES) + + # Make sure we have an authentication value + if (fabric_env.get('password') is None) and \ + (fabric_env.get('key') is None) and \ + (fabric_env.get('key_filename') is None): + reporter.report( + 'must configure "ssh.password", "ssh.key", or "ssh.key_filename" for "{0}"' + .format(operation.implementation), + level=reporter.Issue.BETWEEN_TYPES) + + operation.arguments['fabric_env'] = Argument.wrap('fabric_env', fabric_env, + 'Fabric configuration.') + + operation.function = '{0}.{1}'.format(operations.__name__, + operations.run_script_with_ssh.__name__) + + +def _get_process(operation, reporter): + value = (operation.configurations.get('process')._value + if 'process' in operation.configurations + else None) + if value is None: + return {} + _validate_type(value, dict, 'process', reporter) + value = utils.collections.OrderedDict(value) + for k, v in value.iteritems(): + if k == 'eval_python': + value[k] = _coerce_bool(v, 'process.eval_python', reporter) + elif k == 'cwd': + _validate_type(v, basestring, 'process.cwd', reporter) + elif k == 'command_prefix': + _validate_type(v, basestring, 'process.command_prefix', reporter) + elif k == 'args': + value[k] = _dict_to_list_of_strings(v, 'process.args', reporter) + elif k == 'env': + _validate_type(v, dict, 'process.env', reporter) + else: + reporter.report('unsupported configuration parameter: "process.{0}"'.format(k), + level=reporter.Issue.BETWEEN_TYPES) + return value + + +def _get_ssh(operation, reporter): + value = (operation.configurations.get('ssh')._value + if 'ssh' in operation.configurations + else None) + if value is None: + return {} + _validate_type(value, dict, 'ssh', reporter) + value = utils.collections.OrderedDict(value) + for k, v in value.iteritems(): + if k == 'use_sudo': + value[k] = _coerce_bool(v, 'ssh.use_sudo', reporter) + elif k == 'hide_output': + value[k] = _dict_to_list_of_strings(v, 'ssh.hide_output', reporter) + elif k == 'warn_only': + value[k] = _coerce_bool(v, 'ssh.warn_only', reporter) + elif k == 'user': + _validate_type(v, basestring, 'ssh.user', reporter) + elif k == 'password': + _validate_type(v, basestring, 'ssh.password', reporter) + elif k == 'key': + _validate_type(v, basestring, 'ssh.key', reporter) + elif k == 'key_filename': + _validate_type(v, basestring, 'ssh.key_filename', reporter) + elif k == 'address': + _validate_type(v, basestring, 'ssh.address', reporter) + else: + reporter.report('unsupported configuration parameter: "ssh.{0}"'.format(k), + level=reporter.Issue.BETWEEN_TYPES) + return value + + +def _validate_type(value, the_type, name, reporter): + if isinstance(value, Function): + return + if not isinstance(value, the_type): + reporter.report( + '"{0}" configuration is not a {1}: {2}'.format( + name, utils.type.full_type_name(the_type), utils.formatting.safe_repr(value)), + level=reporter.Issue.BETWEEN_TYPES) + + +def _coerce_bool(value, name, reporter): + if value is None: + return None + if isinstance(value, bool): + return value + _validate_type(value, basestring, name, reporter) + if value == 'true': + return True + elif value == 'false': + return False + else: + reporter.report( + '"{0}" configuration is not "true" or "false": {1}'.format( + name, utils.formatting.safe_repr(value)), + level=reporter.Issue.BETWEEN_TYPES) + + +def _dict_to_list_of_strings(the_dict, name, reporter): + _validate_type(the_dict, dict, name, reporter) + value = [] + for k in sorted(the_dict): + v = the_dict[k] + _validate_type(v, basestring, '{0}.{1}'.format(name, k), reporter) + value.append(v) + return value |