Esempio n. 1
0
def ncclient_call(task: Task,
                  call: str,
                  fmt: str = "xml",
                  *args,
                  **kwargs) -> Result:
    """
    Task to handle a call of NCClient manager object methods

    :param call: (str) ncclient manager object method to call
    :param fmt: (str) result formatter to use - xml (default), raw_xml, json, yaml, pprint, py
    :param arg: (list) any ``*args`` to use with call method
    :param kwargs: (dict) any ``**kwargs`` to use with call method
    """
    # run sanity check
    if not HAS_NCCLIENT:
        return Result(
            host=task.host,
            failed=True,
            exception="No Ncclient found, is it installed?",
        )

    # initiate parameters
    failed = False
    task.name = call

    # get rendered data if any
    if "__task__" in task.host.data:
        kwargs.update(task.host.data["__task__"])

    # check if filter formed properly - as per
    # https://ncclient.readthedocs.io/en/latest/manager.html#filter-params
    # filter should be a tuple of (type, criteria)
    if kwargs.get("filter"):
        if isinstance(kwargs["filter"], list):
            kwargs["filter"] = tuple(kwargs["filter"])
        elif isinstance(kwargs["filter"], str):
            kwargs["filter"] = tuple(
                [kwargs.pop("ftype", "subtree"), kwargs["filter"]])

    # get Ncclient NETCONF connection object
    manager = task.host.get_connection(CONNECTION_NAME, task.nornir.config)

    # add generic RPC operation to Ncclient manager object to support RPC call
    manager._vendor_operations.update(rpc=GenericRPC)

    log.debug(
        "nornir_salt:ncclient_call calling '{}' with args: '{}'; kwargs: '{}'".
        format(call, args, kwargs))

    # check if need to call one of helper function
    if "_call_{}".format(call) in globals():
        result, failed = globals()["_call_{}".format(call)](manager, *args,
                                                            **kwargs)
    # call manager object method otherwise
    else:
        result = getattr(manager, call)(*args, **kwargs)

    # format results
    if hasattr(result, "_root"):
        if fmt == "xml":
            result = etree.tostring(result._root, pretty_print=True).decode()
        elif fmt == "raw_xml":
            result = etree.tostring(result._root, pretty_print=False).decode()
        elif fmt == "json" and HAS_XMLTODICT:
            parsed_data = xmltodict.parse(etree.tostring(result._root))
            result = json.dumps(parsed_data, sort_keys=True, indent=4)
        elif fmt == "yaml" and HAS_XMLTODICT and HAS_YAML:
            parsed_data = xmltodict.parse(etree.tostring(result._root))
            result = yaml.dump(parsed_data, default_flow_style=False)
        elif fmt == "pprint" and HAS_XMLTODICT:
            parsed_data = xmltodict.parse(etree.tostring(result._root))
            result = pprint.pformat(parsed_data, indent=4)
        elif fmt == "py" and HAS_XMLTODICT:
            result = xmltodict.parse(etree.tostring(result._root))
        else:
            result = etree.tostring(result._root, pretty_print=True).decode()
    elif isinstance(result, (list, dict, bool)):
        pass
    else:
        result = str(result)

    return Result(host=task.host, result=result, failed=failed)
def scrapli_netconf_call(task: Task,
                         call: str,
                         fmt: str = "xml",
                         *args,
                         **kwargs) -> Result:
    """
    Discpatcher function to call one of the supported scrapli_netconf methods
    or one of helper functions.
    
    :param call: (str) Scrapli Netconf connection object method to call
    :param fmt: (str) result formatter to use - xml (default), raw_xml, json, yaml, pprint, py
    :param arg: (list) any ``*args`` to use with call method
    :param kwargs: (dict) any ``**kwargs`` to use with call method
    """
    # initiate local parameteres
    result = None
    failed = False
    task.name = call

    # get rendered data if any
    if "__task__" in task.host.data:
        kwargs.update(task.host.data["__task__"])

    log.debug(
        "nornir_salt:scrapli_netconf_call calling '{}' with args: '{}'; kwargs: '{}'"
        .format(call, args, kwargs))

    # get scrapli-netconf connection object
    conn = task.host.get_connection("scrapli_netconf", task.nornir.config)

    # check if need to call one of helper function
    if "_call_{}".format(call) in globals():
        result, failed = globals()["_call_{}".format(call)](conn, *args,
                                                            **kwargs)
    # call conn object method otherwise
    else:
        result = getattr(conn, call)(*args, **kwargs)

    # format results
    if hasattr(result, "result"):
        if fmt == "xml":
            result = result.result
        elif fmt == "raw_xml":
            result = result.result
        elif fmt == "json" and HAS_XMLTODICT:
            parsed_data = xmltodict.parse(result.result)
            result = json.dumps(parsed_data, sort_keys=True, indent=4)
        elif fmt == "yaml" and HAS_XMLTODICT and HAS_YAML:
            parsed_data = xmltodict.parse(result.result)
            result = yaml.dump(parsed_data, default_flow_style=False)
        elif fmt == "pprint" and HAS_XMLTODICT:
            parsed_data = xmltodict.parse(result.result)
            result = pprint.pformat(parsed_data, indent=4)
        elif fmt == "py" and HAS_XMLTODICT:
            result = xmltodict.parse(result.result)
        else:
            result = etree.tostring(result._root, pretty_print=True).decode()
    elif isinstance(result, (list, dict, bool)):
        pass
    else:
        result = str(result)

    return Result(host=task.host, result=result, failed=failed)