def main():
    config_format_choices = [None]
    config_format_choices += juniper_junos_common.CONFIG_FORMAT_CHOICES

    # Create the module instance.
    junos_module = juniper_junos_common.JuniperJunosModule(
        argument_spec=dict(
            config_format=dict(choices=config_format_choices,
                               required=False,
                               default=None),
            savedir=dict(type='path', required=False, default=None),
        ),
        # Since this module doesn't change the device's configuration, there is
        # no additional work required to support check mode. It's inherently
        # supported.
        supports_check_mode=True,
        min_jxmlease_version=juniper_junos_common.MIN_JXMLEASE_VERSION,
    )

    junos_module.logger.debug("Gathering facts.")
    # Get the facts dictionary from the device.
    facts = get_facts_dict(junos_module)
    junos_module.logger.debug("Facts gathered.")

    if junos_module.params.get('savedir') is not None:
        # Save the facts.
        save_facts(junos_module, facts)

        # Get and save the inventory
        try:
            junos_module.logger.debug("Gathering inventory.")
            inventory = junos_module.dev.rpc.get_chassis_inventory()
            junos_module.logger.debug("Inventory gathered.")
            save_inventory(
                junos_module,
                junos_module.etree.tostring(inventory, pretty_print=True))
        except junos_module.pyez_exception.RpcError as ex:
            junos_module.fail_json(msg='Unable to retrieve hardware '
                                   'inventory: %s' % (str(ex)))

    config_format = junos_module.params.get('config_format')
    if config_format is not None:
        (config,
         config_parsed) = junos_module.get_configuration(format=config_format)
        if config is not None:
            facts.update({'config': config})
        # Need to wait until the ordering issues are figured out before
        # using config_parsed.
        # if config_parsed is not None:
        #    facts.update({'config_parsed': config_parsed})

    # Return response.
    junos_module.exit_json(changed=False,
                           failed=False,
                           ansible_facts={'junos': facts},
                           facts=facts)
Example #2
0
def main():
    # Create the module instance.
    junos_module = juniper_junos_common.JuniperJunosModule(
        argument_spec=dict(
            rpcs=dict(required=True,
                      type='list',
                      aliases=['rpc'],
                      default=None),
            formats=dict(required=False,
                         type='list',
                         aliases=['format', 'display', 'output'],
                         default=None),
            kwargs=dict(required=False,
                        aliases=['kwarg', 'args', 'arg'],
                        type='str',
                        default=None),
            attrs=dict(required=False,
                       type='str',
                       aliases=['attr'],
                       default=None),
            filter=dict(required=False,
                        type='str',
                        aliases=['filter_xml'],
                        default=None),
            dest=dict(required=False,
                      type='path',
                      aliases=['destination'],
                      default=None),
            dest_dir=dict(required=False,
                          type='path',
                          aliases=['destination_dir', 'destdir'],
                          default=None),
            return_output=dict(required=False, type='bool', default=True)),
        # Since this module doesn't change the device's configuration, there is
        # no additional work required to support check mode. It's inherently
        # supported. Well, that's not completely true. It does depend on the
        # RPC executed. See the I(changed) key in the RETURN documentation
        # for more details.
        supports_check_mode=True,
        min_jxmlease_version=juniper_junos_common.MIN_JXMLEASE_VERSION,
    )

    # Check over rpcs
    rpcs = junos_module.params.get('rpcs')
    # Ansible allows users to specify a rpcs argument with no value.
    if rpcs is None:
        junos_module.fail_json(msg="The rpcs option must have a value.")

    # Check over formats
    formats = junos_module.params.get('formats')
    if formats is None:
        # Default to xml format
        formats = ['xml']
    valid_formats = juniper_junos_common.RPC_OUTPUT_FORMAT_CHOICES
    # Check format values
    for format in formats:
        # Is it a valid format?
        if format not in valid_formats:
            junos_module.fail_json(
                msg="The value %s in formats is invalid. "
                "Must be one of: %s" %
                (format, ', '.join(map(str, valid_formats))))
    # Correct number of format values?
    if len(formats) != 1 and len(formats) != len(rpcs):
        junos_module.fail_json(msg="The formats option must have a single "
                               "value, or one value per rpc. There "
                               "are %d rpcs and %d formats." %
                               (len(rpcs), len(formats)))
    # Same format for all rpcs
    elif len(formats) == 1 and len(rpcs) > 1:
        formats = formats * len(rpcs)

    # Check over kwargs
    kwstring = junos_module.params.get('kwargs')
    kwargs = junos_module.parse_arg_to_list_of_dicts('kwargs',
                                                     kwstring,
                                                     allow_bool_values=True)
    if kwargs is not None:
        if len(kwargs) != len(rpcs):
            junos_module.fail_json(msg="The kwargs option must have one value "
                                   "per rpc. There are %d rpcs and %d "
                                   "kwargs." % (len(rpcs), len(kwargs)))
    else:
        kwargs = [None] * len(rpcs)

    # Check over attrs
    attrstring = junos_module.params.get('attrs')
    attrs = junos_module.parse_arg_to_list_of_dicts('attrs', attrstring)
    if attrs is not None:
        if len(attrs) != len(rpcs):
            junos_module.fail_json(msg="The attrs option must have one value"
                                   "per rpc. There are %d rpcs and %d "
                                   "attrs." % (len(rpcs), len(attrs)))
    else:
        attrs = [None] * len(rpcs)

    # Check filter
    if junos_module.params.get('filter') is not None:
        if (len(rpcs) != 1
                or (rpcs[0] != 'get-config' and rpcs[0] != 'get_config')):
            junos_module.fail_json(msg="The filter option is only valid "
                                   "when the rpcs option value is a "
                                   "single 'get-config' RPC.")

    results = list()
    for (rpc_string, format, kwarg, attr) in zip(rpcs, formats, kwargs, attrs):
        # Replace underscores with dashes in RPC name.
        rpc_string = rpc_string.replace('_', '-')
        # Set initial result values. Assume failure until we know it's success.
        result = {
            'msg': '',
            'rpc': rpc_string,
            'format': format,
            'kwargs': kwarg,
            'attrs': attr,
            'changed': False,
            'failed': True
        }

        # Execute the RPC
        try:
            if rpc_string == 'get-config':
                filter = junos_module.params.get('filter')
                if attr is None:
                    attr = {}
                if kwarg is None:
                    kwarg = {}
                if format is not None:
                    attr['format'] = format
                junos_module.logger.debug(
                    'Executing "get-config" RPC. '
                    'filter_xml=%s, options=%s, '
                    'kwargs=%s', filter, str(attr), str(kwarg))
                resp = junos_module.dev.rpc.get_config(filter_xml=filter,
                                                       options=attr,
                                                       **kwarg)
                result['msg'] = 'The "get-config" RPC executed successfully.'
                junos_module.logger.debug('The "get-config" RPC executed '
                                          'successfully.')
            else:
                rpc = junos_module.etree.Element(rpc_string, format=format)
                if kwarg is not None:
                    # Add kwarg
                    for (key, value) in iteritems(kwarg):
                        # Replace underscores with dashes in key name.
                        key = key.replace('_', '-')
                        sub_element = junos_module.etree.SubElement(rpc, key)
                        if not isinstance(value, bool):
                            sub_element.text = value
                if attr is not None:
                    # Add attr
                    for (key, value) in iteritems(attr):
                        # Replace underscores with dashes in key name.
                        key = key.replace('_', '-')
                        rpc.set(key, value)
                junos_module.logger.debug(
                    'Executing RPC "%s".',
                    junos_module.etree.tostring(rpc, pretty_print=True))
                resp = junos_module.dev.rpc(rpc,
                                            normalize=bool(format == 'xml'))
                result['msg'] = 'The RPC executed successfully.'
                junos_module.logger.debug(
                    'RPC "%s" executed successfully.',
                    junos_module.etree.tostring(rpc, pretty_print=True))
        except (junos_module.pyez_exception.ConnectError,
                junos_module.pyez_exception.RpcError) as ex:
            junos_module.logger.debug(
                'Unable to execute RPC "%s". Error: %s',
                junos_module.etree.tostring(rpc, pretty_print=True), str(ex))
            result['msg'] = 'Unable to execute the RPC: %s. Error: %s' % \
                            (junos_module.etree.tostring(rpc,
                                                         pretty_print=True),
                             str(ex))
            results.append(result)
            continue

        text_output = None
        parsed_output = None
        if resp is True:
            text_output = ''
        elif (resp, junos_module.etree._Element):
            # Handle the output based on format
            if format == 'text':
                text_output = resp.text
                junos_module.logger.debug('Text output set.')
            elif format == 'xml':
                text_output = junos_module.etree.tostring(resp,
                                                          pretty_print=True)
                parsed_output = junos_module.jxmlease.parse_etree(resp)
                junos_module.logger.debug('XML output set.')
            elif format == 'json':
                text_output = str(resp)
                parsed_output = resp
                junos_module.logger.debug('JSON output set.')
            else:
                result['msg'] = 'Unexpected format %s.' % (format)
                results.append(result)
                junos_module.logger.debug('Unexpected format %s.', format)
                continue
        else:
            result['msg'] = 'Unexpected response type %s.' % (type(resp))
            results.append(result)
            junos_module.logger.debug('Unexpected response type %s.',
                                      type(resp))
            continue

        # Set the output keys
        if junos_module.params['return_output'] is True:
            if text_output is not None:
                result['stdout'] = text_output
                result['stdout_lines'] = text_output.splitlines()
            if parsed_output is not None:
                result['parsed_output'] = parsed_output
        # Save the output
        junos_module.save_text_output(rpc_string, format, text_output)
        # This command succeeded.
        result['failed'] = False
        # Append to the list of results
        results.append(result)

    # Return response.
    if len(results) == 1:
        junos_module.exit_json(**results[0])
    else:
        # Calculate the overall failed. Only failed if all commands failed.
        failed = True
        for result in results:
            if result.get('failed') is False:
                failed = False
                break
        junos_module.exit_json(results=results, changed=False, failed=failed)
def main():
    CHECKSUM_ALGORITHM_CHOICES = ['md5', 'sha1', 'sha256']

    #Define the argument spec.
    software_argument_spec = dict(
        local_package=dict(required=False,
                           aliases=['package'],
                           type='path',
                           default=None),
        remote_package=dict(
            required=False,
            type='path',
            # Default is '/var/tmp/' + filename from the
            # local_package option, if set.
            default=None),
        pkg_set=dict(required=False, type='list', default=None),
        version=dict(
            required=False,
            aliases=['target_version', 'new_version', 'desired_version'],
            type='str',
            # Default is determined from filename portion of
            # remote_package option.
            default=None),
        no_copy=dict(required=False, type='bool', default=False),
        reboot=dict(required=False, type='bool', default=True),
        reboot_pause=dict(required=False, type='int', default=10),
        issu=dict(required=False, type='bool', default=False),
        nssu=dict(required=False, type='bool', default=False),
        force_host=dict(required=False, type='bool', default=False),
        validate=dict(required=False, type='bool', default=False),
        cleanfs=dict(required=False, type='bool', default=True),
        all_re=dict(required=False, type='bool', default=True),
        vmhost=dict(required=False, type='bool', default=False),
        checksum=dict(required=False, type='str', default=None),
        checksum_algorithm=dict(required=False,
                                choices=CHECKSUM_ALGORITHM_CHOICES,
                                type='str',
                                default='md5'),
        checksum_timeout=dict(required=False, type='int', default=300),
        cleanfs_timeout=dict(required=False, type='int', default=300),
        install_timeout=dict(required=False, type='int', default=1800),
        kwargs=dict(required=False,
                    aliases=['kwarg', 'args', 'arg'],
                    type='dict',
                    default=None),
    )
    # Save keys for later. Must do because software_argument_spec gets
    # modified.
    option_keys = list(software_argument_spec.keys())

    # Create the module instance.
    junos_module = juniper_junos_common.JuniperJunosModule(
        argument_spec=software_argument_spec,
        # Mutually exclusive options.
        mutually_exclusive=[['issu', 'nssu']],
        # One of local_package and remote_package is required.
        required_one_of=[['local_package', 'remote_package', 'pkg_set']],
        supports_check_mode=True)

    # Straight from params
    local_package = junos_module.params.pop('local_package')
    remote_package = junos_module.params.pop('remote_package')
    pkg_set = junos_module.params.pop('pkg_set')
    target_version = junos_module.params.pop('version')
    no_copy = junos_module.params.pop('no_copy')
    reboot = junos_module.params.pop('reboot')
    reboot_pause = junos_module.params.pop('reboot_pause')
    install_timeout = junos_module.params.pop('install_timeout')
    cleanfs = junos_module.params.pop('cleanfs')
    all_re = junos_module.params.pop('all_re')
    kwargs = junos_module.params.pop('kwargs')

    url = None
    remote_dir = None
    if remote_package is not None:
        # Is the remote package a URL?
        parsed_url = urlparse(remote_package)
        if parsed_url.scheme == '':
            # A file on the remote host.
            (remote_dir, remote_filename) = os.path.split(remote_package)
        else:
            url = remote_package
            (_, remote_filename) = os.path.split(parsed_url.path)
    else:
        # Default remote_dir value
        remote_dir = '/var/tmp'
        remote_filename = ''

    if url is not None and local_package is not None:
        junos_module.fail_json(msg='There remote_package (%s) is a URL. '
                               'The local_package option is not allowed.' %
                               remote_package)

    if url is not None and no_copy is True:
        junos_module.fail_json(msg='There remote_package (%s) is a URL. '
                               'The no_copy option is not allowed.' %
                               remote_package)

    if url is None:
        local_filename = None
        if local_package is not None:
            # Expand out the path.
            local_package = os.path.abspath(local_package)
            (local_dir, local_filename) = os.path.split(local_package)
            if local_filename == '':
                junos_module.fail_json(msg='There is no filename component to '
                                       'the local_package (%s).' %
                                       local_package)
        elif remote_package is not None:
            # remote package was, so we must assume no_copy.
            no_copy = True

        if no_copy is False:
            if local_package is not None and not os.path.isfile(local_package):
                junos_module.fail_json(msg='The local_package (%s) is not a '
                                       'valid file on the local Ansible '
                                       'control machine.' % local_package)
            elif pkg_set is not None:
                pkg_set = [os.path.abspath(item) for item in pkg_set]
                for pkg_set_item in pkg_set:
                    if not os.path.isfile(pkg_set_item):
                        junos_module.fail_json(
                            msg='The pkg (%s) is not a valid file on the local'
                            ' Ansible control machine.' % pkg_set_item)

        if remote_filename == '':
            # Use the same name as local_filename
            remote_filename = local_filename

        if local_filename is not None and remote_filename != local_filename:
            junos_module.fail_json(msg='The filename of the remote_package '
                                   '(%s) must be the same as the filename '
                                   'of the local_package (%s).' %
                                   (remote_filename, local_filename))

    # If no_copy is True, then we need to turn off cleanfs to keep from
    # deleting the software package which is already present on the device.
    if no_copy is True:
        cleanfs = False

    if target_version is None and pkg_set is None:
        target_version = parse_version_from_filename(remote_filename)
    junos_module.logger.debug("New target version is: %s.", target_version)

    # Initialize the results. Assume not changed and failure until we know.
    results = {
        'msg': '',
        'changed': False,
        'check_mode': junos_module.check_mode,
        'failed': True
    }

    # Check version info to see if we need to do the install.
    if target_version is not None:
        if all_re is True:
            junos_info = junos_module.dev.facts['junos_info']
            for current_re in junos_info:
                current_version = junos_info[current_re]['text']
                if target_version != current_version:
                    junos_module.logger.debug(
                        "Current version on %s: %s. "
                        "Target version: %s.", current_version, current_re,
                        target_version)
                    results['changed'] = True
                else:
                    results['msg'] += "Current version on %s: %s same as Targeted " \
                                      "version: %s.\n" % (current_version, current_re,
                                                          target_version)
        else:
            current_version = junos_module.dev.facts['version']
            re_name = junos_module.dev.re_name
            if target_version != current_version:
                junos_module.logger.debug(
                    "Current version on %s: %s. "
                    "Target version: %s.", current_version, re_name,
                    target_version)
                results['changed'] = True
            else:
                results['msg'] += "Current version on %s: %s same as Targeted " \
                                 "version: %s.\n" % (current_version, re_name,
                                                     target_version)
    else:
        # A non-Junos install. Always attempt to install.
        results['changed'] = True

    # Do the install if necessary
    if results['changed'] is True and not junos_module.check_mode:
        junos_module.logger.debug("Beginning installation of %s.",
                                  remote_filename)
        # Calculate the install parameters
        install_params = {}
        if url is not None:
            install_params['package'] = url
        elif local_package is not None:
            install_params['package'] = local_package
        elif pkg_set is not None:
            install_params['pkg_set'] = pkg_set
        else:
            install_params['package'] = remote_filename
        if remote_dir is not None:
            install_params['remote_path'] = remote_dir
        install_params['progress'] = define_progress_callback(junos_module)
        install_params['cleanfs'] = cleanfs
        install_params['no_copy'] = no_copy
        install_params['timeout'] = install_timeout
        install_params['all_re'] = all_re
        for key in option_keys:
            value = junos_module.params.get(key)
            if value is not None:
                install_params[key] = value
        if kwargs is not None:
            install_params.update(kwargs)
        try:
            junos_module.logger.debug("Install parameters are: %s",
                                      str(install_params))
            junos_module.add_sw()
            ok = junos_module.sw.install(**install_params)
            if ok is not True:
                results['msg'] = 'Unable to install the software'
                junos_module.fail_json(**results)
            msg = 'Package %s successfully installed.' % (
                install_params.get('package') or install_params.get('pkg_set'))
            results['msg'] = msg
            junos_module.logger.debug(msg)
        except (junos_module.pyez_exception.ConnectError,
                junos_module.pyez_exception.RpcError) as ex:
            results['msg'] = 'Installation failed. Error: %s' % str(ex)
            junos_module.fail_json(**results)
        if reboot is True:
            try:
                # Try to deal with the fact that we might not get the closing
                # </rpc-reply> and therefore might get an RpcTimeout.
                # (This is a known Junos bug.) Set the timeout low so this
                # happens relatively quickly.
                if junos_module.dev.timeout > 5:
                    junos_module.logger.debug("Decreasing device RPC timeout "
                                              "to 5 seconds.")
                    junos_module.dev.timeout = 5
                junos_module.logger.debug('Initiating reboot.')
                xpath_list = ['.//request-reboot-status']
                if junos_module.dev.facts['_is_linux']:
                    rpc = junos_module.etree.Element('request-shutdown-reboot')
                elif install_params.get('vmhost'):
                    rpc = junos_module.etree.Element('request-vmhost-reboot')
                    # RPC reply can contain multiple output tags
                    xpath_list.append('output')
                else:
                    rpc = junos_module.etree.Element('request-reboot')

                if all_re is True:
                    if (junos_module.sw._multi_RE is True
                            and junos_module.sw._multi_VC is False):
                        junos_module.etree.SubElement(rpc,
                                                      'both-routing-engines')
                        # At least on some platforms stopping/rebooting both
                        # REs produces <output> messages and
                        # <request-reboot-status> messages.
                        xpath_list.append('output')
                    elif junos_module.sw._mixed_VC is True:
                        junos_module.etree.SubElement(rpc, 'all-members')
                resp = junos_module.dev.rpc(rpc,
                                            ignore_warning=True,
                                            normalize=True)
                junos_module.logger.debug("Reboot RPC executed cleanly.")
                if len(xpath_list) > 0:
                    obj = resp.getparent()
                    for xpath in xpath_list:
                        if junos_module.dev.facts['_is_linux']:
                            got = resp.text
                        else:
                            # there are cases where rpc-reply will have multiple
                            # child element, hence lets work on parent.
                            # for ex:
                            # <rpc-reply><output>Rebooting fpc1</output>
                            # <request-reboot-results>
                            # <request-reboot-status reboot-time="1561371395">
                            # Shutdown at Mon Jun 24 10:16:35 2019.
                            # [pid 1949]
                            # </request-reboot-status>
                            # </request-reboot-results></rpc-reply>
                            if xpath == 'output':
                                got = '\n'.join([
                                    i.text for i in obj.findall('output')
                                    if i.text is not None
                                ])
                            else:
                                got = obj.findtext(xpath)
                        if got is not None:
                            results['msg'] += ' Reboot successfully initiated. ' \
                                              'Reboot message: %s' % got
                            break
                    else:
                        # This is the else clause of the for loop.
                        # It only gets executed if the loop finished without
                        # hitting the break.
                        results['msg'] += ' Did not find expected response ' \
                                          'from reboot RPC. RPC response is ' \
                                          '%s' % \
                                          junos_module.etree.tostring(resp)
                        junos_module.fail_json(**results)
                else:
                    results['msg'] += ' Reboot successfully initiated.'
            except (junos_module.pyez_exception.RpcTimeoutError) as ex:
                # This might be OK. It might just indicate the device didn't
                # send the closing </rpc-reply> (known Junos bug).
                # Try to close the device. If it closes cleanly, then it was
                # still reachable, which probably indicates a problem.
                try:
                    junos_module.close(raise_exceptions=True)
                    # This means the device wasn't already disconnected.
                    results['msg'] += ' Reboot failed. It may not have been ' \
                                      'initiated.'
                    junos_module.fail_json(**results)
                except (junos_module.pyez_exception.RpcError,
                        junos_module.pyez_exception.ConnectError):
                    # This is expected. The device has already disconnected.
                    results['msg'] += ' Reboot succeeded.'
            except (junos_module.pyez_exception.RpcError,
                    junos_module.pyez_exception.ConnectError) as ex:
                results['msg'] += ' Reboot failed. Error: %s' % (str(ex))
                junos_module.fail_json(**results)
            junos_module.logger.debug("Reboot RPC successfully initiated.")
            if reboot_pause > 0:
                junos_module.logger.debug("Sleeping for %d seconds",
                                          reboot_pause)
                time.sleep(reboot_pause)

    # If we made it this far, it's success.
    results['failed'] = False

    junos_module.exit_json(**results)
Example #4
0
def main():
    # Create the module instance.
    junos_module = juniper_junos_common.JuniperJunosModule(
        argument_spec=dict(
            enable=dict(type='bool',
                        required=True,
                        aliases=['cluster_enable'],
                        default=None),
            cluster_id=dict(type='int',
                            required=False,
                            aliases=['cluster'],
                            default=None),
            node_id=dict(type='int',
                         required=False,
                         aliases=['node'],
                         default=None)
        ),
        # Required if options
        # If enable is True, then cluster_id and node_id must be set.
        required_if=[['enable', True, ['cluster_id', 'node_id']]],
        # Check mode is implemented.
        supports_check_mode=True
    )
    # Do additional argument verification.

    # Straight from params
    enable = junos_module.params.get('enable')
    cluster_id = junos_module.params.get('cluster_id')
    node_id = junos_module.params.get('node_id')

    # cluster_id must be between 0 and 255
    if cluster_id is not None:
        if cluster_id < 0 or cluster_id > 255:
            junos_module.fail_json(msg="The cluster_id option (%s) must have "
                                       "an integer value between 0 and 255." %
                                       (cluster_id))

    # node_id must be between 0 and 1
    if node_id is not None:
        if node_id < 0 or node_id > 1:
            junos_module.fail_json(msg="The node_id option (%s) must have a "
                                       "value of 0 or 1." % (node_id))

    # Initialize the results. Assume failure until we know it's success.
    results = {'msg': '',
               'changed': False,
               'reboot': False,
               'failed': True}

    junos_module.logger.debug("Check current SRX cluster operational state.")
    current_cluster_state = junos_module.dev.facts['srx_cluster']
    current_cluster_id = junos_module.dev.facts['srx_cluster_id']
    if current_cluster_id is not None:
        current_cluster_id = int(current_cluster_id)
    current_node_name = junos_module.dev.re_name
    current_node_id = None
    if current_node_name is not None:
        (_, _, current_node_id) = current_node_name.partition('node')
        if current_node_id:
            current_node_id = int(current_node_id)
    junos_module.logger.debug(
        "Current SRX cluster operational state: %s, cluster_id: %s, "
        "node_id: %s",
        'enabled' if current_cluster_state else 'disabled',
        str(current_cluster_id),
        str(current_node_id))

    # Is a state change needed?
    if current_cluster_state != enable:
        junos_module.logger.debug(
            "SRX cluster configuration change needed. Current state: %s. "
            "Desired state: %s",
            'enabled' if current_cluster_state else 'disabled',
            'enabled' if enable else 'disabled')
        results['changed'] = True

    # Is a cluster ID change needed?
    if (enable is True and current_cluster_id is not None and
       current_cluster_id != cluster_id):
        junos_module.logger.debug(
            "SRX cluster ID change needed. Current cluster ID: %d. "
            "Desired cluster ID: %d",
            current_cluster_id, cluster_id)
        results['changed'] = True

    # Is a node ID change needed?
    if (enable is True and current_node_id is not None and
       current_node_id != node_id):
        junos_module.logger.debug(
            "SRX node ID change needed. Current node ID: %d. "
            "Desired cluster ID: %d",
            current_node_id, node_id)
        results['changed'] = True

    results['msg'] = 'Current state: %s, cluster_id: %s, node_id: %s' % \
                     ('enabled' if current_cluster_state else 'disabled',
                      str(current_cluster_id),
                      str(current_node_id))

    if results['changed'] is True:
        results['msg'] += ' Desired state:  %s, cluster_id: %s, ' \
                          'node_id: %s' % \
                          ('enabled' if enable else 'disabled',
                           str(cluster_id),
                           str(node_id))

        if not junos_module.check_mode:
            results['msg'] += ' Initiating change.'
            try:
                output = None
                if enable is True:
                    resp = junos_module.dev.rpc.set_chassis_cluster_enable(
                        cluster_id=str(cluster_id), node=str(node_id),
                        reboot=True, normalize=True
                    )
                else:
                    resp = junos_module.dev.rpc.set_chassis_cluster_disable(
                        reboot=True, normalize=True
                    )
                if resp is not None:
                    output = resp.getparent().findtext('.//output')
                    if output is None:
                        output = resp.getparent().findtext('.//message')
                results['msg'] += ' Reboot initiated. Response: %s' % (output)
                results['reboot'] = True
            except (junos_module.pyez_exception.ConnectError,
                    junos_module.pyez_exception.RpcError) as ex:
                junos_module.logger.debug('Error: %s', str(ex))
                results['msg'] += ' Error: %s' % (str(ex))
                junos_module.fail_json(**results)

    # If we made it this far, everything was successful.
    results['failed'] = False

    # Return response.
    junos_module.exit_json(**results)
def main():
    # Choices which are defined in the common module.
    config_format_choices = juniper_junos_common.CONFIG_FORMAT_CHOICES
    config_database_choices = [None] + \
        juniper_junos_common.CONFIG_DATABASE_CHOICES
    config_action_choices = [None] + juniper_junos_common.CONFIG_ACTION_CHOICES
    config_mode_choices = juniper_junos_common.CONFIG_MODE_CHOICES
    config_model_choices = juniper_junos_common.CONFIG_MODEL_CHOICES

    # Create the module instance.
    junos_module = juniper_junos_common.JuniperJunosModule(
        argument_spec=dict(ignore_warning=dict(required=False,
                                               type='list',
                                               default=None),
                           config_mode=dict(choices=config_mode_choices,
                                            type='str',
                                            required=False,
                                            aliases=[
                                                'config_access', 'edit_mode',
                                                'edit_access'
                                            ],
                                            default='exclusive'),
                           rollback=dict(type='str',
                                         required=False,
                                         default=None),
                           load=dict(choices=config_action_choices,
                                     type='str',
                                     required=False,
                                     default=None),
                           src=dict(type='path',
                                    required=False,
                                    aliases=['source', 'file'],
                                    default=None),
                           lines=dict(type='list',
                                      required=False,
                                      default=None),
                           template=dict(type='path',
                                         required=False,
                                         aliases=['template_path'],
                                         default=None),
                           vars=dict(type='dict',
                                     required=False,
                                     aliases=['template_vars'],
                                     default=None),
                           url=dict(type='str', required=False, default=None),
                           format=dict(choices=config_format_choices,
                                       type='str',
                                       required=False,
                                       default=None),
                           model=dict(required=False,
                                      choices=config_model_choices,
                                      type='str',
                                      default=None),
                           remove_ns=dict(required=False,
                                          type='bool',
                                          default=None),
                           namespace=dict(required=False,
                                          type='str',
                                          default=None),
                           check=dict(required=False,
                                      type='bool',
                                      aliases=['check_commit', 'commit_check'],
                                      default=None),
                           diff=dict(required=False,
                                     type='bool',
                                     aliases=['compare', 'diffs'],
                                     default=None),
                           diffs_file=dict(type='path',
                                           required=False,
                                           default=None),
                           dest_dir=dict(required=False,
                                         type='path',
                                         aliases=[
                                             'destination_dir', 'destdir',
                                             'savedir', 'save_dir'
                                         ],
                                         default=None),
                           return_output=dict(required=False,
                                              type='bool',
                                              default=True),
                           retrieve=dict(choices=config_database_choices,
                                         type='str',
                                         required=False,
                                         default=None),
                           options=dict(type='dict',
                                        required=False,
                                        default={}),
                           filter=dict(required=False,
                                       type='str',
                                       aliases=['filter_xml'],
                                       default=None),
                           dest=dict(type='path',
                                     required=False,
                                     aliases=['destination'],
                                     default=None),
                           commit=dict(required=False,
                                       type='bool',
                                       default=None),
                           commit_empty_changes=dict(required=False,
                                                     type='bool',
                                                     default=False),
                           confirmed=dict(required=False,
                                          type='int',
                                          aliases=['confirm'],
                                          default=None),
                           comment=dict(required=False,
                                        type='str',
                                        default=None),
                           check_commit_wait=dict(required=False,
                                                  type='int',
                                                  default=None)),
        # Mutually exclusive options.
        mutually_exclusive=[['load', 'rollback'],
                            ['src', 'lines', 'template', 'url'],
                            ['diffs_file', 'dest_dir'], ['dest', 'dest_dir']],
        # Required together options.
        required_together=[['template', 'vars']],
        # Check mode is implemented.
        supports_check_mode=True,
        min_jxmlease_version=juniper_junos_common.MIN_JXMLEASE_VERSION,
    )
    # Do additional argument verification.

    # Parse ignore_warning value
    ignore_warning = junos_module.parse_ignore_warning_option()

    # Straight from params
    config_mode = junos_module.params.get('config_mode')

    # Parse rollback value
    rollback = junos_module.parse_rollback_option()

    # Straight from params
    load = junos_module.params.get('load')
    src = junos_module.params.get('src')
    lines = junos_module.params.get('lines')
    template = junos_module.params.get('template')
    vars = junos_module.params.get('vars')
    url = junos_module.params.get('url')
    format = junos_module.params.get('format')
    check = junos_module.params.get('check')
    diff = junos_module.params.get('diff')
    diffs_file = junos_module.params.get('diffs_file')
    dest_dir = junos_module.params.get('dest_dir')
    return_output = junos_module.params.get('return_output')
    retrieve = junos_module.params.get('retrieve')
    options = junos_module.params.get('options')
    filter = junos_module.params.get('filter')
    dest = junos_module.params.get('dest')
    commit = junos_module.params.get('commit')
    commit_empty_changes = junos_module.params.get('commit_empty_changes')
    confirmed = junos_module.params.get('confirmed')
    comment = junos_module.params.get('comment')
    check_commit_wait = junos_module.params.get('check_commit_wait')
    model = junos_module.params.get('model')
    remove_ns = junos_module.params.get('remove_ns')
    namespace = junos_module.params.get('namespace')

    # If retrieve is set and load and rollback are not set, then
    # check, diff, and commit default to False.
    if retrieve is not None and load is None and rollback is None:
        if diff is None:
            diff = False
        if check is None:
            check = False
        if commit is None:
            commit = False
    # Otherwise, diff, check, and commit default to True.
    else:
        if diff is None:
            diff = True
        if check is None:
            check = True
        if commit is None:
            commit = True

    # If load is not None, must have one of src, template, url, lines
    if load is not None:
        for option in ['src', 'lines', 'template', 'url']:
            if junos_module.params.get(option) is not None:
                break
        # for/else only executed if we didn't break out of the loop.
        else:
            junos_module.fail_json(msg="The load option (%s) is specified, "
                                   "but none of 'src', 'lines', "
                                   "'template', or 'url' are specified. "
                                   "Must specify one of the 'src', "
                                   "'lines', 'template', or 'url' options." %
                                   (load))

    # format is valid if retrieve is not None or load is not None.
    if format is not None:
        if load is None and retrieve is None:
            junos_module.fail_json(msg="The format option (%s) is specified, "
                                   "but neither 'load' or 'retrieve' are "
                                   "specified. Must specify one of "
                                   "'load' or 'retrieve' options." % (format))

    # dest_dir is valid if retrieve is not None or diff is True.
    if dest_dir is not None:
        if retrieve is None and diff is False:
            junos_module.fail_json(msg="The dest_dir option (%s) is specified,"
                                   " but neither 'retrieve' or 'diff' "
                                   "are specified. Must specify one of "
                                   "'retrieve' or 'diff' options." %
                                   (dest_dir))

    # dest is valid if retrieve is not None
    if dest is not None:
        if retrieve is None:
            junos_module.fail_json(msg="The dest option (%s) is specified,"
                                   " but 'retrieve' is not specified. "
                                   "Must specify the 'retrieve' option." %
                                   (dest))

    # diffs_file is valid if diff is True
    if diffs_file is not None:
        if diff is False:
            junos_module.fail_json(msg="The diffs_file option (%s) is "
                                   "specified, but 'diff' is false." %
                                   (diffs_file))

    # commit_empty_changes is valid if commit is True
    if commit_empty_changes is True:
        if commit is False:
            junos_module.fail_json(msg="The commit_empty_changes option "
                                   "is true, but 'commit' is false. "
                                   "The commit_empty_changes option "
                                   "may only be specified when "
                                   "'commit' is true.")

    # comment is valid if commit is True
    if comment is not None:
        if commit is False:
            junos_module.fail_json(msg="The comment option (%s) is "
                                   "specified, but 'commit' is false." %
                                   (comment))

    # confirmed is valid if commit is True
    if confirmed is not None:
        if commit is False:
            junos_module.fail_json(msg="The confirmed option (%s) is "
                                   "specified, but 'commit' is false." %
                                   (confirmed))
        # Must be greater >= 1.
        if confirmed < 1:
            junos_module.fail_json(msg="The confirmed option (%s) must have a "
                                   "positive integer value." % (confirmed))

    # check_commit_wait is valid if check is True and commit is True
    if check_commit_wait is not None:
        if commit is False:
            junos_module.fail_json(msg="The check_commit_wait option (%s) is "
                                   "specified, but 'commit' is false." %
                                   (check_commit_wait))
        if check is False:
            junos_module.fail_json(msg="The check_commit_wait option (%s) is "
                                   "specified, but 'check' is false." %
                                   (check_commit_wait))
        # Must be greater >= 1.
        if check_commit_wait < 1:
            junos_module.fail_json(msg="The check_commit_wait option (%s) "
                                   "must have a positive integer value." %
                                   (check_commit_wait))

    # Initialize the results. Assume failure until we know it's success.
    results = {
        'msg': 'Configuration has been: ',
        'changed': False,
        'failed': True
    }

    junos_module.logger.debug("Step 1 - Open a candidate configuration "
                              "database.")
    junos_module.open_configuration(mode=config_mode,
                                    ignore_warning=ignore_warning)
    results['msg'] += 'opened'

    junos_module.logger.debug("Step 2 - Load configuration data into the "
                              "candidate configuration database.")
    if rollback is not None:
        junos_module.rollback_configuration(id=rollback)
        # Assume configuration changed in case we don't perform a diff later.
        # If diff is set, we'll check for actual differences later.
        results['changed'] = True
        results['msg'] += ', rolled back'
    elif load is not None:
        if src is not None:
            junos_module.load_configuration(action=load,
                                            src=src,
                                            ignore_warning=ignore_warning,
                                            format=format)
            results['file'] = src
        elif lines is not None:
            junos_module.load_configuration(action=load,
                                            lines=lines,
                                            ignore_warning=ignore_warning,
                                            format=format)
        elif template is not None:
            junos_module.load_configuration(action=load,
                                            template=template,
                                            vars=vars,
                                            ignore_warning=ignore_warning,
                                            format=format)
        elif url is not None:
            junos_module.load_configuration(action=load,
                                            url=url,
                                            ignore_warning=ignore_warning,
                                            format=format)
        else:
            junos_module.fail_json(msg="The load option was set to: %s, but "
                                   "no 'src', 'lines', 'template', or "
                                   "'url' option was set." % (load))
        # Assume configuration changed in case we don't perform a diff later.
        # If diff is set, we'll check for actual differences later.
        results['changed'] = True
        results['msg'] += ', loaded'

    junos_module.logger.debug("Step 3 - Check the validity of the candidate "
                              "configuration database.")
    if check is True:
        junos_module.check_configuration()
        results['msg'] += ', checked'

    junos_module.logger.debug("Step 4 - Determine differences between the "
                              "candidate and committed configuration "
                              "databases.")
    if diff is True or junos_module._diff:
        diff = junos_module.diff_configuration()
        if diff is not None:
            results['changed'] = True
            if return_output is True or junos_module._diff:
                results['diff'] = {'prepared': diff}
                results['diff_lines'] = diff.splitlines()
            # Save the diff output
            junos_module.save_text_output('diff', 'diff', diff)
        else:
            results['changed'] = False
        results['msg'] += ', diffed'

    junos_module.logger.debug("Step 5 - Retrieve the configuration database "
                              "from the Junos device.")
    if retrieve is not None:
        if format is None:
            format = 'text'
        (config,
         config_parsed) = junos_module.get_configuration(database=retrieve,
                                                         format=format,
                                                         options=options,
                                                         filter=filter,
                                                         model=model,
                                                         namespace=namespace,
                                                         remove_ns=remove_ns)
        if return_output is True:
            if config is not None:
                results['config'] = config
                results['config_lines'] = config.splitlines()
            if config_parsed is not None:
                results['config_parsed'] = config_parsed
        # Save the output
        format_extension = 'config' if format == 'text' else format
        junos_module.save_text_output('config', format_extension, config)
        results['msg'] += ', retrieved'

    junos_module.logger.debug("Step 6 - Commit the configuration changes.")
    if commit is True and not junos_module.check_mode:
        # Perform the commit if:
        # 1) commit_empty_changes is True
        # 2) Neither rollback or load is set. i.e. confirming a previous commit
        # 3) rollback or load is set, and there were actual changes.
        if (commit_empty_changes is True or (rollback is None and load is None)
                or ((rollback is not None or load is not None)
                    and results['changed'] is True)):
            if check_commit_wait is not None:
                time.sleep(check_commit_wait)
            junos_module.commit_configuration(ignore_warning=ignore_warning,
                                              comment=comment,
                                              confirmed=confirmed)
            results['msg'] += ', committed'
        else:
            junos_module.logger.debug("Skipping commit. Nothing changed.")

    junos_module.logger.debug("Step 7 - Close the candidate configuration "
                              "database.")
    junos_module.close_configuration()
    results['msg'] += ', closed.'

    # If we made it this far, everything was successful.
    results['failed'] = False

    # Return response.
    junos_module.exit_json(**results)
def main():
    JSNAPY_ACTION_CHOICES = ['check', 'snapcheck', 'snap_pre', 'snap_post']

    # Create the module instance.
    junos_module = juniper_junos_common.JuniperJunosModule(
        argument_spec=dict(action=dict(required=True,
                                       choices=JSNAPY_ACTION_CHOICES,
                                       type='str',
                                       default=None),
                           test_files=dict(required=False,
                                           type='list',
                                           default=None),
                           config_file=dict(required=False,
                                            type='path',
                                            default=None),
                           dir=dict(required=False,
                                    type='path',
                                    aliases=['directory'],
                                    default='/etc/jsnapy/testfiles')),
        # Mutually exclusive options.
        mutually_exclusive=[['test_files', 'config_file']],
        # One of test_files or config_file is required.
        required_one_of=[['test_files', 'config_file']],
        supports_check_mode=True,
        min_jsnapy_version=juniper_junos_common.MIN_JSNAPY_VERSION,
    )

    # Straight from params
    action = junos_module.params.get('action')
    test_files = junos_module.params.get('test_files')
    config_file = junos_module.params.get('config_file')
    dir = junos_module.params.get('dir')

    # Initialize the results. Assume failure until we know otherwise.
    results = {'msg': '', 'action': action, 'changed': False, 'failed': True}

    if config_file is not None:
        junos_module.logger.debug('Checking config file: %s.', config_file)
        config_file_path = os.path.abspath(config_file)
        config_dir_file_path = os.path.abspath(os.path.join(dir, config_file))
        if os.path.isfile(config_file_path):
            data = config_file_path
        elif os.path.isfile(config_dir_file_path):
            data = config_dir_file_path
        else:
            junos_module.fail_json(
                msg="Unable to locate the %s config file "
                "at %s or %s." %
                (config_file, config_file_path, config_dir_file_path))
    elif test_files is not None and len(test_files) > 0:
        data = {'tests': []}
        for test_file in test_files:
            junos_module.logger.debug('Checking test file: %s.', test_file)
            test_file_path = os.path.abspath(test_file)
            test_dir_file_path = os.path.abspath(os.path.join(dir, test_file))
            if os.path.isfile(test_file_path):
                data['tests'].append(test_file_path)
            elif os.path.isfile(test_dir_file_path):
                data['tests'].append(test_dir_file_path)
            else:
                junos_module.fail_json(
                    msg="Unable to locate the %s test file "
                    "at %s or %s." %
                    (test_file, test_file_path, test_dir_file_path))
    else:
        junos_module.fail_json(msg="No config_file or test_files specified.")

    try:
        junos_module.logger.debug('Creating jnpr.jsnapy.SnapAdmin instance.')
        jsa = junos_module.jsnapy.SnapAdmin()
        junos_module.logger.debug('Executing %s action.', action)
        if action == 'check':
            responses = jsa.check(data=data,
                                  dev=junos_module.dev,
                                  pre_file='PRE',
                                  post_file='POST')
        elif action == 'snapcheck':
            responses = jsa.snapcheck(data=data, dev=junos_module.dev)
        elif action == 'snap_pre':
            responses = jsa.snap(data=data,
                                 dev=junos_module.dev,
                                 file_name='PRE')
        elif action == 'snap_post':
            responses = jsa.snap(data=data,
                                 dev=junos_module.dev,
                                 file_name='POST')
        else:
            junos_module.fail_json(msg="Unexpected action: %s." % (action))
        junos_module.logger.debug('The %s action executed successfully.',
                                  action)
    except (junos_module.pyez_exception.RpcError,
            junos_module.pyez_exception.ConnectError) as ex:
        junos_module.fail_json(msg="Error communicating with the device: %s" %
                               (str(ex)))
    except Exception as ex:
        junos_module.fail_json(msg="Uncaught exception - please report: %s" %
                               (str(ex)))

    if isinstance(responses, list) and len(responses) == 1:
        if action in ('snapcheck', 'check'):
            for response in responses:
                results['device'] = response.device
                results['router'] = response.device
                results['final_result'] = response.result
                results['total_passed'] = response.no_passed
                results['total_failed'] = response.no_failed
                results['test_results'] = response.test_results
                total_tests = int(response.no_passed) + int(response.no_failed)
                results['total_tests'] = total_tests
            pass_percentage = 0
            if total_tests > 0:
                pass_percentage = ((int(response.no_passed) * 100) //
                                   total_tests)
            results['passPercentage'] = pass_percentage
            results['pass_percentage'] = pass_percentage
            if results['final_result'] == 'Failed':
                results['msg'] = 'Test Failed: Passed %s, Failed %s' % \
                                 (results['total_passed'],
                                  results['total_failed'])
            else:
                results['msg'] = 'Test Passed: Passed %s, Failed %s' % \
                                 (results['total_passed'],
                                  results['total_failed'])
        elif action in ('snap_pre', 'snap_post'):
            results['msg'] = "The %s action successfully executed." % (action)
    else:
        junos_module.fail_json(msg="Unexpected JSNAPy responses. Type: %s."
                               "Responses: %s" %
                               (type(responses), str(responses)))

    # If we made it this far, it's success.
    results['failed'] = False

    junos_module.exit_json(**results)
Example #7
0
def main():
    # Create the module instance.
    junos_module = juniper_junos_common.JuniperJunosModule(
        argument_spec=dict(
            file=dict(type='path', required=True, default=None),
            table=dict(type='str', required=False, default=None),
            path=dict(type='path',
                      required=False,
                      aliases=['directory', 'dir'],
                      default=None),
            kwargs=dict(required=False,
                        aliases=['kwarg', 'args', 'arg'],
                        type='dict',
                        default=None),
            response_type=dict(choices=RESPONSE_CHOICES,
                               type='str',
                               required=False,
                               default='list_of_dicts'),
        ),
        # Check mode is implemented.
        supports_check_mode=True,
        min_yaml_version=juniper_junos_common.MIN_YAML_VERSION,
    )

    # Straight from params
    file = junos_module.params.get('file')
    table = junos_module.params.get('table')
    path = junos_module.params.get('path')
    kwargs = junos_module.params.get('kwargs')
    response_type = junos_module.params.get('response_type')

    if not file.endswith('.yml') and not file.endswith('.yaml'):
        junos_module.fail_json(msg='The value of the file option must end '
                               'with the .yml or .yaml extension')

    # If needed, get the default path
    if path is None:
        path = os.path.dirname(
            os.path.abspath(junos_module.pyez_op_table.__file__))

    # file_name is path + file
    file_name = os.path.join(path, file)

    junos_module.logger.debug("Attempting to open: %s.", file_name)
    try:
        with open(file_name, 'r') as fp:
            try:
                junos_module.logger.debug(
                    "Attempting to parse YAML from : "
                    "%s.", file_name)
                table_view = junos_module.yaml.load(fp)
                junos_module.logger.debug("YAML from %s successfully parsed.",
                                          file_name)
            except junos_module.yaml.YAMLError as ex:
                junos_module.fail_json(msg='Failed parsing YAML file %s. '
                                       'Error: %s' % (file_name, str(ex)))
    except IOError:
        junos_module.fail_json(msg='The file name %s could not be opened for'
                               'reading.' % (file_name))
    junos_module.logger.debug("%s successfully read.", file_name)

    # Initialize the results. Assume failure until we know it's success.
    results = {'msg': '', 'changed': False, 'failed': True}

    # Default to the table defined in file_name.
    # Ignore table names which begin with an underscore.
    if table is None:
        for key in table_view:
            if not key.startswith('_') and 'Table' in key:
                if table is not None:
                    junos_module.fail_json(
                        msg='The file name %s contains multiple table '
                        'definitions. Specify the desired table with the '
                        'table option.' % (file_name))
                table = key

    if table is None:
        junos_module.fail_json(
            msg='No table definition was found in the %s file. Specify a '
            'value for the file option which contains a valid table/view '
            'definition.' % (file_name))
    junos_module.logger.debug("Table: %s", table)

    try:
        loader = \
            junos_module.pyez_factory_loader.FactoryLoader().load(table_view)
        junos_module.logger.debug("Loader created successfully.")
    except Exception as ex:
        junos_module.fail_json(msg='Unable to create a table loader from the '
                               '%s file. Error: %s' % (file_name, str(ex)))
    try:
        data = loader[table](junos_module.dev)
        junos_module.logger.debug("Table %s created successfully.", table)
        if kwargs is None:
            data.get()
        else:
            data.get(**kwargs)
        junos_module.logger.debug("Data retrieved from %s successfully.",
                                  table)
    except KeyError:
        junos_module.fail_json(msg='Unable to find table %s in the '
                               '%s file.' % (table, file_name))
    except (junos_module.pyez_exception.ConnectError,
            junos_module.pyez_exception.RpcError) as ex:
        junos_module.fail_json(msg='Unable to retrieve data from table %s. '
                               'Error: %s' % (table, str(ex)))

    if data is not None:
        try:
            len_data = len(data)
        except Exception as ex:
            junos_module.fail_json(msg='Unable to parse table %s data into '
                                   'items. Error: %s' % (table, str(ex)))
        junos_module.logger.debug('Successfully retrieved %d items from %s.',
                                  len_data, table)
        results['msg'] = 'Successfully retrieved %d items from %s.' % \
                         (len_data, table)

    if response_type == 'list_of_dicts':
        junos_module.logger.debug('Converting data to list of dicts.')
        resource = juniper_items_to_list_of_dicts(junos_module, data)
    else:
        resource = expand_items(junos_module, data)

    # If we made it this far, everything was successful.
    results['failed'] = False
    results['resource'] = resource

    # Return response.
    junos_module.exit_json(**results)
def main():
    # Constants for MTU size
    INET_MIN_MTU_SIZE = 68  # As prescribed by RFC 791, Section 3.2 -
    # Fragmentation and Reassembly.
    INET_MAX_MTU_SIZE = 65496  # Size of inet header's total length field is
    # 16 bits. Therefore max inet packet size is 2^16
    # or 65536, but Junos only supports max IP size
    # of 65496 for the ping command in order to
    # accomodate a (potentially) maximum sized IP
    # header.

    # Constants for the size of headers
    INET_HEADER_SIZE = 20
    ICMP_HEADER_SIZE = 8
    INET_AND_ICMP_HEADER_SIZE = INET_HEADER_SIZE + ICMP_HEADER_SIZE

    # Choices for max_size
    MAX_SIZE_CHOICES = [0] + list(map(lambda x: 2**x, range(1, 17)))

    # Create the module instance.
    junos_module = juniper_junos_common.JuniperJunosModule(
        argument_spec=dict(
            dest=dict(type='str',
                      required=True,
                      aliases=[
                          'dest_ip', 'dest_host', 'destination',
                          'destination_ip', 'destination_host'
                      ],
                      default=None),
            max_size=dict(type='int', required=False, default=1500),
            max_range=dict(type='int',
                           required=False,
                           choices=MAX_SIZE_CHOICES,
                           default=512),
            source=dict(type='str',
                        required=False,
                        aliases=[
                            'source_ip', 'source_host', 'src', 'src_ip',
                            'src_host'
                        ],
                        default=None),
            interface=dict(type='str', required=False, default=None),
            routing_instance=dict(type='str', required=False, default=None),
        ),
        # Since this module doesn't change the device's configuration, there is
        # no additional work required to support check mode. It's inherently
        # supported.
        supports_check_mode=True)

    # We're going to be using params a lot
    params = junos_module.params

    # max_size must be between INET_MIN_MTU_SIZE and INET_MAX_MTU_SIZE
    if (params['max_size'] < INET_MIN_MTU_SIZE
            or params['max_size'] > INET_MAX_MTU_SIZE):
        junos_module.fail_json(
            msg='The value of the max_size option(%d) '
            'must be between %d and %d.' %
            (params['max_size'], INET_MIN_MTU_SIZE, INET_MAX_MTU_SIZE))

    # Initialize ping parameters.
    ping_params = {
        'host': params.get('dest'),
        'count': '3',
        'rapid': True,
        'inet': True,
        'do_not_fragment': True
    }

    # Add optional ping parameters
    o_ping_params = {}
    if params['source'] is not None:
        o_ping_params['source'] = params['source']
    if params['interface'] is not None:
        o_ping_params['interface'] = params['interface']
    if params['routing_instance'] is not None:
        o_ping_params['routing_instance'] = params['routing_instance']
    ping_params.update(o_ping_params)

    # Set initial results values. Assume failure until we know it's success.
    results = {
        'changed': False,
        'failed': True,
        'inet_mtu': 0,
        'host': params.get('dest')
    }
    # Results should include all the o_ping_params.
    for key in o_ping_params:
        results[key] = ping_params.get(key)
    # Add aliases for backwards compatibility
    results.update({
        'dest': ping_params.get('host'),
        'dest_ip': ping_params.get('host'),
        'source_ip': ping_params.get('source')
    })

    # Execute a minimally-sized ping just to verify basic connectivity.
    junos_module.logger.debug("Verifying basic connectivity.")
    ping_params['size'] = str(INET_MIN_MTU_SIZE - INET_AND_ICMP_HEADER_SIZE)
    results_for_minimal = dict(results)
    results_for_minimal = junos_module.ping(ping_params,
                                            acceptable_percent_loss=100,
                                            results=results_for_minimal)
    if int(results_for_minimal.get('packet_loss', 100)) == 100:
        results['msg'] = "Basic connectivity to %s failed." % (results['host'])
        junos_module.exit_json(**results)

    # Initialize test_size and step
    test_size = params['max_size']
    step = params['max_range']
    min_test_size = test_size - (params['max_range'] - 1)
    if min_test_size < INET_MIN_MTU_SIZE:
        min_test_size = INET_MIN_MTU_SIZE

    while True:
        if test_size < INET_MIN_MTU_SIZE:
            test_size = INET_MIN_MTU_SIZE
        if test_size > params['max_size']:
            test_size = params['max_size']
        junos_module.logger.debug("Probing with size: %d", test_size)
        step = step // 2 if step >= 2 else 0
        ping_params['size'] = str(test_size - INET_AND_ICMP_HEADER_SIZE)
        current_results = dict(results)
        current_results = junos_module.ping(ping_params,
                                            acceptable_percent_loss=100,
                                            results=current_results)
        loss = int(current_results.get('packet_loss', 100))
        if loss < 100 and test_size == params['max_size']:
            # ping success with max test_size, save and break
            results['failed'] = False
            results['inet_mtu'] = test_size
            break
        elif loss < 100:
            # ping success, increase test_size
            results['failed'] = False
            results['inet_mtu'] = test_size
            test_size += step
        else:
            # ping fail, lower size
            test_size -= step
        if step < 1:
            break

    if results.get('inet_mtu', 0) == 0:
        junos_module.fail_json(msg='The MTU of the path to %s is less than '
                               'the minimum tested size(%d). Try '
                               'decreasing max_size(%d) or increasing '
                               'max_range(%d).' %
                               (results['host'], min_test_size,
                                params['max_size'], params['max_range']),
                               **results)

    # Return results.
    junos_module.exit_json(**results)
Example #9
0
def main():
    # Create the module instance.
    junos_module = juniper_junos_common.JuniperJunosModule(
        argument_spec=dict(
            action=dict(type='str',
                        required=True,
                        choices=[
                            'shutdown', 'off', 'power-off', 'power_off',
                            'halt', 'reboot', 'zeroize'
                        ],
                        default=None),
            at=dict(type='str', required=False, default=None),
            in_min=dict(type='int',
                        required=False,
                        aliases=['in'],
                        default=None),
            all_re=dict(type='bool', required=False, default=True),
            other_re=dict(type='bool', required=False, default=False),
            media=dict(type='bool', required=False, default=False),
        ),
        mutually_exclusive=[['at', 'in_min'], ['all_re', 'other_re']],
        supports_check_mode=True)

    # We're going to be using params a lot
    params = junos_module.params

    action = params['action']
    # Synonymns for shutdown
    if action == 'off' or action == 'power_off' or action == 'power-off':
        action = 'shutdown'

    # at option only applies to reboot, shutdown, or halt actions.
    if (params.get('at') is not None and action != 'reboot'
            and action != 'shutdown' and action != 'halt'):
        junos_module.fail_json(msg='The at option can only be used when '
                               'the action option has the value "reboot", '
                               '"shutdown", or "halt".')

    # in_min option only applies to reboot, shutdown, or halt actions.
    if (params.get('in_min') is not None and action != 'reboot'
            and action != 'shutdown' and action != 'halt'):
        junos_module.fail_json(msg='The in_min option can only be used when '
                               'the action option has the value "reboot", '
                               '"shutdown", or "halt".')

    # other_re option only applies to reboot, shutdown, or halt actions.
    if (params.get('other_re') is True and action != 'reboot'
            and action != 'shutdown' and action != 'halt'):
        junos_module.fail_json(msg='The other_re option can only be used when '
                               'the action option has the value "reboot", '
                               '"shutdown", or "halt".')

    # media option only applies to zeroize action.
    if params['media'] is True and action != 'zeroize':
        junos_module.fail_json(msg='The media option can only be used when '
                               'the action option has the value '
                               '"zeroize".')

    # If other_re, then we should turn off all_re
    if params['other_re'] is True:
        params['all_re'] = False

    # Set initial results values. Assume failure until we know it's success.
    # Assume we haven't changed the state until we do.
    results = {
        'changed': False,
        'msg': '',
        'reboot': bool(action == 'reboot'),
        'action': action,
        'all_re': params.get('all_re'),
        'other_re': params.get('other_re'),
        'media': params.get('media'),
        'failed': True
    }

    # Map the action to an RPC.
    rpc = None
    xpath_list = []
    if action == 'reboot':
        if junos_module.dev.facts['_is_linux']:
            rpc = junos_module.etree.Element('request-shutdown-reboot')
        else:
            rpc = junos_module.etree.Element('request-reboot')
        xpath_list.append('.//request-reboot-status')
    elif action == 'shutdown':
        if junos_module.dev.facts['_is_linux']:
            rpc = junos_module.etree.Element('request-shutdown-power-off')
        else:
            rpc = junos_module.etree.Element('request-power-off')
        xpath_list.append('.//request-reboot-status')
    elif action == 'halt':
        if junos_module.dev.facts['_is_linux']:
            rpc = junos_module.etree.Element('request-shutdown-halt')
        else:
            rpc = junos_module.etree.Element('request-halt')
        xpath_list.append('.//request-reboot-status')
    elif action == 'zeroize':
        rpc = junos_module.etree.Element('request-system-zeroize')
    else:
        results['msg'] = 'No RPC found for the %s action.' % (action)
        junos_module.fail_json(**results)

    # Add the arguments
    if action == 'zeroize':
        if params['all_re'] is False:
            if junos_module.dev.facts['2RE']:
                junos_module.etree.SubElement(rpc, 'local')
        if params['media'] is True:
            junos_module.etree.SubElement(rpc, 'media')
    else:
        if params['in_min'] is not None:
            junos_module.etree.SubElement(rpc,
                                          'in').text = str(params['in_min'])
        elif params['at'] is not None:
            junos_module.etree.SubElement(rpc, 'at').text = params['at']
        if params['other_re'] is True:
            if junos_module.dev.facts['2RE']:
                junos_module.etree.SubElement(rpc, 'other-routing-engine')
                # At least on some platforms stopping/rebooting the other RE
                # just produces <output> messages.
                xpath_list.append('..//output')
        elif params['all_re'] is True:
            junos_module.add_sw()
            if (junos_module.sw._multi_RE is True
                    and junos_module.sw._multi_VC is False):
                junos_module.etree.SubElement(rpc, 'both-routing-engines')
                # At least on some platforms stopping/rebooting both REs
                # produces <output> messages and <request-reboot-status>
                # messages.
                xpath_list.append('..//output')
            elif junos_module.sw._mixed_VC is True:
                junos_module.etree.SubElement(rpc, 'all-members')

    # OK, we're ready to do something. Set changed and log the RPC.
    results['changed'] = True
    junos_module.logger.debug(
        "Ready to execute RPC: %s",
        junos_module.etree.tostring(rpc, pretty_print=True))

    if not junos_module.check_mode:
        if action != 'zeroize':
            # If we're going to do a shutdown, reboot, or halt right away then
            # try to deal with the fact that we might not get the closing
            # </rpc-reply> and therefore might get an RpcTimeout.
            # (This is a known Junos bug.) Set the timeout low so this happens
            # relatively quickly.
            if (params['at'] == 'now' or params['in_min'] == 0
                    or (params['at'] is None and params['in_min'] is None)):
                if junos_module.dev.timeout > 5:
                    junos_module.logger.debug("Decreasing device RPC timeout "
                                              "to 5 seconds.")
                    junos_module.dev.timeout = 5

        # Execute the RPC.
        try:
            junos_module.logger.debug(
                "Executing RPC: %s",
                junos_module.etree.tostring(rpc, pretty_print=True))
            resp = junos_module.dev.rpc(rpc,
                                        ignore_warning=True,
                                        normalize=True)
            junos_module.logger.debug("RPC executed cleanly.")
            if len(xpath_list) > 0:
                for xpath in xpath_list:
                    if junos_module.dev.facts['_is_linux']:
                        got = resp.text
                    else:
                        got = resp.findtext(xpath)
                    if got is not None:
                        results['msg'] = '%s successfully initiated.' % \
                                         (action)
                        results['failed'] = False
                        break
                else:
                    # This is the else clause of the for loop.
                    # It only gets executed if the loop finished without
                    # hitting the break.
                    results['msg'] = 'Did not find expected RPC response.'
                    results['changed'] = False
            else:
                results['msg'] = '%s successfully initiated.' % (action)
                results['failed'] = False
        except (junos_module.pyez_exception.RpcTimeoutError) as ex:
            # This might be OK. It might just indicate the device didn't
            # send the closing </rpc-reply> (known Junos bug).
            # Try to close the device. If it closes cleanly, then it was
            # still reachable, which probably indicates there was a problem.
            try:
                junos_module.close(raise_exceptions=True)
                # This means the device wasn't already disconnected.
                results['changed'] = False
                results['msg'] = '%s failed. %s may not have been ' \
                                 'initiated.' % (action, action)
            except (junos_module.pyez_exception.RpcError,
                    junos_module.pyez_exception.ConnectError):
                # This is expected. The device has already disconnected.
                results['msg'] = '%s succeeded.' % (action)
                results['failed'] = False
        except (junos_module.pyez_exception.RpcError,
                junos_module.pyez_exception.ConnectError) as ex:
            results['changed'] = False
            results['msg'] = '%s failed. Error: %s' % (action, str(ex))

    # Return results.
    junos_module.exit_json(**results)
Example #10
0
def main():
    # The argument spec for the module.
    argument_spec = dict(
        dest=dict(type='str',
                  required=True,
                  aliases=[
                      'dest_ip', 'dest_host', 'destination', 'destination_ip',
                      'destination_host'
                  ],
                  default=None),
        acceptable_percent_loss=dict(type='int',
                                     required=False,
                                     aliases=['acceptable_packet_loss'],
                                     default=0),
    )

    # The portion of the argument spec that's specifically a parameter
    # to the ping RPC.
    ping_argument_spec = dict(
        count=dict(type='int', required=False, default=5),
        rapid=dict(type='bool', required=False, default=True),
        ttl=dict(type='int', required=False, default=None),
        size=dict(type='int', required=False, default=None),
        do_not_fragment=dict(type='bool', required=False, default=False),
        source=dict(
            type='str',
            required=False,
            aliases=['source_ip', 'source_host', 'src', 'src_ip', 'src_host'],
            default=None),
        interface=dict(type='str', required=False, default=None),
        routing_instance=dict(type='str', required=False, default=None),
    )

    # Add the ping RPC parameter argument spec fo the full argument_spec.
    argument_spec.update(ping_argument_spec)

    argument_spec_keys = list(argument_spec.keys())

    # Create the module instance.
    junos_module = juniper_junos_common.JuniperJunosModule(
        argument_spec=argument_spec,
        # Since this module doesn't change the device's configuration, there is
        # no additional work required to support check mode. It's inherently
        # supported.
        supports_check_mode=True)

    # We're going to be using params a lot
    params = junos_module.params

    # acceptable packet loss is a percentage. Check to make sure it's between
    # 0 and 100 inclusive
    if (params['acceptable_percent_loss'] > 100
            or params['acceptable_percent_loss'] < 0):
        junos_module.fail_json(msg='The value of the acceptable_percent_loss'
                               'option (%d) is a percentage and must have '
                               'a value between 0 and 100.' %
                               (params['acceptable_percent_loss']))

    # All of the params keys which are also keys in ping_argument_spec are the
    # ping_params. Omit None and False values because they don't need to be
    # passed to the RPC.
    ping_params = {'host': params.get('dest')}
    for key in ping_argument_spec:
        value = params.get(key)
        # Convert int (but not bool) to str
        if not isinstance(value, bool) and isinstance(value, int):
            params[key] = str(params[key])
            value = params.get(key)
        # None and False values are the default for the RPC and shouldn't be
        # passed to the device.
        if value is not None and value is not False:
            ping_params.update({key: value})

    # Set initial results values. Assume failure until we know it's success.
    results = {'msg': '', 'changed': False, 'failed': True}
    # Results should include all the ping params in argument_spec_keys.
    for key in argument_spec_keys:
        results[key] = params.get(key)
    # Overwrite to be a string in the results
    results['acceptable_percent_loss'] = str(
        params.get('acceptable_percent_loss'))
    # Add timeout to the response even though it's a connect parameter.
    results['timeout'] = str(params.get('timeout'))
    # Add aliases for backwards compatibility
    results.update({
        'host': params.get('dest'),
        'dest_ip': params.get('dest'),
        'source_ip': params.get('source')
    })

    # Execute the ping.
    results = junos_module.ping(
        ping_params,
        acceptable_percent_loss=params['acceptable_percent_loss'],
        results=results)

    # Return results.
    junos_module.exit_json(**results)
Example #11
0
def main():
    # Create the module instance.
    junos_module = juniper_junos_common.JuniperJunosModule(
        argument_spec=dict(
            commands=dict(required=True,
                          type='list',
                          aliases=['cli', 'command', 'cmd', 'cmds'],
                          default=None),
            formats=dict(required=False,
                         type='list',
                         aliases=['format', 'display', 'output'],
                         default=None),
            dest=dict(required=False,
                      type='path',
                      aliases=['destination'],
                      default=None),
            dest_dir=dict(required=False,
                          type='path',
                          aliases=['destination_dir', 'destdir'],
                          default=None),
            return_output=dict(required=False, type='bool', default=True)),
        # Since this module doesn't change the device's configuration, there is
        # no additional work required to support check mode. It's inherently
        # supported. Well, that's not completely true. It does depend on the
        # command executed. See the I(changed) key in the RETURN documentation
        # for more details.
        supports_check_mode=True,
        min_jxmlease_version=juniper_junos_common.MIN_JXMLEASE_VERSION,
    )

    # Check over commands
    commands = junos_module.params.get('commands')
    # Ansible allows users to specify a commands argument with no value.
    if commands is None:
        junos_module.fail_json(msg="The commands option must have a value.")
    # Make sure the commands don't include any pipe modifiers.
    for command in commands:
        pipe_index = command.find('|')
        if (pipe_index != -1
                and command[pipe_index:].strip() != 'display xml rpc'):
            # Allow "show configuration | display set"
            if ('show configuration' in command
                    and 'display set' in command[pipe_index:]
                    and '|' not in command[pipe_index + 1:]):
                continue
            # Any other "| display " should use the format option instead.
            for valid_format in juniper_junos_common.RPC_OUTPUT_FORMAT_CHOICES:
                if 'display ' + valid_format in command[pipe_index:]:
                    junos_module.fail_json(
                        msg='The pipe modifier (%s) in the command '
                        '(%s) is not supported. Use format: "%s" '
                        'instead.' %
                        (command[pipe_index:], command, valid_format))
            # Any other "| " is going to produce an error anyway, so fail
            # with a meaningful message.
            junos_module.fail_json(msg='The pipe modifier (%s) in the command '
                                   '(%s) is not supported.' %
                                   (command[pipe_index:], command))

    # Check over formats
    formats = junos_module.params.get('formats')
    if formats is None:
        # Default to text format
        formats = ['text']
    valid_formats = juniper_junos_common.RPC_OUTPUT_FORMAT_CHOICES
    # Check format values
    for format in formats:
        # Is it a valid format?
        if format not in valid_formats:
            junos_module.fail_json(
                msg="The value %s in formats is invalid. "
                "Must be one of: %s" %
                (format, ', '.join(map(str, valid_formats))))
    # Correct number of format values?
    if len(formats) != 1 and len(formats) != len(commands):
        junos_module.fail_json(msg="The formats option must have a single "
                               "value, or one value per command. There "
                               "are %d commands and %d formats." %
                               (len(commands), len(formats)))
    # Same format for all commands
    elif len(formats) == 1 and len(commands) > 1:
        formats = formats * len(commands)

    results = list()
    for (command, format) in zip(commands, formats):
        # Set initial result values. Assume failure until we know it's success.
        result = {
            'msg': '',
            'command': command,
            'format': format,
            'changed': False,
            'failed': True
        }

        # Execute the CLI command
        try:
            junos_module.logger.debug('Executing command "%s".', command)
            rpc = junos_module.etree.Element('command', format=format)
            rpc.text = command
            resp = junos_module.dev.rpc(rpc, normalize=bool(format == 'xml'))
            result['msg'] = 'The command executed successfully.'
            junos_module.logger.debug('Command "%s" executed successfully.',
                                      command)
        except (junos_module.pyez_exception.ConnectError,
                junos_module.pyez_exception.RpcError) as ex:
            junos_module.logger.debug('Unable to execute "%s". Error: %s',
                                      command, str(ex))
            result['msg'] = 'Unable to execute the command: %s. Error: %s' % \
                            (command, str(ex))
            results.append(result)
            continue

        text_output = None
        parsed_output = None
        if resp is True:
            text_output = ''
        elif (resp, junos_module.etree._Element):
            # Handle the output based on format
            if format == 'text':
                if resp.tag in ['output', 'rpc-reply']:
                    text_output = resp.text
                    junos_module.logger.debug('Text output set.')
                elif resp.tag == 'configuration-information':
                    text_output = resp.findtext('configuration-output')
                    junos_module.logger.debug('Text configuration output set.')
                else:
                    result['msg'] = 'Unexpected text response tag: %s.' % (
                        (resp.tag))
                    results.append(result)
                    junos_module.logger.debug(
                        'Unexpected text response tag '
                        '%s.', resp.tag)
                    continue
            elif format == 'xml':
                encode = None if sys.version < '3' else 'unicode'
                text_output = junos_module.etree.tostring(resp,
                                                          pretty_print=True,
                                                          encoding=encode)
                parsed_output = junos_module.jxmlease.parse_etree(resp)
                junos_module.logger.debug('XML output set.')
            elif format == 'json':
                text_output = str(resp)
                parsed_output = resp
                junos_module.logger.debug('JSON output set.')
            else:
                result['msg'] = 'Unexpected format %s.' % (format)
                results.append(result)
                junos_module.logger.debug('Unexpected format %s.', format)
                continue
        else:
            result['msg'] = 'Unexpected response type %s.' % (type(resp))
            results.append(result)
            junos_module.logger.debug('Unexpected response type %s.',
                                      type(resp))
            continue

        # Set the output keys
        if junos_module.params['return_output'] is True:
            if text_output is not None:
                result['stdout'] = text_output
                result['stdout_lines'] = text_output.splitlines()
            if parsed_output is not None:
                result['parsed_output'] = parsed_output
        # Save the output
        junos_module.save_text_output(command, format, text_output)
        # This command succeeded.
        result['failed'] = False
        # Append to the list of results
        results.append(result)

    # Return response.
    if len(results) == 1:
        junos_module.exit_json(**results[0])
    else:
        # Calculate the overall failed. Only failed if all commands failed.
        failed = True
        for result in results:
            if result.get('failed') is False:
                failed = False
                break
        junos_module.exit_json(results=results, changed=False, failed=failed)