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)
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: #for get-config in case of exception handling it will not display #filters and arguments. To be added in future. rpc = junos_module.etree.Element(rpc_string, format=format) 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: 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(): # 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(): # 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), vmhost=dict(required=False, type='bool', 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'] at = params.get('at') in_min = params.get('in_min') all_re = params.get('all_re') other_re = params.get('other_re') media = params.get('media') vmhost = params.get('vmhost') # Synonymn for shutdown if action == 'off' or action == 'power_off' or action == 'power-off': action = 'shutdown' if action == 'reboot' and vmhost is True: junos_module.fail_json(msg='The vmhost option can only be used when ' 'the action option has the value "reboot".') #Four actions are expected - reboot, shutdown, halt and zeroize if action not in ['reboot', 'shutdown', 'halt']: # at, in_min and other_re option only applies to reboot, shutdown, or halt action. for arg_type, arg_val in { "at": at, "in_min": in_min, "other_re": other_re }: if arg_val is not None: junos_module.fail_json( msg='The %s option can only be used when ' 'the action option has the value "reboot", ' '"shutdown", or "halt".' % arg_type) elif media is True: # media option only applies to zeroize action. junos_module.fail_json(msg='The media option can only be used when ' 'the action option has the value "zeroize".') # Set initial results values. Assume failure until we know it's success. results = { 'changed': True, 'msg': '', 'reboot': bool(action == 'reboot'), 'action': action, 'all_re': all_re, 'other_re': other_re, 'media': media, 'vmhost': vmhost, 'failed': 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 (at == 'now' or in_min == 0 or (at is None and 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") if action == 'reboot': got = junos_module.sw.reboot(in_min, at, all_re, None, vmhost, other_re) elif action == 'shutdown': got = junos_module.sw.poweroff(in_min, at, None, all_re, other_re) elif action == 'halt': got = junos_module.sw.halt(in_min, at, all_re, other_re) elif action == 'zeroize': got = junos_module.sw.zeroize(all_re, media) else: junos_module.fail_json(msg='Relevant action not found') junos_module.logger.debug("RPC executed") if got is None: results['msg'] = 'Did not find expected RPC response.' results['changed'] = False else: results[ 'msg'] = '%s successfully initiated. Response got %s' % ( action, got) 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)
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)
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, msg_ret = junos_module.sw.install(**install_params) if ok is not True: results['msg'] = 'Unable to install the software %s', msg_ret junos_module.fail_json(**results) msg = 'Package %s successfully installed. Response from device is: %s' % ( install_params.get('package') or install_params.get('pkg_set'), msg_ret) 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. restore_timeout = junos_module.dev.timeout 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.') try: got = junos_module.sw.reboot(0, None, all_re, None, install_params.get('vmhost')) junos_module.dev.timeout = restore_timeout except Exception: # pylint: disable=broad-except junos_module.dev.timeout = restore_timeout raise junos_module.logger.debug("Reboot RPC executed.") if got is not None: results['msg'] += ' Reboot successfully initiated. ' \ 'Reboot message: %s' % got 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. ' junos_module.fail_json(**results) 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.RpcTimeoutError, junos_module.pyez_exception.ConnectError): # This is expected. The device has already disconnected. results['msg'] += ' Reboot succeeded.' except (junos_module.ncclient_exception.TimeoutExpiredError): # This is not really expected. Still consider reboot success as # Looks like rpc was consumed but no response as its rebooting. results[ 'msg'] += ' Reboot succeeded. Ignoring close error.' 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) else: try: junos_module.close() except (junos_module.ncclient_exception.TimeoutExpiredError): junos_module.logger.debug( "Ignoring TimeoutError for close call") 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)
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(): # 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)
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)
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(): # 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)
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)