def build_cmdref_objects(td): cmd_ref[td["type"]]["ref"] = [] saved_ids = [] if want.get(td["name"]): for playvals in want[td["name"]]: valiate_input(playvals, td["name"], self._module) if playvals["id"] in saved_ids: continue saved_ids.append(playvals["id"]) resource_key = td["cmd"].format(playvals["id"]) # Only build the NxosCmdRef object for the td['name'] module parameters. self._module.params[ "config" ] = get_module_params_subsection( ALL_MP, td["type"], playvals["id"] ) cmd_ref[td["type"]]["ref"].append( NxosCmdRef(self._module, td["obj"]) ) ref = cmd_ref[td["type"]]["ref"][-1] ref.set_context([resource_key]) if td["type"] == "TMS_SENSORGROUP" and get_setval_path( self._module ): # Sensor group path setting can contain optional values. # Call get_setval_path helper function to process any # optional setval keys. ref._ref["path"]["setval"] = get_setval_path( self._module ) ref.get_existing(device_cache) ref.get_playvals() if td["type"] == "TMS_DESTGROUP": normalize_data(ref)
def main(): argument_spec = dict( echo_interface=dict(required=False, type="str"), echo_rx_interval=dict(required=False, type="int"), interval=dict(required=False, type="dict"), slow_timer=dict(required=False, type="int"), startup_timer=dict(required=False, type="int"), ipv4_echo_rx_interval=dict(required=False, type="int"), ipv4_interval=dict(required=False, type="dict"), ipv4_slow_timer=dict(required=False, type="int"), ipv6_echo_rx_interval=dict(required=False, type="int"), ipv6_interval=dict(required=False, type="dict"), ipv6_slow_timer=dict(required=False, type="int"), fabricpath_interval=dict(required=False, type="dict"), fabricpath_slow_timer=dict(required=False, type="int"), fabricpath_vlan=dict(required=False, type="int"), ) argument_spec.update(nxos_argument_spec) module = AnsibleModule( argument_spec=argument_spec, supports_check_mode=True ) warnings = list() cmd_ref = NxosCmdRef(module, BFD_CMD_REF) cmd_ref.get_existing() cmd_ref.get_playvals() cmds = reorder_cmds(cmd_ref.get_proposed()) result = { "changed": False, "commands": cmds, "warnings": warnings, "check_mode": module.check_mode, } if cmds: result["changed"] = True if not module.check_mode: load_config(module, cmds) module.exit_json(**result)
def _state_replaced(want, have): """ The command generator when state is replaced :rtype: A list :returns: the commands necessary to migrate the current configuration to the desired configuration """ commands = [] massaged_have = massage_data(have) massaged_want = massage_data(want) ref = {} ref["tms_global"] = NxosCmdRef([], TMS_GLOBAL, ref_only=True) ref["tms_destgroup"] = NxosCmdRef([], TMS_DESTGROUP, ref_only=True) ref["tms_sensorgroup"] = NxosCmdRef([], TMS_SENSORGROUP, ref_only=True) ref["tms_subscription"] = NxosCmdRef( [], TMS_SUBSCRIPTION, ref_only=True ) # Order matters for state replaced. # First remove all subscriptions, followed by sensor-groups and destination-groups. # Second add all destination-groups, followed by sensor-groups and subscriptions add = { "TMS_GLOBAL": [], "TMS_DESTGROUP": [], "TMS_SENSORGROUP": [], "TMS_SUBSCRIPTION": [], } delete = { "TMS_DESTGROUP": [], "TMS_SENSORGROUP": [], "TMS_SUBSCRIPTION": [], } # Process Telemetry Global Want and Have Values # Possible states: # - want and have are (set) (equal: no action, not equal: replace with want) # - want (set) have (not set) (add want) # - want (not set) have (set) (delete have) # - want (not set) have (not set) (no action) # global_ctx = ref['tms_global']._ref['_template']['context'] # property_ctx = ref['tms_global']._ref['certificate'].get('context') # setval = ref['tms_global']._ref['certificate']['setval'] # all_global_properties = [ "certificate", "compression", "source_interface", "vrf", ] dest_profile_properties = ["compression", "source_interface", "vrf"] dest_profile_remote_commands = [] for property in all_global_properties: cmd = None global_ctx = ref["tms_global"]._ref["_template"]["context"] property_ctx = ref["tms_global"]._ref[property].get("context") setval = ref["tms_global"]._ref[property]["setval"] kind = ref["tms_global"]._ref[property]["kind"] if want.get(property) is not None: if have.get(property) is not None: if want.get(property) != have.get(property): if kind == "dict": cmd = [setval.format(**want.get(property))] else: cmd = [setval.format(want.get(property))] elif have.get(property) is None: if kind == "dict": cmd = [setval.format(**want.get(property))] else: cmd = [setval.format(want.get(property))] elif want.get(property) is None: if have.get(property) is not None: if kind == "dict": cmd = ["no " + setval.format(**have.get(property))] else: cmd = ["no " + setval.format(have.get(property))] if property in dest_profile_properties: dest_profile_remote_commands.extend(cmd) if cmd is not None: ctx = global_ctx if property_ctx is not None: ctx.extend(property_ctx) add["TMS_GLOBAL"].extend(ctx) add["TMS_GLOBAL"].extend(cmd) add["TMS_GLOBAL"] = remove_duplicate_commands(add["TMS_GLOBAL"]) # If all destination profile commands are being removed then just # remove the config context instead. if len(dest_profile_remote_commands) == 3: for item in dest_profile_remote_commands: add["TMS_GLOBAL"].remove(item) add["TMS_GLOBAL"].remove("destination-profile") add["TMS_GLOBAL"].extend(["no destination-profile"]) # Process Telemetry destination_group, sensor_group and subscription Want and Have Values # Possible states: # - want (not set) have (set) (delete have) # - want and have are (set) (equal: no action, not equal: replace with want) # - want (set) have (not set) (add want) # - want (not set) have (not set) (no action) tms_resources = [ "TMS_DESTGROUP", "TMS_SENSORGROUP", "TMS_SUBSCRIPTION", ] for resource in tms_resources: if resource == "TMS_DESTGROUP": name = "destination-group" cmd_property = "destination" global_ctx = ref["tms_destgroup"]._ref["_template"]["context"] setval = ref["tms_destgroup"]._ref["destination"]["setval"] want_resources = massaged_want.get("destination_groups") have_resources = massaged_have.get("destination_groups") if resource == "TMS_SENSORGROUP": name = "sensor-group" global_ctx = ref["tms_sensorgroup"]._ref["_template"][ "context" ] setval = {} setval["data_source"] = ref["tms_sensorgroup"]._ref[ "data_source" ]["setval"] setval["path"] = ref["tms_sensorgroup"]._ref["path"]["setval"] want_resources = massaged_want.get("sensor_groups") have_resources = massaged_have.get("sensor_groups") if resource == "TMS_SUBSCRIPTION": name = "subscription" global_ctx = ref["tms_subscription"]._ref["_template"][ "context" ] setval = {} setval["destination_group"] = ref["tms_subscription"]._ref[ "destination_group" ]["setval"] setval["sensor_group"] = ref["tms_subscription"]._ref[ "sensor_group" ]["setval"] want_resources = massaged_want.get("subscriptions") have_resources = massaged_have.get("subscriptions") if not want_resources and have_resources: # want not and have not set so delete have for key in have_resources.keys(): remove_context = ["{0} {1} {2}".format("no", name, key)] delete[resource].extend(global_ctx) if remove_context[0] not in delete[resource]: delete[resource].extend(remove_context) else: # want and have are set. # process wants: for want_key in want_resources.keys(): if want_key not in have_resources.keys(): # Want resource key not in have resource key so add it property_ctx = ["{0} {1}".format(name, want_key)] for item in want_resources[want_key]: if resource == "TMS_DESTGROUP": cmd = [setval.format(**item[cmd_property])] add[resource].extend(global_ctx) if property_ctx[0] not in add[resource]: add[resource].extend(property_ctx) add[resource].extend(cmd) if resource == "TMS_SENSORGROUP": cmd = {} if item.get("data_source"): cmd["data_source"] = [ setval["data_source"].format( item["data_source"] ) ] if item.get("path"): setval["path"] = get_setval_path( item.get("path") ) cmd["path"] = [ setval["path"].format(**item["path"]) ] add[resource].extend(global_ctx) if property_ctx[0] not in add[resource]: add[resource].extend(property_ctx) if cmd.get("data_source"): add[resource].extend(cmd["data_source"]) if cmd.get("path"): add[resource].extend(cmd["path"]) if resource == "TMS_SUBSCRIPTION": cmd = {} if item.get("destination_group"): cmd["destination_group"] = [ setval["destination_group"].format( item["destination_group"] ) ] if item.get("sensor_group"): cmd["sensor_group"] = [ setval["sensor_group"].format( **item["sensor_group"] ) ] add[resource].extend(global_ctx) if property_ctx[0] not in add[resource]: add[resource].extend(property_ctx) if cmd.get("destination_group"): add[resource].extend( cmd["destination_group"] ) if cmd.get("sensor_group"): add[resource].extend(cmd["sensor_group"]) elif want_key in have_resources.keys(): # Want resource key exists in have resource keys but we need to # inspect the individual items under the resource key # for differences for item in want_resources[want_key]: if item not in have_resources[want_key]: if item is None: continue # item wanted but does not exist so add it property_ctx = [ "{0} {1}".format(name, want_key) ] if resource == "TMS_DESTGROUP": cmd = [setval.format(**item[cmd_property])] add[resource].extend(global_ctx) if property_ctx[0] not in add[resource]: add[resource].extend(property_ctx) add[resource].extend(cmd) if resource == "TMS_SENSORGROUP": cmd = {} if item.get("data_source"): cmd["data_source"] = [ setval["data_source"].format( item["data_source"] ) ] if item.get("path"): setval["path"] = get_setval_path( item.get("path") ) cmd["path"] = [ setval["path"].format( **item["path"] ) ] add[resource].extend(global_ctx) if property_ctx[0] not in add[resource]: add[resource].extend(property_ctx) if cmd.get("data_source"): add[resource].extend( cmd["data_source"] ) if cmd.get("path"): add[resource].extend(cmd["path"]) if resource == "TMS_SUBSCRIPTION": cmd = {} if item.get("destination_group"): cmd["destination_group"] = [ setval["destination_group"].format( item["destination_group"] ) ] if item.get("sensor_group"): cmd["sensor_group"] = [ setval["sensor_group"].format( **item["sensor_group"] ) ] add[resource].extend(global_ctx) if property_ctx[0] not in add[resource]: add[resource].extend(property_ctx) if cmd.get("destination_group"): add[resource].extend( cmd["destination_group"] ) if cmd.get("sensor_group"): add[resource].extend( cmd["sensor_group"] ) # process haves: for have_key in have_resources.keys(): if have_key not in want_resources.keys(): # Want resource key is not in have resource keys so remove it cmd = ["no " + "{0} {1}".format(name, have_key)] delete[resource].extend(global_ctx) delete[resource].extend(cmd) elif have_key in want_resources.keys(): # Have resource key exists in want resource keys but we need to # inspect the individual items under the resource key # for differences for item in have_resources[have_key]: if item not in want_resources[have_key]: if item is None: continue # have item not wanted so remove it property_ctx = [ "{0} {1}".format(name, have_key) ] if resource == "TMS_DESTGROUP": cmd = [ "no " + setval.format(**item[cmd_property]) ] delete[resource].extend(global_ctx) if property_ctx[0] not in delete[resource]: delete[resource].extend(property_ctx) delete[resource].extend(cmd) if resource == "TMS_SENSORGROUP": cmd = {} if item.get("data_source"): cmd["data_source"] = [ "no " + setval["data_source"].format( item["data_source"] ) ] if item.get("path"): setval["path"] = get_setval_path( item.get("path") ) cmd["path"] = [ "no " + setval["path"].format( **item["path"] ) ] delete[resource].extend(global_ctx) if property_ctx[0] not in delete[resource]: delete[resource].extend(property_ctx) if cmd.get("data_source"): delete[resource].extend( cmd["data_source"] ) if cmd.get("path"): delete[resource].extend(cmd["path"]) if resource == "TMS_SUBSCRIPTION": cmd = {} if item.get("destination_group"): cmd["destination_group"] = [ "no " + setval[ "destination_group" ].format(item["destination_group"]) ] if item.get("sensor_group"): cmd["sensor_group"] = [ "no " + setval["sensor_group"].format( **item["sensor_group"] ) ] delete[resource].extend(global_ctx) if property_ctx[0] not in delete[resource]: delete[resource].extend(property_ctx) if cmd.get("destination_group"): delete[resource].extend( cmd["destination_group"] ) if cmd.get("sensor_group"): delete[resource].extend( cmd["sensor_group"] ) add[resource] = remove_duplicate_context(add[resource]) delete[resource] = remove_duplicate_context(delete[resource]) commands.extend(delete["TMS_SUBSCRIPTION"]) commands.extend(delete["TMS_SENSORGROUP"]) commands.extend(delete["TMS_DESTGROUP"]) commands.extend(add["TMS_DESTGROUP"]) commands.extend(add["TMS_SENSORGROUP"]) commands.extend(add["TMS_SUBSCRIPTION"]) commands.extend(add["TMS_GLOBAL"]) commands = remove_duplicate_context(commands) return commands
def set_state(self, want, have): """ Select the appropriate function based on the state provided :param want: the desired configuration as a dictionary :param have: the current configuration as a dictionary :rtype: A list :returns: the commands necessary to migrate the current configuration to the desired configuration """ state = self._module.params["state"] # The deleted case is very simple since we purge all telemetry config # and does not require any processing using NxosCmdRef objects. if state == "deleted": return self._state_deleted(want, have) elif state == "replaced": if want == have: return [] return self._state_replaced(want, have) # Save off module params ALL_MP = self._module.params["config"] cmd_ref = {} cmd_ref["TMS_GLOBAL"] = {} cmd_ref["TMS_DESTGROUP"] = {} cmd_ref["TMS_SENSORGROUP"] = {} cmd_ref["TMS_SUBSCRIPTION"] = {} # Build Telemetry Global NxosCmdRef Object cmd_ref["TMS_GLOBAL"]["ref"] = [] self._module.params["config"] = get_module_params_subsection( ALL_MP, "TMS_GLOBAL" ) cmd_ref["TMS_GLOBAL"]["ref"].append( NxosCmdRef(self._module, TMS_GLOBAL) ) ref = cmd_ref["TMS_GLOBAL"]["ref"][0] ref.set_context() ref.get_existing() ref.get_playvals() device_cache = ref.cache_existing def build_cmdref_objects(td): cmd_ref[td["type"]]["ref"] = [] saved_ids = [] if want.get(td["name"]): for playvals in want[td["name"]]: valiate_input(playvals, td["name"], self._module) if playvals["id"] in saved_ids: continue saved_ids.append(playvals["id"]) resource_key = td["cmd"].format(playvals["id"]) # Only build the NxosCmdRef object for the td['name'] module parameters. self._module.params[ "config" ] = get_module_params_subsection( ALL_MP, td["type"], playvals["id"] ) cmd_ref[td["type"]]["ref"].append( NxosCmdRef(self._module, td["obj"]) ) ref = cmd_ref[td["type"]]["ref"][-1] ref.set_context([resource_key]) if td["type"] == "TMS_SENSORGROUP" and get_setval_path( self._module ): # Sensor group path setting can contain optional values. # Call get_setval_path helper function to process any # optional setval keys. ref._ref["path"]["setval"] = get_setval_path( self._module ) ref.get_existing(device_cache) ref.get_playvals() if td["type"] == "TMS_DESTGROUP": normalize_data(ref) # Build Telemetry Destination Group NxosCmdRef Objects td = { "name": "destination_groups", "type": "TMS_DESTGROUP", "obj": TMS_DESTGROUP, "cmd": "destination-group {0}", } build_cmdref_objects(td) # Build Telemetry Sensor Group NxosCmdRef Objects td = { "name": "sensor_groups", "type": "TMS_SENSORGROUP", "obj": TMS_SENSORGROUP, "cmd": "sensor-group {0}", } build_cmdref_objects(td) # Build Telemetry Subscription NxosCmdRef Objects td = { "name": "subscriptions", "type": "TMS_SUBSCRIPTION", "obj": TMS_SUBSCRIPTION, "cmd": "subscription {0}", } build_cmdref_objects(td) if state == "merged": if want == have: return [] commands = self._state_merged(cmd_ref) return commands
def populate_facts(self, connection, ansible_facts, data=None): """ Populate the facts for telemetry :param connection: the device connection :param ansible_facts: Facts dictionary :param data: previously collected conf :rtype: dictionary :returns: facts """ if connection: # just for linting purposes, remove pass cmd_ref = {} cmd_ref["TMS_GLOBAL"] = {} cmd_ref["TMS_DESTGROUP"] = {} cmd_ref["TMS_SENSORGROUP"] = {} cmd_ref["TMS_SUBSCRIPTION"] = {} # For fact gathering, module state should be 'present' when using # NxosCmdRef to query state if self._module.params.get("state"): saved_module_state = self._module.params["state"] self._module.params["state"] = "present" # Get Telemetry Global Data cmd_ref["TMS_GLOBAL"]["ref"] = [] cmd_ref["TMS_GLOBAL"]["ref"].append( NxosCmdRef(self._module, TMS_GLOBAL)) ref = cmd_ref["TMS_GLOBAL"]["ref"][0] ref.set_context() ref.get_existing() device_cache = ref.cache_existing if device_cache is None: device_cache_lines = [] else: device_cache_lines = device_cache.split("\n") # Get Telemetry Destination Group Data cmd_ref["TMS_DESTGROUP"]["ref"] = [] for line in device_cache_lines: if re.search(r"destination-group", line): resource_key = line.strip() cmd_ref["TMS_DESTGROUP"]["ref"].append( NxosCmdRef(self._module, TMS_DESTGROUP)) ref = cmd_ref["TMS_DESTGROUP"]["ref"][-1] ref.set_context([resource_key]) ref.get_existing(device_cache) normalize_data(ref) # Get Telemetry Sensorgroup Group Data cmd_ref["TMS_SENSORGROUP"]["ref"] = [] for line in device_cache_lines: if re.search(r"sensor-group", line): resource_key = line.strip() cmd_ref["TMS_SENSORGROUP"]["ref"].append( NxosCmdRef(self._module, TMS_SENSORGROUP)) ref = cmd_ref["TMS_SENSORGROUP"]["ref"][-1] ref.set_context([resource_key]) ref.get_existing(device_cache) # Get Telemetry Subscription Data cmd_ref["TMS_SUBSCRIPTION"]["ref"] = [] for line in device_cache_lines: if re.search(r"subscription", line): resource_key = line.strip() cmd_ref["TMS_SUBSCRIPTION"]["ref"].append( NxosCmdRef(self._module, TMS_SUBSCRIPTION)) ref = cmd_ref["TMS_SUBSCRIPTION"]["ref"][-1] ref.set_context([resource_key]) ref.get_existing(device_cache) objs = [] objs = self.render_config(self.generated_spec, cmd_ref) facts = {"telemetry": {}} if objs: # params = utils.validate_config(self.argument_spec, {'config': objs}) facts["telemetry"] = objs ansible_facts["ansible_network_resources"].update(facts) if self._module.params.get("state"): self._module.params["state"] = saved_module_state return ansible_facts