예제 #1
0
파일: role.py 프로젝트: lmcad-unicamp/CLAP
def role_remove(role, nodes, node):
    """ Perform an group action at a set of nodes.

    The ROLE argument specify the role which the action will be performed.
    """
    role_manager = get_role_manager()
    node += nodes
    nodes, node_vars, host_vars, extra_args = _split_vars(node, [], [], [])

    if not nodes:
        raise ArgumentError('No nodes informed')

    if type(nodes) is list:
        d = defaultdict(list)
        for n in nodes:
            hosts = role_manager.get_role_node_hosts(role, n)
            if not hosts:
                raise NodeRoleError(n, role)
            for hname in hosts:
                d[hname].append(n)
        nodes = defaultdict_to_dict(d)
    else:
        nodes = nodes

    if not nodes:
        raise ValueError(f"No nodes to remove from role {role}")

    result = role_manager.remove_role(role, nodes)
    print(
        f"{len(result)} nodes were removed from {role}: {', '.join(sorted(result))}"
    )
    return 0
예제 #2
0
    def create_inventory(
            hosts_node_map: Union[
                List[NodeDescriptor], Dict[str, List[NodeDescriptor]]],
            private_path: str,
            host_vars: Dict[str, Dict[str, str]] = None,
            node_vars: Dict[str, Dict[str, str]] = None) -> dict:
        inventory = defaultdict(dict)
        hosts = defaultdict(dict)
        host_vars = host_vars or dict()
        node_vars = node_vars or dict()

        if type(hosts_node_map) is list:
            hosts_node_map = {'all': hosts_node_map}
        elif type(hosts_node_map) is not dict:
            raise TypeError(f"Invalid type {type(hosts_node_map)} for "
                            f"hosts_node_map parameter")

        for host, node_list in hosts_node_map.items():
            host_dict = dict()
            try:
                host_dict['vars'] = host_vars[host]
            except KeyError:
                pass

            _hosts = dict()
            for node in node_list:
                _host_vars = dict()
                _host_vars['ansible_host'] = node.ip
                _host_vars['ansible_connection'] = 'ssh'
                _host_vars['ansible_user'] = node.configuration.login.user
                _host_vars['ansible_ssh_private_key_file'] = path_extend(
                    private_path, node.configuration.login.keypair_private_file)
                _host_vars['ansible_port'] = node.configuration.login.ssh_port
                _host_vars.update(node_vars.get(node.node_id, dict()))
                _hosts[node.node_id] = _host_vars

            host_dict['hosts'] = _hosts

            if host == 'all':
                inventory['all'] = host_dict
            else:
                hosts[host] = host_dict

        if hosts:
            inventory['all']['children'] = defaultdict_to_dict(hosts)

        return defaultdict_to_dict(inventory)
예제 #3
0
    def run(self) -> PlaybookResult:
        with tmpdir() as tdir:
            logger.debug(f"Ansible runner will execute the playbook at: "
                         f"`{self.playbook_file}`.")
            logger.debug(f"Inventory: \n{yaml.dump(self.inventory)}")
            logger.debug(f"Extra: \n{yaml.dump(self.extra_args)}")
            ret = ansible_runner.run(
                private_data_dir=tdir, inventory=self.inventory,
                playbook=self.playbook_file, quiet=self.quiet,
                verbosity=self.verbosity, extravars=self.extra_args,
                envvars=self.env_vars,
                debug=True if self.verbosity > 3 else False)

            host_playbook_vars = defaultdict(dict)
            for e in ret.events:
                try:
                    if e['event_data']['task_action'] == 'set_fact' and \
                            e['event'] == 'runner_on_ok':
                        params = e['event_data']['res']['ansible_facts']
                        host = e['event_data']['host']
                        host_playbook_vars[host].update(params)
                except KeyError:
                    continue

            host_playbook_vars = defaultdict_to_dict(host_playbook_vars)
            logger.debug(f"Collected host playbook variables (facts): "
                         f"{host_playbook_vars}")

            stats = ret.stats
            if stats is None:
                r = self.PlaybookResult(
                    ok=False, ret_code=ret.rc, hosts={}, events={},
                    vars=host_playbook_vars
                )
                return r

            all_nodes = list({host for hosts in stats.values()
                              for host in hosts.keys()})
            not_ok_nodes = list({host for s in ['dark', 'failures']
                                 for host in stats[s].keys()})
            hosts_stats = {n: n not in not_ok_nodes for n in all_nodes}
            hosts_events = {n: list(ret.host_events(n)) for n in all_nodes}

            r = self.PlaybookResult(
                ok=ret.status == 'successful',
                ret_code=ret.rc,
                hosts=hosts_stats,
                events=hosts_events,
                vars=host_playbook_vars
            )
            return r
예제 #4
0
    def run_action(self, action: ActionType, node_ids: List[str]) -> bool:
        """ Run a cluster's action in a set of nodes.

        :param action: Cluster's action to be performed
        :param node_ids: ID of the nodes to perform this action
        :return: True if action as sucessfully performed and false otherwise
        """
        # TODO Check this function
        logger.info(f"Executing action: {action} at nodes: {node_ids}")
        try:
            nodes = self.node_manager.get_nodes_by_id(node_ids)
            if type(action) is CommandActionType:
                e = SSHCommandExecutor(action.command, nodes, self.private_dir)
                result = e.run()
                return all(r.ok for r in result.values())

            elif type(action) is RoleActionType:
                d = defaultdict(list)
                for n in node_ids:
                    hosts = self.role_manager.get_role_node_hosts(
                        action.role, n)
                    if not hosts:
                        raise NodeRoleError(n, action.role)
                    for hname in hosts:
                        d[hname].append(n)
                _nodes_ids = defaultdict_to_dict(d)
                result = self.role_manager.perform_action(
                    action.role,
                    action.action,
                    _nodes_ids,
                    extra_args=action.extra)
                return result.ok

            elif type(action) is PlaybookActionType:
                inventory = AnsiblePlaybookExecutor.create_inventory(
                    nodes, self.private_dir)
                e = AnsiblePlaybookExecutor(action.playbook, self.private_dir,
                                            inventory, action.extra)
                result = e.run()
                return result.ok

            else:
                logger.error(f"Invalid action type: {type(action)}")
                return False

        except Exception as e:
            logger.error(f"{e.__class__.__name__}: {e}")
            return False
예제 #5
0
파일: role.py 프로젝트: lmcad-unicamp/CLAP
def role_action(role, action, nodes, node, node_vars, host_vars, extra):
    """ Perform an group action at a set of nodes.

    The ROLE argument specify the role which the action will be performed.
    """
    role_manager = get_role_manager()
    node += nodes
    nodes, node_vars, host_vars, extra_args = _split_vars(
        node, node_vars, host_vars, extra)

    if not nodes:
        nodes = role_manager.get_all_role_nodes_hosts(role)
    else:
        if type(nodes) is list:
            d = defaultdict(list)
            for n in nodes:
                hosts = role_manager.get_role_node_hosts(role, n)
                if not hosts:
                    raise NodeRoleError(n, role)
                for hname in hosts:
                    d[hname].append(n)
            nodes = defaultdict_to_dict(d)
        else:
            nodes = nodes

    all_values = [n for v in nodes.values() for n in v]
    if not all_values:
        raise ValueError(
            f"No nodes to perform the action '{action} of role {role}")

    result = role_manager.perform_action(role,
                                         action,
                                         hosts_node_map=nodes,
                                         host_vars=host_vars,
                                         node_vars=node_vars,
                                         extra_args=extra_args)

    if not result.ok:
        logger.error(f"Playbook for action {action} of role {role} did not "
                     f"executed successfully...")
        return 1

    print(f"Action {action} from role {role} was successfully performed!")
    return 0
예제 #6
0
def cluster_grow(cluster_id, node, no_setup):
    """Start more nodes at a cluster by cluster node type.

    The CLUSTER_ID argument is the id of the cluster to add more nodes.
    """
    cluster_manager = get_cluster_manager()
    nodes_to_start = list()

    for n in node:
        node_name, qtde = n.split(':')[0], int(
            n.split(':')[1]) if ':' in n else 1
        nodes_to_start.append((node_name, qtde))

    all_nodes = defaultdict(list)
    for node_type, qtde in nodes_to_start:
        nodes = cluster_manager.grow(cluster_id,
                                     node_type,
                                     qtde,
                                     min_count=qtde)
        print(
            f"Started {len(nodes)} of type {node_type}: {', '.join(sorted(nodes))}"
        )
        all_nodes[node_type] += nodes
    all_nodes = defaultdict_to_dict(all_nodes)

    if no_setup:
        return 0

    print(f"Performing setup operation in cluster {cluster_id}")
    try:
        cluster_manager.setup_cluster(cluster_id, nodes_being_added=all_nodes)
    except Exception as e:
        logger.error(e)
        print(f"Cluster not properly setup... You may wish perform the setup "
              f"operation again")
        return 1
    print(f"Cluster `{cluster_id}` finished setup!")
    return 0
예제 #7
0
파일: role.py 프로젝트: lmcad-unicamp/CLAP
def _split_vars(nodes, node_vars, host_vars, extra_vars):
    # Preprocess node
    # Is format <role_host_name>:<node>,<node>, ...?
    if nodes:
        if all(':' in n for n in nodes):
            _nodes = defaultdict(list)
            for n in nodes:
                host_name, list_nodes = n.split(':')
                _nodes[host_name] += [n for n in list_nodes.split(',') if n]
            _nodes = dict(_nodes)
        # Is format <node>,<node>  <node>,<node>
        elif all(':' not in n for n in nodes):
            _nodes = [h for n in nodes for h in n.split(',') if h]
        else:
            raise ValueError(
                'Multiple formats for node option. Specify a host or '
                'not for all node options')
    else:
        _nodes = []

    # Preprocess node extra args
    node_variables = defaultdict(dict)
    for nvar in node_vars:
        if ':' not in nvar:
            raise ValueError(f"Invalid value for node argument: `{nvar}`. "
                             f"Did you forgot ':' character?")
        node_id, node_extra_args = nvar.split(':')[0], ':'.join(
            nvar.split(':')[1:])
        for narg in node_extra_args.split(','):
            if '=' not in narg:
                raise ValueError(
                    f"Invalid value for extra argument: '{narg}'. "
                    f"Did you forgot '=' character?")
            extra_name, extra_value = narg.split('=')[0], '='.join(
                narg.split('=')[1:])
            node_variables[node_id].update({extra_name: extra_value})

    # Preprocess host extra args
    host_variables = defaultdict(dict)
    for hvar in host_vars:
        if ':' not in hvar:
            raise ValueError(f"Invalid value for host argument: `{hvar}`. "
                             f"Did you forgot ':' character?")
        host, host_extras = hvar.split(':')[0], ':'.join(hvar.split(':')[1:])
        for harg in host_extras.split(','):
            if '=' not in harg:
                raise ValueError(
                    f"Invalid value for host extra argument: '{harg}'. "
                    f"Did you forgot '=' character?")
            extra_name, extra_value = harg.split('=')[0], '='.join(
                harg.split('=')[1:])
            host_variables[host].update({extra_name: extra_value})

    # Preprocess extra args
    extra_args = dict()
    for e in extra_vars:
        if '=' not in e:
            raise ValueError(f"Invalid value for extra argument: `{e}`. "
                             f"Did you forgot '=' character?")
        extra_name, extra_value = e.split('=')[0], '='.join(e.split('=')[1:])
        extra_args[extra_name] = extra_value

    node_variables = defaultdict_to_dict(node_variables)
    host_variables = defaultdict_to_dict(host_variables)
    return _nodes, node_variables, host_variables, extra_args
예제 #8
0
def cluster_playbook(cluster_id, playbook, extra, node_vars):
    """Execute an Ansible Playbook in all cluster nodes.

    The CLUSTER_ID argument is the id of the cluster to execute the Ansible Playbook.
    """
    cluster_manager = get_cluster_manager()
    node_manager = get_node_manager()
    nodes = cluster_manager.get_all_cluster_nodes(cluster_id)
    nodes = node_manager.get_nodes_by_id(nodes)

    if not nodes:
        print("No nodes in the cluster")
        return 0

    extra_args = dict()
    for e in extra:
        if '=' not in e:
            raise ValueError(f"Invalid value for extra argument: `{e}`. "
                             f"Did you forgot '=' character?")
        extra_name, extra_value = e.split('=')[0], '='.join(e.split('=')[1:])
        extra_args[extra_name] = extra_value

    playbook = path_extend(playbook)
    if not os.path.isfile(playbook):
        raise ValueError(f"Invalid playbook file `{playbook}`")

    node_variables = defaultdict(dict)
    for nvar in node_vars:
        if ':' not in nvar:
            raise ValueError(f"Invalid value for node argument: `{nvar}`. "
                             f"Did you forgot ':' character?")
        node_id, node_extra_args = nvar.split(':')[0], ':'.join(
            nvar.split(':')[1:])
        for narg in node_extra_args.split(','):
            if '=' not in narg:
                raise ValueError(
                    f"Invalid value for extra argument: '{narg}'. "
                    f"Did you forgot '=' character?")
            extra_name, extra_value = narg.split('=')[0], '='.join(
                narg.split('=')[1:])
            node_variables[node_id].update({extra_name: extra_value})

    node_variables = defaultdict_to_dict(node_variables)
    inventory = AnsiblePlaybookExecutor.create_inventory(
        nodes, cluster_defaults.base_defaults.private_path, {}, node_variables)
    executor = AnsiblePlaybookExecutor(
        playbook, cluster_defaults.base_defaults.private_path, inventory,
        extra_args)
    result = executor.run()

    if not result.ok:
        logger.error(f"Playbook {playbook} did not executed successfully...")
        return 1

    print(str_at_middle("Execution Summary", 80))
    for node_id in sorted(list(result.hosts.keys())):
        r = result.hosts[node_id]
        print(f"{node_id}: {'ok' if r else 'not ok'}")

    print(
        f"Playbook at `{playbook}` were executed in {len(result.hosts)} nodes")
    return 0