Exemple #1
0
    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'])
Exemple #2
0
    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))
Exemple #3
0
    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))
Exemple #4
0
    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))