def run(script_path=None, **kwargs): ctx = operation_ctx._get_current_object() script_path = get_script_to_run(script_path, ctx) if not script_path: return script_func = get_run_script_func(script_path, ctx) return process(script_func, script_path, ctx)
def run(script_path, process=None, **kwargs): ctx = operation_ctx._get_current_object() if script_path is None: raise NonRecoverableError('Script path parameter not defined') process = create_process_config(process or {}, kwargs) script_path = download_resource(ctx.download_resource, script_path) os.chmod(script_path, 0755) script_func = get_run_script_func(script_path, process) return process_execution(script_func, script_path, ctx, process)
def calljava(opclass, args, **kwargs): """ Should do whatever "create" is defined as in java code. It is assumed that the java implementation main function accepts an Operation class name and a varargs list """ proxy_server = HTTPCtxProxy(ctx._get_current_object()) try: jarpath = os.path.dirname(os.path.abspath(__file__)) + "/plugin.jar" # below will fail on windows res = subprocess.call( ["java", "-jar", jarpath, str(proxy_server.port), opclass] + args) if res != 0: raise NonRecoverableError( "operation {} execution failed".format(opclass)) finally: proxy_server.close()
def callgo(func, args, **kwargs): """ Should do whatever "create" is defined as in go code. It is assumed that the go implementation main function accepts a funcion name and a varargs list """ install() proxy_server = HTTPCtxProxy(ctx._get_current_object()) try: exepath = ctx.instance.runtime_properties['plugin_path'] # below will fail on windows res = subprocess.call( [exepath, str(proxy_server.port), func, json.dumps(args)]) if res != 0: raise NonRecoverableError("func {} execution faild".format(func)) finally: proxy_server.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()
def execute(script_path, ctx, process): on_posix = 'posix' in sys.builtin_module_names proxy = start_ctx_proxy(ctx, process) env = _get_process_environment(process, proxy) cwd = process.get('cwd') command_prefix = process.get('command_prefix') if command_prefix: command = '{0} {1}'.format(command_prefix, script_path) else: command = script_path args = process.get('args') if args: command = ' '.join([command] + args) # Figure out logging. log_stdout = process.get('log_stdout', True) log_stderr = process.get('log_stderr', True) stderr_to_stdout = process.get('stderr_to_stdout', False) ctx.logger.debug('log_stdout=%r, log_stderr=%r, stderr_to_stdout=%r', log_stdout, log_stderr, stderr_to_stdout) if log_stderr: stderr_value = subprocess.STDOUT if stderr_to_stdout \ else subprocess.PIPE else: stderr_value = None consume_stderr = stderr_value == subprocess.PIPE process = subprocess.Popen(args=command, shell=True, stdout=subprocess.PIPE if log_stdout else None, stderr=stderr_value, env=env, cwd=cwd, bufsize=1, close_fds=on_posix) pid = process.pid ctx.logger.info('Process created, PID: {0}'.format(pid)) stdout_consumer = stderr_consumer = None if log_stdout: stdout_consumer = OutputConsumer( process.stdout, ctx.logger, '<out> ', ctx=operation_ctx._get_current_object()) ctx.logger.debug('Started consumer thread for stdout') if consume_stderr: stderr_consumer = OutputConsumer( process.stderr, ctx.logger, '<err> ', ctx=operation_ctx._get_current_object()) ctx.logger.debug('Started consumer thread for stderr') log_counter = 0 while True: process_ctx_request(proxy) return_code = process.poll() if return_code is not None: break time.sleep(POLL_LOOP_INTERVAL) log_counter += 1 if log_counter == POLL_LOOP_LOG_ITERATIONS: log_counter = 0 ctx.logger.info('Waiting for process {0} to end...'.format(pid)) ctx.logger.info('Execution done (PID={0}, return_code={1}): {2}'.format( pid, return_code, command)) try: proxy.close() except Exception: ctx.logger.warning('Failed closing context proxy', exc_info=True) else: ctx.logger.debug("Context proxy closed") for consumer, name in [(stdout_consumer, 'stdout'), (stderr_consumer, 'stderr')]: if consumer: ctx.logger.debug('Joining consumer thread for %s', name) consumer.join() ctx.logger.debug('Consumer thread for %s ended', name) else: ctx.logger.debug('Consumer thread for %s not created; not joining', name) # happens when more than 1 ctx result command is used if isinstance(ctx._return_value, RuntimeError): raise NonRecoverableError(str(ctx._return_value)) elif return_code != 0: if not (ctx.is_script_exception_defined and isinstance(ctx._return_value, ScriptException)): if log_stdout: stdout = ''.join(stdout_consumer.output) else: stdout = process.stdout.read().decode('utf-8', 'replace') if stderr_to_stdout: stderr = None elif log_stderr: stderr = ''.join(stderr_consumer.output) else: stderr = process.stderr.read().decode('utf-8', 'replace') raise ProcessException(command, return_code, stdout, stderr)
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) 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 tunnel.remote(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, **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()