diff options
author | GomathiselviS <gomathiselvi@gmail.com> | 2022-02-17 10:10:20 -0500 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-02-17 15:10:20 +0000 |
commit | 4662d6d03742ecc2fd09c530cf4b70217975e5bb (patch) | |
tree | 8847ac8ab689e9345cc3bd854bec3ca7bc7a9d94 | |
parent | b30bbaed76a22d002395802a0f72966fa2dde64a (diff) | |
download | vyos.vyos-4662d6d03742ecc2fd09c530cf4b70217975e5bb.tar.gz vyos.vyos-4662d6d03742ecc2fd09c530cf4b70217975e5bb.zip |
Add Vyos hostname resource module (#237)
Add Vyos hostname resource module
SUMMARY
ISSUE TYPE
New Module Pull Request
COMPONENT NAME
ADDITIONAL INFORMATION
Reviewed-by: Nilashish Chakraborty <nilashishchakraborty8@gmail.com>
Reviewed-by: None <None>
31 files changed, 1418 insertions, 0 deletions
@@ -41,6 +41,7 @@ Name | Description [vyos.vyos.vyos_firewall_global](https://github.com/ansible-collections/vyos.vyos/blob/main/docs/vyos.vyos.vyos_firewall_global_module.rst)|FIREWALL global resource module [vyos.vyos.vyos_firewall_interfaces](https://github.com/ansible-collections/vyos.vyos/blob/main/docs/vyos.vyos.vyos_firewall_interfaces_module.rst)|FIREWALL interfaces resource module [vyos.vyos.vyos_firewall_rules](https://github.com/ansible-collections/vyos.vyos/blob/main/docs/vyos.vyos.vyos_firewall_rules_module.rst)|FIREWALL rules resource module +[vyos.vyos.vyos_hostname](https://github.com/ansible-collections/vyos.vyos/blob/main/docs/vyos.vyos.vyos_hostname_module.rst)|Manages hostname resource module [vyos.vyos.vyos_interface](https://github.com/ansible-collections/vyos.vyos/blob/main/docs/vyos.vyos.vyos_interface_module.rst)|(deprecated, removed after 2022-06-01) Manage Interface on VyOS network devices [vyos.vyos.vyos_interfaces](https://github.com/ansible-collections/vyos.vyos/blob/main/docs/vyos.vyos.vyos_interfaces_module.rst)|Interfaces resource module [vyos.vyos.vyos_l3_interface](https://github.com/ansible-collections/vyos.vyos/blob/main/docs/vyos.vyos.vyos_l3_interface_module.rst)|(deprecated, removed after 2022-06-01) Manage L3 interfaces on VyOS network devices diff --git a/changelogs/fragments/vyos_hostname_rm.yaml b/changelogs/fragments/vyos_hostname_rm.yaml new file mode 100644 index 0000000..b9d9341 --- /dev/null +++ b/changelogs/fragments/vyos_hostname_rm.yaml @@ -0,0 +1,3 @@ +--- +minor_changes: + - Add vyos_hostname resource module. diff --git a/docs/vyos.vyos.vyos_hostname_module.rst b/docs/vyos.vyos.vyos_hostname_module.rst new file mode 100644 index 0000000..569017a --- /dev/null +++ b/docs/vyos.vyos.vyos_hostname_module.rst @@ -0,0 +1,386 @@ +.. _vyos.vyos.vyos_hostname_module: + + +*********************** +vyos.vyos.vyos_hostname +*********************** + +**Manages hostname resource module** + + +Version added: 2.8.0 + +.. contents:: + :local: + :depth: 1 + + +Synopsis +-------- +- This module manages the hostname attribute of Vyos network devices + + + + +Parameters +---------- + +.. raw:: html + + <table border=0 cellpadding=0 class="documentation-table"> + <tr> + <th colspan="2">Parameter</th> + <th>Choices/<font color="blue">Defaults</font></th> + <th width="100%">Comments</th> + </tr> + <tr> + <td colspan="2"> + <div class="ansibleOptionAnchor" id="parameter-"></div> + <b>config</b> + <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a> + <div style="font-size: small"> + <span style="color: purple">dictionary</span> + </div> + </td> + <td> + </td> + <td> + <div>Hostname configuration.</div> + </td> + </tr> + <tr> + <td class="elbow-placeholder"></td> + <td colspan="1"> + <div class="ansibleOptionAnchor" id="parameter-"></div> + <b>hostname</b> + <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a> + <div style="font-size: small"> + <span style="color: purple">string</span> + </div> + </td> + <td> + </td> + <td> + <div>set hostname for VYOS.</div> + </td> + </tr> + + <tr> + <td colspan="2"> + <div class="ansibleOptionAnchor" id="parameter-"></div> + <b>running_config</b> + <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a> + <div style="font-size: small"> + <span style="color: purple">string</span> + </div> + </td> + <td> + </td> + <td> + <div>This option is used only with state <em>parsed</em>.</div> + <div>The value of this option should be the output received from the vyos device by executing the command <b>"show configuration commands | grep host-name"</b>.</div> + <div>The state <em>parsed</em> reads the configuration from <code>running_config</code> option and transforms it into Ansible structured data as per the resource module's argspec and the value is then returned in the <em>parsed</em> key within the result.</div> + </td> + </tr> + <tr> + <td colspan="2"> + <div class="ansibleOptionAnchor" id="parameter-"></div> + <b>state</b> + <a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a> + <div style="font-size: small"> + <span style="color: purple">string</span> + </div> + </td> + <td> + <ul style="margin: 0; padding: 0"><b>Choices:</b> + <li><div style="color: blue"><b>merged</b> ←</div></li> + <li>replaced</li> + <li>overridden</li> + <li>deleted</li> + <li>gathered</li> + <li>parsed</li> + <li>rendered</li> + </ul> + </td> + <td> + <div>The state the configuration should be left in</div> + <div>The states <em>rendered</em>, <em>gathered</em> and <em>parsed</em> does not perform any change on the device.</div> + <div>The state <em>rendered</em> will transform the configuration in <code>config</code> option to platform specific CLI commands which will be returned in the <em>rendered</em> key within the result. For state <em>rendered</em> active connection to remote host is not required.</div> + <div>The states <em>merged</em>, <em>replaced</em> and <em>overridden</em> have identical behaviour for this module.</div> + <div>The state <em>gathered</em> will fetch the running configuration from device and transform it into structured data in the format as per the resource module argspec and the value is returned in the <em>gathered</em> key within the result.</div> + <div>The state <em>parsed</em> reads the configuration from <code>running_config</code> option and transforms it into JSON format as per the resource module parameters and the value is returned in the <em>parsed</em> key within the result. The value of <code>running_config</code> option should be the same format as the output of command <em>show configuration commands | grep host-name</em> executed on device. For state <em>parsed</em> active connection to remote host is not required.</div> + </td> + </tr> + </table> + <br/> + + +Notes +----- + +.. note:: + - Tested against vyos 1.1.8 + - This module works with connection ``network_cli``. + - The Configuration defaults of the Vyos network devices are supposed to hinder idempotent behavior of plays + + + +Examples +-------- + +.. code-block:: yaml + + # Using state: merged + # Before state: + # ------------- + # test#show configuration commands | grep host-name + # set system host-name 'vyostest' + # Merged play: + # ------------ + - name: Apply the provided configuration + vyos.vyos.vyos_hostname: + config: + hostname: vyos + state: merged + # Commands Fired: + # --------------- + # "commands": [ + # "hostname vyos", + # ], + # After state: + # ------------ + # test#show configuration commands | grep host-name + # set system host-name 'vyos' + + # Using state: deleted + # Before state: + # ------------- + # test#show configuration commands | grep host-name + # set system host-name 'vyos' + # Deleted play: + # ------------- + - name: Remove all existing configuration + vyos.vyos.vyos_hostname: + state: deleted + # Commands Fired: + # --------------- + # "commands": [ + # "no hostname vyosTest", + # ], + # After state: + # ------------ + # test#show configuration commands | grep host-name + + # Using state: overridden + # Before state: + # ------------- + # test#show configuration commands | grep host-name + # set system host-name 'vyos' + # Overridden play: + # ---------------- + - name: Override commands with provided configuration + vyos.vyos.vyos_hostname: + config: + hostname: vyosTest + state: overridden + # Commands Fired: + # --------------- + # "commands": [ + # "hostname vyosTest", + # ], + # After state: + # ------------ + # test#show configuration commands | grep host-name + # set system host-name 'vyosTest' + + # Using state: replaced + # Before state: + # ------------- + # test#show configuration commands | grep host-name + # set system host-name 'vyosTest' + # Replaced play: + # -------------- + - name: Replace commands with provided configuration + vyos.vyos.vyos_hostname: + config: + hostname: vyos + state: replaced + # After state: + # ------------ + # test#show configuration commands | grep host-name + # set system host-name 'vyos' + + # Using state: gathered + # Before state: + # ------------- + #test#show configuration commands | grep host-name + # set system host-name 'vyos' + # Gathered play: + # -------------- + - name: Gather listed hostname config + vyos.vyos.vyos_hostname: + state: gathered + # Module Execution Result: + # ------------------------ + # "gathered": { + # "hostname": "vyos" + # }, + + # Using state: rendered + # Rendered play: + # -------------- + - name: Render the commands for provided configuration + vyos.vyos.vyos_hostname: + config: + hostname: vyosTest + state: rendered + # Module Execution Result: + # ------------------------ + # "rendered": [ + # "set system host-name vyosTest", + # ] + + # Using state: parsed + # File: parsed.cfg + # ---------------- + # set system host-name 'vyos' + # Parsed play: + # ------------ + - name: Parse the provided configuration with the existing running configuration + vyos.vyos.vyos_hostname: + running_config: "{{ lookup('file', 'parsed.cfg') }}" + state: parsed + # Module Execution Result: + # ------------------------ + # "parsed": { + # "hostname": "vyos" + # } + + + +Return Values +------------- +Common return values are documented `here <https://docs.ansible.com/ansible/latest/reference_appendices/common_return_values.html#common-return-values>`_, the following are the fields unique to this module: + +.. raw:: html + + <table border=0 cellpadding=0 class="documentation-table"> + <tr> + <th colspan="1">Key</th> + <th>Returned</th> + <th width="100%">Description</th> + </tr> + <tr> + <td colspan="1"> + <div class="ansibleOptionAnchor" id="return-"></div> + <b>after</b> + <a class="ansibleOptionLink" href="#return-" title="Permalink to this return value"></a> + <div style="font-size: small"> + <span style="color: purple">dictionary</span> + </div> + </td> + <td>when changed</td> + <td> + <div>The resulting configuration after module execution.</div> + <br/> + <div style="font-size: smaller"><b>Sample:</b></div> + <div style="font-size: smaller; color: blue; word-wrap: break-word; word-break: break-all;">This output will always be in the same format as the module argspec.</div> + </td> + </tr> + <tr> + <td colspan="1"> + <div class="ansibleOptionAnchor" id="return-"></div> + <b>before</b> + <a class="ansibleOptionLink" href="#return-" title="Permalink to this return value"></a> + <div style="font-size: small"> + <span style="color: purple">dictionary</span> + </div> + </td> + <td>when <em>state</em> is <code>merged</code>, <code>replaced</code>, <code>overridden</code>, <code>deleted</code> or <code>purged</code></td> + <td> + <div>The configuration prior to the module execution.</div> + <br/> + <div style="font-size: smaller"><b>Sample:</b></div> + <div style="font-size: smaller; color: blue; word-wrap: break-word; word-break: break-all;">This output will always be in the same format as the module argspec.</div> + </td> + </tr> + <tr> + <td colspan="1"> + <div class="ansibleOptionAnchor" id="return-"></div> + <b>commands</b> + <a class="ansibleOptionLink" href="#return-" title="Permalink to this return value"></a> + <div style="font-size: small"> + <span style="color: purple">list</span> + </div> + </td> + <td>when <em>state</em> is <code>merged</code>, <code>replaced</code>, <code>overridden</code>, <code>deleted</code> or <code>purged</code></td> + <td> + <div>The set of commands pushed to the remote device.</div> + <br/> + <div style="font-size: smaller"><b>Sample:</b></div> + <div style="font-size: smaller; color: blue; word-wrap: break-word; word-break: break-all;">['sample command 1', 'sample command 2', 'sample command 3']</div> + </td> + </tr> + <tr> + <td colspan="1"> + <div class="ansibleOptionAnchor" id="return-"></div> + <b>gathered</b> + <a class="ansibleOptionLink" href="#return-" title="Permalink to this return value"></a> + <div style="font-size: small"> + <span style="color: purple">list</span> + </div> + </td> + <td>when <em>state</em> is <code>gathered</code></td> + <td> + <div>Facts about the network resource gathered from the remote device as structured data.</div> + <br/> + <div style="font-size: smaller"><b>Sample:</b></div> + <div style="font-size: smaller; color: blue; word-wrap: break-word; word-break: break-all;">This output will always be in the same format as the module argspec.</div> + </td> + </tr> + <tr> + <td colspan="1"> + <div class="ansibleOptionAnchor" id="return-"></div> + <b>parsed</b> + <a class="ansibleOptionLink" href="#return-" title="Permalink to this return value"></a> + <div style="font-size: small"> + <span style="color: purple">list</span> + </div> + </td> + <td>when <em>state</em> is <code>parsed</code></td> + <td> + <div>The device native config provided in <em>running_config</em> option parsed into structured data as per module argspec.</div> + <br/> + <div style="font-size: smaller"><b>Sample:</b></div> + <div style="font-size: smaller; color: blue; word-wrap: break-word; word-break: break-all;">This output will always be in the same format as the module argspec.</div> + </td> + </tr> + <tr> + <td colspan="1"> + <div class="ansibleOptionAnchor" id="return-"></div> + <b>rendered</b> + <a class="ansibleOptionLink" href="#return-" title="Permalink to this return value"></a> + <div style="font-size: small"> + <span style="color: purple">list</span> + </div> + </td> + <td>when <em>state</em> is <code>rendered</code></td> + <td> + <div>The provided configuration in the task rendered in device-native format (offline).</div> + <br/> + <div style="font-size: smaller"><b>Sample:</b></div> + <div style="font-size: smaller; color: blue; word-wrap: break-word; word-break: break-all;">['sample command 1', 'sample command 2', 'sample command 3']</div> + </td> + </tr> + </table> + <br/><br/> + + +Status +------ + + +Authors +~~~~~~~ + +- Gomathi Selvi Srinivasan (@GomathiselviS) diff --git a/meta/runtime.yml b/meta/runtime.yml index 73ba6a2..814c20b 100644 --- a/meta/runtime.yml +++ b/meta/runtime.yml @@ -38,6 +38,10 @@ plugin_routing: redirect: vyos.vyos.vyos firewall_rules: redirect: vyos.vyos.vyos + vyos_hostname: + redirect: vyos.vyos.vyos + hostname: + redirect: vyos.vyos.vyos vyos_interface: redirect: vyos.vyos.vyos interface: @@ -153,6 +157,8 @@ plugin_routing: redirect: vyos.vyos.vyos_firewall_interfaces firewall_rules: redirect: vyos.vyos.vyos_firewall_rules + hostname: + redirect: vyos.vyos.vyos_hostname interface: redirect: vyos.vyos.vyos_interface deprecation: diff --git a/plugins/module_utils/network/vyos/argspec/hostname/__init__.py b/plugins/module_utils/network/vyos/argspec/hostname/__init__.py new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/plugins/module_utils/network/vyos/argspec/hostname/__init__.py diff --git a/plugins/module_utils/network/vyos/argspec/hostname/hostname.py b/plugins/module_utils/network/vyos/argspec/hostname/hostname.py new file mode 100644 index 0000000..1a3cf91 --- /dev/null +++ b/plugins/module_utils/network/vyos/argspec/hostname/hostname.py @@ -0,0 +1,49 @@ +# -*- coding: utf-8 -*- +# Copyright 2022 Red Hat +# 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 + +############################################# +# WARNING # +############################################# +# +# This file is auto generated by the +# cli_rm_builder. +# +# Manually editing this file is not advised. +# +# To update the argspec make the desired changes +# in the module docstring and re-run +# cli_rm_builder. +# +############################################# + +""" +The arg spec for the vyos_hostname module +""" + + +class HostnameArgs(object): # pylint: disable=R0903 + """The arg spec for the vyos_hostname module""" + + argument_spec = { + "config": {"type": "dict", "options": {"hostname": {"type": "str"}}}, + "running_config": {"type": "str"}, + "state": { + "choices": [ + "merged", + "replaced", + "overridden", + "deleted", + "gathered", + "parsed", + "rendered", + ], + "default": "merged", + "type": "str", + }, + } # pylint: disable=C0301 diff --git a/plugins/module_utils/network/vyos/config/hostname/__init__.py b/plugins/module_utils/network/vyos/config/hostname/__init__.py new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/plugins/module_utils/network/vyos/config/hostname/__init__.py diff --git a/plugins/module_utils/network/vyos/config/hostname/hostname.py b/plugins/module_utils/network/vyos/config/hostname/hostname.py new file mode 100644 index 0000000..cf2c8c2 --- /dev/null +++ b/plugins/module_utils/network/vyos/config/hostname/hostname.py @@ -0,0 +1,75 @@ +# +# -*- coding: utf-8 -*- +# Copyright 2022 Red Hat +# 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 + +""" +The vyos_hostname config file. +It is in this file where the current configuration (as dict) +is compared to the provided configuration (as dict) and the command set +necessary to bring the current configuration to its desired end-state is +created. +""" + +from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.rm_base.resource_module import ( + ResourceModule, +) +from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.facts.facts import ( + Facts, +) +from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.rm_templates.hostname import ( + HostnameTemplate, +) + + +class Hostname(ResourceModule): + """ + The vyos_hostname config class + """ + + def __init__(self, module): + super(Hostname, self).__init__( + empty_fact_val={}, + facts_module=Facts(module), + module=module, + resource="hostname", + tmplt=HostnameTemplate(), + ) + self.parsers = [] + + def execute_module(self): + """Execute the module + + :rtype: A dictionary + :returns: The result from module execution + """ + if self.state not in ["parsed", "gathered"]: + self.generate_commands() + self.run_commands() + return self.result + + def generate_commands(self): + """Generate configuration commands to send based on + want, have and desired state. + """ + wantd = self.want + haved = self.have + + if self.state == "deleted": + wantd = {} + + self._compare(want=wantd, have=haved) + + def _compare(self, want, have): + """Leverages the base class `compare()` method and + populates the list of commands to be run by comparing + the `want` and `have` data with the `parsers` defined + for the Hostname network resource. + """ + self.compare(parsers="hostname", want=want, have=have) diff --git a/plugins/module_utils/network/vyos/facts/facts.py b/plugins/module_utils/network/vyos/facts/facts.py index 76cfd90..867c427 100644 --- a/plugins/module_utils/network/vyos/facts/facts.py +++ b/plugins/module_utils/network/vyos/facts/facts.py @@ -70,6 +70,9 @@ from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.facts.ntp_g from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.facts.snmp_server.snmp_server import ( Snmp_serverFacts, ) +from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.facts.hostname.hostname import ( + HostnameFacts, +) from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.facts.legacy.base import ( Default, Neighbors, @@ -98,6 +101,7 @@ FACT_RESOURCE_SUBSETS = dict( logging_global=Logging_globalFacts, ntp_global=Ntp_globalFacts, snmp_server=Snmp_serverFacts, + hostname=HostnameFacts, ) diff --git a/plugins/module_utils/network/vyos/facts/hostname/__init__.py b/plugins/module_utils/network/vyos/facts/hostname/__init__.py new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/plugins/module_utils/network/vyos/facts/hostname/__init__.py diff --git a/plugins/module_utils/network/vyos/facts/hostname/hostname.py b/plugins/module_utils/network/vyos/facts/hostname/hostname.py new file mode 100644 index 0000000..acdddca --- /dev/null +++ b/plugins/module_utils/network/vyos/facts/hostname/hostname.py @@ -0,0 +1,76 @@ +# -*- coding: utf-8 -*- +# Copyright 2022 Red Hat +# 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 + +""" +The vyos hostname fact class +It is in this file the configuration is collected from the device +for a given resource, parsed, and the facts tree is populated +based on the configuration. +""" + +from ansible_collections.ansible.netcommon.plugins.module_utils.network.common import ( + utils, +) +from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.rm_templates.hostname import ( + HostnameTemplate, +) +from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.argspec.hostname.hostname import ( + HostnameArgs, +) + +import re + + +class HostnameFacts(object): + """The vyos hostname facts class""" + + def __init__(self, module, subspec="config", options="options"): + self._module = module + self.argument_spec = HostnameArgs.argument_spec + + def get_config(self, connection): + return connection.get("show configuration commands | grep host-name") + + def populate_facts(self, connection, ansible_facts, data=None): + """Populate the facts for Snmp_server network resource + + :param connection: the device connection + :param ansible_facts: Facts dictionary + :param data: previously collected conf + + :rtype: dictionary + :returns: facts + """ + facts = {} + objs = [] + config_lines = [] + + if not data: + data = self.get_config(connection) + for resource in data.splitlines(): + config_lines.append(re.sub("'", "", resource)) + + # parse native config using the Hostname template + hostname_parser = HostnameTemplate( + lines=config_lines, module=self._module + ) + objs = hostname_parser.parse() + + ansible_facts["ansible_network_resources"].pop("hostname", None) + + params = utils.remove_empties( + hostname_parser.validate_config( + self.argument_spec, {"config": objs}, redact=True + ) + ) + + facts["hostname"] = params.get("config", {}) + ansible_facts["ansible_network_resources"].update(facts) + + return ansible_facts diff --git a/plugins/module_utils/network/vyos/rm_templates/hostname.py b/plugins/module_utils/network/vyos/rm_templates/hostname.py new file mode 100644 index 0000000..79caee6 --- /dev/null +++ b/plugins/module_utils/network/vyos/rm_templates/hostname.py @@ -0,0 +1,47 @@ +# -*- coding: utf-8 -*- +# Copyright 2022 Red Hat +# 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 + +""" +The Hostname parser templates file. This contains +a list of parser definitions and associated functions that +facilitates both facts gathering and native command generation for +the given network resource. +""" + +import re +from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.rm_base.network_template import ( + NetworkTemplate, +) + + +class HostnameTemplate(NetworkTemplate): + def __init__(self, lines=None, module=None): + prefix = {"set": "set", "remove": "delete"} + super(HostnameTemplate, self).__init__( + lines=lines, tmplt=self, prefix=prefix, module=module + ) + + # fmt: off + PARSERS = [ + # service snmp community <> + { + "name": "hostname", + "getval": re.compile( + r""" + ^set\ssystem\shost-name + \s+(?P<name>\S+) + $""", + re.VERBOSE), + "setval": "system host-name {{ hostname }}", + "result": { + "hostname": "{{ name }}" + } + }, + ] + # fmt: on diff --git a/plugins/modules/vyos_hostname.py b/plugins/modules/vyos_hostname.py new file mode 100644 index 0000000..da22f41 --- /dev/null +++ b/plugins/modules/vyos_hostname.py @@ -0,0 +1,284 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# Copyright 2022 Red Hat +# GNU General Public License v3.0+ +# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +""" +The module file for vyos_hostname +""" + +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + +DOCUMENTATION = """ +module: vyos_hostname +version_added: 2.8.0 +short_description: Manages hostname resource module +description: This module manages the hostname attribute of Vyos network devices +author: Gomathi Selvi Srinivasan (@GomathiselviS) +notes: + - Tested against vyos 1.1.8 + - This module works with connection C(network_cli). + - The Configuration defaults of the Vyos network devices + are supposed to hinder idempotent behavior of plays +options: + config: + description: Hostname configuration. + type: dict + suboptions: + hostname: + description: set hostname for VYOS. + type: str + running_config: + description: + - This option is used only with state I(parsed). + - The value of this option should be the output received from the vyos device by + executing the command B("show configuration commands | grep host-name"). + - The state I(parsed) reads the configuration from C(running_config) option and + transforms it into Ansible structured data as per the resource module's argspec + and the value is then returned in the I(parsed) key within the result. + type: str + state: + choices: + - merged + - replaced + - overridden + - deleted + - gathered + - parsed + - rendered + default: merged + description: + - The state the configuration should be left in + - The states I(rendered), I(gathered) and I(parsed) does not perform any change + on the device. + - The state I(rendered) will transform the configuration in C(config) option to + platform specific CLI commands which will be returned in the I(rendered) key + within the result. For state I(rendered) active connection to remote host is + not required. + - The states I(merged), I(replaced) and I(overridden) have identical + behaviour for this module. + - The state I(gathered) will fetch the running configuration from device and transform + it into structured data in the format as per the resource module argspec and + the value is returned in the I(gathered) key within the result. + - The state I(parsed) reads the configuration from C(running_config) option and + transforms it into JSON format as per the resource module parameters and the + value is returned in the I(parsed) key within the result. The value of C(running_config) + option should be the same format as the output of command + I(show configuration commands | grep host-name) executed on device. For state I(parsed) active + connection to remote host is not required. + type: str +""" + +EXAMPLES = """ +# Using state: merged +# Before state: +# ------------- +# test#show configuration commands | grep host-name +# set system host-name 'vyostest' +# Merged play: +# ------------ +- name: Apply the provided configuration + vyos.vyos.vyos_hostname: + config: + hostname: vyos + state: merged +# Commands Fired: +# --------------- +# "commands": [ +# "hostname vyos", +# ], +# After state: +# ------------ +# test#show configuration commands | grep host-name +# set system host-name 'vyos' + +# Using state: deleted +# Before state: +# ------------- +# test#show configuration commands | grep host-name +# set system host-name 'vyos' +# Deleted play: +# ------------- +- name: Remove all existing configuration + vyos.vyos.vyos_hostname: + state: deleted +# Commands Fired: +# --------------- +# "commands": [ +# "no hostname vyosTest", +# ], +# After state: +# ------------ +# test#show configuration commands | grep host-name + +# Using state: overridden +# Before state: +# ------------- +# test#show configuration commands | grep host-name +# set system host-name 'vyos' +# Overridden play: +# ---------------- +- name: Override commands with provided configuration + vyos.vyos.vyos_hostname: + config: + hostname: vyosTest + state: overridden +# Commands Fired: +# --------------- +# "commands": [ +# "hostname vyosTest", +# ], +# After state: +# ------------ +# test#show configuration commands | grep host-name +# set system host-name 'vyosTest' + +# Using state: replaced +# Before state: +# ------------- +# test#show configuration commands | grep host-name +# set system host-name 'vyosTest' +# Replaced play: +# -------------- +- name: Replace commands with provided configuration + vyos.vyos.vyos_hostname: + config: + hostname: vyos + state: replaced +# After state: +# ------------ +# test#show configuration commands | grep host-name +# set system host-name 'vyos' + +# Using state: gathered +# Before state: +# ------------- +#test#show configuration commands | grep host-name +# set system host-name 'vyos' +# Gathered play: +# -------------- +- name: Gather listed hostname config + vyos.vyos.vyos_hostname: + state: gathered +# Module Execution Result: +# ------------------------ +# "gathered": { +# "hostname": "vyos" +# }, + +# Using state: rendered +# Rendered play: +# -------------- +- name: Render the commands for provided configuration + vyos.vyos.vyos_hostname: + config: + hostname: vyosTest + state: rendered +# Module Execution Result: +# ------------------------ +# "rendered": [ +# "set system host-name vyosTest", +# ] + +# Using state: parsed +# File: parsed.cfg +# ---------------- +# set system host-name 'vyos' +# Parsed play: +# ------------ +- name: Parse the provided configuration with the existing running configuration + vyos.vyos.vyos_hostname: + running_config: "{{ lookup('file', 'parsed.cfg') }}" + state: parsed +# Module Execution Result: +# ------------------------ +# "parsed": { +# "hostname": "vyos" +# } +""" + + +RETURN = """ +before: + description: The configuration prior to the module execution. + returned: when I(state) is C(merged), C(replaced), C(overridden), C(deleted) or C(purged) + type: dict + sample: > + This output will always be in the same format as the + module argspec. +after: + description: The resulting configuration after module execution. + returned: when changed + type: dict + sample: > + This output will always be in the same format as the + module argspec. +commands: + description: The set of commands pushed to the remote device. + returned: when I(state) is C(merged), C(replaced), C(overridden), C(deleted) or C(purged) + type: list + sample: + - sample command 1 + - sample command 2 + - sample command 3 +rendered: + description: The provided configuration in the task rendered in device-native format (offline). + returned: when I(state) is C(rendered) + type: list + sample: + - sample command 1 + - sample command 2 + - sample command 3 +gathered: + description: Facts about the network resource gathered from the remote device as structured data. + returned: when I(state) is C(gathered) + type: list + sample: > + This output will always be in the same format as the + module argspec. +parsed: + description: The device native config provided in I(running_config) option parsed into structured data as per module argspec. + returned: when I(state) is C(parsed) + type: list + sample: > + This output will always be in the same format as the + module argspec. +""" + +from ansible.module_utils.basic import AnsibleModule +from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.argspec.hostname.hostname import ( + HostnameArgs, +) +from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.config.hostname.hostname import ( + Hostname, +) + + +def main(): + """ + Main entry point for module execution + + :returns: the result form module invocation + """ + module = AnsibleModule( + argument_spec=HostnameArgs.argument_spec, + mutually_exclusive=[["config", "running_config"]], + required_if=[ + ["state", "merged", ["config"]], + ["state", "replaced", ["config"]], + ["state", "overridden", ["config"]], + ["state", "rendered", ["config"]], + ["state", "parsed", ["running_config"]], + ], + supports_check_mode=True, + ) + + result = Hostname(module).execute_module() + module.exit_json(**result) + + +if __name__ == "__main__": + main() diff --git a/tests/integration/targets/vyos_hostname/defaults/main.yaml b/tests/integration/targets/vyos_hostname/defaults/main.yaml new file mode 100644 index 0000000..852a6be --- /dev/null +++ b/tests/integration/targets/vyos_hostname/defaults/main.yaml @@ -0,0 +1,3 @@ +--- +testcase: '[^_].*' +test_items: [] diff --git a/tests/integration/targets/vyos_hostname/meta/main.yaml b/tests/integration/targets/vyos_hostname/meta/main.yaml new file mode 100644 index 0000000..91da2a7 --- /dev/null +++ b/tests/integration/targets/vyos_hostname/meta/main.yaml @@ -0,0 +1,2 @@ +--- +... diff --git a/tests/integration/targets/vyos_hostname/tasks/cli.yaml b/tests/integration/targets/vyos_hostname/tasks/cli.yaml new file mode 100644 index 0000000..93eb2fe --- /dev/null +++ b/tests/integration/targets/vyos_hostname/tasks/cli.yaml @@ -0,0 +1,19 @@ +--- +- name: Collect all cli test cases + find: + paths: '{{ role_path }}/tests/cli' + patterns: '{{ testcase }}.yaml' + use_regex: true + register: test_cases + delegate_to: localhost + +- name: Set test_items + set_fact: test_items="{{ test_cases.files | map(attribute='path') | list }}" + +- name: Run test case (connection=ansible.netcommon.network_cli) + include: '{{ test_case_to_run }}' + vars: + ansible_connection: ansible.netcommon.network_cli + with_items: '{{ test_items }}' + loop_control: + loop_var: test_case_to_run diff --git a/tests/integration/targets/vyos_hostname/tasks/main.yaml b/tests/integration/targets/vyos_hostname/tasks/main.yaml new file mode 100644 index 0000000..b957d2f --- /dev/null +++ b/tests/integration/targets/vyos_hostname/tasks/main.yaml @@ -0,0 +1,4 @@ +--- +- include: cli.yaml + tags: + - network_cli diff --git a/tests/integration/targets/vyos_hostname/tests/cli/_parsed.cfg b/tests/integration/targets/vyos_hostname/tests/cli/_parsed.cfg new file mode 100644 index 0000000..3353c40 --- /dev/null +++ b/tests/integration/targets/vyos_hostname/tests/cli/_parsed.cfg @@ -0,0 +1 @@ +set system host-name 'vyosTest' diff --git a/tests/integration/targets/vyos_hostname/tests/cli/_populate_config.yaml b/tests/integration/targets/vyos_hostname/tests/cli/_populate_config.yaml new file mode 100644 index 0000000..4d33289 --- /dev/null +++ b/tests/integration/targets/vyos_hostname/tests/cli/_populate_config.yaml @@ -0,0 +1,8 @@ +--- +- name: setup + vyos.vyos.vyos_config: + lines: + - set system host-name 'vyos' + ignore_errors: true + vars: + ansible_connection: ansible.netcommon.network_cli diff --git a/tests/integration/targets/vyos_hostname/tests/cli/_remove_config.yaml b/tests/integration/targets/vyos_hostname/tests/cli/_remove_config.yaml new file mode 100644 index 0000000..229c79c --- /dev/null +++ b/tests/integration/targets/vyos_hostname/tests/cli/_remove_config.yaml @@ -0,0 +1,8 @@ +--- +- name: Remove pre-existing hostname config + vyos.vyos.vyos_hostname: + config: + state: deleted + ignore_errors: true + vars: + ansible_connection: ansible.netcommon.network_cli diff --git a/tests/integration/targets/vyos_hostname/tests/cli/deleted.yaml b/tests/integration/targets/vyos_hostname/tests/cli/deleted.yaml new file mode 100644 index 0000000..5f9df51 --- /dev/null +++ b/tests/integration/targets/vyos_hostname/tests/cli/deleted.yaml @@ -0,0 +1,40 @@ +--- +- debug: + msg: START vyos_hostname deleted integration tests on connection={{ansible_connection }} + +- include_tasks: _remove_config.yaml + +- include_tasks: _populate_config.yaml + +- block: + + - name: Delete the provided configuration + register: result + vyos.vyos.vyos_hostname: &id001 + config: + state: deleted + + - name: Assert that before dicts were correctly generated + assert: + that: + - result.changed == true + - result.commands == deleted.commands + + - name: Assert that the after dicts were correctly generated + assert: + that: + - result.after == {} + + - name: Delete the existing configuration with the provided running configuration + (IDEMPOTENT) + register: result + vyos.vyos.vyos_hostname: *id001 + + - name: Assert that the previous task was idempotent + assert: + that: + - result['changed'] == false + + always: + + - include_tasks: _remove_config.yaml diff --git a/tests/integration/targets/vyos_hostname/tests/cli/empty_config.yaml b/tests/integration/targets/vyos_hostname/tests/cli/empty_config.yaml new file mode 100644 index 0000000..8efead2 --- /dev/null +++ b/tests/integration/targets/vyos_hostname/tests/cli/empty_config.yaml @@ -0,0 +1,60 @@ +--- +- debug: + msg: START vyos_hostname empty_config integration tests on connection={{ + ansible_connection }} + +- name: Merged with empty config should give appropriate error message + register: result + ignore_errors: true + vyos.vyos.vyos_hostname: + config: + state: merged + +- assert: + that: + - result.msg == 'value of config parameter must not be empty for state merged' + +- name: Replaced with empty config should give appropriate error message + register: result + ignore_errors: true + vyos.vyos.vyos_hostname: + config: + state: replaced + +- assert: + that: + - result.msg == 'value of config parameter must not be empty for state replaced' + +- name: Overridden with empty config should give appropriate error message + register: result + ignore_errors: true + vyos.vyos.vyos_hostname: + config: + state: overridden + +- assert: + that: + - result.msg == 'value of config parameter must not be empty for state overridden' + +- name: Parsed with empty running_config should give appropriate error message + register: result + ignore_errors: true + vyos.vyos.vyos_hostname: + running_config: + state: parsed + +- assert: + that: + - result.msg == 'value of running_config parameter must not be empty for state + parsed' + +- name: Rendered with empty config should give appropriate error message + register: result + ignore_errors: true + vyos.vyos.vyos_hostname: + config: + state: rendered + +- assert: + that: + - result.msg == 'value of config parameter must not be empty for state rendered' diff --git a/tests/integration/targets/vyos_hostname/tests/cli/gathered.yaml b/tests/integration/targets/vyos_hostname/tests/cli/gathered.yaml new file mode 100644 index 0000000..0509fc5 --- /dev/null +++ b/tests/integration/targets/vyos_hostname/tests/cli/gathered.yaml @@ -0,0 +1,28 @@ +--- +- debug: + msg: START vyos_hostname gathered integration tests on connection={{ + ansible_connection }} + +- include_tasks: _remove_config.yaml + +- include_tasks: _populate_config.yaml + +- block: + + - name: Gather config from the device in structured format. + register: result + vyos.vyos.vyos_hostname: + state: gathered + + - vyos.vyos.vyos_facts: + gather_network_resources: hostname + + - name: Assert that facts are correctly generated + assert: + that: + - result.changed == false + - result.gathered == ansible_facts['network_resources']['hostname'] + + always: + + - include_tasks: _remove_config.yaml diff --git a/tests/integration/targets/vyos_hostname/tests/cli/merged.yaml b/tests/integration/targets/vyos_hostname/tests/cli/merged.yaml new file mode 100644 index 0000000..f9b28c7 --- /dev/null +++ b/tests/integration/targets/vyos_hostname/tests/cli/merged.yaml @@ -0,0 +1,45 @@ +--- +- debug: + msg: START vyos_hostname merged integration tests on connection={{ + ansible_connection }} + +- include_tasks: _remove_config.yaml + +- block: + - name: Merge the provided configuration with the existing running configuration + register: result + vyos.vyos.vyos_hostname: &id001 + config: + hostname: "vyosTest" + state: merged + + - vyos.vyos.vyos_facts: + gather_network_resources: hostname + + - assert: + that: + - result.commands|length == 1 + - result.changed == true + - result.commands|symmetric_difference(merged.commands) == [] + - result.after == ansible_facts['network_resources']['hostname'] + - result.after == merged.after + + + - name: Assert that before dicts were correctly generated + assert: + that: + - result.before == {} + + - name: + Merge the provided configuration with the existing running configuration + (IDEMPOTENT) + register: result + vyos.vyos.vyos_hostname: *id001 + + - name: Assert that the previous task was idempotent + assert: + that: + - result['changed'] == false + + always: + - include_tasks: _remove_config.yaml diff --git a/tests/integration/targets/vyos_hostname/tests/cli/overridden.yaml b/tests/integration/targets/vyos_hostname/tests/cli/overridden.yaml new file mode 100644 index 0000000..d9fd76d --- /dev/null +++ b/tests/integration/targets/vyos_hostname/tests/cli/overridden.yaml @@ -0,0 +1,42 @@ +--- +- debug: + msg: START vyos_hostname overridden integration tests on connection={{ + ansible_connection }} + +- include_tasks: _remove_config.yaml + +- include_tasks: _populate_config.yaml + +- block: + - name: override the provided configuration with the existing running configuration + register: result + vyos.vyos.vyos_hostname: &id001 + config: + hostname: "vyosTest" + state: overridden + + - vyos.vyos.vyos_facts: + gather_network_resources: hostname + + - assert: + that: + - result.commands|length == 1 + - result.changed == true + - result.commands|symmetric_difference(merged.commands) == [] + - result.after == ansible_facts['network_resources']['hostname'] + - result.after == merged.after + + + - name: + override the provided configuration with the existing running configuration + (IDEMPOTENT) + register: result + vyos.vyos.vyos_hostname: *id001 + + - name: Assert that the previous task was idempotent + assert: + that: + - result['changed'] == false + + always: + - include_tasks: _remove_config.yaml diff --git a/tests/integration/targets/vyos_hostname/tests/cli/parsed.yaml b/tests/integration/targets/vyos_hostname/tests/cli/parsed.yaml new file mode 100644 index 0000000..f6c00bb --- /dev/null +++ b/tests/integration/targets/vyos_hostname/tests/cli/parsed.yaml @@ -0,0 +1,17 @@ +--- +- debug: + msg: START vyos_hostname parsed integration tests on connection={{ ansible_connection + }} + +- name: Provide the running configuration for parsing (config to be parsed) + register: result + vyos.vyos.vyos_hostname: + running_config: "{{ lookup('file', '_parsed.cfg') }}" + state: parsed + + +- name: Assert that config was correctly parsed + assert: + that: + - result.changed == false + - result.parsed == merged.after diff --git a/tests/integration/targets/vyos_hostname/tests/cli/rendered.yaml b/tests/integration/targets/vyos_hostname/tests/cli/rendered.yaml new file mode 100644 index 0000000..28ec797 --- /dev/null +++ b/tests/integration/targets/vyos_hostname/tests/cli/rendered.yaml @@ -0,0 +1,21 @@ +--- +- debug: + msg: START vyos_hostname rendered integration tests on connection={{ + ansible_connection }} + +- include_tasks: _remove_config.yaml + +- block: + - name: Render the given configuration in the form of native commands + register: result + vyos.vyos.vyos_hostname: + config: + hostname: 'vyosTest' + state: rendered + + - assert: + that: + - result.changed == false + - result.rendered|symmetric_difference(merged.commands) == [] + always: + - include_tasks: _remove_config.yaml diff --git a/tests/integration/targets/vyos_hostname/tests/cli/replaced.yaml b/tests/integration/targets/vyos_hostname/tests/cli/replaced.yaml new file mode 100644 index 0000000..6acb993 --- /dev/null +++ b/tests/integration/targets/vyos_hostname/tests/cli/replaced.yaml @@ -0,0 +1,42 @@ +--- +- debug: + msg: START vyos_hostname replaced integration tests on connection={{ + ansible_connection }} + +- include_tasks: _remove_config.yaml + +- include_tasks: _populate_config.yaml + +- block: + - name: Replace the provided configuration with the existing running configuration + register: result + vyos.vyos.vyos_hostname: &id001 + config: + hostname: "vyosTest" + state: replaced + + - vyos.vyos.vyos_facts: + gather_network_resources: hostname + + - assert: + that: + - result.commands|length == 1 + - result.changed == true + - result.commands|symmetric_difference(merged.commands) == [] + - result.after == ansible_facts['network_resources']['hostname'] + - result.after == merged.after + + + - name: + Replace the provided configuration with the existing running configuration + (IDEMPOTENT) + register: result + vyos.vyos.vyos_hostname: *id001 + + - name: Assert that the previous task was idempotent + assert: + that: + - result['changed'] == false + + always: + - include_tasks: _remove_config.yaml diff --git a/tests/integration/targets/vyos_hostname/vars/main.yaml b/tests/integration/targets/vyos_hostname/vars/main.yaml new file mode 100644 index 0000000..a6b4986 --- /dev/null +++ b/tests/integration/targets/vyos_hostname/vars/main.yaml @@ -0,0 +1,12 @@ +--- +merged: + before: {} + commands: + - set system host-name vyosTest + after: + hostname: 'vyosTest' + +deleted: + commands: + - delete system host-name vyos + after: {} diff --git a/tests/unit/modules/network/vyos/fixtures/vyos_hostname_config.cfg b/tests/unit/modules/network/vyos/fixtures/vyos_hostname_config.cfg new file mode 100644 index 0000000..f94f7eb --- /dev/null +++ b/tests/unit/modules/network/vyos/fixtures/vyos_hostname_config.cfg @@ -0,0 +1 @@ +set system host-name 'vyos_test' diff --git a/tests/unit/modules/network/vyos/test_vyos_hostname.py b/tests/unit/modules/network/vyos/test_vyos_hostname.py new file mode 100644 index 0000000..8c2fdfb --- /dev/null +++ b/tests/unit/modules/network/vyos/test_vyos_hostname.py @@ -0,0 +1,134 @@ +# (c) 2021 Red Hat Inc. +# +# This file is part of Ansible +# +# Ansible is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Ansible is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Ansible. If not, see <http://www.gnu.org/licenses/>. + +# Make coding more python3-ish +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + +from ansible_collections.vyos.vyos.tests.unit.compat.mock import patch +from ansible_collections.vyos.vyos.plugins.modules import vyos_hostname +from ansible_collections.vyos.vyos.tests.unit.modules.utils import ( + set_module_args, +) +from .vyos_module import TestVyosModule, load_fixture + + +class TestVyosHostnameModule(TestVyosModule): + + module = vyos_hostname + + def setUp(self): + super(TestVyosHostnameModule, self).setUp() + + self.mock_get_resource_connection_config = patch( + "ansible_collections.ansible.netcommon.plugins.module_utils.network.common.rm_base.resource_module_base.get_resource_connection" + ) + self.get_resource_connection_config = ( + self.mock_get_resource_connection_config.start() + ) + + self.mock_get_resource_connection_facts = patch( + "ansible_collections.ansible.netcommon.plugins.module_utils.network.common.facts.facts.get_resource_connection" + ) + self.get_resource_connection_facts = ( + self.mock_get_resource_connection_facts.start() + ) + + self.mock_execute_show_command = patch( + "ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.facts.hostname.hostname.HostnameFacts.get_config" + ) + + self.execute_show_command = self.mock_execute_show_command.start() + + def tearDown(self): + super(TestVyosHostnameModule, self).tearDown() + self.mock_get_resource_connection_config.stop() + self.mock_get_resource_connection_facts.stop() + self.mock_execute_show_command.stop() + + def load_fixtures(self, commands=None, transport="cli", filename=None): + if filename is None: + filename = "vyos_hostname_config.cfg" + + def load_from_file(*args, **kwargs): + output = load_fixture(filename) + return output + + self.execute_show_command.side_effect = load_from_file + + def test_vyos_hostname_merged_idempotent(self): + set_module_args(dict(config=dict(hostname="vyos_test"))) + self.execute_module(changed=False, commands=[]) + + def test_vyos_hostname_replaced_idempotent(self): + set_module_args( + dict(config=dict(hostname="vyos_test"), state="replaced") + ) + self.execute_module(changed=False, commands=[]) + + def test_vyos_hostname_overridden_idempotent(self): + set_module_args( + dict(config=dict(hostname="vyos_test"), state="overridden") + ) + self.execute_module(changed=False, commands=[]) + + def test_vyos_hostname_merged(self): + set_module_args(dict(config=dict(hostname="vyos"))) + self.execute_module( + changed=True, commands=["set system host-name vyos"] + ) + + def test_vyos_hostname_replaced(self): + set_module_args(dict(config=dict(hostname="vyos"), state="replaced")) + self.execute_module( + changed=True, commands=["set system host-name vyos"] + ) + + def test_vyos_hostname_overridden(self): + set_module_args(dict(config=dict(hostname="vyos"), state="overridden")) + + def test_vyos_hostname_deleted(self): + set_module_args(dict(state="deleted")) + self.execute_module( + changed=True, commands=["delete system host-name vyos_test"] + ) + + def test_vyos_hostname_gathered(self): + set_module_args(dict(state="gathered")) + result = self.execute_module( + changed=False, filename="vyos_hostname_config.cfg" + ) + gathered_list = {"hostname": "vyos_test"} + self.assertEqual(sorted(gathered_list), sorted(result["gathered"])) + + def test_vyos_hostname_parsed(self): + parsed_str = "set system host-name vyos_test" + set_module_args(dict(running_config=parsed_str, state="parsed")) + result = self.execute_module(changed=False) + parsed_list = {"hostname": "vyos_test"} + self.assertEqual(sorted(parsed_list), sorted(result["parsed"])) + + def test_vyos_hostname_rendered(self): + set_module_args( + dict(state="rendered", config=dict(hostname="vyos_test")) + ) + commands = ["set system host-name vyos_test"] + result = self.execute_module(changed=False) + self.assertEqual( + sorted(result["rendered"]), sorted(commands), result["rendered"] + ) |