Ejemplo n.º 1
0
def multi_call(*methods, **kwargs):
    '''
    Invoke multiple Netmiko methods at once, and return their output, as list.

    methods
        A list of dictionaries with the following keys:

        - ``name``: the name of the Netmiko method to be executed.
        - ``args``: list of arguments to be sent to the Netmiko method.
        - ``kwargs``: dictionary of arguments to be sent to the Netmiko method.

    kwargs
        Key-value dictionary with the connection details (when not running
        under a Proxy Minion).
    '''
    kwargs = clean_kwargs(**kwargs)
    if 'netmiko.conn' in __proxy__:
        conn = __proxy__['netmiko.conn']()
    else:
        conn, kwargs = _prepare_connection(**kwargs)
    ret = []
    for method in methods:
        # Explicit unpacking
        method_name = method['name']
        method_args = method.get('args', [])
        method_kwargs = method.get('kwargs', [])
        ret.append(getattr(conn, method_name)(*method_args, **method_kwargs))
    if 'netmiko.conn' not in __proxy__:
        conn.disconnect()
    return ret
Ejemplo n.º 2
0
def get_connection(**kwargs):
    '''
    Return the connection object to the pyeapi Node.

    .. warning::

        This function returns an unserializable object, hence it is not meant
        to be used on the CLI. This should mainly be used when invoked from
        other modules for the low level connection with the network device.

    kwargs
        Key-value dictionary with the authentication details.

    USAGE Example:

    .. code-block:: python

        conn = __salt__['pyeapi.get_connection'](host='router1.example.com',
                                                 username='******',
                                                 password='******')
        show_ver = conn.run_commands(['show version', 'show interfaces'])
    '''
    kwargs = clean_kwargs(**kwargs)
    if 'pyeapi.conn' in __proxy__:
        return __proxy__['pyeapi.conn']()
    conn, kwargs = _prepare_connection(**kwargs)
    return conn
Ejemplo n.º 3
0
def replace(old_value, new_value, full_match=False, **kwargs):
    """
    Replace string or full line matches in switch's running config.

    If full_match is set to True, then the whole line will need to be matched
    as part of the old value.

    .. code-block:: bash

        salt '*' nxos.replace 'TESTSTRINGHERE' 'NEWTESTSTRINGHERE'
    """
    if full_match is False:
        matcher = re.compile("^.*{}.*$".format(re.escape(old_value)), re.MULTILINE)
        repl = re.compile(re.escape(old_value))
    else:
        matcher = re.compile(old_value, re.MULTILINE)
        repl = re.compile(old_value)

    lines = {"old": [], "new": []}
    for line in matcher.finditer(show_run()):
        lines["old"].append(line.group(0))
        lines["new"].append(repl.sub(new_value, line.group(0)))

    kwargs = clean_kwargs(**kwargs)
    if lines["old"]:
        delete_config(lines["old"], **kwargs)
    if lines["new"]:
        config(lines["new"], **kwargs)

    return lines
Ejemplo n.º 4
0
def _prepare_connection(**nxos_api_kwargs):
    """
    Prepare the connection with the remote network device, and clean up the key
    value pairs, removing the args used for the connection init.
    """
    nxos_api_kwargs = clean_kwargs(**nxos_api_kwargs)
    init_kwargs = {}
    # Clean up any arguments that are not required
    for karg, warg in nxos_api_kwargs.items():
        if karg in RPC_INIT_KWARGS:
            init_kwargs[karg] = warg
    if "host" not in init_kwargs:
        init_kwargs["host"] = "localhost"
    if "transport" not in init_kwargs:
        init_kwargs["transport"] = "https"
    if "port" not in init_kwargs:
        init_kwargs["port"] = 80 if init_kwargs["transport"] == "http" else 443
    verify = init_kwargs.get("verify", True)
    if isinstance(verify, bool):
        init_kwargs["verify_ssl"] = verify
    else:
        init_kwargs["ca_bundle"] = verify
    if "rpc_version" not in init_kwargs:
        init_kwargs["rpc_version"] = "2.0"
    if "timeout" not in init_kwargs:
        init_kwargs["timeout"] = 60
    return init_kwargs
Ejemplo n.º 5
0
def multi_call(*methods, **kwargs):
    '''
    Invoke multiple Netmiko methods at once, and return their output, as list.

    methods
        A list of dictionaries with the following keys:

        - ``name``: the name of the Netmiko method to be executed.
        - ``args``: list of arguments to be sent to the Netmiko method.
        - ``kwargs``: dictionary of arguments to be sent to the Netmiko method.

    kwargs
        Key-value dictionary with the connection details (when not running
        under a Proxy Minion).
    '''
    kwargs = clean_kwargs(**kwargs)
    if 'netmiko.conn' in __proxy__:
        conn = __proxy__['netmiko.conn']()
    else:
        conn, kwargs = _prepare_connection(**kwargs)
    ret = []
    for method in methods:
        # Explicit unpacking
        method_name = method['name']
        method_args = method.get('args', [])
        method_kwargs = method.get('kwargs', [])
        ret.append(getattr(conn, method_name)(*method_args, **method_kwargs))
    if 'netmiko.conn' not in __proxy__:
        conn.disconnect()
    return ret
Ejemplo n.º 6
0
def set_password(
    username,
    password,
    encrypted=False,
    role=None,
    crypt_salt=None,
    algorithm="sha256",
    **kwargs
):
    """
    Set users password on switch.

    username
        Username to configure

    password
        Password to configure for username

    encrypted
        Whether or not to encrypt the password
        Default: False

    role
        Configure role for the username
        Default: None

    crypt_salt
        Configure crypt_salt setting
        Default: None

    algorithm
        Encryption algorithm
        Default: sha256

    save_config
        If False, don't save configuration commands to startup configuration.
        If True, save configuration to startup configuration.
        Default: True

    .. code-block:: bash

        salt '*' nxos.set_password admin TestPass
        salt '*' nxos.set_password admin \\
            password='******' \\
            encrypted=True
    """
    if algorithm == "blowfish":
        raise SaltInvocationError("Hash algorithm requested isn't available on nxos")
    get_user(username, **kwargs)  # verify user exists
    if encrypted is False:
        hashed_pass = gen_hash(
            crypt_salt=crypt_salt, password=password, algorithm=algorithm
        )
    else:
        hashed_pass = password
    password_line = "username {} password 5 {}".format(username, hashed_pass)
    if role is not None:
        password_line += " role {}".format(role)
    kwargs = clean_kwargs(**kwargs)
    return config(password_line, **kwargs)
Ejemplo n.º 7
0
def add_config(lines, **kwargs):
    """
    Add one or more config lines to the NX-OS device running config.

    lines
        Configuration lines to add

    save_config
        If False, don't save configuration commands to startup configuration.
        If True, save configuration to startup configuration.
        Default: True

    .. code-block:: bash

        salt '*' nxos.add_config 'snmp-server community TESTSTRINGHERE group network-operator'

    .. note::
        For more than one config added per command, lines should be a list.
    """
    warn_until(
        "Argon",
        "'nxos.add_config lines' is deprecated in favor of 'nxos.config commands'",
    )

    kwargs = clean_kwargs(**kwargs)
    return config(lines, **kwargs)
Ejemplo n.º 8
0
def get_connection(**kwargs):
    """
    Return the Netmiko connection object.

    .. warning::

        This function returns an unserializable object, hence it is not meant
        to be used on the CLI. This should mainly be used when invoked from
        other modules for the low level connection with the network device.

    kwargs
        Key-value dictionary with the authentication details.

    USAGE Example:

    .. code-block:: python

        conn = __salt__['netmiko.get_connection'](host='router1.example.com',
                                                  username='******',
                                                  password='******')
        show_if = conn.send_command('show interfaces')
        conn.disconnect()
    """
    kwargs = clean_kwargs(**kwargs)
    if "netmiko.conn" in __proxy__:
        return __proxy__["netmiko.conn"]()
    conn, kwargs = _prepare_connection(**kwargs)
    return conn
Ejemplo n.º 9
0
    def __init__(self, **nxos_kwargs):
        """
        Initialize NxapiClient() connection object.  By default this connects
        to the local unix domain socket (UDS).  If http(s) is required to
        connect to a remote device then
            nxos_kwargs['host'],
            nxos_kwargs['username'],
            nxos_kwargs['password'],
            nxos_kwargs['transport'],
            nxos_kwargs['port'],
        parameters must be provided.
        """
        self.nxargs = self._prepare_conn_args(clean_kwargs(**nxos_kwargs))
        # Default: Connect to unix domain socket on localhost.
        if self.nxargs["connect_over_uds"]:
            if not os.path.exists(self.NXAPI_UDS):
                raise NxosClientError(
                    "No host specified and no UDS found at {}\n".format(
                        self.NXAPI_UDS))

            # Create UHTTPConnection object for NX-API communication over UDS.
            log.info("Nxapi connection arguments: %s", self.nxargs)
            log.info("Connecting over unix domain socket")
            self.connection = UHTTPConnection(self.NXAPI_UDS)
        else:
            # Remote connection - Proxy Minion, connect over http(s)
            log.info("Nxapi connection arguments: %s", self.nxargs)
            log.info("Connecting over %s", self.nxargs["transport"])
            self.connection = salt.utils.http.query
Ejemplo n.º 10
0
def delete_config(lines, **kwargs):
    """
    Delete one or more config lines to the switch running config.

    lines
        Configuration lines to remove.

    save_config
        If False, don't save configuration commands to startup configuration.
        If True, save configuration to startup configuration.
        Default: True

    .. code-block:: bash

        salt '*' nxos.delete_config 'snmp-server community TESTSTRINGHERE group network-operator'

    .. note::
        For more than one config deleted per command, lines should be a list.
    """
    if not isinstance(lines, list):
        lines = [lines]
    for i, _ in enumerate(lines):
        lines[i] = "no " + lines[i]
    result = None
    try:
        kwargs = clean_kwargs(**kwargs)
        result = config(lines, **kwargs)
    except CommandExecutionError as e:
        # Some commands will generate error code 400 if they do not exist
        # and we try to remove them.  These can be ignored.
        if ast.literal_eval(e.message)["code"] != "400":
            raise
    return result
Ejemplo n.º 11
0
def _prepare_connection(**nxos_api_kwargs):
    '''
    Prepare the connection with the remote network device, and clean up the key
    value pairs, removing the args used for the connection init.
    '''
    nxos_api_kwargs = clean_kwargs(**nxos_api_kwargs)
    init_kwargs = {}
    # Clean up any arguments that are not required
    for karg, warg in six.iteritems(nxos_api_kwargs):
        if karg in RPC_INIT_KWARGS:
            init_kwargs[karg] = warg
    if 'host' not in init_kwargs:
        init_kwargs['host'] = 'localhost'
    if 'transport' not in init_kwargs:
        init_kwargs['transport'] = 'https'
    if 'port' not in init_kwargs:
        init_kwargs['port'] = 80 if init_kwargs['transport'] == 'http' else 443
    verify = init_kwargs.get('verify', True)
    if isinstance(verify, bool):
        init_kwargs['verify_ssl'] = verify
    else:
        init_kwargs['ca_bundle'] = verify
    if 'rpc_version' not in init_kwargs:
        init_kwargs['rpc_version'] = '2.0'
    if 'timeout' not in init_kwargs:
        init_kwargs['timeout'] = 60
    return init_kwargs
Ejemplo n.º 12
0
def get_connection(**kwargs):
    '''
    Return the connection object to the pyeapi Node.

    .. warning::

        This function returns an unserializable object, hence it is not meant
        to be used on the CLI. This should mainly be used when invoked from
        other modules for the low level connection with the network device.

    kwargs
        Key-value dictionary with the authentication details.

    USAGE Example:

    .. code-block:: python

        conn = __salt__['pyeapi.get_connection'](host='router1.example.com',
                                                 username='******',
                                                 password='******')
        show_ver = conn.run_commands(['show version', 'show interfaces'])
    '''
    kwargs = clean_kwargs(**kwargs)
    if 'pyeapi.conn' in __proxy__:
        return __proxy__['pyeapi.conn']()
    conn, kwargs = _prepare_connection(**kwargs)
    return conn
Ejemplo n.º 13
0
def call(method, *args, **kwargs):
    """
    Calls an arbitrary netmiko method.
    """
    kwargs = clean_kwargs(**kwargs)
    connection_timeout = __context__["netmiko_device"]["connection_timeout"]

    with connection(connection_timeout) as con:
        return getattr(con, method)(*args, **kwargs)
Ejemplo n.º 14
0
def call(method, *args, **kwargs):
    '''
    Calls an arbitrary netmiko method.
    '''
    kwargs = clean_kwargs(**kwargs)
    if not netmiko_device['always_alive']:
        connection = ConnectHandler(**netmiko_device['args'])
        ret = getattr(connection, method)(*args, **kwargs)
        connection.disconnect()
        return ret
    return getattr(netmiko_device['connection'], method)(*args, **kwargs)
Ejemplo n.º 15
0
def call(method, *args, **kwargs):
    """
    Calls an arbitrary netmiko method.
    """
    kwargs = clean_kwargs(**kwargs)
    if not netmiko_device["always_alive"]:
        connection = ConnectHandler(**netmiko_device["args"])
        ret = getattr(connection, method)(*args, **kwargs)
        connection.disconnect()
        return ret
    return getattr(netmiko_device["connection"], method)(*args, **kwargs)
Ejemplo n.º 16
0
def call(method, *args, **kwargs):
    '''
    Calls an arbitrary netmiko method.
    '''
    kwargs = clean_kwargs(**kwargs)
    if not netmiko_device['always_alive']:
        connection = ConnectHandler(**netmiko_device['args'])
        ret = getattr(connection, method)(*args, **kwargs)
        connection.disconnect()
        return ret
    return getattr(netmiko_device['connection'], method)(*args, **kwargs)
Ejemplo n.º 17
0
def _sendline_ssh(commands, timeout=None, **kwargs):
    if isinstance(commands, str):
        commands = [commands]
    command = " ; ".join(commands)
    if _ping_ssh() is False:
        _init_ssh()
    out, err = DEVICE_DETAILS[_worker_name()].sendline(command)
    _, out = out.split("\n", 1)
    out, _, _ = out.rpartition("\n")
    kwargs = clean_kwargs(**kwargs)
    _parse_output_for_errors(out, command, **kwargs)
    return out
Ejemplo n.º 18
0
def filter(app, endpoint, **kwargs):
    '''
    Get a list of items from NetBox.

    .. code-block:: bash

        salt myminion netbox.filter dcim devices status=1 role=router
    '''
    ret = []
    nb = _nb_obj(auth_required=True if app in AUTH_ENDPOINTS else False)
    nb_query = getattr(getattr(nb, app),
                       endpoint).filter(**clean_kwargs(**kwargs))
    if nb_query:
        ret = [_strip_url_field(dict(i)) for i in nb_query]
    return sorted(ret)
Ejemplo n.º 19
0
def freeze(name=None, force=False, **kwargs):
    '''
    Save the list of package and repos in a freeze file.

    As this module is build on top of the pkg module, the user can
    send extra attributes to the underlying pkg module via kwargs.
    This function will call ``pkg.list_pkgs`` and ``pkg.list_repos``,
    and any additional arguments will be passed through to those
    functions.

    name
        Name of the frozen state. Optional.

    force
        If true, overwrite the state. Optional.

    CLI Example:

    .. code-block:: bash

        salt '*' freezer.freeze
        salt '*' freezer.freeze pre_install
        salt '*' freezer.freeze force=True root=/chroot

    '''
    states_path = _states_path()

    try:
        if not os.path.exists(states_path):
            os.makedirs(states_path)
    except OSError as e:
        msg = 'Error when trying to create the freezer storage %s: %s'
        log.error(msg, states_path, e)
        raise CommandExecutionError(msg % (states_path, e))

    if status(name) and not force:
        raise CommandExecutionError('The state is already present. Use '
                                    'force parameter to overwrite.')
    safe_kwargs = clean_kwargs(**kwargs)
    pkgs = __salt__['pkg.list_pkgs'](**safe_kwargs)
    repos = __salt__['pkg.list_repos'](**safe_kwargs)
    for fname, content in zip(_paths(name), (pkgs, repos)):
        with fopen(fname, 'w') as fp:
            json.dump(content, fp)
    return True
Ejemplo n.º 20
0
def remove_user(username, **kwargs):
    """
    Remove user from switch.

    username
        Username to remove

    save_config
        If False, don't save configuration commands to startup configuration.
        If True, save configuration to startup configuration.
        Default: True

    .. code-block:: bash

        salt '*' nxos.remove_user username=daniel
    """
    user_line = "no username {}".format(username)
    kwargs = clean_kwargs(**kwargs)
    return config(user_line, **kwargs)
Ejemplo n.º 21
0
def _get_endpoint(endpoint, id=None, **kwargs):
    username, password = _get_auth(kwargs.pop("username", None),
                                   kwargs.pop("password", None))
    kwargs = clean_kwargs(**kwargs)
    url = _build_url(endpoint, id=id)
    ret = {"comment": "", "result": True, "out": None}
    res = salt.utils.http.query(
        url,
        method="GET",
        decode=True,
        username=username,
        password=password,
        params=kwargs,
    )
    if "error" in res:
        ret.update({"result": False, "comment": res["error"]})
        return ret
    ret["out"] = res["dict"]["data"]
    return ret
Ejemplo n.º 22
0
def call(method, *args, **kwargs):
    '''
    Invoke an arbitrary Netmiko method.

    method
        The name of the Netmiko method to invoke.

    args
        A list of arguments to send to the method invoked.

    kwargs
        Key-value dictionary to send to the method invoked.
    '''
    kwargs = clean_kwargs(**kwargs)
    if 'netmiko.call' in __proxy__:
        return __proxy__['netmiko.call'](method, *args, **kwargs)
    conn, kwargs = _prepare_connection(**kwargs)
    ret = getattr(conn, method)(*args, **kwargs)
    conn.disconnect()
    return ret
Ejemplo n.º 23
0
def call(method, *args, **kwargs):
    '''
    Invoke an arbitrary Netmiko method.

    method
        The name of the Netmiko method to invoke.

    args
        A list of arguments to send to the method invoked.

    kwargs
        Key-value dictionary to send to the method invoked.
    '''
    kwargs = clean_kwargs(**kwargs)
    if 'netmiko.call' in __proxy__:
        return __proxy__['netmiko.call'](method, *args, **kwargs)
    conn, kwargs = _prepare_connection(**kwargs)
    ret = getattr(conn, method)(*args, **kwargs)
    conn.disconnect()
    return ret
Ejemplo n.º 24
0
def multi_call(*methods, **kwargs):
    """
    Invoke multiple Netmiko methods at once, and return their output, as list.

    methods
        A list of dictionaries with the following keys:

        - ``name``: the name of the Netmiko method to be executed.
        - ``args``: list of arguments to be sent to the Netmiko method.
        - ``kwargs``: dictionary of arguments to be sent to the Netmiko method.

    kwargs
        Key-value dictionary with the connection details (when not running
        under a Proxy Minion).

    CLI Example:

    .. code-block:: bash

        salt '*' netmiko.multi_call "{'name': 'enable', 'args': ['sudo su']}" "{'name': 'send_command', 'kwargs': {'command_string': 'whoami'}}"
    """
    kwargs = clean_kwargs(**kwargs)
    if "netmiko.conn" in __proxy__:
        conn = __proxy__["netmiko.conn"]()
    else:
        conn, kwargs = _prepare_connection(**kwargs)
    ret = []
    for method in methods:
        # Explicit unpacking
        method_name = method["name"]
        method_args = method.get("args", [])
        method_kwargs = method.get("kwargs", {})
        if "netmiko.call" in __proxy__:
            ret.append(__proxy__["netmiko.call"](method_name, *method_args,
                                                 **method_kwargs))
        else:
            ret.append(
                getattr(conn, method_name)(*method_args, **method_kwargs))
    if "netmiko.conn" not in __proxy__:
        conn.disconnect()
    return ret
Ejemplo n.º 25
0
def set_role(username, role, **kwargs):
    """
    Assign role to username.

    username
        Username for role configuration

    role
        Configure role for username

    save_config
        If False, don't save configuration commands to startup configuration.
        If True, save configuration to startup configuration.
        Default: True

    .. code-block:: bash

        salt '*' nxos.set_role username=daniel role=vdc-admin.
    """
    role_line = "username {} role {}".format(username, role)
    kwargs = clean_kwargs(**kwargs)
    return config(role_line, **kwargs)
Ejemplo n.º 26
0
def unset_role(username, role, **kwargs):
    """
    Remove role from username.

    username
        Username for role removal

    role
        Role to remove

    save_config
        If False, don't save configuration commands to startup configuration.
        If True, save configuration to startup configuration.
        Default: True

    .. code-block:: bash

        salt '*' nxos.unset_role username=daniel role=vdc-admin
    """
    role_line = "no username {} role {}".format(username, role)
    kwargs = clean_kwargs(**kwargs)
    return config(role_line, **kwargs)
Ejemplo n.º 27
0
def get(app, endpoint, id=None, **kwargs):
    '''
    Get a single item from NetBox.

    To get an item based on ID.

    .. code-block:: bash

        salt myminion netbox.get dcim devices id=123

    Or using named arguments that correspond with accepted filters on
    the NetBox endpoint.

    .. code-block:: bash

        salt myminion netbox.get dcim devices name=my-router
    '''
    nb = _nb_obj(auth_required=True if app in AUTH_ENDPOINTS else False)
    if id:
        return dict(getattr(getattr(nb, app), endpoint).get(id))
    else:
        return dict(
            getattr(getattr(nb, app), endpoint).get(**clean_kwargs(**kwargs)))
Ejemplo n.º 28
0
def _get_endpoint(endpoint, id=None, **kwargs):
    username, password = _get_auth(kwargs.pop('username', None),
                                   kwargs.pop('password', None))
    kwargs = clean_kwargs(**kwargs)
    url = _build_url(endpoint, id=id)
    ret = {
        'comment': '',
        'result': True,
        'out': None
    }
    res = salt.utils.http.query(url,
                                method='GET',
                                decode=True,
                                username=username,
                                password=password,
                                params=kwargs)
    if 'error' in res:
        ret.update({
            'result': False,
            'comment': res['error']
        })
        return ret
    ret['out'] = res['dict']['data']
    return ret
Ejemplo n.º 29
0
def restore(name=None, clean=False, **kwargs):
    '''
    Make sure that the system contains the packages and repos from a
    frozen state.

    Read the list of packages and repositories from the freeze file,
    and compare it with the current list of packages and repos. If
    there is any difference, all the missing packages are repos will
    be installed, and all the extra packages and repos will be
    removed.

    As this module is build on top of the pkg module, the user can
    send extra attributes to the underlying pkg module via kwargs.
    This function will call ``pkg.list_repos``, ``pkg.mod_repo``,
    ``pkg.list_pkgs``, ``pkg.install``, ``pkg.remove`` and
    ``pkg.del_repo``, and any additional arguments will be passed
    through to those functions.

    name
        Name of the frozen state. Optional.

    clean
        If True remove the frozen information YAML from the cache

        .. versionadded:: 3000

    CLI Example:

    .. code-block:: bash

        salt '*' freezer.restore
        salt '*' freezer.restore root=/chroot

    '''
    if not status(name):
        raise CommandExecutionError('Frozen state not found.')

    frozen_pkgs = {}
    frozen_repos = {}
    for fname, content in zip(_paths(name), (frozen_pkgs, frozen_repos)):
        with fopen(fname) as fp:
            content.update(json.load(fp))

    # The ordering of removing or adding packages and repos can be
    # relevant, as maybe some missing package comes from a repo that
    # is also missing, so it cannot be installed. But can also happend
    # that a missing package comes from a repo that is present, but
    # will be removed.
    #
    # So the proposed order is;
    #   - Add missing repos
    #   - Add missing packages
    #   - Remove extra packages
    #   - Remove extra repos

    safe_kwargs = clean_kwargs(**kwargs)

    # Note that we expect that the information stored in list_XXX
    # match with the mod_XXX counterpart. If this is not the case the
    # recovery will be partial.

    ret = {
        'pkgs': {
            'add': [],
            'remove': []
        },
        'repos': {
            'add': [],
            'remove': []
        },
        'comment': [],
    }

    _add_missing_repositories(frozen_repos, ret, **safe_kwargs)
    _add_missing_packages(frozen_pkgs, ret, **safe_kwargs)
    _remove_extra_packages(frozen_pkgs, ret, **safe_kwargs)
    _remove_extra_repositories(frozen_repos, ret, **safe_kwargs)

    # Clean the cached YAML files
    if clean and not ret['comment']:
        for fname in _paths(name):
            os.remove(fname)

    return ret
Ejemplo n.º 30
0
def send_config(config_file=None,
                config_commands=None,
                template_engine='jinja',
                commit=False,
                context=None,
                defaults=None,
                saltenv='base',
                **kwargs):
    '''
    Send configuration commands down the SSH channel.
    Return the configuration lines sent to the device.

    The function is flexible to send the configuration from a local or remote
    file, or simply the commands as list.

    config_file
        The source file with the configuration commands to be sent to the
        device.

        The file can also be a template that can be rendered using the template
        engine of choice.

        This can be specified using the absolute path to the file, or using one
        of the following URL schemes:

        - ``salt://``, to fetch the file from the Salt fileserver.
        - ``http://`` or ``https://``
        - ``ftp://``
        - ``s3://``
        - ``swift://``

    config_commands
        Multiple configuration commands to be sent to the device.

        .. note::

            This argument is ignored when ``config_file`` is specified.

    template_engine: ``jinja``
        The template engine to use when rendering the source file. Default:
        ``jinja``. To simply fetch the file without attempting to render, set
        this argument to ``None``.

    commit: ``False``
        Commit the configuration changes before exiting the config mode. This
        option is by default disabled, as many platforms don't have this
        capability natively.

    context
        Variables to add to the template context.

    defaults
        Default values of the context_dict.

    exit_config_mode: ``True``
        Determines whether or not to exit config mode after complete.

    delay_factor: ``1``
        Factor to adjust delays.

    max_loops: ``150``
        Controls wait time in conjunction with delay_factor (default: ``150``).

    strip_prompt: ``False``
        Determines whether or not to strip the prompt (default: ``False``).

    strip_command: ``False``
        Determines whether or not to strip the command (default: ``False``).

    config_mode_command
        The command to enter into config mode.

    CLI Example:

    .. code-block:: bash

        salt '*' netmiko.send_config config_commands="['interface GigabitEthernet3', 'no ip address']"
        salt '*' netmiko.send_config config_commands="['snmp-server location {{ grains.location }}']"
        salt '*' netmiko.send_config config_file=salt://config.txt
        salt '*' netmiko.send_config config_file=https://bit.ly/2sgljCB device_type='cisco_ios' ip='1.2.3.4' username='******'
    '''
    if config_file:
        file_str = __salt__['cp.get_file_str'](config_file, saltenv=saltenv)
        if file_str is False:
            raise CommandExecutionError('Source file {} not found'.format(config_file))
    elif config_commands:
        if isinstance(config_commands, (six.string_types, six.text_type)):
            config_commands = [config_commands]
        file_str = '\n'.join(config_commands)
        # unify all the commands in a single file, to render them in a go
    if template_engine:
        file_str = __salt__['file.apply_template_on_contents'](file_str,
                                                               template_engine,
                                                               context,
                                                               defaults,
                                                               saltenv)
    # whatever the source of the commands would be, split them line by line
    config_commands = [line for line in file_str.splitlines() if line.strip()]
    kwargs = clean_kwargs(**kwargs)
    if 'netmiko.conn' in __proxy__:
        conn = __proxy__['netmiko.conn']()
    else:
        conn, kwargs = _prepare_connection(**kwargs)
    if commit:
        kwargs['exit_config_mode'] = False  # don't exit config mode after
        # loading the commands, wait for explicit commit
    ret = conn.send_config_set(config_commands=config_commands, **kwargs)
    if commit:
        ret += conn.commit()
    return ret
Ejemplo n.º 31
0
def send_config(config_file=None,
                config_commands=None,
                template_engine="jinja",
                commit=False,
                context=None,
                defaults=None,
                saltenv="base",
                **kwargs):
    """
    Send configuration commands down the SSH channel.
    Return the configuration lines sent to the device.

    The function is flexible to send the configuration from a local or remote
    file, or simply the commands as list.

    config_file
        The source file with the configuration commands to be sent to the
        device.

        The file can also be a template that can be rendered using the template
        engine of choice.

        This can be specified using the absolute path to the file, or using one
        of the following URL schemes:

        - ``salt://``, to fetch the file from the Salt fileserver.
        - ``http://`` or ``https://``
        - ``ftp://``
        - ``s3://``
        - ``swift://``

    config_commands
        Multiple configuration commands to be sent to the device.

        .. note::

            This argument is ignored when ``config_file`` is specified.

    template_engine: ``jinja``
        The template engine to use when rendering the source file. Default:
        ``jinja``. To simply fetch the file without attempting to render, set
        this argument to ``None``.

    commit: ``False``
        Commit the configuration changes before exiting the config mode. This
        option is by default disabled, as many platforms don't have this
        capability natively.

    context
        Variables to add to the template context.

    defaults
        Default values of the context_dict.

    exit_config_mode: ``True``
        Determines whether or not to exit config mode after complete.

    delay_factor: ``1``
        Factor to adjust delays.

    max_loops: ``150``
        Controls wait time in conjunction with delay_factor (default: ``150``).

    strip_prompt: ``False``
        Determines whether or not to strip the prompt (default: ``False``).

    strip_command: ``False``
        Determines whether or not to strip the command (default: ``False``).

    config_mode_command
        The command to enter into config mode.

    CLI Example:

    .. code-block:: bash

        salt '*' netmiko.send_config config_commands="['interface GigabitEthernet3', 'no ip address']"
        salt '*' netmiko.send_config config_commands="['snmp-server location {{ grains.location }}']"
        salt '*' netmiko.send_config config_file=salt://config.txt
        salt '*' netmiko.send_config config_file=https://bit.ly/2sgljCB device_type='cisco_ios' ip='1.2.3.4' username='******'
    """
    if config_file:
        file_str = __salt__["cp.get_file_str"](config_file, saltenv=saltenv)
        if file_str is False:
            raise CommandExecutionError(
                "Source file {} not found".format(config_file))
    elif config_commands:
        if isinstance(config_commands, ((str, ), str)):
            config_commands = [config_commands]
        file_str = "\n".join(config_commands)
        # unify all the commands in a single file, to render them in a go
    if template_engine:
        file_str = __salt__["file.apply_template_on_contents"](file_str,
                                                               template_engine,
                                                               context,
                                                               defaults,
                                                               saltenv)
    # whatever the source of the commands would be, split them line by line
    config_commands = [line for line in file_str.splitlines() if line.strip()]
    kwargs = clean_kwargs(**kwargs)
    if "netmiko.conn" in __proxy__:
        if __proxy__["netmiko.conn"]().is_alive():
            conn = __proxy__["netmiko.conn"]()
        else:
            conn, _ = _prepare_connection(**__proxy__["netmiko.args"]())
    else:
        conn, kwargs = _prepare_connection(**kwargs)
    if commit:
        kwargs["exit_config_mode"] = False  # don't exit config mode after
        # loading the commands, wait for explicit commit
    ret = conn.send_config_set(config_commands=config_commands, **kwargs)
    if commit:
        ret += conn.commit()
    return ret
Ejemplo n.º 32
0
def call(method, *args, **kwargs):
    '''
    Calls an arbitrary pyeapi method.
    '''
    kwargs = clean_kwargs(**kwargs)
    return getattr(pyeapi_device['connection'], method)(*args, **kwargs)
Ejemplo n.º 33
0
def call(method, *args, **kwargs):
    '''
    Invoke an arbitrary pyeapi method.

    method
        The name of the pyeapi method to invoke.

    args
        A list of arguments to send to the method invoked.

    kwargs
        Key-value dictionary to send to the method invoked.

    transport: ``https``
        Specifies the type of connection transport to use. Valid values for the
        connection are ``socket``, ``http_local``, ``http``, and  ``https``.

        .. note::

            This argument does not need to be specified when running in a
            :mod:`pyeapi <salt.proxy.arista_pyeapi>` Proxy Minion.

    host: ``localhost``
        The IP address or DNS host name of the connection device.

        .. note::

            This argument does not need to be specified when running in a
            :mod:`pyeapi <salt.proxy.arista_pyeapi>` Proxy Minion.

    username: ``admin``
        The username to pass to the device to authenticate the eAPI connection.

         .. note::

            This argument does not need to be specified when running in a
            :mod:`pyeapi <salt.proxy.arista_pyeapi>` Proxy Minion.

    password
        The password to pass to the device to authenticate the eAPI connection.

        .. note::

            This argument does not need to be specified when running in a
            :mod:`pyeapi <salt.proxy.arista_pyeapi>` Proxy Minion.

    port
        The TCP port of the endpoint for the eAPI connection. If this keyword is
        not specified, the default value is automatically determined by the
        transport type (``80`` for ``http``, or ``443`` for ``https``).

        .. note::

            This argument does not need to be specified when running in a
            :mod:`pyeapi <salt.proxy.arista_pyeapi>` Proxy Minion.

    enablepwd
        The enable mode password if required by the destination node.

        .. note::

            This argument does not need to be specified when running in a
            :mod:`pyeapi <salt.proxy.arista_pyeapi>` Proxy Minion.

    CLI Example:

    .. code-block:: bash

        salt '*' pyeapi.call run_commands "['show version']"
    '''
    kwargs = clean_kwargs(**kwargs)
    if 'pyeapi.call' in __proxy__:
        return __proxy__['pyeapi.call'](method, *args, **kwargs)
    conn, kwargs = _prepare_connection(**kwargs)
    ret = getattr(conn, method)(*args, **kwargs)
    return ret
Ejemplo n.º 34
0
def call(method, *args, **kwargs):
    """
    Calls an arbitrary pyeapi method.
    """
    kwargs = clean_kwargs(**kwargs)
    return getattr(pyeapi_device["connection"], method)(*args, **kwargs)
Ejemplo n.º 35
0
def call(method, *args, **kwargs):
    '''
    Invoke an arbitrary pyeapi method.

    method
        The name of the pyeapi method to invoke.

    args
        A list of arguments to send to the method invoked.

    kwargs
        Key-value dictionary to send to the method invoked.

    transport: ``https``
        Specifies the type of connection transport to use. Valid values for the
        connection are ``socket``, ``http_local``, ``http``, and  ``https``.

        .. note::

            This argument does not need to be specified when running in a
            :mod:`pyeapi <salt.proxy.arista_pyeapi>` Proxy Minion.

    host: ``localhost``
        The IP address or DNS host name of the connection device.

        .. note::

            This argument does not need to be specified when running in a
            :mod:`pyeapi <salt.proxy.arista_pyeapi>` Proxy Minion.

    username: ``admin``
        The username to pass to the device to authenticate the eAPI connection.

         .. note::

            This argument does not need to be specified when running in a
            :mod:`pyeapi <salt.proxy.arista_pyeapi>` Proxy Minion.

    password
        The password to pass to the device to authenticate the eAPI connection.

        .. note::

            This argument does not need to be specified when running in a
            :mod:`pyeapi <salt.proxy.arista_pyeapi>` Proxy Minion.

    port
        The TCP port of the endpoint for the eAPI connection. If this keyword is
        not specified, the default value is automatically determined by the
        transport type (``80`` for ``http``, or ``443`` for ``https``).

        .. note::

            This argument does not need to be specified when running in a
            :mod:`pyeapi <salt.proxy.arista_pyeapi>` Proxy Minion.

    enablepwd
        The enable mode password if required by the destination node.

        .. note::

            This argument does not need to be specified when running in a
            :mod:`pyeapi <salt.proxy.arista_pyeapi>` Proxy Minion.

    CLI Example:

    .. code-block:: bash

        salt '*' pyeapi.call run_commands "['show version']"
    '''
    kwargs = clean_kwargs(**kwargs)
    if 'pyeapi.call' in __proxy__:
        return __proxy__['pyeapi.call'](method, *args, **kwargs)
    conn, kwargs = _prepare_connection(**kwargs)
    ret = getattr(conn, method)(*args, **kwargs)
    return ret
Ejemplo n.º 36
0
def restore(name=None, **kwargs):
    '''
    Make sure that the system contains the packages and repos from a
    frozen state.

    Read the list of packages and repositories from the freeze file,
    and compare it with the current list of packages and repos. If
    there is any difference, all the missing packages are repos will
    be installed, and all the extra packages and repos will be
    removed.

    As this module is build on top of the pkg module, the user can
    send extra attributes to the underlying pkg module via kwargs.
    This function will call ``pkg.list_repos``, ``pkg.mod_repo``,
    ``pkg.list_pkgs``, ``pkg.install``, ``pkg.remove`` and
    ``pkg.del_repo``, and any additional arguments will be passed
    through to those functions.

    name
        Name of the frozen state. Optional.

    CLI Example:

    .. code-block:: bash

        salt '*' freezer.restore
        salt '*' freezer.restore root=/chroot

    '''
    if not status(name):
        raise CommandExecutionError('Frozen state not found.')

    frozen_pkgs = {}
    frozen_repos = {}
    for name, content in zip(_paths(name), (frozen_pkgs, frozen_repos)):
        with fopen(name) as fp:
            content.update(json.load(fp))

    # The ordering of removing or adding packages and repos can be
    # relevant, as maybe some missing package comes from a repo that
    # is also missing, so it cannot be installed. But can also happend
    # that a missing package comes from a repo that is present, but
    # will be removed.
    #
    # So the proposed order is;
    #   - Add missing repos
    #   - Add missing packages
    #   - Remove extra packages
    #   - Remove extra repos

    safe_kwargs = clean_kwargs(**kwargs)

    # Note that we expect that the information stored in list_XXX
    # match with the mod_XXX counterpart. If this is not the case the
    # recovery will be partial.

    res = {
        'pkgs': {
            'add': [],
            'remove': []
        },
        'repos': {
            'add': [],
            'remove': []
        },
        'comment': [],
    }

    # Add missing repositories
    repos = __salt__['pkg.list_repos'](**safe_kwargs)
    missing_repos = set(frozen_repos) - set(repos)
    for repo in missing_repos:
        try:
            # In Python 2 we cannot do advance destructuring, so we
            # need to create a temporary dictionary that will merge
            # all the parameters
            _tmp_kwargs = frozen_repos[repo].copy()
            _tmp_kwargs.update(safe_kwargs)
            __salt__['pkg.mod_repo'](repo, **_tmp_kwargs)
            res['repos']['add'].append(repo)
            log.info('Added missing repository %s', repo)
        except Exception as e:
            msg = 'Error adding %s repository: %s'
            log.error(msg, repo, e)
            res['comment'].append(msg % (repo, e))

    # Add missing packages
    # NOTE: we can remove the `for` using `pkgs`. This will improve
    # performance, but I want to have a more detalied report of what
    # packages are installed or failled.
    pkgs = __salt__['pkg.list_pkgs'](**safe_kwargs)
    missing_pkgs = set(frozen_pkgs) - set(pkgs)
    for pkg in missing_pkgs:
        try:
            __salt__['pkg.install'](name=pkg, **safe_kwargs)
            res['pkgs']['add'].append(pkg)
            log.info('Added missing package %s', pkg)
        except Exception as e:
            msg = 'Error adding %s package: %s'
            log.error(msg, pkg, e)
            res['comment'].append(msg % (pkg, e))

    # Remove extra packages
    pkgs = __salt__['pkg.list_pkgs'](**safe_kwargs)
    extra_pkgs = set(pkgs) - set(frozen_pkgs)
    for pkg in extra_pkgs:
        try:
            __salt__['pkg.remove'](name=pkg, **safe_kwargs)
            res['pkgs']['remove'].append(pkg)
            log.info('Removed extra package %s', pkg)
        except Exception as e:
            msg = 'Error removing %s package: %s'
            log.error(msg, pkg, e)
            res['comment'].append(msg % (pkg, e))

    # Remove extra repositories
    repos = __salt__['pkg.list_repos'](**safe_kwargs)
    extra_repos = set(repos) - set(frozen_repos)
    for repo in extra_repos:
        try:
            __salt__['pkg.del_repo'](repo, **safe_kwargs)
            res['repos']['remove'].append(repo)
            log.info('Removed extra repository %s', repo)
        except Exception as e:
            msg = 'Error removing %s repository: %s'
            log.error(msg, repo, e)
            res['comment'].append(msg % (repo, e))

    return res
Ejemplo n.º 37
0
def config(
    commands=None,
    config_file=None,
    template_engine="jinja",
    context=None,
    defaults=None,
    saltenv="base",
    **kwargs
):
    """
    Configures the Nexus switch with the specified commands.

    This method is used to send configuration commands to the switch.  It
    will take either a string or a list and prepend the necessary commands
    to put the session into config mode.

    .. warning::

        All the commands will be applied directly to the running-config.

    config_file
        The source file with the configuration commands to be sent to the
        device.

        The file can also be a template that can be rendered using the template
        engine of choice.

        This can be specified using the absolute path to the file, or using one
        of the following URL schemes:

        - ``salt://``, to fetch the file from the Salt fileserver.
        - ``http://`` or ``https://``
        - ``ftp://``
        - ``s3://``
        - ``swift://``

    commands
        The commands to send to the switch in config mode.  If the commands
        argument is a string it will be cast to a list.
        The list of commands will also be prepended with the necessary commands
        to put the session in config mode.

        .. note::

            This argument is ignored when ``config_file`` is specified.

    template_engine: ``jinja``
        The template engine to use when rendering the source file. Default:
        ``jinja``. To simply fetch the file without attempting to render, set
        this argument to ``None``.

    context
        Variables to add to the template context.

    defaults
        Default values of the context_dict.

    save_config
        If False, don't save configuration commands to startup configuration.
        If True, save configuration to startup configuration.
        Default: True

    CLI Example:

    .. code-block:: bash

        salt '*' nxos.config commands="['spanning-tree mode mstp']"
        salt '*' nxos.config config_file=salt://config.txt
        salt '*' nxos.config config_file=https://bit.ly/2LGLcDy context="{'servers': ['1.2.3.4']}"
    """
    kwargs = clean_kwargs(**kwargs)
    initial_config = sendline("show running-config", **kwargs)
    if isinstance(initial_config, list):
        initial_config = initial_config[0]
    if config_file:
        file_str = __salt__["cp.get_file_str"](config_file, saltenv=saltenv)
        if file_str is False:
            raise CommandExecutionError("Source file {} not found".format(config_file))
    elif commands:
        if isinstance(commands, str):
            commands = [commands]
        file_str = "\n".join(commands)
        # unify all the commands in a single file, to render them in a go
    else:
        raise CommandExecutionError(
            "Either arg <config_file> or <commands> must be specified"
        )
    if template_engine:
        file_str = __salt__["file.apply_template_on_contents"](
            file_str, template_engine, context, defaults, saltenv
        )
    # whatever the source of the commands would be, split them line by line
    commands = [line for line in file_str.splitlines() if line.strip()]
    try:
        config_result = _configure_device(commands, **kwargs)
    except socket_error as e:
        return e.strerror + "\n" + CONNECTION_ERROR_MSG
    except NxosError as e:
        return e.strerror + "\n" + CONNECTION_ERROR_MSG

    config_result = _parse_config_result(config_result)
    current_config = sendline("show running-config", **kwargs)
    if isinstance(current_config, list):
        current_config = current_config[0]
    diff = difflib.unified_diff(
        initial_config.splitlines(1)[4:], current_config.splitlines(1)[4:]
    )
    clean_diff = "".join([x.replace("\r", "") for x in diff])
    head = "COMMAND_LIST: "
    cc = config_result[0]
    cr = config_result[1]
    return head + cc + "\n" + cr + "\n" + clean_diff