def resolve_block_path(self, block): # modify block['path'] # dicts in python are mutable so it doesn't need to # be passed back # search in global_hooks first if found resolve to # global_hooks_path if block['name'] in GLOBAL_HOOKS.keys(): # cp ~ current_file_path cfp = os.path.realpath(__file__).split("/")[0:-1] cfp = "/".join(cfp) block["path"] = '{0}/built_ins/{1}/'.format( cfp, block["name"]) # if the path is not defined it defaults to # workspace/hooks/typeofhook/name else: block['path'] = '{0}/{1}/{2}/{3}/'.format( self.api.ctx.workspace, self.api.get_evar('hooks_folder', default='hooks'), block.get('type', 'ansible'), block['name'])
def run_actions(self, action_blocks, tgt_data, is_global=False): """ Runs actions inside each action block of each target :param action_blocks: list of action_blocks each block constitues to a type of hook :param tgt_data: data specific to target, which can be dict of topology , layout, outputs, inventory :param is_global: scope of the hook example: action_block: - name: do_something type: shell actions: - echo ' this is 'postup' operation Hello hai how r u ?' """ global_hook_names = GLOBAL_HOOKS.keys() if is_global: raise NotImplementedError('Run Hooks is not implemented \ for global scoped hooks') else: # a_b -> abbr for action_block for a_b in action_blocks: if a_b['name'] in global_hook_names: t_a_b = GLOBAL_HOOKS.get(a_b['name']) # update the extra_vars dict # fetch vars from linchpin.conf # and update them as context vars t_a_b["actions"][0]["extra_vars"].update( self.api.get_evar()) t_a_b["actions"][0]["extra_vars"].update( a_b.get("extra_vars", {})) a_b = t_a_b # currently built-ins support only ansible action_type = a_b.get('type', 'ansible') ab_ctx = a_b['context'] if 'context' in a_b else False if 'path' not in a_b: # search in global_hooks first if found resolve to # global_hooks_path if a_b['name'] in global_hook_names: # cp ~ current_file_path cfp = os.path.realpath(__file__).split("/")[0:-1] cfp = "/".join(cfp) a_b["path"] = '{0}/built_ins/{1}/'.format( cfp, a_b["name"]) # if the path is not defined it defaults to # workspace/hooks/typeofhook/name else: a_b['path'] = '{0}/{1}/{2}/{3}/'.format( self.api.ctx.workspace, self.api.get_evar('hooks_folder', default='hooks'), a_b.get('type', 'ansible'), a_b['name']) if 'action_manager' in a_b: # fetches the action object from the path # add path to python path sys.path.append(a_b['path']) # get the module path module_path = '{0}{1}'.format(a_b['path'], a_b['action_manager']) if os.path.exists(a_b['action_manager']): module_path = a_b['action_manager'] # get module src module_src = open(module_path, 'r').read() # strip .py ext from module path module_path = module_path.strip('.py') # strip .py ext from action_manager a_b['action_manager'] = a_b['action_manager'].strip('.py') # parse the module module_src = ast.parse(module_src) # get all classes inside the class classes = ([ node.name for node in ast.walk(module_src) if isinstance(node, ast.ClassDef) ]) # choose the first name as the class name class_name = classes[0] # import the module with class name, it should work module = __import__(a_b['action_manager']) # get the class class_ = getattr(module, class_name) # a_b_obj is action_block_object a_b_obj = class_(action_type, a_b, tgt_data, context=ab_ctx, verbosity=self.verbosity) else: a_b_obj = ActionBlockRouter(action_type, a_b, tgt_data, context=ab_ctx, verbosity=self.verbosity) try: self.api.ctx.log_state('-------\n' 'start hook' ' {0}:{1}'.format( a_b['type'], a_b['name'])) # validates the class object a_b_obj.validate() # executes the hook hook_result = a_b_obj.execute() if type(hook_result) is list: for result in hook_result: if result[0] > 0: raise HookError("Error in executing hook") else: # for other types of hooks if hook_result > 0: raise HookError("Error in executing hook") # intentionally using print here self.api.ctx.log_state('end hook {0}:{1}\n-------'.format( a_b['type'], a_b['name'])) except Exception as e: dflt = self.api.get_cfg("hook_flags", "ignore_failed_hooks") if not dflt: raise HookError( "Error executing hook: '{0}'".format(e)) self.api.ctx.log_info(str(e))
def run_action(self, state, block, tgt_data): use_shell = ast.literal_eval(self.api.get_cfg("ansible", "use_shell")) if block['name'] in GLOBAL_HOOKS.keys(): block = self.global_hooks_block(block) # currently built-ins support only ansible action_type = block.get('type', 'ansible') ab_ctx = block['context'] if 'context' in block else False if 'path' not in block: self.resolve_block_path(block) if 'action_manager' in block: class_ = self.get_custom_action_manager_class(block) block_obj = class_(action_type, block, tgt_data, context=ab_ctx, state=state, verbosity=self.verbosity, use_shell=use_shell) else: block_obj = ActionBlockRouter(action_type, block, tgt_data, context=ab_ctx, state=state, verbosity=self.verbosity, use_shell=use_shell) try: self.api.ctx.log_state('-------\n' 'start hook' ' {0}:{1}'.format(block['type'], block['name'])) # validates the class object block_obj.validate() if 'src' in block.keys(): self.fetch_src(block) target = self.api.get_evar('target', default=None) hook_result = self.execute_hook(block_obj, target) # write results to rundb self._rundb.update_record(target, self._rundb_id, 'hooks', hook_result) for result in hook_result: if result['return_code'] > 0: raise HookError("Hook execution failed") # intentionally using print here self.api.ctx.log_state('end hook {0}:{1}\n-------'.format( block['type'], block['name'])) except Exception as e: dflt = self.api.get_cfg("hook_flags", "ignore_failed_hooks") if not dflt: raise HookError("Error executing hook: '{0}'".format(e)) self.api.ctx.log_info(str(e))
def run_actions(self, state, action_blocks, tgt_data, is_global=False): """ Runs actions inside each action block of each target :param action_blocks: list of action_blocks each block constitues to a type of hook :param tgt_data: data specific to target, which can be dict of topology , layout, outputs, inventory :param is_global: scope of the hook example: action_block: - name: do_something type: shell actions: - echo ' this is 'postup' operation Hello hai how r u ?' """ global_hook_names = GLOBAL_HOOKS.keys() use_shell = self.api.get_cfg("ansible", "use_shell") if is_global: raise NotImplementedError('Run Hooks is not implemented \ for global scoped hooks') else: # a_b -> abbr for action_block for a_b in action_blocks: if a_b['name'] in global_hook_names: t_a_b = GLOBAL_HOOKS.get(a_b['name']) # update the extra_vars dict # fetch vars from linchpin.conf # and update them as context vars t_a_b["actions"][0]["extra_vars"].update( self.api.get_evar()) t_a_b["actions"][0]["extra_vars"].update( a_b.get("extra_vars", {})) a_b = t_a_b # currently built-ins support only ansible action_type = a_b.get('type', 'ansible') ab_ctx = a_b['context'] if 'context' in a_b else False if 'path' not in a_b: # search in global_hooks first if found resolve to # global_hooks_path if a_b['name'] in global_hook_names: # cp ~ current_file_path cfp = os.path.realpath(__file__).split("/")[0:-1] cfp = "/".join(cfp) a_b["path"] = '{0}/built_ins/{1}/'.format( cfp, a_b["name"]) # if the path is not defined it defaults to # workspace/hooks/typeofhook/name else: a_b['path'] = '{0}/{1}/{2}/{3}/'.format( self.api.ctx.workspace, self.api.get_evar('hooks_folder', default='hooks'), a_b.get('type', 'ansible'), a_b['name']) if 'action_manager' in a_b: # fetches the action object from the path # add path to python path sys.path.append(a_b['path']) # get the module path module_path = '{0}{1}'.format(a_b['path'], a_b['action_manager']) if os.path.exists(a_b['action_manager']): module_path = a_b['action_manager'] # get module src module_src = open(module_path, 'r').read() # strip .py ext from module path module_path = module_path.strip('.py') # strip .py ext from action_manager a_b['action_manager'] = a_b['action_manager'].strip('.py') # parse the module module_src = ast.parse(module_src) # get all classes inside the class classes = ([ node.name for node in ast.walk(module_src) if isinstance(node, ast.ClassDef) ]) # choose the first name as the class name class_name = classes[0] # import the module with class name, it should work module = __import__(a_b['action_manager']) # get the class class_ = getattr(module, class_name) # a_b_obj is action_block_object a_b_obj = class_(action_type, a_b, tgt_data, context=ab_ctx, state=state, verbosity=self.verbosity, use_shell=use_shell) else: a_b_obj = ActionBlockRouter(action_type, a_b, tgt_data, context=ab_ctx, state=state, verbosity=self.verbosity, use_shell=use_shell) try: self.api.ctx.log_state('-------\n' 'start hook' ' {0}:{1}'.format( a_b['type'], a_b['name'])) # validates the class object a_b_obj.validate() if 'src' in a_b.keys(): # fetch the src src_type = a_b['src']['type'] # we can add other source types later # e.g. 'ftp', 'svn', or 'local' for hooks that exist ib # a different location on the local machine if src_type == 'git': git_remote = a_b['src']['url'] # clone repository cwd = os.getcwd() try: git.Git(cwd).clone(git_remote) except GitCommandError as e: err_str = "already exists and is not an" + \ " empty directory" if err_str not in e.stderr: raise pass # move files to relevant section of hooks dir dest_dir = "{0}/hooks/{1}/{2}".format( cwd, a_b['type'], a_b['name']) try: os.makedirs(dest_dir) except OSError as e: if e.errno != os.errno.EEXIST: raise pass repo_name = git_remote.rsplit('/', 1)[-1] for filename in glob.glob( os.path.join(cwd, repo_name, a_b['type'], a_b['name'], '*.*')): if os.path.isdir(filename): shutil.copytree(filename, dest_dir) else: shutil.copy(filename, dest_dir) # remove old directory shutil.rmtree(os.path.join(cwd, repo_name)) else: raise HookError("Invalid type for src") # produce a partial application of update_record to limit # data passed to action managers # get past results from rundb target = self.api.get_evar('target', default=None) action = 'hooks' record = self._rundb.get_record(target, action, self._rundb_id) # executes the hook hook_record = dict(record[0])['hooks'] hook_result = a_b_obj.execute(hook_record) self._rundb.update_record(target, self._rundb_id, 'hooks', hook_result) # write results to rundb for result in hook_result: if result['return_code'] > 0: raise HookError("Error in executing hook") # intentionally using print here self.api.ctx.log_state('end hook {0}:{1}\n-------'.format( a_b['type'], a_b['name'])) except Exception as e: dflt = self.api.get_cfg("hook_flags", "ignore_failed_hooks") if not dflt: raise HookError( "Error executing hook: '{0}'".format(e)) self.api.ctx.log_info(str(e))