1 # Licensed to the Apache Software Foundation (ASF) under one or more
2 # contributor license agreements. See the NOTICE file distributed with
3 # this work for additional information regarding copyright ownership.
4 # The ASF licenses this file to You under the Apache License, Version 2.0
5 # (the "License"); you may not use this file except in compliance with
6 # the License. You may obtain a copy of the License at
8 # http://www.apache.org/licenses/LICENSE-2.0
10 # Unless required by applicable law or agreed to in writing, software
11 # distributed under the License is distributed on an "AS IS" BASIS,
12 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 # See the License for the specific language governing permissions and
14 # limitations under the License.
17 Instantiation of :class:`~aria.modeling.models.Operation` models.
20 # TODO: this module will eventually be moved to a new "aria.instantiation" package
21 from ...modeling.functions import Function
25 def configure_operation(operation, reporter):
27 interface = operation.interface
28 if interface.node is not None:
29 host = interface.node.host
30 elif interface.relationship is not None:
31 if operation.relationship_edge is True:
32 host = interface.relationship.target_node.host
33 else: # either False or None (None meaning that edge was not specified)
34 host = interface.relationship.source_node.host
36 _configure_common(operation, reporter)
38 _configure_local(operation)
40 _configure_remote(operation, reporter)
42 # Any remaining un-handled configuration parameters will become extra arguments, available as
43 # kwargs in either "run_script_locally" or "run_script_with_ssh"
44 for key, value in operation.configurations.iteritems():
45 if key not in ('process', 'ssh'):
46 operation.arguments[key] = value.instantiate(None)
49 def _configure_common(operation, reporter):
51 Local and remote operations.
54 from ...modeling.models import Argument
55 operation.arguments['script_path'] = Argument.wrap('script_path', operation.implementation,
56 'Relative path to the executable file.')
57 operation.arguments['process'] = Argument.wrap('process', _get_process(operation, reporter),
58 'Sub-process configuration.')
61 def _configure_local(operation):
66 from . import operations
67 operation.function = '{0}.{1}'.format(operations.__name__,
68 operations.run_script_locally.__name__)
71 def _configure_remote(operation, reporter):
73 Remote SSH operation via Fabric.
76 from ...modeling.models import Argument
77 from . import operations
79 ssh = _get_ssh(operation, reporter)
82 # TODO: find a way to configure these generally in the service template
86 ssh['user'] = default_user
87 if ('password' not in ssh) and ('key' not in ssh) and ('key_filename' not in ssh):
88 ssh['password'] = default_password
90 operation.arguments['use_sudo'] = Argument.wrap('use_sudo', ssh.get('use_sudo', False),
91 'Whether to execute with sudo.')
93 operation.arguments['hide_output'] = Argument.wrap('hide_output', ssh.get('hide_output', []),
94 'Hide output of these Fabric groups.')
97 if 'warn_only' in ssh:
98 fabric_env['warn_only'] = ssh['warn_only']
99 fabric_env['user'] = ssh.get('user')
100 fabric_env['password'] = ssh.get('password')
101 fabric_env['key'] = ssh.get('key')
102 fabric_env['key_filename'] = ssh.get('key_filename')
104 fabric_env['host_string'] = ssh['address']
106 # Make sure we have a user
107 if fabric_env.get('user') is None:
108 reporter.report('must configure "ssh.user" for "{0}"'.format(operation.implementation),
109 level=reporter.Issue.BETWEEN_TYPES)
111 # Make sure we have an authentication value
112 if (fabric_env.get('password') is None) and \
113 (fabric_env.get('key') is None) and \
114 (fabric_env.get('key_filename') is None):
116 'must configure "ssh.password", "ssh.key", or "ssh.key_filename" for "{0}"'
117 .format(operation.implementation),
118 level=reporter.Issue.BETWEEN_TYPES)
120 operation.arguments['fabric_env'] = Argument.wrap('fabric_env', fabric_env,
121 'Fabric configuration.')
123 operation.function = '{0}.{1}'.format(operations.__name__,
124 operations.run_script_with_ssh.__name__)
127 def _get_process(operation, reporter):
128 value = (operation.configurations.get('process')._value
129 if 'process' in operation.configurations
133 _validate_type(value, dict, 'process', reporter)
134 value = utils.collections.OrderedDict(value)
135 for k, v in value.iteritems():
136 if k == 'eval_python':
137 value[k] = _coerce_bool(v, 'process.eval_python', reporter)
139 _validate_type(v, basestring, 'process.cwd', reporter)
140 elif k == 'command_prefix':
141 _validate_type(v, basestring, 'process.command_prefix', reporter)
143 value[k] = _dict_to_list_of_strings(v, 'process.args', reporter)
145 _validate_type(v, dict, 'process.env', reporter)
147 reporter.report('unsupported configuration parameter: "process.{0}"'.format(k),
148 level=reporter.Issue.BETWEEN_TYPES)
152 def _get_ssh(operation, reporter):
153 value = (operation.configurations.get('ssh')._value
154 if 'ssh' in operation.configurations
158 _validate_type(value, dict, 'ssh', reporter)
159 value = utils.collections.OrderedDict(value)
160 for k, v in value.iteritems():
162 value[k] = _coerce_bool(v, 'ssh.use_sudo', reporter)
163 elif k == 'hide_output':
164 value[k] = _dict_to_list_of_strings(v, 'ssh.hide_output', reporter)
165 elif k == 'warn_only':
166 value[k] = _coerce_bool(v, 'ssh.warn_only', reporter)
168 _validate_type(v, basestring, 'ssh.user', reporter)
169 elif k == 'password':
170 _validate_type(v, basestring, 'ssh.password', reporter)
172 _validate_type(v, basestring, 'ssh.key', reporter)
173 elif k == 'key_filename':
174 _validate_type(v, basestring, 'ssh.key_filename', reporter)
176 _validate_type(v, basestring, 'ssh.address', reporter)
178 reporter.report('unsupported configuration parameter: "ssh.{0}"'.format(k),
179 level=reporter.Issue.BETWEEN_TYPES)
183 def _validate_type(value, the_type, name, reporter):
184 if isinstance(value, Function):
186 if not isinstance(value, the_type):
188 '"{0}" configuration is not a {1}: {2}'.format(
189 name, utils.type.full_type_name(the_type), utils.formatting.safe_repr(value)),
190 level=reporter.Issue.BETWEEN_TYPES)
193 def _coerce_bool(value, name, reporter):
196 if isinstance(value, bool):
198 _validate_type(value, basestring, name, reporter)
201 elif value == 'false':
205 '"{0}" configuration is not "true" or "false": {1}'.format(
206 name, utils.formatting.safe_repr(value)),
207 level=reporter.Issue.BETWEEN_TYPES)
210 def _dict_to_list_of_strings(the_dict, name, reporter):
211 _validate_type(the_dict, dict, name, reporter)
213 for k in sorted(the_dict):
215 _validate_type(v, basestring, '{0}.{1}'.format(name, k), reporter)