Skip to content

Commit

Permalink
ios_user_global - Take in count no username question
Browse files Browse the repository at this point in the history
Currently, on IOS devices, when you enter a `no username` command, the
system request you a question to confirm the suppression.

To handle this part, I have done some change:
- I have "created" the module IosNetworkTemplate, a override class of
  NetworkTemplate that take care the case of commands with a specific
  prompt
- The ios_user_global module use this class for the User_globalTemplate

I have done this part in a super class to allow other template module to
use this possibility.

I don't have done a super class for the assert function in tests module.
If you want, I can try to do it also.
  • Loading branch information
earendilfr committed Aug 17, 2023
1 parent fc60ee7 commit 6d52861
Show file tree
Hide file tree
Showing 3 changed files with 71 additions and 8 deletions.
57 changes: 57 additions & 0 deletions plugins/module_utils/network/ios/rm_templates/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
# -*- coding: utf-8 -*-
# Copyright 2023 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 User_global 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 copy import deepcopy

from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.rm_base.network_template import (
NetworkTemplate,
)


class IosNetworkTemplate(NetworkTemplate):
def __init__(self, lines=None, tmplt=None, prefix=None, module=None):
super(IosNetworkTemplate, self).__init__(lines=lines, tmplt=tmplt, prefix=prefix, module=module)

def _render(self, tmplt, data, negate):
if isinstance(tmplt, dict) and "command" in tmplt:
res = deepcopy(tmplt)
try:
if callable(res["command"]):
res["command"] = res["command"](data)
else:
res["command"] = self._template(value=res["command"], variables=data, fail_on_undefined=False)
except KeyError:
return None

if res:
if negate:
rem = "{0} ".format(self._prefix.get("remove", "no"))
if isinstance(res["command"], list):
res["command"] = list(map(rem,res["command"]))
else:
res["command"] = rem + res["command"]
return res
else:
set_cmd = "{0} ".format(self._prefix.get("set", ""))
if isinstance(res["command"], list):
res["command"] = list(map(set_cmd,res["command"]))
else:
res["command"] = set_cmd + res["command"]
return res
return super(IosNetworkTemplate, self)._render(tmplt, data, negate)

14 changes: 10 additions & 4 deletions plugins/module_utils/network/ios/rm_templates/user_global.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,14 @@

import re

from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.rm_base.network_template import (
NetworkTemplate,
from ansible_collections.cisco.ios.plugins.module_utils.network.ios.rm_templates import (
IosNetworkTemplate,
)


class User_globalTemplate(NetworkTemplate):
class User_globalTemplate(IosNetworkTemplate):
def __init__(self, lines=None, module=None):
super(User_globalTemplate, self).__init__(lines=lines, tmplt=self, module=module)
super(IosNetworkTemplate, self).__init__(lines=lines, tmplt=self, module=module)

# fmt: off
PARSERS = [
Expand Down Expand Up @@ -76,6 +76,12 @@ def __init__(self, lines=None, module=None):
(\s(?P<value>\S+))?
""", re.VERBOSE,
),
"remval": {
"command": "username {{ name }}",
"prompt": "This operation will remove all username related configurations with same name",
"answer": "y",
"newline": False,
},
"setval": "username {{ name }}"
"{{ ' privilege ' + privilege|string if privilege is defined and 0 <= privilege|int <= 15 and privilege|int != 1 else '' }}"
"{% if 'type' in password and password.type == 'password' %}"
Expand Down
8 changes: 4 additions & 4 deletions tests/unit/modules/network/ios/test_ios_user_global.py
Original file line number Diff line number Diff line change
Expand Up @@ -138,13 +138,13 @@ def test_ios_user_global_deleted(self):
)
playbook = {"config": {}}
deleted = [
"no username johndoe secret 5 $5$cAYu$0he5yPyPAbXoXo6U0fjzb4NbLLyqDRehwQU3ysKEC33",
"no username johndoe",
]
playbook["state"] = "deleted"
set_module_args(playbook)
self.maxDiff = None
result = self.execute_module(changed=True)
self.assertEqual(sorted(result["commands"]), sorted(deleted))
self.assertEqual(sorted(list(map(lambda x: x["command"] if isinstance(x, dict) and "command" in x else x, result["commands"]))), sorted(deleted))

def test_ios_user_global_overridden(self):
self.execute_show_command.return_value = dedent(
Expand Down Expand Up @@ -178,13 +178,13 @@ def test_ios_user_global_overridden(self):
}
overridden = [
"enable secret 9 $9$q3zuC3f3vjWnWk$4BwPgPt25AUkm8Gts6aqW.NLK/90zBDnmWtOeMQqoDo",
"no username johndoe secret 5 $5$cAYu$0he5yPyPAbXoXo6U0fjzb4NbLLyqDRehwQU3ysKEC33",
"no username johndoe",
"username admin secret 9 $9$oV7t.SyAkhiemE$D7GYIpVS/IOc0c15ev/n3p4Wo509XwQpPfyL1fuC5Dg",
]
playbook["state"] = "overridden"
set_module_args(playbook)
result = self.execute_module(changed=True)
self.assertEqual(sorted(result["commands"]), sorted(overridden))
self.assertEqual(sorted(list(map(lambda x: x["command"] if isinstance(x, dict) and "command" in x else x, result["commands"]))), sorted(overridden))

def test_ios_user_global_overridden_idempotent(self):
self.execute_show_command.return_value = dedent(
Expand Down

0 comments on commit 6d52861

Please sign in to comment.