def run_script(script_path, fabric_env=None, process=None, **kwargs): if not process: process = {} process = _create_process_config(process, kwargs) base_dir = process.get('base_dir', DEFAULT_BASE_DIR) ctx_server_port = process.get('ctx_server_port') proxy_client_path = proxy_client.__file__ if proxy_client_path.endswith('.pyc'): proxy_client_path = proxy_client_path[:-1] local_script_path = get_script(ctx.download_resource, script_path) base_script_path = os.path.basename(local_script_path) remote_ctx_dir = base_dir remote_ctx_path = '{0}/ctx'.format(remote_ctx_dir) remote_scripts_dir = '{0}/scripts'.format(remote_ctx_dir) remote_work_dir = '{0}/work'.format(remote_ctx_dir) remote_env_script_path = '{0}/env-{1}'.format(remote_scripts_dir, base_script_path) remote_script_path = '{0}/{1}'.format(remote_scripts_dir, base_script_path) env = process.get('env', {}) cwd = process.get('cwd', remote_work_dir) args = process.get('args') command_prefix = process.get('command_prefix') command = remote_script_path if command_prefix: command = '{0} {1}'.format(command_prefix, command) if args: command = ' '.join([command] + args) with fabric_api.settings(**_fabric_env(fabric_env, warn_only=False)): if not fabric_files.exists(remote_ctx_dir): # there may be race conditions with other operations that # may be running in parallel, so we pass -p to make sure # we get 0 exit code if the directory already exists fabric_api.run('mkdir -p {0}'.format(remote_scripts_dir)) fabric_api.run('mkdir -p {0}'.format(remote_work_dir)) fabric_api.put(proxy_client_path, remote_ctx_path) actual_ctx = ctx._get_current_object() def returns(_value): actual_ctx._return_value = _value actual_ctx._return_value = None actual_ctx.returns = returns original_download_resource = actual_ctx.download_resource def download_resource(resource_path, target_path=None): local_target_path = original_download_resource( resource_path, target_path) if target_path: remote_target_path = target_path else: remote_target_path = '{0}/{1}'.format( remote_work_dir, os.path.basename(local_target_path)) fabric_api.put(local_target_path, remote_target_path) return remote_target_path actual_ctx.download_resource = download_resource proxy = proxy_server.HTTPCtxProxy(actual_ctx, port=ctx_server_port) env_script = StringIO() env['PATH'] = '{0}:$PATH'.format(remote_ctx_dir) env[CTX_SOCKET_URL] = proxy.socket_url for key, value in env.iteritems(): env_script.write('export {0}={1}\n'.format(key, value)) env_script.write('chmod +x {0}\n'.format(remote_script_path)) env_script.write('chmod +x {0}\n'.format(remote_ctx_path)) try: fabric_api.put(local_script_path, remote_script_path) fabric_api.put(env_script, remote_env_script_path) with fabric_context.cd(cwd): with fabric_context.remote_tunnel(proxy.port): fabric_api.run('source {0} && {1}'.format( remote_env_script_path, command)) return actual_ctx._return_value finally: proxy.close()
def run_script(script_path, fabric_env=None, process=None, use_sudo=False, hide_output=None, **kwargs): if not process: process = {} process = _create_process_config(process, kwargs) ctx_server_port = process.get('ctx_server_port') proxy_client_path = proxy_client.__file__ if proxy_client_path.endswith('.pyc'): proxy_client_path = proxy_client_path[:-1] local_ctx_sh_path = os.path.join(_get_bin_dir(), 'ctx-sh') local_ctx_py_path = os.path.join( os.path.dirname(cloudify.ctx_wrappers.__file__), 'ctx-py.py') local_script_path = get_script(ctx.download_resource, script_path) base_script_path = os.path.basename(local_script_path) remote_path_suffix = '{0}-{1}'.format(base_script_path, utils.id_generator(size=8)) env = process.get('env', {}) args = process.get('args') command_prefix = process.get('command_prefix') with fabric_api.settings( _hide_output(groups=hide_output), **_fabric_env(fabric_env, warn_only=False)): # Determine the basedir. In order of precedence: # * 'base_dir' process input # * ${CFY_EXEC_TEMP}/cloudify-ctx on the remote machine, if # CFY_EXEC_TEMP is defined # * <python default tempdir>/cloudify-ctx base_dir = process.get('base_dir') if not base_dir: # "CFY_EXEC_TEMPDIR_ENVVAR" doesn't exist in 3.3.1, so # to remain backward compatible... if hasattr(utils, 'CFY_EXEC_TEMPDIR_ENVVAR'): base_dir = fabric_api.run( '( [[ -n "${0}" ]] && echo -n ${0} ) || ' 'echo -n $(dirname $(mktemp -u))'.format( utils.CFY_EXEC_TEMPDIR_ENVVAR)) else: base_dir = fabric_api.run('echo -n $(dirname $(mktemp -u))') if not base_dir: raise NonRecoverableError('Could not conclude temporary directory') base_dir = posixpath.join(base_dir, DEFAULT_BASE_SUBDIR) ctx.logger.debug('base_dir set to: {0}'.format(base_dir)) remote_ctx_dir = base_dir remote_ctx_path = '{0}/ctx'.format(remote_ctx_dir) remote_ctx_sh_path = '{0}/ctx-sh'.format(remote_ctx_dir) remote_ctx_py_path = '{0}/cloudify.py'.format(remote_ctx_dir) remote_scripts_dir = '{0}/scripts'.format(remote_ctx_dir) remote_work_dir = '{0}/work'.format(remote_ctx_dir) remote_env_script_path = '{0}/env-{1}'.format(remote_scripts_dir, remote_path_suffix) remote_script_path = '{0}/{1}'.format(remote_scripts_dir, remote_path_suffix) cwd = process.get('cwd', remote_work_dir) command = remote_script_path if command_prefix: command = '{0} {1}'.format(command_prefix, command) if args: command = ' '.join([command] + args) # the remote host must have ctx and any related files before # running any fabric scripts if not fabric_files.exists(remote_ctx_path): # there may be race conditions with other operations that # may be running in parallel, so we pass -p to make sure # we get 0 exit code if the directory already exists fabric_api.run('mkdir -p {0}'.format(remote_scripts_dir)) fabric_api.run('mkdir -p {0}'.format(remote_work_dir)) # this file has to be present before using ctx fabric_api.put(local_ctx_sh_path, remote_ctx_sh_path) fabric_api.put(proxy_client_path, remote_ctx_path) fabric_api.put(local_ctx_py_path, remote_ctx_py_path) actual_ctx = ctx._get_current_object() actual_ctx.is_script_exception_defined = ScriptException is not None def abort_operation(message=None): if actual_ctx._return_value is not None: actual_ctx._return_value = ILLEGAL_CTX_OPERATION_ERROR raise actual_ctx._return_value if actual_ctx.is_script_exception_defined: actual_ctx._return_value = ScriptException(message) else: actual_ctx._return_value = UNSUPPORTED_SCRIPT_FEATURE_ERROR raise actual_ctx return actual_ctx._return_value def retry_operation(message=None, retry_after=None): if actual_ctx._return_value is not None: actual_ctx._return_value = ILLEGAL_CTX_OPERATION_ERROR raise actual_ctx._return_value actual_ctx.operation.retry(message=message, retry_after=retry_after) if actual_ctx.is_script_exception_defined: actual_ctx._return_value = ScriptException(message, retry=True) else: actual_ctx._return_value = UNSUPPORTED_SCRIPT_FEATURE_ERROR raise actual_ctx._return_value return actual_ctx._return_value actual_ctx.abort_operation = abort_operation actual_ctx.retry_operation = retry_operation def returns(_value): if actual_ctx._return_value is not None: actual_ctx._return_value = ILLEGAL_CTX_OPERATION_ERROR raise actual_ctx._return_value actual_ctx._return_value = _value actual_ctx.returns = returns actual_ctx._return_value = None original_download_resource = actual_ctx.download_resource def download_resource(resource_path, target_path=None): local_target_path = original_download_resource(resource_path) return fabric_put_in_remote_path(local_target_path, target_path) actual_ctx.download_resource = download_resource original_download_resource_and_render = \ actual_ctx.download_resource_and_render def download_resource_and_render(resource_path, target_path=None, template_variables=None): local_target_path = original_download_resource_and_render( resource_path, template_variables=template_variables) return fabric_put_in_remote_path(local_target_path, target_path) actual_ctx.download_resource_and_render = download_resource_and_render def fabric_put_in_remote_path(local_target_path, target_path): if target_path: remote_target_path = target_path else: remote_target_path = '{0}/{1}'.format( remote_work_dir, os.path.basename(local_target_path)) fabric_api.put(local_target_path, remote_target_path) return remote_target_path def handle_script_result(script_result): if (actual_ctx.is_script_exception_defined and isinstance(script_result, ScriptException)): if script_result.retry: return script_result else: raise NonRecoverableError(str(script_result)) # this happens when more than 1 ctx operation is invoked or # the plugin runs an unsupported feature on older Cloudify elif isinstance(script_result, RuntimeError): raise NonRecoverableError(str(script_result)) # determine if this code runs during exception handling current_exception = sys.exc_info()[1] if current_exception: raise else: return script_result env_script = StringIO() env['PATH'] = '{0}:$PATH'.format(remote_ctx_dir) env['PYTHONPATH'] = '{0}:$PYTHONPATH'.format(remote_ctx_dir) env_script.write('chmod +x {0}\n'.format(remote_script_path)) env_script.write('chmod +x {0}\n'.format(remote_ctx_path)) fabric_api.put(local_script_path, remote_script_path) proxy = proxy_server.HTTPCtxProxy(actual_ctx, port=ctx_server_port) try: with fabric_context.cd(cwd): local_port = proxy.port with tunnel.remote(local_port=local_port) as remote_port: env[CTX_SOCKET_URL] = proxy.socket_url.replace( str(local_port), str(remote_port)) env['LOCAL_{0}'.format(CTX_SOCKET_URL)] = proxy.socket_url for key, value in env.iteritems(): env_script.write('export {0}={1}\n'.format(key, value)) fabric_api.put(env_script, remote_env_script_path) # invoke sys.exc_clear() because handle_script_result # invokes sys.exc_info() sys.exc_clear() try: command = 'source {0} && {1}'.format( remote_env_script_path, command) run = fabric_api.sudo if use_sudo else fabric_api.run run(command) except FabricTaskError: return handle_script_result(actual_ctx._return_value) return handle_script_result(actual_ctx._return_value) finally: proxy.close()
def run_script(script_path, fabric_env=None, process=None, **kwargs): if not process: process = {} process = _create_process_config(process, kwargs) base_dir = process.get('base_dir', DEFAULT_BASE_DIR) ctx_server_port = process.get('ctx_server_port') proxy_client_path = proxy_client.__file__ if proxy_client_path.endswith('.pyc'): proxy_client_path = proxy_client_path[:-1] local_ctx_sh_path = os.path.join(_get_bin_dir(), 'ctx-sh') local_script_path = get_script(ctx.download_resource, script_path) base_script_path = os.path.basename(local_script_path) remote_ctx_dir = base_dir remote_ctx_path = '{0}/ctx'.format(remote_ctx_dir) remote_ctx_sh_path = '{0}/ctx-sh'.format(remote_ctx_dir) remote_scripts_dir = '{0}/scripts'.format(remote_ctx_dir) remote_work_dir = '{0}/work'.format(remote_ctx_dir) remote_path_suffix = '{0}-{1}'.format(base_script_path, utils.id_generator(size=8)) remote_env_script_path = '{0}/env-{1}'.format(remote_scripts_dir, remote_path_suffix) remote_script_path = '{0}/{1}'.format(remote_scripts_dir, remote_path_suffix) env = process.get('env', {}) cwd = process.get('cwd', remote_work_dir) args = process.get('args') command_prefix = process.get('command_prefix') command = remote_script_path if command_prefix: command = '{0} {1}'.format(command_prefix, command) if args: command = ' '.join([command] + args) with fabric_api.settings(**_fabric_env(fabric_env, warn_only=False)): # the remote host must have ctx and any related files before # running any fabric scripts if not fabric_files.exists(remote_ctx_path): # there may be race conditions with other operations that # may be running in parallel, so we pass -p to make sure # we get 0 exit code if the directory already exists fabric_api.run('mkdir -p {0}'.format(remote_scripts_dir)) fabric_api.run('mkdir -p {0}'.format(remote_work_dir)) # this file has to be present before using ctx fabric_api.put(local_ctx_sh_path, remote_ctx_sh_path) fabric_api.put(proxy_client_path, remote_ctx_path) actual_ctx = ctx._get_current_object() actual_ctx.is_script_exception_defined = ScriptException is not None def abort_operation(message=None): if actual_ctx._return_value is not None: actual_ctx._return_value = ILLEGAL_CTX_OPERATION_ERROR raise actual_ctx._return_value if actual_ctx.is_script_exception_defined: actual_ctx._return_value = ScriptException(message) else: actual_ctx._return_value = UNSUPPORTED_SCRIPT_FEATURE_ERROR raise actual_ctx return actual_ctx._return_value def retry_operation(message=None, retry_after=None): if actual_ctx._return_value is not None: actual_ctx._return_value = ILLEGAL_CTX_OPERATION_ERROR raise actual_ctx._return_value actual_ctx.operation.retry(message=message, retry_after=retry_after) if actual_ctx.is_script_exception_defined: actual_ctx._return_value = ScriptException(message, retry=True) else: actual_ctx._return_value = UNSUPPORTED_SCRIPT_FEATURE_ERROR raise actual_ctx._return_value return actual_ctx._return_value actual_ctx.abort_operation = abort_operation actual_ctx.retry_operation = retry_operation def returns(_value): if actual_ctx._return_value is not None: actual_ctx._return_value = ILLEGAL_CTX_OPERATION_ERROR raise actual_ctx._return_value actual_ctx._return_value = _value actual_ctx.returns = returns actual_ctx._return_value = None original_download_resource = actual_ctx.download_resource def download_resource(resource_path, target_path=None): local_target_path = original_download_resource(resource_path) return fabric_put_in_remote_path(local_target_path, target_path) actual_ctx.download_resource = download_resource original_download_resource_and_render = \ actual_ctx.download_resource_and_render def download_resource_and_render(resource_path, target_path=None, template_variables=None): local_target_path = original_download_resource_and_render( resource_path, template_variables=template_variables) return fabric_put_in_remote_path(local_target_path, target_path) actual_ctx.download_resource_and_render = download_resource_and_render def fabric_put_in_remote_path(local_target_path, target_path): if target_path: remote_target_path = target_path else: remote_target_path = '{0}/{1}'.format( remote_work_dir, os.path.basename(local_target_path)) fabric_api.put(local_target_path, remote_target_path) return remote_target_path def handle_script_result(script_result): if (actual_ctx.is_script_exception_defined and isinstance(script_result, ScriptException)): if script_result.retry: return script_result else: raise NonRecoverableError(str(script_result)) # this happens when more than 1 ctx operation is invoked or # the plugin runs an unsupported feature on older Cloudify elif isinstance(script_result, RuntimeError): raise NonRecoverableError(str(script_result)) # determine if this code runs during exception handling current_exception = sys.exc_info()[1] if current_exception: raise else: return script_result proxy = proxy_server.HTTPCtxProxy(actual_ctx, port=ctx_server_port) env_script = StringIO() env['PATH'] = '{0}:$PATH'.format(remote_ctx_dir) env[CTX_SOCKET_URL] = proxy.socket_url for key, value in env.iteritems(): env_script.write('export {0}={1}\n'.format(key, value)) env_script.write('chmod +x {0}\n'.format(remote_script_path)) env_script.write('chmod +x {0}\n'.format(remote_ctx_path)) # invoke sys.exc_clear() because handle_script_result # invokes sys.exc_info() sys.exc_clear() try: fabric_api.put(local_script_path, remote_script_path) fabric_api.put(env_script, remote_env_script_path) with fabric_context.cd(cwd): with tunnel.remote(proxy.port): try: fabric_api.run('source {0} && {1}'.format( remote_env_script_path, command)) except FabricTaskError: return handle_script_result(actual_ctx._return_value) return handle_script_result(actual_ctx._return_value) finally: proxy.close()