summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--changelogs/fragments/config_confirm.yml3
-rw-r--r--plugins/cliconf/vyos.py23
-rw-r--r--plugins/module_utils/network/vyos/vyos.py6
-rw-r--r--plugins/modules/vyos_config.py33
-rw-r--r--tests/integration/targets/vyos_config/tests/cli/confirm.yaml44
-rw-r--r--tests/unit/modules/network/vyos/test_vyos_config.py38
6 files changed, 137 insertions, 10 deletions
diff --git a/changelogs/fragments/config_confirm.yml b/changelogs/fragments/config_confirm.yml
new file mode 100644
index 00000000..7c0565af
--- /dev/null
+++ b/changelogs/fragments/config_confirm.yml
@@ -0,0 +1,3 @@
+---
+minor_changes:
+ - vyos_config - add support for commit-confirm workflows (automatic/manual) including configurable timeout
diff --git a/plugins/cliconf/vyos.py b/plugins/cliconf/vyos.py
index c35ff1ec..17fcdf24 100644
--- a/plugins/cliconf/vyos.py
+++ b/plugins/cliconf/vyos.py
@@ -122,7 +122,9 @@ class Cliconf(CliconfBase):
out = self.send_command(command)
return out
- def edit_config(self, candidate=None, commit=True, replace=None, comment=None):
+ def edit_config(
+ self, candidate=None, commit=True, replace=None, diff=False, comment=None, confirm=None
+ ):
resp = {}
operations = self.get_device_operations()
self.check_edit_config_capability(operations, candidate, commit, replace, comment)
@@ -143,7 +145,7 @@ class Cliconf(CliconfBase):
if diff_config:
if commit:
try:
- self.commit(comment)
+ self.commit(comment, confirm)
except AnsibleConnectionFailure as e:
msg = "commit failed: %s" % e.message
self.discard_changes()
@@ -191,12 +193,19 @@ class Cliconf(CliconfBase):
check_all=check_all,
)
- def commit(self, comment=None):
- if comment:
- command = 'commit comment "{0}"'.format(comment)
+ def commit(self, comment=None, confirm=None):
+ if confirm:
+ if comment:
+ command = 'commit-confirm {0} comment "{1}"'.format(confirm, comment)
+ else:
+ command = 'commit-confirm {0}'.format(confirm)
+ self.send_command(command, "Proceed?", "\n")
else:
- command = "commit"
- self.send_command(command)
+ if comment:
+ command = 'commit comment "{0}"'.format(comment)
+ else:
+ command = "commit"
+ self.send_command(command)
def discard_changes(self):
self.send_command("exit discard")
diff --git a/plugins/module_utils/network/vyos/vyos.py b/plugins/module_utils/network/vyos/vyos.py
index 6bd8daee..4987d6b0 100644
--- a/plugins/module_utils/network/vyos/vyos.py
+++ b/plugins/module_utils/network/vyos/vyos.py
@@ -96,11 +96,13 @@ def run_commands(module, commands, check_rc=True):
return response
-def load_config(module, commands, commit=False, comment=None):
+def load_config(module, commands, commit=False, comment=None, confirm=None):
connection = get_connection(module)
try:
- response = connection.edit_config(candidate=commands, commit=commit, comment=comment)
+ response = connection.edit_config(
+ candidate=commands, commit=commit, comment=comment, confirm=confirm
+ )
except ConnectionError as exc:
module.fail_json(msg=to_text(exc, errors="surrogate_then_replace"))
diff --git a/plugins/modules/vyos_config.py b/plugins/modules/vyos_config.py
index eeb6bc44..a9774638 100644
--- a/plugins/modules/vyos_config.py
+++ b/plugins/modules/vyos_config.py
@@ -84,6 +84,25 @@ options:
is ignored.
default: configured by vyos_config
type: str
+ confirm:
+ description:
+ - The C(confirm) argument will tell vyos to revert to the previous configuration
+ if not explicitly confirmed after applying the new config. When set to C(automatic)
+ this module will automatically confirm the configuration, if the current session
+ remains working with the new config. When set to C(manual), this module does
+ not issue the confirmation itself.
+ type: str
+ default: none
+ choices:
+ - automatic
+ - manual
+ - none
+ confirm_timeout:
+ description:
+ - Minutes to wait for confirmation before reverting the configuration. Does
+ not apply when C(confirm) is set to C(none) .
+ type: int
+ default: 10
config:
description:
- The C(config) argument specifies the base configuration to use to compare against
@@ -142,6 +161,11 @@ EXAMPLES = """
vyos.vyos.vyos_config:
src: vyos_template.j2
+- name: revert after ten minutes, if connection is lost
+ vyos.vyos.vyos_config:
+ src: vyos_template.j2
+ confirm: automatic
+
- name: for idempotency, use full-form commands
vyos.vyos.vyos_config:
lines:
@@ -310,10 +334,15 @@ def run(module, result):
commit = not module.check_mode
comment = module.params["comment"]
+ confirm = None
+ if module.params["confirm"] == "automatic" or module.params["confirm"] == "manual":
+ confirm = module.params["confirm_timeout"]
diff = None
if commands:
- diff = load_config(module, commands, commit=commit, comment=comment)
+ diff = load_config(module, commands, commit=commit, comment=comment, confirm=confirm)
+ if module.params["confirm"] == "automatic":
+ run_commands(module, ["configure", "confirm", "exit"])
if result.get("filtered"):
result["warnings"].append(
@@ -333,6 +362,8 @@ def main():
lines=dict(type="list", elements="str"),
match=dict(default="line", choices=["line", "none"]),
comment=dict(default=DEFAULT_COMMENT),
+ confirm=dict(choices=["automatic", "manual", "none"], default='none'),
+ confirm_timeout=dict(type="int", default=10),
config=dict(),
backup=dict(type="bool", default=False),
backup_options=dict(type="dict", options=backup_spec),
diff --git a/tests/integration/targets/vyos_config/tests/cli/confirm.yaml b/tests/integration/targets/vyos_config/tests/cli/confirm.yaml
new file mode 100644
index 00000000..73674a17
--- /dev/null
+++ b/tests/integration/targets/vyos_config/tests/cli/confirm.yaml
@@ -0,0 +1,44 @@
+---
+- debug: msg="START cli/confirm.yaml on connection={{ ansible_connection }}"
+
+- name: setup
+ vyos.vyos.vyos_config:
+ lines: set system host-name {{ inventory_hostname_short }}
+ match: none
+
+- name: configure with confirm (manual)
+ register: result
+ vyos.vyos.vyos_config:
+ lines: set system host-name foo
+ comment: confirm manual test
+ confirm: manual
+ confirm_timeout: 1
+
+- assert:
+ that:
+ - result.changed == true
+ - "'set system host-name foo' in result.commands"
+
+- name: verify hostname changed to foo
+ register: hostname_after
+ vyos.vyos.vyos_command:
+ commands: show host name
+
+- assert:
+ that:
+ - "'foo' in hostname_after.stdout[0]"
+
+- name: wait until config auto-reverts (no confirmation)
+ register: hostname_reverted
+ vyos.vyos.vyos_command:
+ commands: show host name
+ retries: 18
+ delay: 5
+ until: inventory_hostname_short in hostname_reverted.stdout[0]
+
+- name: teardown
+ vyos.vyos.vyos_config:
+ lines: set system host-name {{ inventory_hostname_short }}
+ match: none
+
+- debug: msg="END cli/confirm.yaml on connection={{ ansible_connection }}"
diff --git a/tests/unit/modules/network/vyos/test_vyos_config.py b/tests/unit/modules/network/vyos/test_vyos_config.py
index 4f1cac6a..601971cd 100644
--- a/tests/unit/modules/network/vyos/test_vyos_config.py
+++ b/tests/unit/modules/network/vyos/test_vyos_config.py
@@ -140,3 +140,41 @@ class TestVyosConfigModule(TestVyosModule):
return_value=self.cliconf_obj.get_diff(candidate, None, diff_match="none"),
)
self.execute_module(changed=True, commands=lines, sort=False)
+
+ def test_vyos_config_confirm_automatic(self):
+ src = load_fixture("vyos_config_src.cfg")
+ confirm_timeout = 7
+ set_module_args(dict(src=src, confirm="automatic", confirm_timeout=confirm_timeout))
+ candidate = "\n".join(self.module.format_commands(src.splitlines()))
+ commands = [
+ "set system host-name foo",
+ "delete interfaces ethernet eth0 address",
+ ]
+ self.conn.get_diff = MagicMock(
+ return_value=self.cliconf_obj.get_diff(candidate, self.running_config),
+ )
+
+ self.execute_module(changed=True, commands=commands)
+
+ self.assertEqual(self.load_config.call_args[1]["confirm"], confirm_timeout)
+ self.run_commands.assert_called_once()
+ self.assertEqual(
+ ["configure", "confirm", "exit"],
+ self.run_commands.call_args[0][1],
+ )
+
+ def test_vyos_config_confirm_manual(self):
+ lines = [
+ "set system host-name foo",
+ ]
+ confirm_timeout = 12
+ set_module_args(dict(lines=lines, confirm="manual", confirm_timeout=confirm_timeout))
+ candidate = "\n".join(lines)
+ self.conn.get_diff = MagicMock(
+ return_value=self.cliconf_obj.get_diff(candidate, self.running_config),
+ )
+
+ self.execute_module(changed=True, commands=lines)
+
+ self.assertEqual(self.load_config.call_args[1]["confirm"], confirm_timeout)
+ self.run_commands.assert_not_called()