Configd YANG extensions

In the "configd-v1" YANG module several extensions are defined. These extensions enable DANOS specific tweaks to the YANG module files. Many of the extensions are centered around providing better context when rendering the CLI. The extensions that are currently supported are described below.

There are a few other extensions in the "configd-v1" YANG module, these are deprecated and should not be used in new features. As DANOS has evolved the need for many extensions has been replaced using other means to accomplish the same thing, several older features will still mention these deprecated extensions. The deprecated extensions are described by the provisiond document as they are interpreted by provisiond. The YANG definitions in DANOS were originally converted from a proprietary format used by the original Vyatta product line, this conversion was done in an automated fashion and as such some of the referenced scripts are in odd locations. One may encounter all of this in existing features that have yet to convert to the newer VCI mechanisms.

Extensions

help

Allows one to define the help summary text that the CLI will display. Currently the default behavior is to not provide help text. In the roadmap there is an item that will derive the help summary from the first sentence of the YANG "description" field if this field is not provided.

This field takes a string and will render that string exactly as defined. Help strings should be a single short sentence.

Example

YANG snippit:

1 2 3 container test { configd:help "The demonstration config"; }

CLI render:

1 2 3 4 5 6 vyatta@vyatta# set <tab> Possible Completions: > test The demonstration config [edit] vyatta@vyatta# set test

pattern-help

Allows one to define the help values for a pattern. Some patterns do not render in a friendly way, this allows one to override the default behavior.

This field takes a string and will render that string exactly as defined. Pattern-help strings should be a single description enclosed in "<>".

Example

YANG snippit:

1 2 3 4 5 6 7 8 9 10 11 12 13 container test { configd:help "The demonstration config"; leaf aleaf { configd:help "A leaf"; type string { pattern '[0-9A-Za-z][-_0-9A-Za-z]*' { error-message "only alpha-numeric name allowed"; } configd:pattern-help "<alpha-numeric>"; configd:help "Alpha-numeric, with non-leading - or _"; } } }

CLI Render:

1 2 3 4 5 6 7 8 [edit] vyatta@vyatta# set test aleaf <tab> Possible Completions: <alpha-numeric> Alpha-numeric, with non-leading - or _ [edit] vyatta@vyatta# set test aleaf

allowed

Allows one to define the values that users may tab complete for leaf and leaf-list nodes. These values are not enforced and are only provided as hints of possibly valid completions to the users.

Allowed takes a shell script and returns a list of the whitespace separated strings returned.

Example

YANG snippit:

1 2 3 4 5 6 7 8 container test { configd:help "The demonstration config"; leaf aleaf { configd:help "A leaf"; type string; configd:allowed "echo foo bar baz"; } }

CLI Render:

1 2 3 4 5 6 7 8 9 10 11 [edit] vyatta@vyatta# set test aleaf <tab> Possible Completions: <text> A leaf bar baz foo [edit] vyatta@vyatta# set test aleaf

must

"must" is similar to basic YANG must, but allows custom functions to be added where performance of base must statement is a problem.

secret

"secret" is used to mark a leaf node as secret so it can only be viewed if the user is in the secrets group. When viewing nodes marked secret from user that are not members of the "secrets" group one sees only the obfuscated "********" values.

"secret" takes a boolean as the argument "true" or "false".

Example

YANG snippit:

1 2 3 4 5 6 7 8 container test { configd:help "The demonstration config"; leaf aleaf { configd:help "A leaf"; type string; configd:secret true; } }

CLI Render:

1 2 3 4 5 6 7 8 9 [edit] vyatta@vyatta# set test aleaf foo [edit] vyatta@vyatta# show test +test { + aleaf "********" +} [edit] vyatta@vyatta#

subst

"subst" is used at node creation time to generate a different node in the config hierarchy in lieu of the one actually called by the user. This is used for things like "plaintext-password" to generate an "encrypted-password" which is actually stored.

The argument to subst is a script that will preform the substitution. Many scripts that exist today use the cliexpr interpreter to preform the substitution, but one can and should do this using the normal configd APIs instead as "cliexpr" is considered deprecated.

Example

YANG Snippit:

1 2 3 4 5 6 7 8 9 10 11 12 container test { configd:help "The demonstration config"; leaf aleaf { configd:help "A leaf"; type string; } leaf asubstleaf { configd:help "A leaf that substitutes"; type string; configd:subst /lib/demo/asubstleaf.subst; } }

subst program ("/lib/demo/asubstleaf.subst"):

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 package main import ( "fmt" "os" "github.com/danos/configd/client" "github.com/danos/utils/pathutil" ) func main() { c, err := client.Connect(client.SessionID(os.Getenv("VYATTA_CONFIG_SID"))) // Connect to the same session. if err != nil { fmt.Fprintln(os.Stderr, err) os.Exit(1) } path := pathutil.Makepath(os.Getenv("CONFIGD_PATH")) // Extract the path as requested if len(path) == 0 { fmt.Fprintln(os.Stderr, "NO PATH!") os.Exit(1) } val := path[len(path)-1] // Get the value that was set path[len(path)-2] = "aleaf" // Adjust the path we want to actually set path[len(path)-1] = "substituted value for: " + val // Adjust the value as desired _, err = c.Set(pathutil.Pathstr(path)) // Actually set the path if err != nil { fmt.Fprintln(os.Stderr, err) os.Exit(1) } }

CLI Render:

1 2 3 4 5 6 7 8 9 [edit] vyatta@vyatta# set test asubstleaf foo [edit] vyatta@vyatta# show test +test { + aleaf "substituted value for: foo" +} [edit] vyatta@vyatta#



normalize

"normalize" defines a script that is used to convert input value to canonical format prior to any syntax or validate script or YANG validation being carried out.

The input to normalize scripts is provided on stdin and the normalized value is consumed from stdout. For convenience typical normalization are provided by a "normalize" utility program in /bin.

Example

YANG snippit:

1 2 3 4 5 6 7 typedef mac-address { type ietf:mac-address { configd:pattern-help "<h:h:h:h:h:h>"; configd:help "MAC Address"; configd:normalize "normalize mac"; } }



CLI Render:

1 2 3 4 5 6 7 [edit] vyatta@vyatta# set protocols static bridge-mac a:b:c:d:e:f [edit] vyatta@vyatta# show protocols static bridge-mac +bridge-mac 0a:0b:0c:0d:0e:0f [edit] vyatta@vyatta#



syntax

"syntax" defines a script to be run at node creation time to do additional syntax checks. This can be used when the syntax modeling in YANG is insufficient for checking the validity of a provided value. The syntax scripts should only be used when YANG validation is not possible due to the complexity of the required validation. Many syntax scripts are currently written using the "cliexpr" interpreter. This interpreter is deprecated, one should use the standard configd APIs instead.

Example

YANG snippit:

1 2 3 4 5 6 7 8 9 container test { configd:help "The demonstration config"; leaf aleaf { configd:help "A leaf"; type string { configd:syntax /lib/demo/validmac; } } }

syntax checking program ("/lib/demo/validmac"):

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 package main import ( "errors" "fmt" "net" "os" "strconv" "strings" "github.com/danos/utils/pathutil" ) func parseMac48(mac string) (net.HardwareAddr, error) { const MAC_LEN = 6 // bytes melem := strings.Split(mac, ":") if len(melem) != MAC_LEN { return nil, errors.New("Incorrect size for MAC-48") } hwaddr := make(net.HardwareAddr, MAC_LEN) for i, v := range melem { a, err := strconv.ParseUint(v, 16, 8) if err != nil { return nil, err } hwaddr[i] = byte(a) } return hwaddr, nil } func main() { path := pathutil.Makepath(os.Getenv("CONFIGD_PATH")) if len(path) == 0 { fmt.Fprintln(os.Stderr, "NO PATH!") os.Exit(0) } val := path[len(path)-1] _, err := parseMac48(val) if err != nil { fmt.Fprintln(os.Stderr, err) os.Exit(1) } }

CLI Render:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 [edit] vyatta@vyatta# set test aleaf foo Configuration path: test aleaf [foo] is not valid Incorrect size for MAC-48 Set failed [edit] vyatta@vyatta# set test aleaf a:b:c:d:e:gf Configuration path: test aleaf [a:b:c:d:e:gf] is not valid strconv.ParseUint: parsing "gf": invalid syntax Set failed [edit] vyatta@vyatta# set test aleaf a:b:c:d:e:f [edit] vyatta@vyatta# show test aleaf +aleaf a:b:c:d:e:f