def netmiko_file_transfer(task, source_file, dest_file, **kwargs): """ Execute Netmiko file_transfer method Arguments: source_file(str): Source file. dest_file(str): Destination file. kwargs (dict, optional): Additional arguments to pass to file_transfer Returns: :obj:`brigade.core.task.Result`: * result (``bool``): file exists and MD5 is valid * changed (``bool``): the destination file was changed """ net_connect = task.host.get_connection("netmiko") kwargs.setdefault("direction", "put") scp_result = file_transfer(net_connect, source_file=source_file, dest_file=dest_file, **kwargs) if kwargs.get("disable_md5") is True: file_valid = scp_result["file_exists"] else: file_valid = scp_result["file_exists"] and scp_result["file_verified"] return Result(host=task.host, result=file_valid, changed=scp_result["file_transferred"])
def remote_command(task, command): """ Executes a command locally Arguments: command (``str``): command to execute Returns: :obj:`brigade.core.task.Result`: * result (``str``): stderr or stdout * stdout (``str``): stdout * stderr (``srr``): stderr Raises: :obj:`brigade.core.exceptions.CommandError`: when there is a command error """ client = task.host.get_connection("paramiko") chan = client.get_transport().open_session() chan.exec_command(command) exit_status_code = chan.recv_exit_status() with chan.makefile() as f: stdout = f.read().decode() with chan.makefile_stderr() as f: stderr = f.read().decode() if exit_status_code: raise CommandError(command, exit_status_code, stdout, stderr) result = stderr if stderr else stdout return Result(result=result, host=task.host, stderr=stderr, stdout=stdout)
def napalm_configure(task, dry_run=None, filename=None, configuration=None, replace=False): """ Loads configuration into a network devices using napalm Arguments: dry_run (bool): Whether to apply changes or not configuration (str): configuration to load into the device filename (str): filename containing the configuration to load into the device replace (bool): whether to replace or merge the configuration Returns: :obj:`brigade.core.task.Result`: * changed (``bool``): whether if the task is changing the system or not * diff (``string``): change in the system """ device = task.host.get_connection("napalm") if replace: device.load_replace_candidate(filename=filename, config=configuration) else: device.load_merge_candidate(filename=filename, config=configuration) diff = device.compare_config() dry_run = task.is_dry_run(dry_run) if not dry_run and diff: device.commit_config() else: device.discard_config() return Result(host=task.host, diff=diff, changed=len(diff) > 0)
def parse_data(task): data = {} data["failed"] = False data["changed"] = False if "dev1.group_1" == task.host.name: data["values"] = [1, 2, 3] data["changed"] = True elif "dev2.group_1" == task.host.name: data["values"] = [4, 5, 6] elif "dev3.group_2" == task.host.name: data["values"] = [7, 8, 9] elif "dev4.group_2" == task.host.name: data["values"] = [10, 11, 12] data["changed"] = False data["failed"] = True if data["failed"]: raise Exception("Unknown Error -> Contact your system administrator") return Result(host=task.host, changed=data["changed"], result=data["values"])
def command(task, command): """ Executes a command locally Arguments: command (``str``): command to execute Returns: :obj:`brigade.core.task.Result`: * result (``str``): stderr or stdout * stdout (``str``): stdout * stderr (``srr``): stderr Raises: :obj:`brigade.core.exceptions.CommandError`: when there is a command error """ cmd = subprocess.Popen( shlex.split(command), stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=False, ) stdout, stderr = cmd.communicate() stdout = stdout.decode() stderr = stderr.decode() if cmd.poll(): raise CommandError(command, cmd.returncode, stdout, stderr) result = stderr if stderr else stdout return Result(result=result, host=task.host, stderr=stderr, stdout=stdout)
def napalm_cli(task, commands): """ Run commands on remote devices using napalm Arguments: commands (``list``): List of commands to execute Returns: :obj:`brigade.core.task.Result`: * result (``dict``): dictionary with the result of the commands """ device = task.host.get_connection("napalm") result = device.cli(commands) return Result(host=task.host, result=result)
def load_yaml(task, file): """ Loads a yaml file. Arguments: file (str): path to the file containing the yaml file to load Returns: :obj:`brigade.core.task.Result`: * result (``dict``): dictionary with the contents of the file """ with open(file, "r") as f: data = yaml.load(f.read()) return Result(host=task.host, result=data)
def tcp_ping(task, ports, timeout=2, host=None): """ Tests connection to a tcp port and tries to establish a three way handshake. To be used for network discovery or testing. Arguments: ports (list of int): tcp port to ping timeout (int, optional): defaults to 0.5 host (string, optional): defaults to ``brigade_ip`` Returns: :obj:`brigade.core.task.Result`: * result (``dict``): Contains port numbers as keys with True/False as values """ if isinstance(ports, int): ports = [ports] if isinstance(ports, list): if not all(isinstance(port, int) for port in ports): raise ValueError("Invalid value for 'ports'") else: raise ValueError("Invalid value for 'ports'") host = host or task.host.host result = {} for port in ports: s = socket.socket() s.settimeout(timeout) try: status = s.connect_ex((host, port)) if status == 0: connection = True else: connection = False except (socket.gaierror, socket.timeout, socket.error): connection = False finally: s.close() result[port] = connection return Result(host=task.host, result=result)
def napalm_validate(task, src=None, validation_source=None): """ Gather information with napalm and validate it: http://napalm.readthedocs.io/en/develop/validate/index.html Arguments: src: file to use as validation source validation_source (list): instead of a file data needed to validate device's state Returns: :obj:`brigade.core.task.Result`: * result (``dict``): dictionary with the result of the validation * complies (``bool``): Whether the device complies or not """ device = task.host.get_connection("napalm") r = device.compliance_report(validation_file=src, validation_source=validation_source) return Result(host=task.host, result=r)
def netmiko_send_command(task, command_string, use_timing=False, **kwargs): """ Execute Netmiko send_command method (or send_command_timing) Arguments: command_string(str): Command to execute on the remote network device. use_timing(bool, optional): Set to True to switch to send_command_timing method. kwargs (dict, optional): Additional arguments to pass to send_command method. Returns: :obj:`brigade.core.task.Result`: * result (``dict``): dictionary with the result of the show command. """ net_connect = task.host.get_connection("netmiko") if use_timing: result = net_connect.send_command_timing(command_string, **kwargs) else: result = net_connect.send_command(command_string, **kwargs) return Result(host=task.host, result=result)
def template_string(task, template, jinja_filters=None, **kwargs): """ Renders a string with jinja2. All the host data is available in the tempalte Arguments: template (string): template string jinja_filters (dict): jinja filters to enable. Defaults to brigade.config.jinja_filters **kwargs: additional data to pass to the template Returns: :obj:`brigade.core.task.Result`: * result (``string``): rendered string """ jinja_filters = jinja_filters or {} or task.brigade.config.jinja_filters merged = merge_two_dicts(task.host, kwargs) text = jinja_helper.render_from_string(template=template, host=task.host, jinja_filters=jinja_filters, **merged) return Result(host=task.host, result=text)
def http_method(task=None, method="get", url="", raise_for_status=True, **kwargs): """ This is a convenience task that uses `requests <http://docs.python-requests.org/en/master/>`_ to interact with an HTTP server. Arguments: method (string): HTTP method to call url (string): URL to connect to raise_for_status (bool): Whether to call `raise_for_status <http://docs.python-requests.org/en/master/api/#requests.Response.raise_for_status>`_ method automatically or not. For quick reference, raise_for_status will consider an error if the return code is any of 4xx or 5xx **kwargs: Keyword arguments will be passed to the `request <http://docs.python-requests.org/en/master/api/#requests.request>`_ method Returns: :obj:`brigade.core.task.Result`: * result (``string/dict``): Body of the response. Either text or a dict if the response was a json object * reponse (object): Original `Response <http://docs.python-requests.org/en/master/api/#requests.Response>`_ """ r = requests.request(method, url, **kwargs) if raise_for_status: r.raise_for_status() try: content_type = r.headers["Content-type"] except KeyError: content_type = "text" result = r.json() if "application/json" == content_type else r.text return Result(host=task.host if task else None, response=r, result=result)
def write_file(task, filename, content, append=False, dry_run=None): """ Write contents to a file (locally) Arguments: dry_run (bool): Whether to apply changes or not filename (``str``): file you want to write into conteint (``str``): content you want to write append (``bool``): whether you want to replace the contents or append to it Returns: * changed (``bool``): * diff (``str``): unified diff """ diff = _generate_diff(filename, content, append) if not task.is_dry_run(dry_run): mode = "a+" if append else "w+" with open(filename, mode=mode) as f: f.write(content) return Result(host=task.host, diff=diff, changed=bool(diff))
def napalm_get(task, getters): """ Gather information from network devices using napalm Arguments: getters (list of str): getters to use Returns: :obj:`brigade.core.task.Result`: * result (``dict``): dictionary with the result of the getter """ device = task.host.get_connection("napalm") if isinstance(getters, str): getters = [getters] result = {} for g in getters: getter = g if g.startswith("get_") else "get_{}".format(g) method = getattr(device, getter) result[g] = method() return Result(host=task.host, result=result)
def load_data(task): data = {"os": "Linux", "services": ["http", "smtp", "dns"]} return Result(host=task.host, result=data)
def echo_task(task, msg="Brigade"): return Result( host=task.host, result="Hello from {}".format(msg), output="Hello from {}".format(msg), )