diff options
author | John Estabrook <jestabro@vyos.io> | 2021-08-12 11:09:58 -0500 |
---|---|---|
committer | John Estabrook <jestabro@vyos.io> | 2021-08-12 11:09:58 -0500 |
commit | d19b35d668184fdac00a8ef56ff58c0748f22816 (patch) | |
tree | 1a5de49dcba9fe12911322809715e7db399e05a5 | |
parent | e75db1c0c23bb8615dea92316148871edd18749e (diff) | |
download | vyos-1x-d19b35d668184fdac00a8ef56ff58c0748f22816.tar.gz vyos-1x-d19b35d668184fdac00a8ef56ff58c0748f22816.zip |
T3574: add constraintGroup for combining validators with logical AND
(cherry picked from commit 591b8bcadd8b6bbd46c61484193d2bf7e16bd1ae
commit 31553283aaa929da63147082e85513e8d4dacf0e
commit 59a4aadfe419eca16e6288b37d6c51acd9789903)
-rw-r--r-- | python/vyos/xml/load.py | 3 | ||||
-rw-r--r-- | schema/interface_definition.rnc | 11 | ||||
-rw-r--r-- | schema/interface_definition.rng | 21 | ||||
-rwxr-xr-x | scripts/build-command-templates | 76 |
4 files changed, 81 insertions, 30 deletions
diff --git a/python/vyos/xml/load.py b/python/vyos/xml/load.py index 0965d4220..37479c6e1 100644 --- a/python/vyos/xml/load.py +++ b/python/vyos/xml/load.py @@ -225,6 +225,9 @@ def _format_node(inside, conf, xml): else: _fatal(constraint) + elif 'constraintGroup' in properties: + properties.pop('constraintGroup') + elif 'constraintErrorMessage' in properties: r[kw.error] = properties.pop('constraintErrorMessage') diff --git a/schema/interface_definition.rnc b/schema/interface_definition.rnc index 6647f5e11..d7fc4966c 100644 --- a/schema/interface_definition.rnc +++ b/schema/interface_definition.rnc @@ -93,6 +93,7 @@ properties = element properties { help? & constraint? & + constraintGroup* & valueHelp* & (element constraintErrorMessage { text })? & completionHelp* & @@ -140,6 +141,16 @@ constraint = element constraint validator )+ } +# Tag and leaf nodes may have constraintGroups on their names and +# values (respectively). +# When multiple constraints are listed within a group, they work as +# logical AND +constraintGroup = element constraintGroup +{ + ( (element regex { text }) | + validator )+ +} + # A constraint may also use an external validator rather than regex validator = element validator { diff --git a/schema/interface_definition.rng b/schema/interface_definition.rng index 22e886006..3ff60cf18 100644 --- a/schema/interface_definition.rng +++ b/schema/interface_definition.rng @@ -161,6 +161,9 @@ <ref name="constraint"/> </optional> <zeroOrMore> + <ref name="constraintGroup"/> + </zeroOrMore> + <zeroOrMore> <ref name="valueHelp"/> </zeroOrMore> <optional> @@ -244,6 +247,24 @@ </oneOrMore> </element> </define> + <!-- + Tag and leaf nodes may have constraintGroups on their names and + values (respectively). + When multiple constraints are listed within a group, they work as + logical AND + --> + <define name="constraintGroup"> + <element name="constraintGroup"> + <oneOrMore> + <choice> + <element name="regex"> + <text/> + </element> + <ref name="validator"/> + </choice> + </oneOrMore> + </element> + </define> <!-- A constraint may also use an external validator rather than regex --> <define name="validator"> <element name="validator"> diff --git a/scripts/build-command-templates b/scripts/build-command-templates index 452c420eb..d8abb0a13 100755 --- a/scripts/build-command-templates +++ b/scripts/build-command-templates @@ -86,6 +86,37 @@ def make_path(l): print(path) return path +def collect_validators(ve): + regexes = [] + regex_elements = ve.findall("regex") + if regex_elements is not None: + regexes = list(map(lambda e: e.text.strip().replace('\\','\\\\'), regex_elements)) + if "" in regexes: + print("Warning: empty regex, node will be accepting any value") + + validator_elements = ve.findall("validator") + validators = [] + if validator_elements is not None: + for v in validator_elements: + v_name = os.path.join(validator_dir, v.get("name")) + + # XXX: lxml returns None for empty arguments + v_argument = None + try: + v_argument = v.get("argument") + except: + pass + if v_argument is None: + v_argument = "" + + validators.append("{0} {1}".format(v_name, v_argument)) + + + regex_args = " ".join(map(lambda s: "--regex \\\'{0}\\\'".format(s), regexes)) + validator_args = " ".join(map(lambda s: "--exec \\\"{0}\\\"".format(s), validators)) + + return regex_args + " " + validator_args + def get_properties(p): props = {} @@ -108,7 +139,8 @@ def get_properties(p): except: props["val_help"] = [] - # Get the constraint statements + # Get the constraint and constraintGroup statements + error_msg = default_constraint_err_msg # Get the error message if it's there try: @@ -117,40 +149,24 @@ def get_properties(p): pass vce = p.find("constraint") - vc = [] + + distinct_validator_string = "" if vce is not None: # The old backend doesn't support multiple validators in OR mode # so we emulate it - regexes = [] - regex_elements = vce.findall("regex") - if regex_elements is not None: - regexes = list(map(lambda e: e.text.strip().replace('\\','\\\\'), regex_elements)) - if "" in regexes: - print("Warning: empty regex, node will be accepting any value") - - validator_elements = vce.findall("validator") - validators = [] - if validator_elements is not None: - for v in validator_elements: - v_name = os.path.join(validator_dir, v.get("name")) - - # XXX: lxml returns None for empty arguments - v_argument = None - try: - v_argument = v.get("argument") - except: - pass - if v_argument is None: - v_argument = "" - - validators.append("{0} {1}".format(v_name, v_argument)) - - - regex_args = " ".join(map(lambda s: "--regex \\\'{0}\\\'".format(s), regexes)) - validator_args = " ".join(map(lambda s: "--exec \\\"{0}\\\"".format(s), validators)) + distinct_validator_string = collect_validators(vce) + + vcge = p.findall("constraintGroup") + + group_validator_string = "" + if len(vcge): + for vcg in vcge: + group_validator_string = group_validator_string + " --grp " + collect_validators(vcg) + + if vce is not None or len(vcge): validator_script = '${vyos_libexec_dir}/validate-value' - validator_string = "exec \"{0} {1} {2} --value \\\'$VAR(@)\\\'\"; \"{3}\"".format(validator_script, regex_args, validator_args, error_msg) + validator_string = "exec \"{0} {1} {2} --value \\\'$VAR(@)\\\'\"; \"{3}\"".format(validator_script, distinct_validator_string, group_validator_string, error_msg) props["constraint"] = validator_string |