summaryrefslogtreecommitdiff
path: root/plugins/cliconf/vyos.py
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/cliconf/vyos.py')
-rw-r--r--plugins/cliconf/vyos.py82
1 files changed, 76 insertions, 6 deletions
diff --git a/plugins/cliconf/vyos.py b/plugins/cliconf/vyos.py
index 96c24c15..e693f820 100644
--- a/plugins/cliconf/vyos.py
+++ b/plugins/cliconf/vyos.py
@@ -17,6 +17,7 @@
#
from __future__ import absolute_import, division, print_function
+
__metaclass__ = type
DOCUMENTATION = """
@@ -48,11 +49,13 @@ import re
from ansible.errors import AnsibleConnectionFailure
from ansible.module_utils._text import to_text
from ansible.module_utils.common._collections_compat import Mapping
+from ansible.plugins.cliconf import CliconfBase
from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.config import (
NetworkConfig,
)
from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.utils import to_list
-from ansible_collections.ansible.netcommon.plugins.plugin_utils.cliconf_base import CliconfBase
+
+from ansible_collections.vyos.vyos.plugins.cliconf_utils.vyosconf import VyosConf
class Cliconf(CliconfBase):
@@ -122,7 +125,13 @@ class Cliconf(CliconfBase):
return out
def edit_config(
- self, candidate=None, commit=True, replace=None, diff=False, comment=None, confirm=None
+ self,
+ candidate=None,
+ commit=True,
+ replace=None,
+ diff=False,
+ comment=None,
+ confirm=None,
):
resp = {}
operations = self.get_device_operations()
@@ -240,14 +249,21 @@ class Cliconf(CliconfBase):
if path:
raise ValueError("'path' in diff is not supported")
- set_format = candidate.startswith("set") or candidate.startswith("delete")
+ first_line = next(
+ (
+ stripped
+ for stripped in (line.strip() for line in candidate.splitlines())
+ if stripped and not stripped.startswith("#")
+ ),
+ "",
+ )
+ set_format = first_line.startswith("set") or first_line.startswith("delete")
candidate_obj = NetworkConfig(indent=4, contents=candidate)
if not set_format:
config = [c.line for c in candidate_obj.items]
commands = list()
- # this filters out less specific lines
for item in config:
for index, entry in enumerate(commands):
if item.startswith(entry):
@@ -259,11 +275,65 @@ class Cliconf(CliconfBase):
else:
- candidate_commands = str(candidate).strip().split("\n")
+ candidate_commands = [
+ line.strip()
+ for line in str(candidate).splitlines()
+ if line.strip() and not line.lstrip().startswith("#")
+ ]
if diff_match == "none":
diff["config_diff"] = list(candidate_commands)
return diff
+ if diff_match == "enforce":
+ if running is None:
+ raise ValueError(
+ "diff_match=enforce requires a running configuration to diff against",
+ )
+
+ enforce_candidate_lines = list(candidate_commands)
+
+ if not enforce_candidate_lines:
+ raise ValueError(
+ "diff_match=enforce received an empty candidate (after stripping blank/"
+ "comment lines); refusing to treat that as a desired end-state of "
+ "'delete everything'. Provide 'set' commands describing the desired "
+ "configuration.",
+ )
+
+ for line in enforce_candidate_lines:
+ tokens = line.strip().split()
+ if tokens[0] != "set":
+ raise ValueError(
+ "diff_match=enforce treats the candidate as the complete desired "
+ "configuration end-state and only supports 'set' commands; "
+ "line does not start with 'set' (found: {0!r})".format(
+ line.strip(),
+ ),
+ )
+ if len(VyosConf().parse_line(line)[1]) < 1:
+ raise ValueError(
+ "diff_match=enforce only supports complete 'set' commands with at least "
+ "a path and a leaf; got: {0!r}".format(line.strip()),
+ )
+ running_conf = VyosConf(
+ [
+ line
+ for line in running.splitlines()
+ if line.strip() and not line.lstrip().startswith("#")
+ ],
+ )
+
+ candidate_conf = VyosConf(enforce_candidate_lines)
+ diff["config_diff"] = running_conf.diff_commands_to(candidate_conf)
+ for cmd in diff["config_diff"]:
+ if re.match(r"^delete\s+service\s+ssh\b", cmd):
+ raise ValueError(
+ "diff_match=enforce refuses to generate 'delete service ssh ...' "
+ "commands, since this could sever the management connection. "
+ "Remove SSH configuration explicitly with a separate match=line "
+ "or match=none task instead.",
+ )
+ return diff
running_commands = [str(c).replace("'", "") for c in running.splitlines()]
@@ -336,7 +406,7 @@ class Cliconf(CliconfBase):
def get_option_values(self):
return {
"format": ["text", "set"],
- "diff_match": ["line", "none"],
+ "diff_match": ["line", "enforce", "none"],
"diff_replace": [],
"output": [],
}