diff --git a/lib/ansible/module_utils/eos.py b/lib/ansible/module_utils/eos.py
index e3fbf415fa..28bcfb5a6c 100644
--- a/lib/ansible/module_utils/eos.py
+++ b/lib/ansible/module_utils/eos.py
@@ -66,6 +66,10 @@ ARGS_DEFAULT_VALUE = {
}
+def get_argspec():
+ return eos_argument_spec
+
+
def check_args(module, warnings):
provider = module.params['provider'] or {}
for key in eos_argument_spec:
diff --git a/lib/ansible/module_utils/ios.py b/lib/ansible/module_utils/ios.py
index c574b4c091..6ff369c484 100644
--- a/lib/ansible/module_utils/ios.py
+++ b/lib/ansible/module_utils/ios.py
@@ -45,6 +45,10 @@ ios_argument_spec = {
}
+def get_argspec():
+ return ios_argument_spec
+
+
def check_args(module, warnings):
provider = module.params['provider'] or {}
for key in ios_argument_spec:
diff --git a/lib/ansible/module_utils/iosxr.py b/lib/ansible/module_utils/iosxr.py
index 769f487f52..07ffe10738 100644
--- a/lib/ansible/module_utils/iosxr.py
+++ b/lib/ansible/module_utils/iosxr.py
@@ -44,6 +44,10 @@ iosxr_argument_spec = {
}
+def get_argspec():
+ return iosxr_argument_spec
+
+
def check_args(module, warnings):
provider = module.params['provider'] or {}
for key in iosxr_argument_spec:
diff --git a/lib/ansible/module_utils/junos.py b/lib/ansible/module_utils/junos.py
index b45acfb640..83813ace48 100644
--- a/lib/ansible/module_utils/junos.py
+++ b/lib/ansible/module_utils/junos.py
@@ -48,6 +48,10 @@ ARGS_DEFAULT_VALUE = {
}
+def get_argspec():
+ return junos_argument_spec
+
+
def check_args(module, warnings):
provider = module.params['provider'] or {}
for key in junos_argument_spec:
diff --git a/lib/ansible/module_utils/nxos.py b/lib/ansible/module_utils/nxos.py
index fce1e8eba9..2c0db76757 100644
--- a/lib/ansible/module_utils/nxos.py
+++ b/lib/ansible/module_utils/nxos.py
@@ -62,6 +62,10 @@ ARGS_DEFAULT_VALUE = {
}
+def get_argspec():
+ return nxos_argument_spec
+
+
def check_args(module, warnings):
provider = module.params['provider'] or {}
for key in nxos_argument_spec:
diff --git a/lib/ansible/module_utils/vyos.py b/lib/ansible/module_utils/vyos.py
index 9d4ef682b3..881bfb8b87 100644
--- a/lib/ansible/module_utils/vyos.py
+++ b/lib/ansible/module_utils/vyos.py
@@ -45,6 +45,10 @@ vyos_argument_spec = {
}
+def get_argspec():
+ return vyos_argument_spec
+
+
def check_args(module, warnings):
provider = module.params['provider'] or {}
for key in vyos_argument_spec:
diff --git a/lib/ansible/modules/network/net_system.py b/lib/ansible/modules/network/net_system.py
new file mode 100644
index 0000000000..5776f6967c
--- /dev/null
+++ b/lib/ansible/modules/network/net_system.py
@@ -0,0 +1,110 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+# (c) 2017, Ansible by Red Hat, inc
+#
+# This file is part of Ansible by Red Hat
+#
+# 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 .
+#
+
+ANSIBLE_METADATA = {'metadata_version': '1.0',
+ 'status': ['preview'],
+ 'supported_by': 'core'}
+
+
+DOCUMENTATION = """
+---
+module: net_system
+version_added: "2.4"
+author: "Ricardo Carrillo Cruz (@rcarrillocruz)"
+short_description: Manage the system attributes on network devices
+description:
+ - This module provides declarative management of node system attributes
+ on network 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.
+ domain_name:
+ description:
+ - Configure the IP domain name
+ on the remote device to the provided value. Value
+ should be in the dotted name form and will be
+ appended to the C(hostname) to create a fully-qualified
+ domain name.
+ domain_search:
+ description:
+ - Provides the list of domain suffixes to
+ append to the hostname for the purpose of doing name resolution.
+ This argument accepts a list of names and will be reconciled
+ with the current active configuration on the running node.
+ lookup_source:
+ description:
+ - Provides one or more source
+ interfaces to use for performing DNS lookups. The interface
+ provided in C(lookup_source) must be a valid interface configured
+ on the device.
+ 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 See
+ examples.
+ 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
+ net_system:
+ hostname: ios01
+ domain_name: test.example.com
+ domain-search:
+ - ansible.com
+ - redhat.com
+ - cisco.com
+
+- name: remove configuration
+ net_system:
+ state: absent
+
+- name: configure DNS lookup sources
+ net_system:
+ lookup_source: MgmtEth0/0/CPU0/0
+
+- name: configure name servers
+ net_system:
+ name_servers:
+ - 8.8.8.8
+ - 8.8.4.4
+"""
+
+RETURN = """
+commands:
+ description: The list of configuration mode commands to send to the device
+ returned: always
+ type: list
+ sample:
+ - hostname ios01
+ - ip domain name test.example.com
+"""
diff --git a/lib/ansible/plugins/action/net_base.py b/lib/ansible/plugins/action/net_base.py
new file mode 100644
index 0000000000..6df0bdc09c
--- /dev/null
+++ b/lib/ansible/plugins/action/net_base.py
@@ -0,0 +1,195 @@
+# (c) 2015, Ansible 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 .
+from __future__ import (absolute_import, division, print_function)
+__metaclass__ = type
+
+import os
+import sys
+import copy
+
+from ansible.plugins.action import ActionBase
+from ansible.utils.path import unfrackpath
+from ansible.plugins import connection_loader
+from ansible.module_utils.basic import AnsibleFallbackNotFound
+from ansible.module_utils.six import iteritems
+from ansible.module_utils._text import to_bytes
+
+from imp import find_module, load_module
+
+try:
+ from __main__ import display
+except ImportError:
+ from ansible.utils.display import Display
+ display = Display()
+
+
+class ActionModule(ActionBase):
+
+ def run(self, tmp=None, task_vars=None):
+ if self._play_context.connection != 'local':
+ return dict(
+ failed=True,
+ msg='invalid connection specified, expected connection=local, '
+ 'got %s' % self._play_context.connection
+ )
+
+ play_context = copy.deepcopy(self._play_context)
+ play_context.network_os = self._get_network_os(task_vars)
+ # TODO this can be netconf
+ play_context.connection = 'network_cli'
+
+ self.provider = self._load_provider(play_context.network_os)
+
+ play_context.remote_addr = self.provider['host'] or self._play_context.remote_addr
+ play_context.port = self.provider['port'] or self._play_context.port or 22
+ play_context.remote_user = self.provider['username'] or self._play_context.connection_user
+ play_context.password = self.provider['password'] or self._play_context.password
+ play_context.private_key_file = self.provider['ssh_keyfile'] or self._play_context.private_key_file
+ play_context.timeout = self.provider['timeout'] or self._play_context.timeout
+ if 'authorize' in self.provider.keys():
+ play_context.become = self.provider['authorize'] or False
+ play_context.become_pass = self.provider['auth_pass']
+
+ socket_path = self._start_connection(play_context)
+ task_vars['ansible_socket'] = socket_path
+
+ result = super(ActionModule, self).run(tmp, task_vars)
+
+ module = self._get_implementation_module(play_context.network_os, self._task.action)
+
+ if not module:
+ result['failed'] = True
+ result['msg'] = ('Could not find implementation module %s for %s' %
+ (self._task.action, play_context.network_os))
+ else:
+ new_module_args = self._task.args.copy()
+ # perhaps delete the provider argument here as well since the
+ # module code doesn't need the information, the connection is
+ # already started
+ if 'network_os' in new_module_args:
+ del new_module_args['network_os']
+
+ display.vvvv('Running implementation module %s' % module)
+ result.update(self._execute_module(module_name=module,
+ module_args=new_module_args, task_vars=task_vars,
+ wrap_async=self._task.async))
+
+ display.vvvv('Caching network OS %s in facts' % play_context.network_os)
+ result['ansible_facts'] = {'network_os': play_context.network_os}
+
+ return result
+
+ def _start_connection(self, play_context):
+
+ display.vvv('using connection plugin %s' % play_context.connection, play_context.remote_addr)
+ connection = self._shared_loader_obj.connection_loader.get('persistent',
+ play_context, sys.stdin)
+
+ socket_path = self._get_socket_path(play_context)
+ display.vvvv('socket_path: %s' % socket_path, play_context.remote_addr)
+
+ if not os.path.exists(socket_path):
+ # start the connection if it isn't started
+ rc, out, err = connection.exec_command('open_shell()')
+ display.vvvv('open_shell() returned %s %s %s' % (rc, out, err))
+ if not rc == 0:
+ return {'failed': True,
+ 'msg': 'unable to open shell. Please see: ' +
+ 'https://docs.ansible.com/ansible/network_debug_troubleshooting.html#unable-to-open-shell',
+ 'rc': rc}
+ else:
+ # make sure we are in the right cli context which should be
+ # enable mode and not config module
+ rc, out, err = connection.exec_command('prompt()')
+ if str(out).strip().endswith(')#'):
+ display.vvvv('wrong context, sending exit to device', self._play_context.remote_addr)
+ connection.exec_command('exit')
+
+ if self._play_context.become_method == 'enable':
+ self._play_context.become = False
+ self._play_context.become_method = None
+
+ return socket_path
+
+ def _get_network_os(self, task_vars):
+ if ('network_os' in self._task.args and self._task.args['network_os']):
+ display.vvvv('Getting network OS from task argument')
+ network_os = self._task.args['network_os']
+ elif (self._play_context.network_os):
+ display.vvvv('Getting network OS from inventory')
+ network_os = self._play_context.network_os
+ elif ('network_os' in task_vars['ansible_facts'] and
+ task_vars['ansible_facts']['network_os']):
+ display.vvvv('Getting network OS from fact')
+ network_os = task_vars['ansible_facts']['network_os']
+ else:
+ # this will be replaced by the call to get_capabilities() on the
+ # connection
+ display.vvvv('Getting network OS from net discovery')
+ network_os = None
+
+ return network_os
+
+ def _get_implementation_module(self, network_os, platform_agnostic_module):
+ implementation_module = network_os + '_' + platform_agnostic_module.partition('_')[2]
+ if implementation_module not in self._shared_loader_obj.module_loader:
+ implementation_module = None
+
+ return implementation_module
+
+ # this will be removed once the new connection work is done
+ def _get_socket_path(self, play_context):
+ ssh = connection_loader.get('ssh', class_only=True)
+ cp = ssh._create_control_path(play_context.remote_addr, play_context.port, play_context.remote_user)
+ path = unfrackpath("$HOME/.ansible/pc")
+ return cp % dict(directory=path)
+
+ def _load_provider(self, network_os):
+ # we should be able to stream line this a bit by creating a common
+ # provider argument spec in module_utils/network_common.py or another
+ # option is that there isn't a need to push provider into the module
+ # since the connection is started in the action handler.
+ f, p, d = find_module('ansible')
+ f2, p2, d2 = find_module('module_utils', [p])
+ f3, p3, d3 = find_module(network_os, [p2])
+ module = load_module('ansible.module_utils.' + network_os, f3, p3, d3)
+
+ provider = self._task.args.get('provider', {})
+ for key, value in iteritems(module.get_argspec()):
+ if key != 'provider' and key not in provider:
+ if key in self._task.args:
+ provider[key] = self._task.args[key]
+ elif 'fallback' in value:
+ provider[key] = self._fallback(value['fallback'])
+ elif key not in provider:
+ provider[key] = None
+ return provider
+
+ def _fallback(self, fallback):
+ strategy = fallback[0]
+ args = []
+ kwargs = {}
+
+ for item in fallback[1:]:
+ if isinstance(item, dict):
+ kwargs = item
+ else:
+ args = item
+ try:
+ return strategy(*args, **kwargs)
+ except AnsibleFallbackNotFound:
+ pass
diff --git a/lib/ansible/plugins/action/net_system.py b/lib/ansible/plugins/action/net_system.py
new file mode 100644
index 0000000000..a4ee4db0b6
--- /dev/null
+++ b/lib/ansible/plugins/action/net_system.py
@@ -0,0 +1,26 @@
+# (c) 2017, Ansible 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 .
+from __future__ import (absolute_import, division, print_function)
+__metaclass__ = type
+
+from ansible.plugins.action.net_base import ActionModule as _ActionModule
+
+
+class ActionModule(_ActionModule):
+ def run(self, tmp=None, task_vars=None):
+ result = super(ActionModule, self).run(tmp, task_vars)
+ return result
diff --git a/test/integration/inventory.network b/test/integration/inventory.network
index c959e33613..d90e1aff93 100644
--- a/test/integration/inventory.network
+++ b/test/integration/inventory.network
@@ -5,27 +5,27 @@ ansible_python_interpreter=python
[eos]
#veos-dut-01
-veos01
+veos01 ansible_network_os=eos
[nxos]
-nxos01
+nxos01 ansible_network_os=nxos
[iosxr]
-iosxr01
+iosxr01 ansible_network_os=iosxr
[ios]
-ios01
+ios01 ansible_network_os=ios
#csr01
[junos]
-vsrx01
+vsrx01 ansible_network_os=junos
[cumulus]
clvx01
[vyos]
-vyos-dut-01
+vyos01 ansible_network_os=vyos
[ops]
ops01
@@ -33,4 +33,12 @@ ops01
[asa]
asa01
+[platform_agnostic:children]
+ios
+iosxr
+eos
+junos
+vyos
+nxos
+
# vim: nospell filetype=dosini
diff --git a/test/integration/platform_agnostic.yaml b/test/integration/platform_agnostic.yaml
new file mode 100644
index 0000000000..ee9c55c2a5
--- /dev/null
+++ b/test/integration/platform_agnostic.yaml
@@ -0,0 +1,11 @@
+---
+- hosts: platform_agnostic
+ gather_facts: no
+ connection: local
+
+ vars:
+ limit_to: "*"
+ debug: false
+
+ roles:
+ - { role: net_system, when: "limit_to in ['*', 'net_system']" }
diff --git a/test/integration/targets/net_system/aliases b/test/integration/targets/net_system/aliases
new file mode 100644
index 0000000000..5c43f4b8f8
--- /dev/null
+++ b/test/integration/targets/net_system/aliases
@@ -0,0 +1,2 @@
+network/ci
+skip/python3
diff --git a/test/integration/targets/net_system/defaults/main.yaml b/test/integration/targets/net_system/defaults/main.yaml
new file mode 100644
index 0000000000..5f709c5aac
--- /dev/null
+++ b/test/integration/targets/net_system/defaults/main.yaml
@@ -0,0 +1,2 @@
+---
+testcase: "*"
diff --git a/test/integration/targets/net_system/tasks/cli.yaml b/test/integration/targets/net_system/tasks/cli.yaml
new file mode 100644
index 0000000000..46d86dd698
--- /dev/null
+++ b/test/integration/targets/net_system/tasks/cli.yaml
@@ -0,0 +1,16 @@
+---
+- name: collect all cli test cases
+ find:
+ paths: "{{ role_path }}/tests/cli"
+ patterns: "{{ testcase }}.yaml"
+ 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
+ include: "{{ test_case_to_run }}"
+ with_items: "{{ test_items }}"
+ loop_control:
+ loop_var: test_case_to_run
diff --git a/test/integration/targets/net_system/tasks/main.yaml b/test/integration/targets/net_system/tasks/main.yaml
new file mode 100644
index 0000000000..415c99d8b1
--- /dev/null
+++ b/test/integration/targets/net_system/tasks/main.yaml
@@ -0,0 +1,2 @@
+---
+- { include: cli.yaml, tags: ['cli'] }
diff --git a/test/integration/targets/net_system/tests/cli/set_name_servers.yaml b/test/integration/targets/net_system/tests/cli/set_name_servers.yaml
new file mode 100644
index 0000000000..e803e60e48
--- /dev/null
+++ b/test/integration/targets/net_system/tests/cli/set_name_servers.yaml
@@ -0,0 +1,16 @@
+---
+- debug: msg="START cli/set_name_servers.yaml"
+
+- include: "{{ role_path }}/tests/ios/set_name_servers.yaml"
+ when: hostvars[inventory_hostname]['ansible_network_os'] == 'ios'
+
+- include: "{{ role_path }}/tests/iosxr/set_name_servers.yaml"
+ when: hostvars[inventory_hostname]['ansible_network_os'] == 'iosxr'
+
+- include: "{{ role_path }}/tests/nxos/set_name_servers.yaml"
+ when: hostvars[inventory_hostname]['ansible_network_os'] == 'nxos'
+
+- include: "{{ role_path }}/tests/eos/set_name_servers.yaml"
+ when: hostvars[inventory_hostname]['ansible_network_os'] == 'eos'
+
+- debug: msg="END cli/set_name_servers.yaml"
diff --git a/test/integration/targets/net_system/tests/eos/set_name_servers.yaml b/test/integration/targets/net_system/tests/eos/set_name_servers.yaml
new file mode 100644
index 0000000000..4cb1b51602
--- /dev/null
+++ b/test/integration/targets/net_system/tests/eos/set_name_servers.yaml
@@ -0,0 +1,64 @@
+---
+- debug: msg="START eos/set_name_servers.yaml"
+
+- name: setup
+ eos_config:
+ lines:
+ - no ip name-server
+ - vrf definition ansible
+ match: none
+ provider: "{{ cli }}"
+
+- name: configure name_servers
+ net_system:
+ name_servers:
+ - 1.1.1.1
+ - 2.2.2.2
+ - 3.3.3.3
+ provider: "{{ cli }}"
+ register: result
+
+- assert:
+ that:
+ - result.changed == true
+ - result.commands|length == 3
+ - "'ip name-server 1.1.1.1' in result.commands"
+ - "'ip name-server 2.2.2.2' in result.commands"
+ - "'ip name-server 3.3.3.3' in result.commands"
+
+- name: verify name_servers
+ net_system:
+ name_servers:
+ - 1.1.1.1
+ - 2.2.2.2
+ - 3.3.3.3
+ provider: "{{ cli }}"
+ register: result
+
+- assert:
+ that:
+ - result.changed == false
+
+- name: remove one
+ net_system:
+ name_servers:
+ - 1.1.1.1
+ - 2.2.2.2
+ provider: "{{ cli }}"
+ register: result
+
+- assert:
+ that:
+ - result.changed == true
+ - result.commands|length == 1
+ - "'no ip name-server 3.3.3.3' in result.commands"
+
+- name: teardown
+ eos_config:
+ lines:
+ - no ip domain lookup source-interface
+ - no vrf definition ansible
+ match: none
+ provider: "{{ cli }}"
+
+- debug: msg="END eos/set_name_servers.yaml"
diff --git a/test/integration/targets/net_system/tests/ios/set_name_servers.yaml b/test/integration/targets/net_system/tests/ios/set_name_servers.yaml
new file mode 100644
index 0000000000..c355a1e233
--- /dev/null
+++ b/test/integration/targets/net_system/tests/ios/set_name_servers.yaml
@@ -0,0 +1,67 @@
+---
+- debug: msg="START ios/set_name_servers.yaml"
+
+- name: setup
+ ios_config:
+ lines:
+ - no ip name-server
+ match: none
+ authorize: yes
+ provider: "{{ cli }}"
+
+- name: configure name_servers
+ net_system:
+ name_servers:
+ - 1.1.1.1
+ - 2.2.2.2
+ - 3.3.3.3
+ authorize: yes
+ provider: "{{ cli }}"
+ register: result
+
+- assert:
+ that:
+ - result.changed == true
+ - result.commands|length == 3
+ - "'ip name-server 1.1.1.1' in result.commands"
+ - "'ip name-server 2.2.2.2' in result.commands"
+ - "'ip name-server 3.3.3.3' in result.commands"
+
+- name: verify name_servers
+ net_system:
+ name_servers:
+ - 1.1.1.1
+ - 2.2.2.2
+ - 3.3.3.3
+ authorize: yes
+ provider: "{{ cli }}"
+ register: result
+
+- assert:
+ that:
+ - result.changed == false
+
+- name: remove one
+ net_system:
+ name_servers:
+ - 1.1.1.1
+ - 2.2.2.2
+ authorize: yes
+ provider: "{{ cli }}"
+ register: result
+
+- assert:
+ that:
+ - result.changed == true
+ - result.commands|length == 1
+ - "'no ip name-server 3.3.3.3' in result.commands"
+
+- name: teardown
+ ios_config:
+ lines:
+ - no ip domain lookup source-interface
+ match: none
+ authorize: yes
+ provider: "{{ cli }}"
+
+- debug: msg="END ios/set_name_servers.yaml"
diff --git a/test/integration/targets/net_system/tests/iosxr/set_name_servers.yaml b/test/integration/targets/net_system/tests/iosxr/set_name_servers.yaml
new file mode 100644
index 0000000000..c8103f4bb1
--- /dev/null
+++ b/test/integration/targets/net_system/tests/iosxr/set_name_servers.yaml
@@ -0,0 +1,59 @@
+---
+- debug: msg="START iosxr/set_name_servers.yaml"
+
+- name: setup
+ iosxr_config:
+ lines:
+ - no ip name-server 1.1.1.1
+ - no ip name-server 2.2.2.2
+ - no ip name-server 3.3.3.3
+ match: none
+ provider: "{{ cli }}"
+
+- name: configure name_servers
+ net_system:
+ name_servers:
+ - 1.1.1.1
+ - 2.2.2.2
+ - 3.3.3.3
+ provider: "{{ cli }}"
+ register: result
+
+- assert:
+ that:
+ - result.changed == true
+ - result.commands|length == 3
+ - "'domain name-server 1.1.1.1' in result.commands"
+ - "'domain name-server 2.2.2.2' in result.commands"
+ - "'domain name-server 3.3.3.3' in result.commands"
+
+- name: verify name_servers
+ net_system:
+ name_servers:
+ - 1.1.1.1
+ - 2.2.2.2
+ - 3.3.3.3
+ provider: "{{ cli }}"
+ register: result
+
+- assert:
+ that:
+ - result.changed == false
+
+- name: remove one
+ net_system:
+ name_servers:
+ - 1.1.1.1
+ - 2.2.2.2
+ provider: "{{ cli }}"
+ register: result
+
+- assert:
+ that:
+ - result.changed == true
+ - result.commands|length == 1
+ - "'no domain name-server 3.3.3.3' in result.commands"
+
+# FIXME: No teardown
+#
+- debug: msg="END iosxr/set_name_servers.yaml"
diff --git a/test/integration/targets/net_system/tests/nxos/set_name_servers.yaml b/test/integration/targets/net_system/tests/nxos/set_name_servers.yaml
new file mode 100644
index 0000000000..1e0e9e6ebf
--- /dev/null
+++ b/test/integration/targets/net_system/tests/nxos/set_name_servers.yaml
@@ -0,0 +1,66 @@
+---
+- debug: msg="START nxos/set_name_servers.yaml"
+
+- name: setup
+ nxos_config:
+ lines:
+ - no ip name-server 1.1.1.1
+ - no ip name-server 2.2.2.2
+ - no ip name-server 3.3.3.3
+ match: none
+ provider: "{{ cli }}"
+
+- name: configure name_servers
+ nxos_system:
+ name_servers:
+ - 1.1.1.1
+ - 2.2.2.2
+ - 3.3.3.3
+ provider: "{{ cli }}"
+ register: result
+
+- assert:
+ that:
+ - result.changed == true
+ - result.commands|length == 3
+ - "'ip name-server 1.1.1.1' in result.commands"
+ - "'ip name-server 2.2.2.2' in result.commands"
+ - "'ip name-server 3.3.3.3' in result.commands"
+
+- name: verify name_servers
+ nxos_system:
+ name_servers:
+ - 1.1.1.1
+ - 2.2.2.2
+ - 3.3.3.3
+ provider: "{{ cli }}"
+ register: result
+
+- assert:
+ that:
+ - result.changed == false
+
+- name: remove one
+ nxos_system:
+ name_servers:
+ - 1.1.1.1
+ - 2.2.2.2
+ provider: "{{ cli }}"
+ register: result
+
+- assert:
+ that:
+ - result.changed == true
+ - result.commands|length == 1
+ - "'no ip name-server 3.3.3.3' in result.commands"
+
+- name: teardown
+ nxos_config:
+ lines:
+ - no ip lookup source-interface
+ match: none
+ provider: "{{ cli }}"
+ ignore_errors: yes
+ # FIXME Copied from iosxr, not sure what we need here
+
+- debug: msg="END nxos/set_name_servers.yaml"