genutil

package
v0.29.19 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 25, 2024 License: Apache-2.0 Imports: 10 Imported by: 22

Documentation

Overview

Package genutil provides utility functions for package that generate code based on a YANG schema.

Index

Constants

View Source
const (
	// GoDefaultYgotImportPath is the default import path used for the ygot library
	// in the generated code.
	GoDefaultYgotImportPath = "github.com/openconfig/ygot/ygot"
	// GoDefaultYtypesImportPath is the default import path used for the ytypes library
	// in the generated code.
	GoDefaultYtypesImportPath = "github.com/openconfig/ygot/ytypes"
	// GoDefaultGoyangImportPath is the default path for the goyang/pkg/yang library that
	// is used in the generated code.
	GoDefaultGoyangImportPath = "github.com/openconfig/goyang/pkg/yang"
	// GoDefaultGNMIImportPath is the default import path that is used for the gNMI generated
	// Go protobuf code in the generated output.
	GoDefaultGNMIImportPath = "github.com/openconfig/gnmi/proto/gnmi"
)

Variables

This section is empty.

Functions

func CallerName

func CallerName() string

CallerName returns the name of the Go binary that is currently running.

func CamelCaseNameExt

func CamelCaseNameExt(exts []*yang.Statement) (string, bool)

CamelCaseNameExt returns the CamelCase name from the slice of extensions, if one of the extensions is named "camelcase-name". It returns the a string containing the name if the bool return argument is set to true; otherwise no such extension was specified. TODO(wenbli): add unit test

func EntryCamelCaseName

func EntryCamelCaseName(e *yang.Entry) string

EntryCamelCaseName returns the camel case version of the Entry Name field, or the CamelCase name that is specified by a "camelcase-name" extension on the field. The returned name is not guaranteed to be unique within any context.

func FindAllChildren

func FindAllChildren(e *yang.Entry, compBehaviour CompressBehaviour) (map[string]*yang.Entry, map[string]*yang.Entry, []error)

FindAllChildren finds the data tree elements that are children of a YANG entry e, which should have code generated for them. In general, this means data tree elements that are directly connected to a particular data tree element; however, when compression of the schema is enabled then recursion is required. The second return value is only populated when compression is enabled, and it contains the fields that have been removed due to being a duplicate field (e.g., `config/foo` is a duplicate of `state/foo` when `PreferOperationalState` is used), and are thus "shadow" fields of their corresponding direct fields within the first return value.

For example, if we have a YANG tree:

/interface (list)
/interface/config (container)
/interface/config/admin-state (leaf)
/interface/state (container)
/interface/state/admin-state (leaf)
/interface/state/oper-state (leaf)
/interface/state/counters (container)
/interface/state/counters/in-pkts (leaf)
/interface/ethernet/config (container)
/interface/ethernet/config/mac-address (leaf)
/interface/ethernet/state (state)
/interface/ethernet/state/mac-address (leaf)
/interface/subinterfaces (container)
/interface/subinterfaces/subinterface (list)

With compression disabled, then each directly connected child of a container should have code generated for it - so therefore we end up with:

/interface: config, state, ethernet, subinterfaces
/interface/config: admin-state
/interface/state: admin-state, oper-state, counters
/interface/state/counters: in-pkts
/interface/ethernet: config, state
/interface/ethernet/config: mac-address
/interface/ethernet/state: mac-address
/interface/subinterfaces: subinterface

This is simply achieved by examining the directory provided by goyang (e.Dir) and extracting the direct children that exist. These are appended to the directChildren map (keyed on element name) and then returned.

When compression is on, then more complex logic is required based on the OpenConfig path rules. In this case, the following "look-aheads" are implemented:

  1. The 'config' and 'state' containers under a directory are removed. This is because OpenConfig duplicates nodes under config and state to represent intended versus applied configuration. In the compressed schema then we need to drop one of these configuration leaves (those leaves that are defined as the set under the 'state' container that also exist within the 'config' container), and compressBehaviour specifies which one to drop. The logic implemented is to recurse into the config container, and select these leaves as direct children of the original parent. Any leaves that do not exist in the 'config' container but do within 'state' are operation state leaves, and hence are also mapped.

    Above, this means that /interfaces/interface has the admin-state and oper-state as direct children.

    Since containers can exist under the 'state' container, then these containers are also considered as direct children of e.

  2. Surrounding containers for lists are removed - that is to say, in an OpenConfig schema a list (e.g. /interface/subinterfaces/subinterface) always has a container that surrounds it. This is due to implementation requirements when it is supported on vendor devices. However, to a developer this looks like stuttering, and hence we remove this - by checking that for each directory that would be a child of e, if it has only one child, which is a list, then we skip over it.

Implementing these two rules means that the schema is simplified, such that the tree described becomes:

/interface: admin-state, oper-state, counters, ethernet, subinterface
/interface/counters: in-pkts
/interface/ethernet: mac-address

As can be seen the advantage of this compression is that the set of entities for which code generation is done is smaller, with less levels of schema hierarchy. However, it depends upon a number of rules of the OpenConfig schema. If compression is on but the schema does not comply with the rules of OpenConfig schema, then errors may occur and be returned in the []error slice by findAllChildren.

It should be noted that special handling is required for choice and case - because these are directories within the resulting schema, but they are not data tree nodes. So for example, we can have:

/container/choice/case-one/leaf-a
/container/choice/case-two/leaf-b

In this tree, "choice" and "case-one" (which are choice and case nodes respectively) are not valid data tree elements, so we recurse down both of the branches of "choice" to return leaf-a and leaf-b. Since choices can be nested (/choice-a/choice-b/choice-c/case-a), and can have multiple data nodes per case, then the addNonChoiceChildren function will find the first children of the specified node that are not choice or case statements themselves (i.e., leaf-a and leaf-b in the above example).

The .*ExcludeDerivedState compress behaviour options further filters the returned set of children based on their YANG 'config' status. When set, then any read-only (config false) node is excluded from the returned set of children. The 'config' status is inherited from a entry's parent if required, as per the rules in RFC6020.

func GetOrderedEntryKeys

func GetOrderedEntryKeys(entries map[string]*yang.Entry) []string

GetOrderedEntryKeys returns the keys of a map of *yang.Entry in alphabetical order.

func MakeNameUnique

func MakeNameUnique(name string, definedNames map[string]bool) string

MakeNameUnique makes the name specified as an argument unique based on the names already defined within a particular context which are specified within the definedNames map. If the name has already been defined, an underscore is appended to the name until it is unique.

func OpenFile

func OpenFile(fn string) *os.File

OpenFile opens a file with the supplied name, logging and exiting if it cannot be opened.

func ParentModuleName

func ParentModuleName(node yang.Node) string

ParentModuleName returns the name of the module or submodule that defined the supplied node.

func ParentModulePrettyName

func ParentModulePrettyName(node yang.Node, orgPrefixesToTrim ...string) string

ParentModulePrettyName returns the name of the module that defined the yang.Node supplied as the node argument. If the discovered root node of the node is found to be a submodule, the name of the parent module is returned. If the root has a camel case extension, this is returned rather than the actual module name. If organization prefixes (e.g. "openconfig", "ietf") are given, they are trimmed from the module name if a match is found.

func SyncFile

func SyncFile(fh *os.File)

SyncFile synchronises the supplied os.File and closes it.

func TransformEntry added in v0.8.5

func TransformEntry(e *yang.Entry, compressBehaviour CompressBehaviour) util.Errors

TransformEntry makes changes to the given AST subtree returned by goyang depending on the compress behaviour. Currently, only PreferOperationalState entails a transformation, where leafrefs pointing to config leaves are changed to point to state leaves.

func TrimOrgPrefix added in v0.8.10

func TrimOrgPrefix(modName string, orgPrefixesToTrim ...string) string

TrimOrgPrefix checks each input organization prefix (e.g. "openconfig", "ietf") (https://tools.ietf.org/html/rfc8407#section-4.1), and if matching the input module name, trims it and returns it. If none is matching, the original module name is returned. E.g. If "openconfig" is provided as a prefix to trim, then "openconfig-interfaces" becomes simply "interfaces".

func TypeDefaultValue

func TypeDefaultValue(t *yang.YangType) *string

TypeDefaultValue returns the default value of the type t if it is specified. nil is returned if no default is specified.

func WriteIfNotEmpty

func WriteIfNotEmpty(b io.StringWriter, s string)

WriteIfNotEmpty writes the string s to b if it has a non-zero length.

Types

type CompressBehaviour

type CompressBehaviour int64

CompressBehaviour specifies how the set of direct children of any entry should determined. Compression indicates whether paths should be compressed in the output of an OpenConfig schema; however, there are different ways of compressing nodes.

const (
	// Uncompressed does not compress the generated code. This means list
	// containers and config/state containers are retained in the generated
	// code.
	Uncompressed CompressBehaviour = iota
	// UncompressedExcludeDerivedState excludes config false subtrees in
	// the generated code.
	UncompressedExcludeDerivedState
	// PreferIntendedConfig generates only the "config" version of a field
	// when it exists under both "config" and "state" containers of its
	// parent YANG model. If no conflict exists between these containers,
	// then the field is always generated.
	PreferIntendedConfig
	// PreferOperationalState generates only the "state" version of a field
	// when it exists under both "config" and "state" containers of its
	// parent YANG model. If no conflict exists between these containers,
	// then the field is always generated.
	PreferOperationalState
	// ExcludeDerivedState excludes all values that are not writeable
	// (i.e. config false), including their children, from the generated
	// code output.
	ExcludeDerivedState
)

Why use an enum? There are 3 dimensions here: compress|preferState|excludeDerivedState No dimension spans across all others' options, so can't extract any out without having to error out for some combinations.

func TranslateToCompressBehaviour

func TranslateToCompressBehaviour(compressPaths, excludeState, preferOperationalState bool) (CompressBehaviour, error)

TranslateToCompressBehaviour translates the set of (compressPaths, excludeState, preferOperationalState) into a CompressBehaviour. Invalid combinations produces an error.

func (CompressBehaviour) CompressEnabled

func (c CompressBehaviour) CompressEnabled() bool

CompressEnabled is a helper to query whether compression is on.

func (CompressBehaviour) StateExcluded

func (c CompressBehaviour) StateExcluded() bool

StateExcluded is a helper to query whether derived state is excluded.

func (CompressBehaviour) String added in v0.9.0

func (c CompressBehaviour) String() string

CompressEnabled is a helper to query whether compression is on.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL