Lenovo cnos system module (#53764)

* Adding cnos_system module to Ansible.

* Adding UT, Functional test required for cnos_system. Bugs came up are fixed

* Adding more files to the cnos_system suit.
pull/54105/head
Anil Kumar Muraleedharan 6 years ago committed by Nathaniel Case
parent e4a1473a8f
commit 7a24ecde86

@ -0,0 +1,388 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
from __future__ import (absolute_import, division, print_function)
__metaclass__ = type
#
# Copyright (C) 2019 Lenovo.
# (c) 2017, Ansible by 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/>.
#
# Module to work on System Configuration with Lenovo Switches
# Lenovo Networking
#
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'community'}
DOCUMENTATION = """
---
module: cnos_system
version_added: "2.8"
author: "Anil Kumar Muraleedharan (@amuraleedhar)"
short_description: Manage the system attributes on Lenovo CNOS devices
description:
- This module provides declarative management of node system attributes
on Lenovo CNOS devices. It provides an option to configure host system
parameters or remove those parameters from the device active
configuration.
options:
hostname:
description:
- Configure the device hostname parameter. This option takes an
ASCII string value or keyword 'default'
domain_name:
description:
- Configures the default domain
name suffix to be used when referencing this node by its
FQDN. This argument accepts either a list of domain names or
a list of dicts that configure the domain name and VRF name or
keyword 'default'. See examples.
lookup_enabled:
description:
- Administrative control for enabling or disabling DNS lookups.
When this argument is set to True, lookups are performed and
when it is set to False, lookups are not performed.
type: bool
domain_search:
description:
- Configures a list of domain
name suffixes to search when performing DNS name resolution.
This argument accepts either a list of domain names or
a list of dicts that configure the domain name and VRF name or
keyword 'default'. See examples.
name_servers:
description:
- List of DNS name servers by IP address to use to perform name resolution
lookups. This argument accepts either a list of DNS servers or
a list of hashes that configure the name server and VRF name or
keyword 'default'. See examples.
lookup_source:
description:
- Provides one or more source interfaces to use for performing DNS
lookups. The interface must be a valid interface configured.
on the device.
state:
description:
- State of the configuration
values in the device's current active configuration. When set
to I(present), the values should be configured in the device active
configuration and when set to I(absent) the values should not be
in the device active configuration
default: present
choices: ['present', 'absent']
"""
EXAMPLES = """
- name: configure hostname and domain-name
cnos_system:
hostname: cnos01
domain_name: test.example.com
- name: remove configuration
cnos_system:
state: absent
- name: configure name servers
cnos_system:
name_servers:
- 8.8.8.8
- 8.8.4.4
- name: configure DNS Lookup sources
cnos_system:
lookup_source: MgmtEth0/0/CPU0/0
lookup_enabled: yes
- name: configure name servers with VRF support
nxos_system:
name_servers:
- { server: 8.8.8.8, vrf: mgmt }
- { server: 8.8.4.4, vrf: mgmt }
"""
RETURN = """
commands:
description: The list of configuration mode commands to send to the device
returned: always
type: list
sample:
- hostname cnos01
- ip domain-name test.example.com vrf default
"""
import re
from ansible.module_utils.network.cnos.cnos import get_config, load_config
from ansible.module_utils.network.cnos.cnos import cnos_argument_spec
from ansible.module_utils.network.cnos.cnos import check_args, debugOutput
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.six import iteritems
from ansible.module_utils.network.common.config import NetworkConfig
from ansible.module_utils.network.common.utils import ComplexList
_CONFIGURED_VRFS = None
def map_obj_to_commands(want, have, module):
commands = list()
state = module.params['state']
def needs_update(x):
return want.get(x) and (want.get(x) != have.get(x))
def difference(x, y, z):
return [item for item in x[z] if item not in y[z]]
if state == 'absent':
if have['hostname']:
commands.append('no hostname')
for item in have['domain_name']:
my_vrf = 'default'
if item['vrf'] is not None:
my_vrf = item['vrf']
cmd = 'no ip domain-name {0} vrf {1}'.format(item['name'], my_vrf)
commands.append(cmd)
for item in have['domain_search']:
my_vrf = 'default'
if item['vrf'] is not None:
my_vrf = item['vrf']
cmd = 'no ip domain-list {0} vrf {1}'.format(item['name'], my_vrf)
commands.append(cmd)
for item in have['name_servers']:
my_vrf = 'default'
if item['vrf'] is not None:
my_vrf = item['vrf']
cmd = 'no ip name-server {0} vrf {1}'.format(item['server'], my_vrf)
commands.append(cmd)
if state == 'present':
if needs_update('hostname'):
if want['hostname'] == 'default':
if have['hostname']:
commands.append('no hostname')
else:
commands.append('hostname %s' % want['hostname'])
if want.get('lookup_enabled') is not None:
if have.get('lookup_enabled') != want.get('lookup_enabled'):
cmd = 'ip domain-lookup'
if want['lookup_enabled'] is False:
cmd = 'no %s' % cmd
commands.append(cmd)
if want['domain_name']:
if want.get('domain_name')[0]['name'] == 'default':
if have['domain_name']:
for item in have['domain_name']:
my_vrf = 'default'
if item['vrf'] is not None:
my_vrf = item['vrf']
cmd = 'no ip domain-name {0} vrf {1}'.format(item['name'], my_vrf)
commands.append(cmd)
else:
for item in difference(have, want, 'domain_name'):
my_vrf = 'default'
if item['vrf'] is not None:
my_vrf = item['vrf']
cmd = 'no ip domain-name {0} vrf {1}'.format(item['name'], my_vrf)
commands.append(cmd)
for item in difference(want, have, 'domain_name'):
my_vrf = 'default'
if item['vrf'] is not None:
my_vrf = item['vrf']
cmd = 'ip domain-name {0} vrf {1}'.format(item['name'], my_vrf)
commands.append(cmd)
if want['domain_search']:
if want.get('domain_search')[0]['name'] == 'default':
if have['domain_search']:
for item in have['domain_search']:
my_vrf = 'default'
if item['vrf'] is not None:
my_vrf = item['vrf']
cmd = 'no ip domain-list {0} vrf {1}'.format(item['name'], my_vrf)
commands.append(cmd)
else:
for item in difference(have, want, 'domain_search'):
my_vrf = 'default'
if item['vrf'] is not None:
my_vrf = item['vrf']
cmd = 'no ip domain-list {0} vrf {1}'.format(item['name'], my_vrf)
commands.append(cmd)
for item in difference(want, have, 'domain_search'):
my_vrf = 'default'
if item['vrf'] is not None:
my_vrf = item['vrf']
cmd = 'ip domain-list {0} vrf {1}'.format(item['name'], my_vrf)
commands.append(cmd)
if want['name_servers']:
if want.get('name_servers')[0]['server'] == 'default':
if have['name_servers']:
for item in have['name_servers']:
my_vrf = 'default'
if item['vrf'] is not None:
my_vrf = item['vrf']
cmd = 'no ip name-server {0} vrf {1}'.format(item['server'], my_vrf)
commands.append(cmd)
else:
for item in difference(have, want, 'name_servers'):
my_vrf = 'default'
if item['vrf'] is not None:
my_vrf = item['vrf']
cmd = 'no ip name-server {0} vrf {1}'.format(item['server'], my_vrf)
commands.append(cmd)
for item in difference(want, have, 'name_servers'):
my_vrf = 'default'
if item['vrf'] is not None:
my_vrf = item['vrf']
cmd = 'ip name-server {0} vrf {1}'.format(item['server'], my_vrf)
commands.append(cmd)
return commands
def parse_hostname(config):
match = re.search(r'^hostname (\S+)', config, re.M)
if match:
return match.group(1)
def parse_domain_name(config):
objects = list()
myconf = config.splitlines()
for line in myconf:
if 'ip domain-name' in line:
datas = line.split()
objects.append({'name': datas[2], 'vrf': datas[4]})
return objects
def parse_domain_search(config):
objects = list()
myconf = config.splitlines()
for line in myconf:
if 'ip domain-list' in line:
datas = line.split()
objects.append({'name': datas[2], 'vrf': datas[4]})
return objects
def parse_name_servers(config):
objects = list()
myconf = config.splitlines()
for line in myconf:
if 'ip name-server' in line:
datas = line.split()
objects.append({'server': datas[2], 'vrf': datas[4]})
return objects
def map_config_to_obj(module):
config = get_config(module)
configobj = NetworkConfig(indent=2, contents=config)
return {
'hostname': parse_hostname(config),
'lookup_enabled': 'no ip domain-lookup' not in config,
'domain_name': parse_domain_name(config),
'domain_search': parse_domain_search(config),
'name_servers': parse_name_servers(config),
}
def map_params_to_obj(module):
obj = {
'hostname': module.params['hostname'],
'lookup_enabled': module.params['lookup_enabled'],
}
domain_name = ComplexList(dict(
name=dict(key=True),
vrf=dict()
), module)
domain_search = ComplexList(dict(
name=dict(key=True),
vrf=dict()
), module)
name_servers = ComplexList(dict(
server=dict(key=True),
vrf=dict()
), module)
for arg, cast in [('domain_name', domain_name),
('domain_search', domain_search),
('name_servers', name_servers)]:
if module.params[arg] is not None:
obj[arg] = cast(module.params[arg])
else:
obj[arg] = None
return obj
def main():
""" main entry point for module execution
"""
argument_spec = dict(
hostname=dict(),
lookup_enabled=dict(type='bool'),
# { name: <str>, vrf: <str> }
domain_name=dict(type='list'),
# {name: <str>, vrf: <str> }
domain_search=dict(type='list'),
# { server: <str>; vrf: <str> }
name_servers=dict(type='list'),
lookup_source=dict(type='str'),
state=dict(default='present', choices=['present', 'absent'])
)
module = AnsibleModule(argument_spec=argument_spec,
supports_check_mode=True)
warnings = list()
check_args(module, warnings)
result = {'changed': False}
if warnings:
result['warnings'] = warnings
want = map_params_to_obj(module)
have = map_config_to_obj(module)
commands = map_obj_to_commands(want, have, module)
result['commands'] = commands
if commands:
if not module.check_mode:
load_config(module, commands)
result['changed'] = True
module.exit_json(**result)
if __name__ == '__main__':
main()

@ -6,9 +6,9 @@
# - You can enter hostnames or ip Addresses
# - A hostname/ip can be a member of multiple groups
#
# In the /etc/ansible/hosts file u have to enter [cnos_portchannel_sample] tag
# In the /etc/ansible/hosts file u have to enter [cnos_linkagg_sample] tag
# Following you should specify IP Addresses details
# Please change <username> and <password> with appropriate value for your switch.
[cnos_linkagg_sample]
10.241.107.39 ansible_network_os=cnos ansible_ssh_user=<username> ansible_ssh_pass=<password>
10.241.107.39 ansible_network_os=cnos ansible_ssh_user=<username> ansible_ssh_pass=<password>

@ -0,0 +1,2 @@
# No Lenovo Switch simulator yet, so not enabled
unsupported

@ -0,0 +1,14 @@
# You have to paste this dummy information in /etc/ansible/hosts
# Notes:
# - Comments begin with the '#' character
# - Blank lines are ignored
# - Groups of hosts are delimited by [header] elements
# - You can enter hostnames or ip Addresses
# - A hostname/ip can be a member of multiple groups
#
# In the /etc/ansible/hosts file u have to enter [cnos_system_sample] tag
# Following you should specify IP Addresses details
# Please change <username> and <password> with appropriate value for your switch.
[cnos_system_sample]
<ip address> ansible_network_os=cnos ansible_ssh_user=<username> ansible_ssh_pass=<password>

@ -0,0 +1,33 @@
---
- name: collect common test cases
find:
paths: "{{ role_path }}/tests/common"
patterns: "{{ testcase }}.yaml"
connection: local
register: test_cases
- name: collect cli test cases
find:
paths: "{{ role_path }}/tests/cli"
patterns: "{{ testcase }}.yaml"
connection: local
register: cli_cases
- set_fact:
test_cases:
files: "{{ test_cases.files }} + {{ cli_cases.files }}"
- name: set test_items
set_fact: test_items="{{ test_cases.files | map(attribute='path') | list }}"
- name: run test cases (connection=network_cli)
include: "{{ test_case_to_run }} ansible_connection=network_cli connection={{ cli }}"
with_items: "{{ test_items }}"
loop_control:
loop_var: test_case_to_run
- name: run test case (connection=local)
include: "{{ test_case_to_run }} ansible_connection=local"
with_first_found: "{{ test_items }}"
loop_control:
loop_var: test_case_to_run

@ -0,0 +1,2 @@
---
- { include: cli.yaml, tags: ['cli'] }

@ -0,0 +1,34 @@
---
- debug: msg="START cnos cli/net_system.yaml on connection={{ ansible_connection }}"
# Add minimal testcase to check args are passed correctly to
# implementation module and module run is successful.
- name: setup
cnos_config:
lines:
- no ip domain-list ansible.com vrf default
- no ip domain-list redhat.com vrf default
match: none
- name: configure domain_list using platform agnostic module
net_system:
domain_search:
- ansible.com
- redhat.com
register: result
- assert:
that:
- result.changed == true
- "'ip domain-list ansible.com vrf default' in result.commands"
- "'ip domain-list redhat.com vrf default' in result.commands"
- name: setup
cnos_config:
lines:
- no ip domain-list ansible.com vrf default
- no ip domain-list redhat.com vrf default
match: none
- debug: msg="END cnos cli/net_system.yaml on connection={{ ansible_connection }}"

@ -0,0 +1,111 @@
---
- debug: msg="START cli/set_domain_list.yaml"
- name: setup
cnos_config:
lines:
- no ip domain-list ansible.com vrf default
- no ip domain-list redhat.com vrf default
match: none
- name: configure domain_list
cnos_system:
domain_search:
- ansible.com
- redhat.com
register: result
- assert:
that:
- result.changed == true
- "'ip domain-list ansible.com vrf default' in result.commands"
- "'ip domain-list redhat.com vrf default' in result.commands"
- name: verify domain_list
cnos_system:
domain_search:
- ansible.com
- redhat.com
register: result
- assert:
that:
- result.changed == true
- name: remove one entry
cnos_system:
domain_search:
- ansible.com
register: result
- assert:
that:
- result.changed == true
- "'no ip domain-list redhat.com vrf default' in result.commands"
- name: verify remove one entry
cnos_system:
domain_search:
- ansible.com
register: result
- assert:
that:
- result.changed == true
- name: add one entry
cnos_system:
domain_search:
- ansible.com
- redhat.com
register: result
- assert:
that:
- result.changed == true
- "'ip domain-list redhat.com vrf default' in result.commands"
- name: verify add one entry
cnos_system:
domain_search:
- ansible.com
- redhat.com
register: result
- assert:
that:
- result.changed == true
- name: add and remove one entry
cnos_system:
domain_search:
- ansible.com
- eng.ansible.com
register: result
- assert:
that:
- result.changed == true
- "'no ip domain-list redhat.com vrf default' in result.commands"
- "'ip domain-list eng.ansible.com vrf default' in result.commands"
- name: verify add and remove one entry
cnos_system:
domain_search:
- ansible.com
- eng.ansible.com
register: result
- assert:
that:
- result.changed == true
- name: teardown
cnos_config:
lines:
- no ip domain-list ansible.com vrf default
- no ip domain-list redhat.com vrf default
- no ip domain-list eng.ansible.com vrf default
match: none
- debug: msg="END cli/set_domain_search.yaml"

@ -0,0 +1,32 @@
---
- debug: msg="START cli/set_domain_name.yaml"
- name: setup
cnos_config:
lines: no ip domain-name eng.ansible.com vrf default
match: none
- name: configure domain_name
cnos_system:
domain_name: eng.ansible.com
register: result
- assert:
that:
- "result.changed == true"
- name: verify domain_name
cnos_system:
domain_name: eng.ansible.com
register: result
- assert:
that:
- "result.changed == true"
- name: teardown
cnos_config:
lines: no ip domain-name eng.ansible.com vrf default
match: none
- debug: msg="END cli/set_domain_name.yaml"

@ -0,0 +1,73 @@
---
- debug: msg="START cli/set_name_servers.yaml"
- name: setup
cnos_config: &reset
lines:
- no ip name-server 10.241.107.1 vrf default
- no ip name-server 10.241.107.2 vrf default
- no ip name-server 10.241.107.3 vrf default
match: none
- name: configure name_servers
cnos_system:
name_servers:
- 10.241.107.1
- 10.241.107.2
- 10.241.107.3
register: result
- assert:
that:
- result.changed == true
- "'ip name-server 10.241.107.1 vrf default' in result.commands"
- "'ip name-server 10.241.107.2 vrf default' in result.commands"
- "'ip name-server 10.241.107.3 vrf default' in result.commands"
- name: verify name_servers
cnos_system:
name_servers:
- 10.241.107.1
- 10.241.107.2
- 10.241.107.3
register: result
- assert:
that:
- result.changed == true
- name: remove one
cnos_system:
name_servers:
- 10.241.107.1
- 10.241.107.2
register: result
- assert:
that:
- result.changed == true
# - result.commands|length == 1
- "'no ip name-server 10.241.107.3 vrf default' in result.commands"
- name: default name server
cnos_system: &defns
name_servers: default
register: result
- assert:
that:
- result.changed == true
- name: Idempotent check
cnos_system: *defns
register: result
- assert:
that:
- result.changed == false
- name: teardown
cnos_config: *reset
ignore_errors: yes
- debug: msg="END cli/set_name_servers.yaml"

@ -0,0 +1,122 @@
---
- debug: msg="START connection={{ ansible_connection }}/sanity.yaml"
- debug: msg="Using provider={{ connection.transport }}"
when: ansible_connection == "local"
- block:
- name: remove configuration
cnos_system: &remove
state: absent
register: result
ignore_errors: yes
- name: configure lookup_enabled
cnos_system: &dlo
lookup_enabled: true
state: present
register: result
- name: configure hostname and domain-name
cnos_system: &hostname
hostname: switch
domain_name: test.example.com
register: result
- assert: &true
that:
- "result.changed == true"
- name: Idempotence check
cnos_system: *hostname
register: result
- assert: &false
that:
- "result.changed == true"
- name: configure name servers
cnos_system: &ns
name_servers:
- 8.8.8.8
- 8.8.4.4
register: result
- assert: *true
- name: Idempotence check
cnos_system: *ns
register: result
- assert: *false
- name: configure name servers with VRF support
cnos_system: &nsv
name_servers:
- { server: 8.8.8.8, vrf: management }
- { server: 8.8.4.4, vrf: management }
register: result
- assert: *true
- name: Idempotence check
cnos_system: *nsv
register: result
- assert:
that:
- "result.changed == false"
- name: configure lookup_enabled1
cnos_system: &ndlo
lookup_enabled: false
register: result
- assert: *true
- name: Idempotence check
cnos_system: *ndlo
register: result
- assert:
that:
- "result.changed == false"
- name: configure lookup_enabled2
cnos_system: *dlo
register: result
- assert: *true
- name: Idempotence check
cnos_system: *dlo
register: result
- assert:
that:
- "result.changed == false"
- name: default configuration
cnos_system: &default
hostname: default
domain_name: default
name_servers: default
register: result
- assert: *true
- name: Idempotence check
cnos_system: *default
register: result
- assert:
that:
- "result.changed == false"
always:
- name: remove configuration
cnos_system: *remove
- name: Re-configure hostname
cnos_system: *hostname
- debug: msg="END connection={{ ansible_connection }}/sanity.yaml"

@ -0,0 +1,36 @@
---
- debug: msg="START connection={{ ansible_connection }}/set_hostname.yaml"
- debug: msg="Using provider={{ connection.transport }}"
when: ansible_connection == "local"
- block:
- name: setup
cnos_config:
lines: "hostname switch"
match: none
- name: configure hostname
cnos_system:
hostname: foo
register: result
- assert:
that:
- "result.changed == true"
- name: verify hostname
cnos_system:
hostname: foo
register: result
- assert:
that:
- "result.changed == false"
always:
- name: teardown
cnos_config:
lines: "hostname switch"
match: none
- debug: msg="END connection={{ ansible_connection }}/set_hostname.yaml"

@ -0,0 +1,11 @@
hostname lenovo
ip route 1.2.0.0/24 Null0 255
ip route 1.2.3.4/31 Ethernet1/44 1.2.3.1
ip route 1.2.3.4/32 1.2.34.5
ip route 10.241.106.0/24 Ethernet1/13 10.241.107.1 113 tag 1013 description anil
ip route 10.241.106.4/32 1.2.3.5 tag 333 description anillll
ip route 10.241.106.4/32 1.3.56.7
ip route 10.241.107.0/24 10.241.107.1
ip route 10.241.107.1/32 Ethernet1/33 10.241.107.2 100 tag 111 description anil

@ -0,0 +1,103 @@
#
# (c) 2016 Red Hat Inc.
# Copyright (C) 2017 Lenovo.
#
# 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 units.compat.mock import patch
from ansible.modules.network.cnos import cnos_system
from units.modules.utils import set_module_args
from .cnos_module import TestCnosModule, load_fixture
class TestCnosSystemModule(TestCnosModule):
module = cnos_system
def setUp(self):
super(TestCnosSystemModule, self).setUp()
self.mock_get_config = patch('ansible.modules.network.cnos.cnos_system.get_config')
self.get_config = self.mock_get_config.start()
self.mock_load_config = patch('ansible.modules.network.cnos.cnos_system.load_config')
self.load_config = self.mock_load_config.start()
def tearDown(self):
super(TestCnosSystemModule, self).tearDown()
self.mock_get_config.stop()
self.mock_load_config.stop()
def load_fixtures(self, commands=None, device=''):
self.get_config.return_value = load_fixture('cnos_system_config.cfg')
self.load_config.return_value = None
def test_cnos_system_hostname_changed(self):
set_module_args(dict(hostname='foo'))
commands = ['hostname foo']
self.execute_module(changed=True, commands=commands)
def test_cnos_system_domain_lookup(self):
set_module_args(dict(lookup_enabled=False))
commands = ['no ip domain-lookup']
self.execute_module(changed=True, commands=commands)
def test_cnos_system_missing_vrf(self):
domain_name = dict(name='example.com', vrf='example')
set_module_args(dict(domain_name=domain_name))
self.execute_module(failed=True)
def test_cnos_system_domain_name(self):
set_module_args(dict(domain_name=['example.net']))
commands = ['ip domain-name example.net vrf default']
self.execute_module(changed=True, commands=commands)
def test_cnos_system_domain_name_complex(self):
domain_name = dict(name='example.net', vrf='management')
set_module_args(dict(domain_name=[domain_name]))
commands = ['ip domain-name example.net vrf management']
self.execute_module(changed=True, commands=commands)
def test_cnos_system_domain_search(self):
set_module_args(dict(domain_search=['example.net']))
commands = ['ip domain-list example.net vrf default']
self.execute_module(changed=True, commands=commands)
def test_cnos_system_domain_search_complex(self):
domain_search = dict(name='example.net', vrf='management')
set_module_args(dict(domain_search=[domain_search]))
commands = ['ip domain-list example.net vrf management']
self.execute_module(changed=True, commands=commands)
def test_cnos_system_name_servers(self):
set_module_args(dict(name_servers=['1.2.3.4', '8.8.8.8']))
commands = ['ip name-server 1.2.3.4 vrf default', 'ip name-server 8.8.8.8 vrf default']
self.execute_module(changed=True, commands=commands)
def test_cnos_system_name_servers_complex(self):
name_servers = dict(server='1.2.3.4', vrf='management')
set_module_args(dict(name_servers=[name_servers]))
commands = ['ip name-server 1.2.3.4 vrf management']
self.execute_module(changed=True, commands=commands)
def test_cnos_system_state_absent(self):
set_module_args(dict(state='absent'))
commands = ['no hostname']
self.execute_module(changed=True, commands=commands)
Loading…
Cancel
Save