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
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)
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
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
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
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
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
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