diff --git a/changelogs/fragments/ios_service_fix.yml b/changelogs/fragments/ios_service_fix.yml
new file mode 100644
index 000000000..3ec24d6a9
--- /dev/null
+++ b/changelogs/fragments/ios_service_fix.yml
@@ -0,0 +1,4 @@
+---
+bugfixes:
+ - ios_service - Fix timestamps attribute, to generate right configuration.
+ - ios_service - Add tcp_small_servers and udp_small_servers attributes, to generate configuration.
diff --git a/docs/cisco.ios.ios_service_module.rst b/docs/cisco.ios.ios_service_module.rst
index ed859129d..a2d5eef38 100644
--- a/docs/cisco.ios.ios_service_module.rst
+++ b/docs/cisco.ios.ios_service_module.rst
@@ -45,7 +45,7 @@ Parameters
|
- A dictionnary of service configuration
+ A dictionary of service configuration
|
@@ -658,7 +658,7 @@ Parameters
|
- TCP and UDP small servers are servers (daemons, in Unix parlance) that run in the router which are useful for diagnostics.
+ TCP small servers are servers (daemons, in Unix parlance) that run in the router which are useful for diagnostics.
|
@@ -690,14 +690,35 @@ Parameters
max_servers
- string
+ integer
|
Set number of allowable TCP small servers
- 1 to 2147483647 or no-limit
+ 1 to 2147483647
+ |
+
+
+ |
+ |
+
+
+ no_limit
+
+
+ boolean
+
+ |
+
+
+ |
+
+ No limit on number of allowable TCP small servers
|
@@ -921,7 +942,7 @@ Parameters
|
- TCP and UDP small servers are servers (daemons, in Unix parlance) that run in the router which are useful for diagnostics.
+ UDP small servers are servers (daemons, in Unix parlance) that run in the router which are useful for diagnostics.
|
@@ -953,14 +974,35 @@ Parameters
max_servers
- string
+ integer
|
- Set number of allowable TCP small servers
- 1 to 2147483647 or no-limit
+ Set number of allowable UDP small servers
+ 1 to 2147483647
+ |
+
+
+ |
+ |
+
+
+ no_limit
+
+
+ boolean
+
+ |
+
+
+ |
+
+ No limit on number of allowable UDP small servers
|
@@ -1036,7 +1078,7 @@ Notes
-----
.. note::
- - Tested against Cisco IOSXE Version 16.9
+ - Tested against Cisco IOSXE Version 17.9.1a on CML.
- This module works with connection ``network_cli``. See https://docs.ansible.com/ansible/latest/network/user_guide/platform_ios.html
@@ -1556,3 +1598,4 @@ Authors
~~~~~~~
- Ambroise Rosset (@earendilfr)
+- Sagar Paul (@KB-perByte)
diff --git a/plugins/module_utils/network/ios/argspec/service/service.py b/plugins/module_utils/network/ios/argspec/service/service.py
index 238fc64a2..647eeb3d2 100644
--- a/plugins/module_utils/network/ios/argspec/service/service.py
+++ b/plugins/module_utils/network/ios/argspec/service/service.py
@@ -68,7 +68,8 @@ class ServiceArgs(object): # pylint: disable=R0903
"tcp_small_servers": {
"options": {
"enable": {"type": "bool"},
- "max_servers": {"type": "str"},
+ "max_servers": {"type": "int"},
+ "no_limit": {"type": "bool"},
},
"type": "dict",
},
@@ -97,7 +98,8 @@ class ServiceArgs(object): # pylint: disable=R0903
"udp_small_servers": {
"options": {
"enable": {"type": "bool"},
- "max_servers": {"type": "str"},
+ "max_servers": {"type": "int"},
+ "no_limit": {"type": "bool"},
},
"type": "dict",
},
diff --git a/plugins/module_utils/network/ios/config/service/service.py b/plugins/module_utils/network/ios/config/service/service.py
index 6a4c8a1ff..603e1060b 100644
--- a/plugins/module_utils/network/ios/config/service/service.py
+++ b/plugins/module_utils/network/ios/config/service/service.py
@@ -75,7 +75,9 @@ def __init__(self, module):
"slave_log",
"tcp_keepalives_in",
"tcp_keepalives_out",
+ "tcp_small_servers",
"telnet_zeroidle",
+ "udp_small_servers",
"unsupported_transceiver",
]
@@ -138,9 +140,9 @@ def _compare_lists_attrs(self, want, have):
for key, wanting in iteritems(i_want):
haveing = i_have.pop(key, {})
if wanting != haveing:
- self.addcmd(wanting, "timestamps")
+ self.addcmd(wanting, key + "_timestamps", False)
for key, haveing in iteritems(i_have):
- self.addcmd(haveing, "timestamps", negate=True)
+ self.addcmd(haveing, key + "_timestamps", negate=True)
def _service_list_to_dict(self, data):
"""Convert all list of dicts to dicts of dicts"""
diff --git a/plugins/module_utils/network/ios/facts/service/service.py b/plugins/module_utils/network/ios/facts/service/service.py
index df2dcf993..6ada10748 100644
--- a/plugins/module_utils/network/ios/facts/service/service.py
+++ b/plugins/module_utils/network/ios/facts/service/service.py
@@ -33,7 +33,7 @@ def __init__(self, module, subspec="config", options="options"):
self.argument_spec = ServiceArgs.argument_spec
def get_service_data(self, connection):
- return connection.get("show running-config all | section ^service ")
+ return connection.get("show running-config all | section ^service")
def populate_facts(self, connection, ansible_facts, data=None):
"""Populate the facts for Service network resource
@@ -59,7 +59,11 @@ def populate_facts(self, connection, ansible_facts, data=None):
ansible_facts["ansible_network_resources"].pop("service", None)
params = utils.remove_empties(
- service_parser.validate_config(self.argument_spec, {"config": objs}, redact=True),
+ service_parser.validate_config(
+ self.argument_spec,
+ {"config": objs},
+ redact=True,
+ ),
)
facts["service"] = params.get("config", {})
diff --git a/plugins/module_utils/network/ios/rm_templates/service.py b/plugins/module_utils/network/ios/rm_templates/service.py
index 992892db8..c81593226 100644
--- a/plugins/module_utils/network/ios/rm_templates/service.py
+++ b/plugins/module_utils/network/ios/rm_templates/service.py
@@ -22,6 +22,21 @@
)
+def handleTimestamp(config_data):
+ command = "service timestamps"
+ command += " " + config_data.get("msg") if config_data.get("msg") else ""
+ command += " " + config_data.get("timestamp") if config_data.get("timestamp") else ""
+
+ if config_data.get("datetime_options"):
+ datetime_op = config_data.get("datetime_options")
+ command += " mesc" if datetime_op.get("msec") else ""
+ command += " localtime" if datetime_op.get("localtime") else ""
+ command += " show-timezone" if datetime_op.get("show_timezone") else ""
+ command += " year" if datetime_op.get("year") else ""
+
+ return command
+
+
class ServiceTemplate(NetworkTemplate):
def __init__(self, lines=None, module=None):
super(ServiceTemplate, self).__init__(lines=lines, tmplt=self, module=module)
@@ -32,36 +47,36 @@ def __init__(self, lines=None, module=None):
"name": "call_home",
"getval": re.compile(
r"""
- ^service\s(?Pcall-home)
+ ^service\scall-home
""", re.VERBOSE,
),
"setval": "service call-home",
"result": {
- "call_home": "{{ not not call_home }}",
+ "call_home": True,
},
},
{
"name": "compress_config",
"getval": re.compile(
r"""
- ^service\s(?Pcompress-config)
+ ^service\scompress-config
""", re.VERBOSE,
),
"setval": "service compress-config",
"result": {
- "compress_config": "{{ not not compress_config }}",
+ "compress_config": True,
},
},
{
"name": "config",
"getval": re.compile(
r"""
- ^service\s(?Pconfig)
+ ^service\sconfig
""", re.VERBOSE,
),
"setval": "service config",
"result": {
- "config": "{{ not not config }}",
+ "config": True,
},
},
{
@@ -92,120 +107,120 @@ def __init__(self, lines=None, module=None):
"name": "disable_ip_fast_frag",
"getval": re.compile(
r"""
- ^service\s(?Pdisable-ip-fast-frag)
+ ^service\sdisable-ip-fast-frag
""", re.VERBOSE,
),
"setval": "service disable-ip-fast-frag",
"result": {
- "disable_ip_fast_frag": "{{ not not disable_ip_fast_frag }}",
+ "disable_ip_fast_frag": True,
},
},
{
"name": "exec_callback",
"getval": re.compile(
r"""
- ^service\s(?Pexec-callback)
+ ^service\sexec-callback
""", re.VERBOSE,
),
"setval": "service exec-callback",
"result": {
- "exec_callback": "{{ not not exec_callback }}",
+ "exec_callback": True,
},
},
{
"name": "exec_wait",
"getval": re.compile(
r"""
- ^service\s(?Pexec-wait)
+ ^service\sexec-wait
""", re.VERBOSE,
),
"setval": "service exec-wait",
"return": {
- "exec_wait": "{{ not not exec_wait }}",
+ "exec_wait": True,
},
},
{
"name": "hide_telnet_addresses",
"getval": re.compile(
r"""
- ^service\s(?Phide-telnet-addresses)
+ ^service\shide-telnet-addresses
""", re.VERBOSE,
),
"setval": "service hide-telnet-addresses",
"result": {
- "hide_telnet_addresses": "{{ not not hide_telnet_addresses }}",
+ "hide_telnet_addresses": True,
},
},
{
"name": "internal",
"getval": re.compile(
r"""
- ^service\s(?Pinternal)
+ ^service\sinternal
""", re.VERBOSE,
),
"setval": "service internal",
"result": {
- "internal": "{{ not not internal }}",
+ "internal": True,
},
},
{
"name": "linenumber",
"getval": re.compile(
r"""
- ^service\s(?Plinenumber)
+ ^service\slinenumber
""", re.VERBOSE,
),
"setval": "service linenumber",
"result": {
- "linenumber": "{{ not not linenumber }}",
+ "linenumber": True,
},
},
{
"name": "log",
"getval": re.compile(
r"""
- ^service\slog(\s(?Pbacktrace))?
+ ^service\slog\sbacktrace?
""", re.VERBOSE,
),
"setval": "service log backtrace",
"result": {
- "log": "{{ not not backtrace }}",
+ "log": True,
},
},
{
"name": "log_hidden",
"getval": re.compile(
r"""
- ^service\s(?Plog-hidden)
+ ^service\slog-hidden
""", re.VERBOSE,
),
"setval": "service log-hidden",
"result": {
- "log_hidden": "{{ not not log_hidden }}",
+ "log_hidden": True,
},
},
{
"name": "nagle",
"getval": re.compile(
r"""
- ^service\s(?Pnagle)
+ ^service\snagle
""", re.VERBOSE,
),
"setval": "service nagle",
"result": {
- "nagle": "{{ not not nagle }}",
+ "nagle": True,
},
},
{
"name": "old_slip_prompts",
"getval": re.compile(
r"""
- ^service\s(?Pold-slip-prompts)
+ ^service\sold-slip-prompts
""", re.VERBOSE,
),
"setval": "service old-slip-prompts",
"result": {
- "old_slip_prompts": "{{ not not old_slip_prompts }}",
+ "old_slip_prompts": True,
},
},
{
@@ -260,12 +275,12 @@ def __init__(self, lines=None, module=None):
"name": "password_encryption",
"getval": re.compile(
r"""
- ^service\s(?Ppassword-encryption)
+ ^service\spassword-encryption
""", re.VERBOSE,
),
"setval": "service password-encryption",
"result": {
- "password_encryption": "{{ not not password_encryption }}",
+ "password_encryption": True,
},
},
{
@@ -309,48 +324,48 @@ def __init__(self, lines=None, module=None):
"name": "pt_vty_logging",
"getval": re.compile(
r"""
- ^service\s(?Ppt-vty-logging)
+ ^service\spt-vty-logging
""", re.VERBOSE,
),
"setval": "service pt-vty-logging",
"result": {
- "pt_vty_logging": "{{ not not pt_vty_logging }}",
+ "pt_vty_logging": True,
},
},
{
"name": "scripting",
"getval": re.compile(
r"""
- ^service\s(?Pscripting)
+ ^service\sscripting
""", re.VERBOSE,
),
"setval": "service scripting",
"result": {
- "scripting": "{{ not not scripting }}",
+ "scripting": True,
},
},
{
"name": "sequence_numbers",
"getval": re.compile(
r"""
- ^service\s(?Psequence-numbers)
+ ^service\ssequence-numbers
""", re.VERBOSE,
),
"setval": "service sequence-numbers",
"result": {
- "sequence_numbers": "{{ not not sequence_numbers }}",
+ "sequence_numbers": True,
},
},
{
"name": "slave_coredump",
"getval": re.compile(
r"""
- ^service\s(?Pslave-coredump)
+ ^service\sslave-coredump
""", re.VERBOSE,
),
"setval": "service slave-coredump",
"result": {
- "slave_coredump": "{{ not not slave_coredump }}",
+ "slave_coredump": True,
},
},
{
@@ -389,6 +404,46 @@ def __init__(self, lines=None, module=None):
"tcp_keepalives_out": True,
},
},
+ {
+ "name": "tcp_small_servers",
+ "getval": re.compile(
+ r"""
+ ^service\stcp-small-servers
+ (\s(?P\d+))?
+ (\s(?Pno-limit))?
+ """, re.VERBOSE,
+ ),
+ "setval": "service tcp-small-servers"
+ "{{ (' ' + tcp_small_servers.max_servers|string) if tcp_small_servers.max_servers is defined else '' }}"
+ "{{ (' no-limit') if tcp_small_servers.no_limit|d(False) else '' }}",
+ "result": {
+ "tcp_small_servers": {
+ "enable": True,
+ "max_servers": "{{ max_servers }}",
+ "no_limit": "{{ not not no_limit }}",
+ },
+ },
+ },
+ {
+ "name": "udp_small_servers",
+ "getval": re.compile(
+ r"""
+ ^service\sudp-small-servers
+ (\s(?P\d+))?
+ (\s(?Pno-limit))?
+ """, re.VERBOSE,
+ ),
+ "setval": "{{ ('service udp-small-servers') if udp_small_servers.enable|d(False) else '' }}"
+ "{{ (' ' + udp_small_servers.max_servers|string) if udp_small_servers.max_servers is defined else '' }}"
+ "{{ (' no-limit') if udp_small_servers.no_limit|d(False) else '' }}",
+ "result": {
+ "udp_small_servers": {
+ "enable": True,
+ "max_servers": "{{ max_servers }}",
+ "no_limit": "{{ not not no_limit }}",
+ },
+ },
+ },
{
"name": "telnet_zeroidle",
"getval": re.compile(
@@ -402,11 +457,39 @@ def __init__(self, lines=None, module=None):
},
},
{
- "name": "timestamps",
+ "name": "log_timestamps",
+ "getval": re.compile(
+ r"""
+ ^service\stimestamps\slog
+ (\s(?P\S+))?
+ (\s(?Pmsec))?
+ (\s(?Plocaltime))?
+ (\s(?Pshow-timezone))?
+ (\s(?Pyear))?
+ """, re.VERBOSE,
+ ),
+ "remval": "service timestamps log",
+ "setval": handleTimestamp,
+ "result": {
+ "timestamps": [
+ {
+ "msg": "log",
+ "timestamp": "{{ timestamp if timestamp is defined else 'uptime' }}",
+ "datetime_options": {
+ "msec": "{{ True if msec else False}}",
+ "localtime": "{{ True if localtime else False }}",
+ "show_timezone": "{{ True if show_timezone else False }}",
+ "year": "{{ True if year else False }}",
+ },
+ },
+ ],
+ },
+ },
+ {
+ "name": "debug_timestamps",
"getval": re.compile(
r"""
- ^service\stimestamps
- (\s(?P\S+))?
+ ^service\stimestamps\sdebug
(\s(?P\S+))?
(\s(?Pmsec))?
(\s(?Plocaltime))?
@@ -414,23 +497,12 @@ def __init__(self, lines=None, module=None):
(\s(?Pyear))?
""", re.VERBOSE,
),
- "remval": "service timestamps{{ (' ' + msg) if msg is defined else '' }}",
- "setval": "service timestamps"
- "{{ (' ' + msg) if msg is defined else '' }}"
- "{% if msg is defined %}"
- "{{ (' ' + timestamp) if timestamp is defined else '' }}"
- "{% if timestamp == 'datetime' and datetime_options is defined %}"
- "{{ ' msec' if datetime_options.msec else '' }}"
- "{{ ' localtime' if datetime_options.localtime else '' }}"
- "{{ ' show-timezone' if datetime_options.show_timezone else '' }}"
- "{{ ' year' if datetime_options.year else '' }}"
- "{% endif %}"
- "{% endif %}"
- "",
+ "remval": "service timestamps debug",
+ "setval": handleTimestamp,
"result": {
"timestamps": [
{
- "msg": "{{ msg if msg is defined else 'debug' }}",
+ "msg": "debug",
"timestamp": "{{ timestamp if timestamp is defined else 'uptime' }}",
"datetime_options": {
"msec": "{{ True if msec else False}}",
diff --git a/plugins/modules/ios_service.py b/plugins/modules/ios_service.py
index 46c456569..ebe0e7881 100644
--- a/plugins/modules/ios_service.py
+++ b/plugins/modules/ios_service.py
@@ -22,13 +22,14 @@
version_added: 4.6.0
author:
- Ambroise Rosset (@earendilfr)
+ - Sagar Paul (@KB-perByte)
notes:
- - Tested against Cisco IOSXE Version 16.9
+ - Tested against Cisco IOSXE Version 17.9.1a on CML.
- This module works with connection C(network_cli).
See U(https://docs.ansible.com/ansible/latest/network/user_guide/platform_ios.html)
options:
config:
- description: A dictionnary of service configuration
+ description: A dictionary of service configuration
suboptions:
call_home:
description: Cisco call-home service
@@ -128,7 +129,7 @@
type: bool
tcp_small_servers:
description:
- - TCP and UDP small servers are servers (daemons, in Unix parlance) that run in the
+ - TCP small servers are servers (daemons, in Unix parlance) that run in the
router which are useful for diagnostics.
suboptions:
enable:
@@ -137,8 +138,11 @@
max_servers:
description:
- Set number of allowable TCP small servers
- - 1 to 2147483647 or no-limit
- type: str
+ - 1 to 2147483647
+ type: int
+ no_limit:
+ description: No limit on number of allowable TCP small servers
+ type: bool
type: dict
telnet_zeroidle:
description: Set TCP window 0 when connection is idle
@@ -181,7 +185,7 @@
type: list
udp_small_servers:
description:
- - TCP and UDP small servers are servers (daemons, in Unix parlance) that run in the
+ - UDP small servers are servers (daemons, in Unix parlance) that run in the
router which are useful for diagnostics.
suboptions:
enable:
@@ -189,9 +193,12 @@
type: bool
max_servers:
description:
- - Set number of allowable TCP small servers
- - 1 to 2147483647 or no-limit
- type: str
+ - Set number of allowable UDP small servers
+ - 1 to 2147483647
+ type: int
+ no_limit:
+ description: No limit on number of allowable UDP small servers
+ type: bool
type: dict
unsupported_transceiver:
description: enable support for third-party transceivers
diff --git a/tests/unit/modules/network/ios/test_ios_service.py b/tests/unit/modules/network/ios/test_ios_service.py
index fa92efcdc..69af87eda 100644
--- a/tests/unit/modules/network/ios/test_ios_service.py
+++ b/tests/unit/modules/network/ios/test_ios_service.py
@@ -128,14 +128,13 @@ def test_ios_service_merged(self):
},
}
merged = [
- "service timestamps debug uptime",
- "service timestamps log datetime msec localtime show-timezone year",
"service password-encryption",
+ "service timestamps debug uptime mesc",
+ "service timestamps log datetime mesc localtime show-timezone year",
]
playbook["state"] = "merged"
set_module_args(playbook)
result = self.execute_module(changed=True)
-
self.assertEqual(sorted(result["commands"]), sorted(merged))
def test_ios_snm_server_deleted(self):
@@ -213,18 +212,17 @@ def test_ios_service_overridden(self):
overridden = [
"no service call-home",
"no service config",
- "no service pad",
"service counters max age 5",
+ "no service pad",
"service password-encryption",
"service tcp-keepalives-in",
"service tcp-keepalives-out",
+ "service timestamps log datetime mesc localtime show-timezone year",
"service timestamps debug datetime",
- "service timestamps log datetime msec localtime show-timezone year",
]
playbook["state"] = "overridden"
set_module_args(playbook)
result = self.execute_module(changed=True)
-
self.assertEqual(sorted(result["commands"]), sorted(overridden))
def test_ios_service_replaced(self):
@@ -258,6 +256,10 @@ def test_ios_service_replaced(self):
{
"msg": "debug",
"timestamp": "datetime",
+ "datetime_options": {
+ "localtime": True,
+ "msec": True,
+ },
},
],
"tcp_keepalives_in": True,
@@ -269,18 +271,17 @@ def test_ios_service_replaced(self):
replaced = [
"no service call-home",
"no service config",
- "no service pad",
"service counters max age 5",
+ "no service pad",
"service password-encryption",
"service tcp-keepalives-in",
"service tcp-keepalives-out",
- "service timestamps debug datetime",
- "service timestamps log datetime msec localtime show-timezone year",
+ "service timestamps log datetime mesc localtime show-timezone year",
+ "service timestamps debug datetime mesc localtime",
]
playbook["state"] = "replaced"
set_module_args(playbook)
result = self.execute_module(changed=True)
-
self.assertEqual(sorted(result["commands"]), sorted(replaced))
def test_ios_service_replaced_idempotent(self):
@@ -368,8 +369,6 @@ def test_ios_service_replaced_idempotent_old(self):
self.assertEqual(sorted(result["commands"]), sorted(replaced))
- ####################
-
def test_ios_service_parsed(self):
set_module_args(
dict(
@@ -426,36 +425,36 @@ def test_ios_service_gathered(self):
service timestamps log datetime msec localtime show-timezone year
service timestamps debug uptime
service call-home
+ service udp-small-servers
+ service tcp-small-servers no-limit
""",
)
set_module_args(dict(state="gathered"))
gathered = {
"timestamps": [
- {
- "msg": "debug",
- "timestamp": "uptime",
- },
{
"msg": "log",
"timestamp": "datetime",
"datetime_options": {
- "localtime": True,
"msec": True,
+ "localtime": True,
"show_timezone": True,
"year": True,
},
},
+ {"msg": "debug", "timestamp": "uptime"},
],
"call_home": True,
- "dhcp": True,
+ "udp_small_servers": {"enable": True},
+ "tcp_small_servers": {"enable": True, "no_limit": True},
"counters": 0,
+ "dhcp": True,
"password_recovery": True,
"prompt": True,
"slave_log": True,
}
result = self.execute_module(changed=False)
self.maxDiff = None
-
self.assertEqual(sorted(result["gathered"]), sorted(gathered))
def test_ios_service_rendered(self):
@@ -472,6 +471,9 @@ def test_ios_service_rendered(self):
{
"msg": "debug",
"timestamp": "uptime",
+ "datetime_options": {
+ "localtime": True,
+ },
},
{
"msg": "log",
@@ -497,10 +499,9 @@ def test_ios_service_rendered(self):
"service slave-log",
"service tcp-keepalives-in",
"service tcp-keepalives-out",
- "service timestamps debug uptime",
- "service timestamps log datetime msec localtime show-timezone year",
+ "service timestamps debug uptime localtime",
+ "service timestamps log datetime mesc localtime show-timezone year",
]
result = self.execute_module(changed=False)
self.maxDiff = None
-
self.assertEqual(sorted(result["rendered"]), sorted(rendered))