Esempio n. 1
0
def _write_policy_file(policy_template):
    policy_file = mkstemp()
    try:
        with io.open(policy_file, mode='wb') as fh_:
            fh_.write(os.linesep.join(policy_template).encode('utf-8'))
    except Exception as exc:
        raise CommandExecutionError('Error saving LGPO policy file "{0}". '
                                    'Exception: {1}'.format(policy_file, exc))
    return policy_file
Esempio n. 2
0
def send_config(config_file=None,
                config_commands=None,
                template_engine='jinja',
                source_hash=None,
                source_hash_name=None,
                user=None,
                group=None,
                mode=None,
                attrs=None,
                context=None,
                defaults=None,
                skip_verify=False,
                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``.

    source_hash
        The hash of the ``config_file``

    source_hash_name
        When ``source_hash`` refers to a remote file, this specifies the
        filename to look for in that file.

    user
        Owner of the file.

    group
        Group owner of the file.

    mode
        Permissions of the file.

    attrs
        Attributes of the file.

    context
        Variables to add to the template context.

    defaults
        Default values of the context_dict.

    skip_verify: ``False``
        If ``True``, hash verification of remote file sources (``http://``,
        ``https://``, ``ftp://``, etc.) will be skipped, and the ``source_hash``
        argument will be ignored.

    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_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:
        if template_engine:
            tmp_file = mkstemp()
            file_mgd = __salt__['file.get_managed'](tmp_file, template_engine,
                                                    config_file, source_hash,
                                                    source_hash_name, user,
                                                    group, mode, attrs,
                                                    saltenv, context, defaults,
                                                    skip_verify)
            if not file_mgd[0]:
                raise CommandExecutionError(file_mgd[2])
            file_str = __salt__['file.read'](file_mgd[0])
            __salt__['file.remove'](file_mgd[0])
        else:
            # If no template engine wanted, simply fetch the source 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))
        config_commands = file_str.splitlines()
    if isinstance(config_commands, (six.string_types, six.text_type)):
        config_commands = [config_commands]
    call('send_config_set', config_commands=config_commands, **kwargs)
    return config_commands
Esempio n. 3
0
def install_os(path=None, **kwargs):
    '''
    Installs the given image on the device. After the installation is complete\
     the device is rebooted,
    if reboot=True is given as a keyworded argument.

    Usage:

    .. code-block:: bash

        salt 'device_name' junos.install_os 'salt://images/junos_image.tgz' reboot=True

        salt 'device_name' junos.install_os 'salt://junos_16_1.tgz' dev_timeout=300


    Parameters:
      Required
        * path:
          Path where the image file is present on the proxy minion.
      Optional
        * kwargs: keyworded arguments to be given such as dev_timeout, reboot etc
            * dev_timeout:
              Set NETCONF RPC timeout. Can be used to RPCs which
              take a while to execute. (default = 30 seconds)
            * reboot:
              Whether to reboot after installation (default = False)
            * no_copy:
              When True the software package will not be SCP’d to the device. \
              (default = False)

    '''
    conn = __proxy__['junos.conn']()
    ret = dict()
    ret['out'] = True

    if path is None:
        ret['message'] = \
            'Please provide the salt path where the junos image is present.'
        ret['out'] = False
        return ret

    image_cached_path = files.mkstemp()
    __salt__['cp.get_template'](path, image_cached_path)

    if not os.path.isfile(image_cached_path):
        ret['message'] = 'Invalid image path.'
        ret['out'] = False
        return ret

    if os.path.getsize(image_cached_path) == 0:
        ret['message'] = 'Failed to copy image'
        ret['out'] = False
        return ret
    path = image_cached_path

    op = dict()
    if '__pub_arg' in kwargs:
        if kwargs['__pub_arg']:
            if isinstance(kwargs['__pub_arg'][-1], dict):
                op.update(kwargs['__pub_arg'][-1])
    else:
        op.update(kwargs)

    try:
        conn.sw.install(path, progress=True)
        ret['message'] = 'Installed the os.'
    except Exception as exception:
        ret['message'] = 'Installation failed due to: "{0}"'.format(exception)
        ret['out'] = False
        return ret
    finally:
        safe_rm(image_cached_path)

    if 'reboot' in op and op['reboot'] is True:
        try:
            conn.sw.reboot()
        except Exception as exception:
            ret['message'] = \
                'Installation successful but reboot failed due to : "{0}"' \
                .format(exception)
            ret['out'] = False
            return ret
        ret['message'] = 'Successfully installed and rebooted!'
    return ret
Esempio n. 4
0
def install_config(path=None, **kwargs):
    '''
    Installs the given configuration file into the candidate configuration.
    Commits the changes if the commit checks or throws an error.

    Usage:

    .. code-block:: bash

        salt 'device_name' junos.install_config 'salt://production/network/routers/config.set'

        salt 'device_name' junos.install_config 'salt://templates/replace_config.conf' replace=True comment='Committed via SaltStack'

        salt 'device_name' junos.install_config 'salt://my_new_configuration.conf' dev_timeout=300 diffs_file='/salt/confs/old_config.conf' overwrite=True

        salt 'device_name' junos.install_config 'salt://syslog_template.conf' template_vars='{"syslog_host": "10.180.222.7"}'

    Parameters:
      Required
        * path:
          Path where the configuration/template file is present. If the file has a \
          '*.conf' extension,
          the content is treated as text format. If the file has a '*.xml' \
          extension,
          the content is treated as XML format. If the file has a '*.set' \
          extension,
          the content is treated as Junos OS 'set' commands.(default = None)
      Optional
        * kwargs: Keyworded arguments which can be provided like-
            * dev_timeout:
              Set NETCONF RPC timeout. Can be used for commands which
              take a while to execute. (default = 30 seconds)
            * overwrite:
              Set to True if you want this file is to completely replace the\
               configuration file. (default = False)
            * replace:
              Specify whether the configuration file uses "replace:" statements.
              Those statements under the 'replace' tag will only be changed.\
               (default = False)
            * comment:
              Provide a comment to the commit. (default = None)
            * confirm:
              Provide time in minutes for commit confirmation.
              If this option is specified, the commit will be rollbacked in \
              the given time unless the commit is confirmed.
            * diffs_file:
              Path to the file where the diff (difference in old configuration
              and the committed configuration) will be stored.(default = None)
              Note that the file will be stored on the proxy minion. To push the
              files to the master use the salt's following execution module: \
              :py:func:`cp.push <salt.modules.cp.push>`
            * template_vars:
              Variables to be passed into the template processing engine in addition
              to those present in __pillar__, __opts__, __grains__, etc.
              You may reference these variables in your template like so:
              {{ template_vars["var_name"] }}

    '''
    conn = __proxy__['junos.conn']()
    ret = dict()
    ret['out'] = True

    if path is None:
        ret['message'] = \
            'Please provide the salt path where the configuration is present'
        ret['out'] = False
        return ret

    op = dict()
    if '__pub_arg' in kwargs:
        if kwargs['__pub_arg']:
            if isinstance(kwargs['__pub_arg'][-1], dict):
                op.update(kwargs['__pub_arg'][-1])
    else:
        op.update(kwargs)

    template_vars = dict()
    if "template_vars" in op:
        template_vars = op["template_vars"]

    template_cached_path = files.mkstemp()
    __salt__['cp.get_template'](
        path,
        template_cached_path,
        template_vars=template_vars)

    if not os.path.isfile(template_cached_path):
        ret['message'] = 'Invalid file path.'
        ret['out'] = False
        return ret

    if os.path.getsize(template_cached_path) == 0:
        ret['message'] = 'Template failed to render'
        ret['out'] = False
        return ret

    write_diff = ''
    if 'diffs_file' in op and op['diffs_file'] is not None:
        write_diff = op['diffs_file']
        del op['diffs_file']

    op['path'] = template_cached_path

    if 'format' not in op:
        if path.endswith('set'):
            template_format = 'set'
        elif path.endswith('xml'):
            template_format = 'xml'
        else:
            template_format = 'text'

        op['format'] = template_format

    if 'replace' in op and op['replace']:
        op['merge'] = False
        del op['replace']
    elif 'overwrite' in op and op['overwrite']:
        op['overwrite'] = True
    elif 'overwrite' in op and not op['overwrite']:
        op['merge'] = True
        del op['overwrite']

    try:
        conn.cu.load(**op)

    except Exception as exception:
        ret['message'] = 'Could not load configuration due to : "{0}"'.format(
            exception)
        ret['format'] = template_format
        ret['out'] = False
        return ret

    finally:
        safe_rm(template_cached_path)

    config_diff = conn.cu.diff()
    if config_diff is None:
        ret['message'] = 'Configuration already applied!'
        ret['out'] = True
        return ret

    commit_params = {}
    if 'confirm' in op:
        commit_params['confirm'] = op['confirm']
    if 'comment' in op:
        commit_params['comment'] = op['comment']

    try:
        check = conn.cu.commit_check()
    except Exception as exception:
        ret['message'] = \
            'Commit check threw the following exception: "{0}"'\
            .format(exception)

        ret['out'] = False
        return ret

    if check:
        try:
            conn.cu.commit(**commit_params)
            ret['message'] = 'Successfully loaded and committed!'
        except Exception as exception:
            ret['message'] = \
                'Commit check successful but commit failed with "{0}"'\
                .format(exception)
            ret['out'] = False
            return ret
    else:
        ret['message'] = 'Loaded configuration but commit check failed.'
        ret['out'] = False
        conn.cu.rollback()

    try:
        if write_diff and config_diff is not None:
            with fopen(write_diff, 'w') as fp:
                fp.write(config_diff)
    except Exception as exception:
        ret['message'] = 'Could not write into diffs_file due to: "{0}"'.format(
            exception)
        ret['out'] = False

    return ret
Esempio n. 5
0
def render(source=None,
           source_string=None,
           template_engine='jinja',
           source_hash=None,
           source_hash_name=None,
           user=None,
           group=None,
           mode=None,
           attrs=None,
           context=None,
           defaults=None,
           skip_verify=True,
           saltenv='base'):
    '''
    Render the remote template file, or the template as string.

    source
        The template source file to be rendered. No need to use this argument
        when passing ``source_string``.

        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://``

    source_string
        The template source, as text. No need to use this argument when passing
        ``source``.

    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``.

    source_hash
        The hash of the ``source`` file.

    source_hash_name
        When ``source_hash`` refers to a remote file, this specifies the
        filename to look for in that file.

    user
        Owner of the file.

    group
        Group owner of the file.

    mode
        Permissions of the file.

    attrs
        Attributes of the file.

    context
        Variables to add to the template context.

    defaults
        Default values of the context dictionary.

    skip_verify: ``True``
        If ``True``, hash verification of remote file sources (``http://``,
        ``https://``, ``ftp://``, etc.) will be skipped, and the ``source_hash``
        argument will be ignored.

    CLI Example:

    .. code-block:: bash

        salt '*' template.render source=https://bit.ly/2yuSs2Y context="{'hostname': 'example.com'}"
        salt '*' template.render source=salt://path/to/template.mako context="{'hostname': 'example.com'}"
        salt '*' template.render source_string='hostname {{ hostname }}' context="{'hostname': 'example.com'}"
    '''
    dest_file = mkstemp()
    if source_string:
        source = mkstemp()
        __salt__['file.write'](source, source_string)
    file_mgd = __salt__['file.get_managed'](dest_file, template_engine, source,
                                            source_hash, source_hash_name,
                                            user, group, mode, attrs, saltenv,
                                            context, defaults, skip_verify)
    if not file_mgd[0]:
        raise CommandExecutionError(file_mgd[2])
    file_str = __salt__['file.read'](file_mgd[0])
    # Removing the temporary file(s) created along the way
    __salt__['file.remove'](file_mgd[0])
    if source_string:
        __salt__['file.remove'](source)
    return file_str
Esempio n. 6
0
File: junos.py Progetto: yc2yuy/salt
def load(path=None, **kwargs):
    """

    Loads the configuration from the file provided onto the device.

    Usage:

    .. code-block:: bash

        salt 'device_name' junos.load 'salt://production/network/routers/config.set'

        salt 'device_name' junos.load 'salt://templates/replace_config.conf' replace=True

        salt 'device_name' junos.load 'salt://my_new_configuration.conf' overwrite=True

        salt 'device_name' junos.load 'salt://syslog_template.conf' template_vars='{"syslog_host": "10.180.222.7"}'

    Parameters:
      Required
        * path:
          Path where the configuration/template file is present. If the file has a \
          '*.conf' extension,
          the content is treated as text format. If the file has a '*.xml' \
          extension,
          the content is treated as XML format. If the file has a '*.set' \
          extension,
          the content is treated as Junos OS 'set' commands.(default = None)
      Optional
        * kwargs: Keyworded arguments which can be provided like-
            * overwrite:
              Set to True if you want this file is to completely replace the\
              configuration file. (default = False)
            * replace:
              Specify whether the configuration file uses "replace:" statements.
              Those statements under the 'replace' tag will only be changed.\
               (default = False)
            * format:
              Determines the format of the contents.
            * update:
              Compare a complete loaded configuration against
              the candidate configuration. For each hierarchy level or
              configuration object that is different in the two configurations,
              the version in the loaded configuration replaces the version in the
              candidate configuration. When the configuration is later committed,
              only system processes that are affected by the changed configuration
              elements parse the new configuration. This action is supported from
              PyEZ 2.1 (default = False)
            * template_vars:
              Variables to be passed into the template processing engine in addition
              to those present in __pillar__, __opts__, __grains__, etc.
              You may reference these variables in your template like so:
              {{ template_vars["var_name"] }}


    """
    conn = __proxy__['junos.conn']()
    ret = dict()
    ret['out'] = True

    if path is None:
        ret['message'] = \
            'Please provide the salt path where the configuration is present'
        ret['out'] = False
        return ret

    op = dict()
    if '__pub_arg' in kwargs:
        if kwargs['__pub_arg']:
            if isinstance(kwargs['__pub_arg'][-1], dict):
                op.update(kwargs['__pub_arg'][-1])
    else:
        op.update(kwargs)

    template_vars = dict()
    if "template_vars" in op:
        template_vars = op["template_vars"]

    template_cached_path = files.mkstemp()
    __salt__['cp.get_template'](
        path,
        template_cached_path,
        template_vars=template_vars)

    if not os.path.isfile(template_cached_path):
        ret['message'] = 'Invalid file path.'
        ret['out'] = False
        return ret

    if os.path.getsize(template_cached_path) == 0:
        ret['message'] = 'Template failed to render'
        ret['out'] = False
        return ret

    op['path'] = template_cached_path

    if 'format' not in op:
        if path.endswith('set'):
            template_format = 'set'
        elif path.endswith('xml'):
            template_format = 'xml'
        else:
            template_format = 'text'

        op['format'] = template_format

    if 'replace' in op and op['replace']:
        op['merge'] = False
        del op['replace']
    elif 'overwrite' in op and op['overwrite']:
        op['overwrite'] = True
    elif 'overwrite' in op and not op['overwrite']:
        op['merge'] = True
        del op['overwrite']

    try:
        conn.cu.load(**op)
        ret['message'] = "Successfully loaded the configuration."
    except Exception as exception:
        ret['message'] = 'Could not load configuration due to : "{0}"'.format(
            exception)
        ret['format'] = template_format
        ret['out'] = False
        return ret
    finally:
        safe_rm(template_cached_path)

    return ret
Esempio n. 7
0
def apply_policies(policies=None, logfile=True, errorfile=True):
    r"""
    Apply a policy that manages Local Group Policy Objects.

    :param policies:
        A policy dictionary, or a list of policy dictionaries. Each policy
        dictionary must be of one of the forms below:
            {
                'policy_type' : 'regpol',
                'key'    : '<hive>\path\to\registry\key\value_name',
                'value'  : 'value of the registry key',
                'vtype'  : 'DWORD' | 'SZ' | 'EXSZ'
            }
        -OR-
            {
                'policy_type' : 'regpol',
                'key'    : '<hive>\path\to\registry\key\name',
                'action' : 'DELETE' | 'DELETEALLVALUES' | 'CREATEKEY'
            }
        -OR-
            {
                'policy_type' : 'secedit',
                'name'   : 'name of the secedit inf setting',
                'value'  : 'value to apply to the setting'
            }
        Policy dictionaries support the same aliases as the individual policy
        parameters. See ``lgpo.set_registry_value`` for the aliases.
    :param logfile:
        The path to the log file where the results of applying the policy will
        be saved. If set to ``True`` (the Default), then the log file will be
        created in the system temp directory. If set to ``False``, then no log
        file will be created.
    :param errorfile:
        The path to the error file where errors resulting from applying the
        policy will be saved. If set to ``True`` (the Default), then the error
        file will be created in the system temp directory. If set to
        ``False``, then no error file will be created.

    CLI Examples:

    .. code-block:: bash

        policies="[{'policy_type':'regpol', \
            'key':'HKLM\Software\Salt\Policies\Foo', \
            'value':'0', \
            'vtype':'DWORD'}]"
        salt '*' lgpo.apply_policies policies="${policies}"
    """
    valid_policies, reason, policy = validate_policies(policies)
    if not valid_policies:
        raise SaltInvocationError('{0}; policy={1}'.format(reason, policy))
    policy_files = _write_policy_files(valid_policies)
    command = ' '.join([LGPO_EXE, policy_files.get('regpol', ''),
                        policy_files.get('secedit', '')])
    if logfile is True:
        logfile = mkstemp(prefix='lgpo_', suffix='.log')
    if logfile:
        try:
            __salt__['file.makedirs'](path=logfile)
        except Exception as exc:
            raise CommandExecutionError('Error creating directory for logfile '
                                        '"{0}". Exception: {1}'.format(logfile,
                                                                       exc))
        log.info('LGPO log file is "{0}"'.format(logfile))
        command = ' '.join([command, '/log', logfile])
    if errorfile is True:
        errorfile = mkstemp(prefix='lgpo_', suffix='.err')
    if errorfile:
        try:
            __salt__['file.makedirs'](path=errorfile)
        except Exception as exc:
            raise CommandExecutionError('Error creating directory for '
                                        'errorfile "{0}". Exception: {1}'
                                        .format(errorfile, exc))
        log.info('LGPO error file is "{0}"'.format(errorfile))
        command = ' '.join([command, '/error', errorfile])
    log.info('Applying LGPO policies')
    log.debug('LGPO policy data: {0}'.format(valid_policies))
    try:
        ret = __salt__['cmd.retcode'](command, python_shell=False)
    except Exception as exc:
        raise CommandExecutionError('Error applying LGPO policy template '
                                    '"{0}". Exception: {1}'
                                    .format(valid_policies, exc))

    if errorfile and os.path.getsize(errorfile) > 0:
        raise CommandExecutionError(
            'Encountered errors processing the LGPO policy template. See the '
            'error file for details -- {0}'.format(errorfile))

    if ret:
        raise CommandExecutionError('Non-zero exit [{0}] from {1}. We do not '
                                    'know what this means. Hopefully the '
                                    'error log contains details -- {2}'
                                    .format(ret, LGPO_EXE, errorfile))
    for policy_file in policy_files.values():
        if os.path.isfile(policy_file):
            os.remove(policy_file)
    return valid_policies