Server IP : 85.214.239.14 / Your IP : 18.119.213.78 Web Server : Apache/2.4.62 (Debian) System : Linux h2886529.stratoserver.net 4.9.0 #1 SMP Tue Jan 9 19:45:01 MSK 2024 x86_64 User : www-data ( 33) PHP Version : 7.4.18 Disable Function : pcntl_alarm,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexited,pcntl_wifstopped,pcntl_wifsignaled,pcntl_wifcontinued,pcntl_wexitstatus,pcntl_wtermsig,pcntl_wstopsig,pcntl_signal,pcntl_signal_get_handler,pcntl_signal_dispatch,pcntl_get_last_error,pcntl_strerror,pcntl_sigprocmask,pcntl_sigwaitinfo,pcntl_sigtimedwait,pcntl_exec,pcntl_getpriority,pcntl_setpriority,pcntl_async_signals,pcntl_unshare, MySQL : OFF | cURL : OFF | WGET : ON | Perl : ON | Python : ON | Sudo : ON | Pkexec : OFF Directory : /usr/lib/python3/dist-packages/ansible_collections/cisco/iosxr/plugins/modules/ |
Upload File : |
#!/usr/bin/python # -*- coding: utf-8 -*- # Copyright: (c) 2017, Ansible by Red Hat, inc # GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) from __future__ import absolute_import, division, print_function __metaclass__ = type DOCUMENTATION = """ module: iosxr_banner author: - Trishna Guha (@trishnaguha) - Kedar Kekan (@kedarX) short_description: Module to configure multiline banners. description: - This module will configure both exec and motd banners on remote device running Cisco IOS XR. It allows playbooks to add or remove banner text from the running configuration. version_added: 1.0.0 requirements: - ncclient >= 0.5.3 when using netconf - lxml >= 4.1.1 when using netconf extends_documentation_fragment: - cisco.iosxr.iosxr notes: - This module works with connection C(network_cli) and C(netconf). See L(the IOS-XR Platform Options,../network/user_guide/platform_iosxr.html). options: banner: description: - Specifies the type of banner to configure on remote device. required: true type: str choices: - login - motd text: description: - Banner text to be configured. Accepts multi line string, without empty lines. When using a multi line string, the first and last characters must be the start and end delimiters for the banner Requires I(state=present). type: str state: description: - Existential state of the configuration on the device. default: present type: str choices: - present - absent """ EXAMPLES = """ - name: configure the login banner cisco.iosxr.iosxr_banner: banner: login text: | @this is my login banner that contains a multiline string@ state: present - name: remove the motd banner cisco.iosxr.iosxr_banner: banner: motd state: absent - name: Configure banner from file cisco.iosxr.iosxr_banner: banner: motd text: "{{ lookup('file', './config_partial/raw_banner.cfg') }}" state: present """ RETURN = """ commands: description: The list of configuration mode commands sent to device with transport C(cli) returned: always (empty list when no commands to send) type: list sample: - banner login - "@this is my login banner" - that contains a multiline - string@ xml: description: NetConf rpc xml sent to device with transport C(netconf) returned: always (empty list when no xml rpc to send) type: list sample: - '<config xmlns:xc="urn:ietf:params:xml:ns:netconf:base:1.0"> <banners xmlns="http://cisco.com/ns/yang/Cisco-IOS-XR-infra-infra-cfg"> <banner xc:operation="merge"> <banner-name>motd</banner-name> <banner-text>Ansible banner example</banner-text> </banner> </banners> </config>' """ import collections import re from ansible.module_utils.basic import AnsibleModule from ansible_collections.cisco.iosxr.plugins.module_utils.network.iosxr.iosxr import ( build_xml, etree_find, get_config, is_cliconf, is_netconf, load_config, ) class ConfigBase(object): def __init__(self, module): self._module = module self._result = {"changed": False, "warnings": []} self._want = {} self._have = {} def map_params_to_obj(self): text = self._module.params["text"] if text: text = "{0}".format(str(text).strip()) self._want.update( { "banner": self._module.params["banner"], "text": text, "state": self._module.params["state"], }, ) class CliConfiguration(ConfigBase): def __init__(self, module): super(CliConfiguration, self).__init__(module) def map_obj_to_commands(self): commands = list() state = self._module.params["state"] if state == "absent": if self._have.get("state") != "absent" and ( "text" in self._have.keys() and self._have["text"] ): commands.append("no banner {0!s}".format(self._module.params["banner"])) elif state == "present": if self._want["text"] and self._want["text"].encode().decode( "unicode_escape", ) != self._have.get("text"): banner_cmd = "banner {0!s} ".format(self._module.params["banner"]) banner_cmd += self._want["text"].strip() commands.append(banner_cmd) self._result["commands"] = commands if commands: commit = not self._module.check_mode diff = load_config(self._module, commands, commit=commit) if diff: self._result["diff"] = dict(prepared=diff) self._result["changed"] = True def map_config_to_obj(self): cli_filter = "banner {0!s}".format(self._module.params["banner"]) output = get_config(self._module, config_filter=cli_filter) match = re.search(r"banner (\S+) (.*)", output, re.DOTALL) if match: text = match.group(2) else: text = None obj = {"banner": self._module.params["banner"], "state": "absent"} if output: obj["text"] = text obj["state"] = "present" self._have.update(obj) def run(self): self.map_params_to_obj() self.map_config_to_obj() self.map_obj_to_commands() return self._result class NCConfiguration(ConfigBase): def __init__(self, module): super(NCConfiguration, self).__init__(module) self._banners_meta = collections.OrderedDict() self._banners_meta.update( [ ("banner", {"xpath": "banners/banner", "tag": True, "attrib": "operation"}), ("a:banner", {"xpath": "banner/banner-name"}), ("a:text", {"xpath": "banner/banner-text", "operation": "edit"}), ], ) def map_obj_to_xml_rpc(self): state = self._module.params["state"] _get_filter = build_xml( "banners", xmap=self._banners_meta, params=self._module.params, opcode="filter", ) running = get_config(self._module, source="running", config_filter=_get_filter) banner_name = None banner_text = None if etree_find(running, "banner-text") is not None: banner_name = etree_find(running, "banner-name").text banner_text = etree_find(running, "banner-text").text opcode = None if state == "absent" and banner_name == self._module.params["banner"] and len(banner_text): opcode = "delete" elif state == "present": opcode = "merge" self._result["xml"] = [] if opcode: _edit_filter = build_xml( "banners", xmap=self._banners_meta, params=self._module.params, opcode=opcode, ) if _edit_filter is not None: commit = not self._module.check_mode diff = load_config( self._module, _edit_filter, commit=commit, running=running, nc_get_filter=_get_filter, ) if diff: self._result["xml"] = _edit_filter if self._module._diff: self._result["diff"] = dict(prepared=diff) self._result["changed"] = True def run(self): self.map_params_to_obj() self.map_obj_to_xml_rpc() return self._result def main(): """main entry point for module execution""" argument_spec = dict( banner=dict(required=True, choices=["login", "motd"]), text=dict(), state=dict(default="present", choices=["present", "absent"]), ) required_if = [("state", "present", ("text",))] module = AnsibleModule( argument_spec=argument_spec, required_if=required_if, supports_check_mode=True, ) config_object = None if is_cliconf(module): # Commenting the below cliconf deprecation support call for Ansible 2.9 as it'll be continued to be supported config_object = CliConfiguration(module) elif is_netconf(module): config_object = NCConfiguration(module) result = None if config_object is not None: result = config_object.run() module.exit_json(**result) if __name__ == "__main__": main()