github.com/openconfig/goyang@v1.4.5/pkg/yang/entry.go (about) 1 // Copyright 2015 Google Inc. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package yang 16 17 // The file contains the code to convert an AST (Node) tree into an Entry tree 18 // via the ToEntry function. The entry tree, once fully resolved, is the 19 // product of this package. The tree should have all types and references 20 // resolved. 21 // 22 // TODO(borman): handle types, leafrefs, and extensions 23 24 import ( 25 "errors" 26 "fmt" 27 "io" 28 "math" 29 "reflect" 30 "sort" 31 "strconv" 32 "strings" 33 34 "github.com/openconfig/goyang/pkg/indent" 35 ) 36 37 // A TriState may be true, false, or unset 38 type TriState int 39 40 // The possible states of a TriState. 41 const ( 42 TSUnset = TriState(iota) 43 TSTrue 44 TSFalse 45 ) 46 47 // Value returns the value of t as a boolean. Unset is returned as false. 48 func (t TriState) Value() bool { 49 return t == TSTrue 50 } 51 52 // String displays t as a string. 53 func (t TriState) String() string { 54 switch t { 55 case TSUnset: 56 return "unset" 57 case TSTrue: 58 return "true" 59 case TSFalse: 60 return "false" 61 default: 62 return fmt.Sprintf("ts-%d", t) 63 } 64 } 65 66 // deviationPresence stores whether certain attributes for a DeviateEntry-type 67 // Entry have been given deviation values. This is useful when the attribute 68 // doesn't have a presence indicator (e.g. non-pointers). 69 type deviationPresence struct { 70 hasMinElements bool 71 hasMaxElements bool 72 } 73 74 // Entry represents a single schema tree node, which can be a directory 75 // (containing a subtree) or a leaf node (which contains YANG types that have 76 // no children, e.g., leaf, leaf-list). They can be distinguished by whether 77 // their "Dir" field is nil. This object is created from a corresponding AST 78 // node after applying modifications (i.e. uses, augments, deviations). If 79 // Errors is not nil then it means semantic errors existed while converting the 80 // AST, in which case the only other valid field other than Errors is Node. 81 type Entry struct { 82 Parent *Entry `json:"-"` 83 Node Node `json:"-"` // the base node this Entry was derived from. 84 Name string // our name, same as the key in our parent Dirs 85 Description string `json:",omitempty"` // description from node, if any 86 // Default value for the node, if any. Note that only leaf-lists may 87 // have more than one value. For all other types, use the 88 // SingleDefaultValue() method to access the default value. 89 Default []string `json:",omitempty"` 90 Units string `json:",omitempty"` // units associated with the type, if any 91 Errors []error `json:"-"` // list of errors encountered on this node 92 Kind EntryKind // kind of Entry 93 Config TriState // config state of this entry, if known 94 Prefix *Value `json:",omitempty"` // prefix to use from this point down 95 Mandatory TriState `json:",omitempty"` // whether this entry is mandatory in the tree 96 97 // Fields associated with directory nodes 98 Dir map[string]*Entry `json:",omitempty"` 99 Key string `json:",omitempty"` // Optional key name for lists (i.e., maps) 100 101 // Fields associated with leaf nodes 102 Type *YangType `json:",omitempty"` 103 104 // Extensions found 105 Exts []*Statement `json:",omitempty"` 106 107 // Fields associated with list nodes (both lists and leaf-lists) 108 ListAttr *ListAttr `json:",omitempty"` 109 110 RPC *RPCEntry `json:",omitempty"` // set if we are an RPC 111 112 // Identities that are defined in this context, this is set if the Entry 113 // is a module only. 114 Identities []*Identity `json:",omitempty"` 115 116 Augments []*Entry `json:",omitempty"` // Augments defined in this entry. 117 Augmented []*Entry `json:",omitempty"` // Augments merged into this entry. 118 Deviations []*DeviatedEntry `json:"-"` // Deviations associated with this entry. 119 Deviate map[deviationType][]*Entry `json:"-"` 120 // deviationPresence tracks whether certain attributes for a DeviateEntry-type 121 // Entry have been given deviation values. 122 deviatePresence deviationPresence 123 Uses []*UsesStmt `json:",omitempty"` // Uses merged into this entry. 124 125 // Extra maps all the unsupported fields to their values 126 Extra map[string][]interface{} `json:"extra-unstable,omitempty"` 127 128 // Annotation stores annotated values, and is not populated by this 129 // library but rather can be used by calling code where additional 130 // information should be stored alongside the Entry. 131 Annotation map[string]interface{} `json:",omitempty"` 132 133 // namespace stores the namespace of the Entry if it overrides the 134 // root namespace within the schema tree. This is the case where an 135 // entry is augmented into the tree, and it retains the namespace of 136 // the augmenting entity per RFC6020 Section 7.15.2. The namespace 137 // of the Entry should be accessed using the Namespace function. 138 namespace *Value 139 } 140 141 // An RPCEntry contains information related to an RPC Node. 142 type RPCEntry struct { 143 Input *Entry 144 Output *Entry 145 } 146 147 // A ListAttr is associated with an Entry that represents a List node 148 type ListAttr struct { 149 MinElements uint64 // leaf-list or list MUST have at least min-elements 150 MaxElements uint64 // leaf-list or list has at most max-elements 151 // OrderedBy is deprecated. Use OrderedByUser instead. 152 OrderedBy *Value 153 // OrderedByUser indicates whether the entries are "ordered-by user". 154 // Otherwise the order is determined by the system. 155 OrderedByUser bool 156 } 157 158 // parseOrderedBy parses the ordered-by value and classifies the list/leaf-list 159 // by whether the `ordered-by user` modifier is active. 160 // 161 // For more information see 162 // https://datatracker.ietf.org/doc/html/rfc7950#section-7.7.7 163 func (l *ListAttr) parseOrderedBy(s *Value) error { 164 if s == nil { 165 return nil 166 } 167 l.OrderedBy = s 168 switch s.Name { 169 case "user": 170 l.OrderedByUser = true 171 case "system": 172 default: 173 return fmt.Errorf("%s: ordered-by has invalid argument: %q", Source(s), s.Name) 174 } 175 return nil 176 } 177 178 // NewDefaultListAttr returns a new ListAttr object with min/max elements being 179 // set to 0/math.MaxUint64 respectively. 180 func NewDefaultListAttr() *ListAttr { 181 return &ListAttr{ 182 MinElements: 0, 183 MaxElements: math.MaxUint64, 184 } 185 } 186 187 // A UsesStmt associates a *Uses with its referenced grouping *Entry 188 type UsesStmt struct { 189 Uses *Uses 190 Grouping *Entry 191 } 192 193 // Modules returns the Modules structure that e is part of. This is needed 194 // when looking for rooted nodes not part of this Entry tree. 195 func (e *Entry) Modules() *Modules { 196 for e.Parent != nil { 197 e = e.Parent 198 } 199 return e.Node.(*Module).Modules 200 } 201 202 // IsDir returns true if e is a directory. 203 func (e *Entry) IsDir() bool { 204 return e.Dir != nil 205 } 206 207 // IsLeaf returns true if e is a leaf i.e. is not a container, list, leaf-list, 208 // choice or case statement. 209 func (e *Entry) IsLeaf() bool { 210 return !e.IsDir() && e.Kind == LeafEntry && e.ListAttr == nil 211 } 212 213 // IsLeafList returns true if e is a leaf-list. 214 func (e *Entry) IsLeafList() bool { 215 return !e.IsDir() && e.Kind == LeafEntry && e.ListAttr != nil 216 } 217 218 // IsList returns true if e is a list. 219 func (e *Entry) IsList() bool { 220 return e.IsDir() && e.ListAttr != nil 221 } 222 223 // IsContainer returns true if e is a container. 224 func (e *Entry) IsContainer() bool { 225 return e.Kind == DirectoryEntry && e.ListAttr == nil 226 } 227 228 // IsChoice returns true if the entry is a choice node within the schema. 229 func (e *Entry) IsChoice() bool { 230 return e.Kind == ChoiceEntry 231 } 232 233 // IsCase returns true if the entry is a case node within the schema. 234 func (e *Entry) IsCase() bool { 235 return e.Kind == CaseEntry 236 } 237 238 // Print prints e to w in human readable form. 239 func (e *Entry) Print(w io.Writer) { 240 if e.Description != "" { 241 fmt.Fprintln(w) 242 fmt.Fprintln(indent.NewWriter(w, "// "), e.Description) 243 } 244 if e.ReadOnly() { 245 fmt.Fprintf(w, "RO: ") 246 } else { 247 fmt.Fprintf(w, "rw: ") 248 } 249 if e.Type != nil { 250 fmt.Fprintf(w, "%s ", e.Type.Name) 251 } 252 switch { 253 case e.Dir == nil && e.ListAttr != nil: 254 fmt.Fprintf(w, "[]%s\n", e.Name) 255 return 256 case e.Dir == nil: 257 fmt.Fprintf(w, "%s\n", e.Name) 258 return 259 case e.ListAttr != nil: 260 fmt.Fprintf(w, "[%s]%s {\n", e.Key, e.Name) //} 261 default: 262 fmt.Fprintf(w, "%s {\n", e.Name) //} 263 } 264 var names []string 265 for k := range e.Dir { 266 names = append(names, k) 267 } 268 sort.Strings(names) 269 for _, k := range names { 270 e.Dir[k].Print(indent.NewWriter(w, " ")) 271 } 272 // { to match the brace below to keep brace matching working 273 fmt.Fprintln(w, "}") 274 } 275 276 // An EntryKind is the kind of node an Entry is. All leaf nodes are of kind 277 // LeafEntry. A LeafList is also considered a leaf node. All other kinds are 278 // directory nodes. 279 type EntryKind int 280 281 // Enumeration of the types of entries. 282 const ( 283 LeafEntry = EntryKind(iota) 284 DirectoryEntry 285 AnyDataEntry 286 AnyXMLEntry 287 CaseEntry 288 ChoiceEntry 289 InputEntry 290 NotificationEntry 291 OutputEntry 292 DeviateEntry 293 ) 294 295 // EntryKindToName maps EntryKind to their names 296 var EntryKindToName = map[EntryKind]string{ 297 LeafEntry: "Leaf", 298 DirectoryEntry: "Directory", 299 AnyDataEntry: "AnyData", 300 AnyXMLEntry: "AnyXML", 301 CaseEntry: "Case", 302 ChoiceEntry: "Choice", 303 InputEntry: "Input", 304 NotificationEntry: "Notification", 305 OutputEntry: "Output", 306 DeviateEntry: "Deviate", 307 } 308 309 func (k EntryKind) String() string { 310 if s := EntryKindToName[k]; s != "" { 311 return s 312 } 313 return fmt.Sprintf("unknown-entry-%d", k) 314 } 315 316 // newDirectory returns an empty directory Entry. 317 func newDirectory(n Node) *Entry { 318 return &Entry{ 319 Kind: DirectoryEntry, 320 Dir: make(map[string]*Entry), 321 Node: n, 322 Name: n.NName(), 323 Extra: map[string][]interface{}{}, 324 } 325 } 326 327 // newLeaf returns an empty leaf Entry. 328 func newLeaf(n Node) *Entry { 329 return &Entry{ 330 Kind: LeafEntry, 331 Node: n, 332 Name: n.NName(), 333 Extra: map[string][]interface{}{}, 334 } 335 } 336 337 // newError returns an error Entry using format and v to create the error 338 // contained in the node. The location of the error is prepended. 339 func newError(n Node, format string, v ...interface{}) *Entry { 340 e := &Entry{Node: n} 341 e.errorf("%s: "+format, append([]interface{}{Source(n)}, v...)...) 342 return e 343 } 344 345 // errorf appends the error constructed from string and v to the list of errors 346 // on e. 347 func (e *Entry) errorf(format string, v ...interface{}) { 348 e.Errors = append(e.Errors, fmt.Errorf(format, v...)) 349 } 350 351 // addError appends err to the list of errors on e if err is not nil. 352 func (e *Entry) addError(err error) { 353 if err != nil { 354 e.Errors = append(e.Errors, err) 355 } 356 } 357 358 // importErrors imports all the errors from c and its children into e. 359 func (e *Entry) importErrors(c *Entry) { 360 if c == nil { 361 return 362 } 363 for _, err := range c.Errors { 364 e.addError(err) 365 } 366 // TODO(borman): need to determine if the extensions have errors 367 // for _, ce := range e.Exts { 368 // e.importErrors(ce) 369 // } 370 for _, ce := range c.Dir { 371 e.importErrors(ce) 372 } 373 } 374 375 // checkErrors calls f on every error found in the tree e and its children. 376 func (e *Entry) checkErrors(f func(error)) { 377 if e == nil { 378 return 379 } 380 for _, e := range e.Dir { 381 e.checkErrors(f) 382 } 383 for _, err := range e.Errors { 384 f(err) 385 } 386 // TODO(borman): need to determine if the extensions have errors 387 // for _, e := range e.Exts { 388 // e.checkErrors(f) 389 // } 390 } 391 392 // GetErrors returns a sorted list of errors found in e. 393 func (e *Entry) GetErrors() []error { 394 // the seen map is used to eliminate duplicate errors. 395 // Some entries will be processed more than once 396 // (groupings in particular) and as such may cause 397 // duplication of errors. 398 seen := map[error]bool{} 399 var errs []error 400 e.checkErrors(func(err error) { 401 if !seen[err] { 402 errs = append(errs, err) 403 seen[err] = true 404 } 405 }) 406 return errorSort(errs) 407 } 408 409 // add adds the directory entry key assigned to the provided value. 410 func (e *Entry) add(key string, value *Entry) *Entry { 411 value.Parent = e 412 if e.Dir[key] != nil { 413 e.errorf("%s: duplicate key from %s: %s", Source(e.Node), Source(value.Node), key) 414 return e 415 } 416 e.Dir[key] = value 417 return e 418 } 419 420 // delete removes the directory entry key from the entry. 421 func (e *Entry) delete(key string) { 422 if _, ok := e.Dir[key]; !ok { 423 e.errorf("%s: unknown child key %s", Source(e.Node), key) 424 } 425 delete(e.Dir, key) 426 } 427 428 // GetWhenXPath returns the when XPath statement of e if able. 429 func (e *Entry) GetWhenXPath() (string, bool) { 430 switch n := e.Node.(type) { 431 case *Container: 432 if n.When != nil && n.When.Statement() != nil { 433 return n.When.Statement().Arg() 434 } 435 case *Leaf: 436 if n.When != nil && n.When.Statement() != nil { 437 return n.When.Statement().Arg() 438 } 439 case *LeafList: 440 if n.When != nil && n.When.Statement() != nil { 441 return n.When.Statement().Arg() 442 } 443 case *List: 444 if n.When != nil && n.When.Statement() != nil { 445 return n.When.Statement().Arg() 446 } 447 case *Choice: 448 if n.When != nil && n.When.Statement() != nil { 449 return n.When.Statement().Arg() 450 } 451 case *Case: 452 if n.When != nil && n.When.Statement() != nil { 453 return n.When.Statement().Arg() 454 } 455 case *AnyXML: 456 if n.When != nil && n.When.Statement() != nil { 457 return n.When.Statement().Arg() 458 } 459 case *AnyData: 460 if n.When != nil && n.When.Statement() != nil { 461 return n.When.Statement().Arg() 462 } 463 case *Augment: 464 if n.When != nil && n.When.Statement() != nil { 465 return n.When.Statement().Arg() 466 } 467 } 468 return "", false 469 } 470 471 // deviationType specifies an enumerated value covering the different substatements 472 // to the deviate statement. 473 type deviationType int64 474 475 const ( 476 // DeviationUnset specifies that the argument was unset, which is invalid. 477 DeviationUnset deviationType = iota 478 // DeviationNotSupported corresponds to the not-supported deviate argument. 479 DeviationNotSupported 480 // DeviationAdd corresponds to the add deviate argument to the deviate stmt. 481 DeviationAdd 482 // DeviationReplace corresponds to the replace argument to the deviate stmt. 483 DeviationReplace 484 // DeviationDelete corresponds to the delete argument to the deviate stmt. 485 DeviationDelete 486 ) 487 488 var ( 489 // fromDeviation maps from an enumerated deviation type to the YANG keyword. 490 fromDeviation = map[deviationType]string{ 491 DeviationNotSupported: "not-supported", 492 DeviationAdd: "add", 493 DeviationReplace: "replace", 494 DeviationDelete: "delete", 495 DeviationUnset: "unknown", 496 } 497 498 // toDeviation maps from the YANG keyword to an enumerated deviation type. 499 toDeviation = map[string]deviationType{ 500 "not-supported": DeviationNotSupported, 501 "add": DeviationAdd, 502 "replace": DeviationReplace, 503 "delete": DeviationDelete, 504 } 505 ) 506 507 func (d deviationType) String() string { 508 return fromDeviation[d] 509 } 510 511 // DeviatedEntry stores a wrapped Entry that corresponds to a deviation. 512 type DeviatedEntry struct { 513 Type deviationType // Type specifies the deviation type. 514 DeviatedPath string // DeviatedPath corresponds to the path that is being deviated. 515 // Entry is the embedded Entry storing the deviations that are made. Fields 516 // are set to the value in the schema after the deviation has been applied. 517 *Entry 518 } 519 520 // semCheckMaxElements checks whether the max-element argument is valid, and returns the specified value. 521 func semCheckMaxElements(v *Value) (uint64, error) { 522 if v == nil || v.Name == "unbounded" { 523 return math.MaxUint64, nil 524 } 525 val, err := strconv.ParseUint(v.Name, 10, 64) 526 if err != nil { 527 return val, fmt.Errorf(`%s: invalid max-elements value %q (expect "unbounded" or a positive integer): %v`, Source(v), v.Name, err) 528 } 529 if val == 0 { 530 return val, fmt.Errorf(`%s: invalid max-elements value 0 (expect "unbounded" or a positive integer)`, Source(v)) 531 } 532 return val, nil 533 } 534 535 // semCheckMinElements checks whether the min-element argument is valid, and returns the specified value. 536 func semCheckMinElements(v *Value) (uint64, error) { 537 if v == nil { 538 return 0, nil 539 } 540 val, err := strconv.ParseUint(v.Name, 10, 64) 541 if err != nil { 542 return val, fmt.Errorf(`%s: invalid min-elements value %q (expect a non-negative integer): %v`, Source(v), v.Name, err) 543 } 544 return val, nil 545 } 546 547 // ToEntry expands node n into a directory Entry. Expansion is based on the 548 // YANG tags in the structure behind n. ToEntry must only be used 549 // with nodes that are directories, such as top level modules and sub-modules. 550 // ToEntry never returns nil. Any errors encountered are found in the Errors 551 // fields of the returned Entry and its children. Use GetErrors to determine 552 // if there were any errors. 553 func ToEntry(n Node) (e *Entry) { 554 if n == nil { 555 err := errors.New("ToEntry called on nil AST node") 556 return &Entry{ 557 Node: &ErrorNode{Error: err}, 558 Errors: []error{err}, 559 } 560 } 561 ms := RootNode(n).Modules 562 if e := ms.getEntryCache(n); e != nil { 563 return e 564 } 565 defer func() { 566 ms.setEntryCache(n, e) 567 }() 568 569 // Copy in the extensions from our Node, if any. 570 defer func(n Node) { 571 if e != nil { 572 e.Exts = append(e.Exts, n.Exts()...) 573 } 574 }(n) 575 576 // tristateValue returns TSTrue if i contains the value of true, TSFalse 577 // if it contains the value of false, and TSUnset if i does not have 578 // a set value (for instance, i is nil). An error is returned if i 579 // contains a value other than true or false. 580 tristateValue := func(i interface{}) (TriState, error) { 581 if v, ok := i.(*Value); ok && v != nil { 582 switch v.Name { 583 case "true": 584 return TSTrue, nil 585 case "false": 586 return TSFalse, nil 587 default: 588 return TSUnset, fmt.Errorf("%s: invalid config value: %s", Source(n), v.Name) 589 } 590 } 591 return TSUnset, nil 592 } 593 594 var err error 595 // Handle non-directory nodes (leaf, leafref, and oddly enough, uses). 596 switch s := n.(type) { 597 case *Leaf: 598 e := newLeaf(n) 599 if errs := s.Type.resolve(ms.typeDict); errs != nil { 600 e.Errors = errs 601 } 602 if s.Description != nil { 603 e.Description = s.Description.Name 604 } 605 if s.Default != nil { 606 e.Default = []string{s.Default.Name} 607 } 608 e.Type = s.Type.YangType 609 e.Config, err = tristateValue(s.Config) 610 e.addError(err) 611 e.Prefix = getRootPrefix(e) 612 addExtraKeywordsToLeafEntry(n, e) 613 e.Mandatory, err = tristateValue(s.Mandatory) 614 e.addError(err) 615 return e 616 case *LeafList: 617 // Create the equivalent leaf element that we are a list of. 618 // We can then just annotate it as a list rather than a leaf. 619 leaf := &Leaf{ 620 Name: s.Name, 621 Source: s.Source, 622 Parent: s.Parent, 623 Extensions: s.Extensions, 624 Config: s.Config, 625 Description: s.Description, 626 IfFeature: s.IfFeature, 627 Must: s.Must, 628 Reference: s.Reference, 629 Status: s.Status, 630 Type: s.Type, 631 Units: s.Units, 632 When: s.When, 633 } 634 635 e = ToEntry(leaf) 636 e.ListAttr = NewDefaultListAttr() 637 if err := e.ListAttr.parseOrderedBy(s.OrderedBy); err != nil { 638 e.addError(err) 639 } 640 var err error 641 if e.ListAttr.MaxElements, err = semCheckMaxElements(s.MaxElements); err != nil { 642 e.addError(err) 643 } 644 if e.ListAttr.MinElements, err = semCheckMinElements(s.MinElements); err != nil { 645 e.addError(err) 646 } 647 if len(s.Default) != 0 { 648 for _, def := range s.Default { 649 e.Default = append(e.Default, def.Name) 650 } 651 } 652 e.Prefix = getRootPrefix(e) 653 return e 654 case *Uses: 655 g := FindGrouping(s, s.Name, map[string]bool{}) 656 if g == nil { 657 return newError(n, "unknown group: %s", s.Name) 658 } 659 // We need to return a duplicate so we resolve properly 660 // when the group is used in multiple locations and the 661 // grouping has a leafref that references outside the group. 662 e = ToEntry(g).dup() 663 addExtraKeywordsToLeafEntry(n, e) 664 return e 665 } 666 667 e = newDirectory(n) 668 669 // Special handling for individual Node types. Lists are like any other 670 // node except a List has a ListAttr. 671 // 672 // Nodes of identified special kinds have their Kind set here. 673 switch s := n.(type) { 674 case *List: 675 e.ListAttr = NewDefaultListAttr() 676 if err := e.ListAttr.parseOrderedBy(s.OrderedBy); err != nil { 677 e.addError(err) 678 } 679 var err error 680 if e.ListAttr.MaxElements, err = semCheckMaxElements(s.MaxElements); err != nil { 681 e.addError(err) 682 } 683 if e.ListAttr.MinElements, err = semCheckMinElements(s.MinElements); err != nil { 684 e.addError(err) 685 } 686 case *Choice: 687 e.Kind = ChoiceEntry 688 if s.Default != nil { 689 e.Default = []string{s.Default.Name} 690 } 691 case *Case: 692 e.Kind = CaseEntry 693 case *AnyData: 694 e.Kind = AnyDataEntry 695 case *AnyXML: 696 e.Kind = AnyXMLEntry 697 case *Input: 698 e.Kind = InputEntry 699 case *Output: 700 e.Kind = OutputEntry 701 case *Notification: 702 e.Kind = NotificationEntry 703 case *Deviate: 704 e.Kind = DeviateEntry 705 } 706 707 // Use Elem to get the Value of structure that n is pointing to. 708 v := reflect.ValueOf(n).Elem() 709 t := v.Type() 710 found := false 711 712 for i := t.NumField() - 1; i > 0; i-- { 713 f := t.Field(i) 714 yang := f.Tag.Get("yang") 715 if yang == "" { 716 continue 717 } 718 fv := v.Field(i) 719 name := strings.Split(yang, ",")[0] 720 switch name { 721 case "": 722 e.addError(fmt.Errorf("%s: nil statement", Source(n))) 723 case "config": 724 e.Config, err = tristateValue(fv.Interface()) 725 e.addError(err) 726 case "description": 727 if v := fv.Interface().(*Value); v != nil { 728 e.Description = v.Name 729 } 730 case "prefix": 731 if v := fv.Interface().(*Value); v != nil { 732 e.Prefix = v 733 } 734 case "action": 735 for _, r := range fv.Interface().([]*Action) { 736 e.add(r.Name, ToEntry(r)) 737 } 738 case "augment": 739 for _, a := range fv.Interface().([]*Augment) { 740 ne := ToEntry(a) 741 ne.Parent = e 742 e.Augments = append(e.Augments, ne) 743 } 744 case "anydata": 745 for _, a := range fv.Interface().([]*AnyData) { 746 e.add(a.Name, ToEntry(a)) 747 } 748 case "anyxml": 749 for _, a := range fv.Interface().([]*AnyXML) { 750 e.add(a.Name, ToEntry(a)) 751 } 752 case "case": 753 for _, a := range fv.Interface().([]*Case) { 754 e.add(a.Name, ToEntry(a)) 755 } 756 case "choice": 757 for _, a := range fv.Interface().([]*Choice) { 758 e.add(a.Name, ToEntry(a)) 759 } 760 case "container": 761 for _, a := range fv.Interface().([]*Container) { 762 e.add(a.Name, ToEntry(a)) 763 } 764 case "grouping": 765 for _, a := range fv.Interface().([]*Grouping) { 766 // We just want to parse the grouping to 767 // collect errors. 768 e.importErrors(ToEntry(a)) 769 } 770 case "import": 771 // Import only makes types and such available. 772 // There is nothing else for us to do. 773 case "include": 774 for _, a := range fv.Interface().([]*Include) { 775 // Handle circular dependencies between submodules. This can occur in 776 // two ways: 777 // - Where submodule A imports submodule B, and vice versa then the 778 // whilst processing A we will also try and process A (learnt via 779 // B). The default case of the switch handles this case. 780 // - Where submodule A imports submodule B that imports C, which also 781 // imports A, then we need to check whether we already have merged 782 // the specified module during this parse attempt. We check this 783 // against a map of merged submodules. 784 // The key of the map used is a synthesised value which is formed by 785 // concatenating the name of this node and the included submodule, 786 // separated by a ":". 787 srcToIncluded := a.Module.Name + ":" + n.NName() 788 includedToSrc := n.NName() + ":" + a.Module.Name 789 790 switch { 791 case ms.mergedSubmodule[srcToIncluded]: 792 // We have already merged this module, so don't try and do it 793 // again. 794 continue 795 case !ms.mergedSubmodule[includedToSrc] && a.Module.NName() != n.NName(): 796 // We have not merged A->B, and B != B hence go ahead and merge. 797 includedToParent := a.Module.Name + ":" + a.Module.BelongsTo.Name 798 if ms.mergedSubmodule[includedToParent] { 799 // Don't try and re-import submodules that have already been imported 800 // into the top-level module. Note that this ensures that we get to the 801 // top the tree (whichever the actual module for the chain of 802 // submodules is). The tracking of the immediate parent is achieved 803 // through 'key', which ensures that we do not end up in loops 804 // walking through a sub-cycle of the include graph. 805 continue 806 } 807 ms.mergedSubmodule[srcToIncluded] = true 808 ms.mergedSubmodule[includedToParent] = true 809 e.merge(a.Module.Prefix, nil, ToEntry(a.Module)) 810 case ms.ParseOptions.IgnoreSubmoduleCircularDependencies: 811 continue 812 default: 813 e.addError(fmt.Errorf("%s: has a circular dependency, importing %s", n.NName(), a.Module.NName())) 814 } 815 } 816 case "leaf": 817 for _, a := range fv.Interface().([]*Leaf) { 818 e.add(a.Name, ToEntry(a)) 819 } 820 case "leaf-list": 821 for _, a := range fv.Interface().([]*LeafList) { 822 e.add(a.Name, ToEntry(a)) 823 } 824 case "list": 825 for _, a := range fv.Interface().([]*List) { 826 e.add(a.Name, ToEntry(a)) 827 } 828 case "key": 829 if v := fv.Interface().(*Value); v != nil { 830 e.Key = v.Name 831 } 832 case "notification": 833 for _, a := range fv.Interface().([]*Notification) { 834 e.add(a.Name, ToEntry(a)) 835 } 836 case "rpc": 837 // TODO(borman): what do we do with these? 838 // seems fine to ignore them for now, we are 839 // just interested in the tree structure. 840 for _, r := range fv.Interface().([]*RPC) { 841 switch rpc := ToEntry(r); { 842 case rpc.RPC == nil: 843 // When "rpc" has no "input" or "output" children 844 rpc.RPC = &RPCEntry{} 845 fallthrough 846 default: 847 e.add(r.Name, rpc) 848 } 849 } 850 851 case "input": 852 if i := fv.Interface().(*Input); i != nil { 853 if e.RPC == nil { 854 e.RPC = &RPCEntry{} 855 } 856 in := ToEntry(i) 857 in.Parent = e 858 e.RPC.Input = in 859 e.RPC.Input.Name = "input" 860 e.RPC.Input.Kind = InputEntry 861 } 862 case "output": 863 if o := fv.Interface().(*Output); o != nil { 864 if e.RPC == nil { 865 e.RPC = &RPCEntry{} 866 } 867 out := ToEntry(o) 868 out.Parent = e 869 e.RPC.Output = out 870 e.RPC.Output.Name = "output" 871 e.RPC.Output.Kind = OutputEntry 872 } 873 case "identity": 874 if i := fv.Interface().([]*Identity); i != nil { 875 e.Identities = i 876 } 877 case "uses": 878 for _, a := range fv.Interface().([]*Uses) { 879 grouping := ToEntry(a) 880 e.merge(nil, nil, grouping) 881 if ms.ParseOptions.StoreUses { 882 e.Uses = append(e.Uses, &UsesStmt{a, grouping.shallowDup()}) 883 } 884 } 885 case "type": 886 // The type keyword is specific to deviate to change a type. Other type handling 887 // (e.g., leaf type resolution) is done outside of this case. 888 n, ok := n.(*Deviate) 889 if !ok { 890 e.addError(fmt.Errorf("unexpected type found, only valid under Deviate, is %T", n)) 891 continue 892 } 893 894 if n.Type != nil { 895 if errs := n.Type.resolve(ms.typeDict); errs != nil { 896 e.addError(fmt.Errorf("deviation has unresolvable type, %v", errs)) 897 continue 898 } 899 e.Type = n.Type.YangType 900 } 901 continue 902 // Keywords that do not need to be handled as an Entry as they are added 903 // to other dictionaries. 904 case "default": 905 switch e.Kind { 906 case LeafEntry, ChoiceEntry: 907 // default is handled separately for leaf, leaf-list and choice 908 case DeviateEntry: 909 // handle deviate statements. 910 // TODO(wenovus): support refine statement's default substatement. 911 d, ok := fv.Interface().(*Value) 912 if !ok { 913 e.addError(fmt.Errorf("%s: unexpected default type in %s:%s", Source(n), n.Kind(), n.NName())) 914 } 915 // TODO(wenovus): deviate statement and refine statement should 916 // allow multiple default substatements for leaf-list types (YANG1.1). 917 if d != nil { 918 e.Default = []string{d.asString()} 919 } 920 } 921 case "typedef": 922 continue 923 case "deviation": 924 if a := fv.Interface().([]*Deviation); a != nil { 925 for _, d := range a { 926 deviatedEntry := ToEntry(d) 927 e.importErrors(deviatedEntry) 928 e.Deviations = append(e.Deviations, &DeviatedEntry{ 929 Entry: deviatedEntry, 930 DeviatedPath: d.Statement().Argument, 931 }) 932 933 for _, sd := range d.Deviate { 934 if sd.Type != nil { 935 sd.Type.resolve(ms.typeDict) 936 } 937 } 938 } 939 } 940 case "deviate": 941 if a := fv.Interface().([]*Deviate); a != nil { 942 for _, d := range a { 943 de := ToEntry(d) 944 945 dt, ok := toDeviation[d.Statement().Argument] 946 if !ok { 947 e.addError(fmt.Errorf("%s: unknown deviation type in %s:%s", Source(n), n.Kind(), n.NName())) 948 continue 949 } 950 951 if e.Deviate == nil { 952 e.Deviate = map[deviationType][]*Entry{} 953 } 954 955 e.Deviate[dt] = append(e.Deviate[dt], de) 956 } 957 } 958 case "mandatory": 959 v, ok := fv.Interface().(*Value) 960 if !ok { 961 e.addError(fmt.Errorf("%s: did not get expected value type", Source(n))) 962 } 963 e.Mandatory, err = tristateValue(v) 964 e.addError(err) 965 case "max-elements", "min-elements": 966 if e.Kind != DeviateEntry { 967 continue 968 } 969 // we can get max-elements or min-elements in a deviate statement, so create the 970 // corresponding logic. 971 v, ok := fv.Interface().(*Value) 972 if !ok { 973 e.addError(fmt.Errorf("%s: max or min elements had wrong type, %s:%s", Source(n), n.Kind(), n.NName())) 974 continue 975 } 976 977 if e.ListAttr == nil { 978 e.ListAttr = NewDefaultListAttr() 979 } 980 981 // Only record the deviation if the statement exists. 982 if v != nil { 983 var err error 984 if name == "max-elements" { 985 e.deviatePresence.hasMaxElements = true 986 if e.ListAttr.MaxElements, err = semCheckMaxElements(v); err != nil { 987 e.addError(err) 988 } 989 } else { 990 e.deviatePresence.hasMinElements = true 991 if e.ListAttr.MinElements, err = semCheckMinElements(v); err != nil { 992 e.addError(err) 993 } 994 } 995 } 996 case "units": 997 v, ok := fv.Interface().(*Value) 998 if !ok { 999 e.addError(fmt.Errorf("%s: units had wrong type, %s:%s", Source(n), n.Kind(), n.NName())) 1000 } 1001 if v != nil { 1002 e.Units = v.asString() 1003 } 1004 // TODO(borman): unimplemented keywords 1005 case "belongs-to", 1006 "contact", 1007 "extension", 1008 "feature", 1009 "if-feature", 1010 "must", 1011 "namespace", 1012 "ordered-by", 1013 "organization", 1014 "presence", 1015 "reference", 1016 "revision", 1017 "status", 1018 "unique", 1019 "when", 1020 "yang-version": 1021 if !fv.IsNil() { 1022 addToExtrasSlice(fv, name, e) 1023 } 1024 continue 1025 1026 case "Ext", "Name", "Parent", "Statement": 1027 // These are meta-keywords used internally 1028 continue 1029 default: 1030 e.addError(fmt.Errorf("%s: unexpected statement: %s", Source(n), name)) 1031 continue 1032 1033 } 1034 // We found at least one field. 1035 found = true 1036 } 1037 if !found { 1038 return newError(n, "%T: cannot be converted to a *Entry", n) 1039 } 1040 // If prefix isn't set, provide it based on our root node (module) 1041 if e.Prefix == nil { 1042 e.Prefix = getRootPrefix(e) 1043 } 1044 1045 return e 1046 } 1047 1048 // addExtraKeywordsToLeafEntry stores the values for unimplemented keywords in leaf entries. 1049 func addExtraKeywordsToLeafEntry(n Node, e *Entry) { 1050 v := reflect.ValueOf(n).Elem() 1051 t := v.Type() 1052 1053 for i := t.NumField() - 1; i > 0; i-- { 1054 f := t.Field(i) 1055 yang := f.Tag.Get("yang") 1056 if yang == "" { 1057 continue 1058 } 1059 fv := v.Field(i) 1060 name := strings.Split(yang, ",")[0] 1061 switch name { 1062 case "if-feature", 1063 "must", 1064 "reference", 1065 "status", 1066 "when": 1067 if !fv.IsNil() { 1068 addToExtrasSlice(fv, name, e) 1069 } 1070 } 1071 } 1072 } 1073 1074 func addToExtrasSlice(fv reflect.Value, name string, e *Entry) { 1075 if fv.Kind() == reflect.Slice { 1076 for j := 0; j < fv.Len(); j++ { 1077 e.Extra[name] = append(e.Extra[name], fv.Index(j).Interface()) 1078 } 1079 } else { 1080 e.Extra[name] = append(e.Extra[name], fv.Interface()) 1081 } 1082 } 1083 1084 // getRootPrefix returns the prefix of e's root node (module) 1085 func getRootPrefix(e *Entry) *Value { 1086 if m := RootNode(e.Node); m != nil { 1087 return m.getPrefix() 1088 } 1089 return nil 1090 } 1091 1092 // Augment processes augments in e, return the number of augments processed 1093 // and the augments skipped. If addErrors is true then missing augments will 1094 // generate errors. 1095 func (e *Entry) Augment(addErrors bool) (processed, skipped int) { 1096 // Now process the augments we found 1097 // NOTE(borman): is it possible this will fail if the augment refers 1098 // to some removed sibling that has not been processed? Perhaps this 1099 // should be done after the entire tree is built. Is it correct to 1100 // assume augment paths are data tree paths and not schema tree paths? 1101 // Augments can depend upon augments. We need to figure out how to 1102 // order the augments (or just keep trying until we can make no further 1103 // progress) 1104 var unapplied []*Entry 1105 for _, a := range e.Augments { 1106 target := a.Find(a.Name) 1107 if target == nil { 1108 if addErrors { 1109 e.errorf("%s: augment %s not found", Source(a.Node), a.Name) 1110 } 1111 skipped++ 1112 unapplied = append(unapplied, a) 1113 continue 1114 } 1115 // Augments do not have a prefix we merge in, just a node. 1116 // We retain the namespace from the original context of the 1117 // augment since the nodes have this namespace even though they 1118 // are merged into another entry. 1119 processed++ 1120 target.merge(nil, a.Namespace(), a) 1121 target.Augmented = append(target.Augmented, a.shallowDup()) 1122 } 1123 e.Augments = unapplied 1124 return processed, skipped 1125 } 1126 1127 // ApplyDeviate walks the deviations within the supplied entry, and applies them to the 1128 // schema. 1129 func (e *Entry) ApplyDeviate(deviateOpts ...DeviateOpt) []error { 1130 var errs []error 1131 appendErr := func(err error) { errs = append(errs, err) } 1132 for _, d := range e.Deviations { 1133 deviatedNode := e.Find(d.DeviatedPath) 1134 if deviatedNode == nil { 1135 appendErr(fmt.Errorf("cannot find target node to deviate, %s", d.DeviatedPath)) 1136 continue 1137 } 1138 1139 for dt, dv := range d.Deviate { 1140 for _, devSpec := range dv { 1141 switch dt { 1142 case DeviationAdd, DeviationReplace: 1143 if devSpec.Config != TSUnset { 1144 deviatedNode.Config = devSpec.Config 1145 } 1146 1147 if len(devSpec.Default) > 0 { 1148 switch dt { 1149 case DeviationAdd: 1150 switch { 1151 case deviatedNode.IsLeafList(): 1152 deviatedNode.Default = append(deviatedNode.Default, devSpec.Default...) 1153 case len(devSpec.Default) > 1: 1154 appendErr(fmt.Errorf("%s: tried to add more than one default to a non-leaflist entry at deviation", Source(e.Node))) 1155 case len(deviatedNode.Default) != 0: 1156 appendErr(fmt.Errorf("%s: tried to add a default value to an entry that already has a default value", Source(e.Node))) 1157 case len(devSpec.Default) == 1 && len(deviatedNode.Default) == 0: 1158 deviatedNode.Default = append([]string{}, devSpec.Default[0]) 1159 } 1160 case DeviationReplace: 1161 deviatedNode.Default = append([]string{}, devSpec.Default...) 1162 } 1163 } 1164 1165 if devSpec.Mandatory != TSUnset { 1166 deviatedNode.Mandatory = devSpec.Mandatory 1167 } 1168 1169 if devSpec.deviatePresence.hasMinElements { 1170 if !deviatedNode.IsList() && !deviatedNode.IsLeafList() { 1171 appendErr(fmt.Errorf("tried to deviate min-elements on a non-list type %s", deviatedNode.Kind)) 1172 continue 1173 } 1174 deviatedNode.ListAttr.MinElements = devSpec.ListAttr.MinElements 1175 } 1176 1177 if devSpec.deviatePresence.hasMaxElements { 1178 if !deviatedNode.IsList() && !deviatedNode.IsLeafList() { 1179 appendErr(fmt.Errorf("tried to deviate max-elements on a non-list type %s", deviatedNode.Kind)) 1180 continue 1181 } 1182 deviatedNode.ListAttr.MaxElements = devSpec.ListAttr.MaxElements 1183 } 1184 1185 if devSpec.Units != "" { 1186 deviatedNode.Units = devSpec.Units 1187 } 1188 1189 if devSpec.Type != nil { 1190 deviatedNode.Type = devSpec.Type 1191 } 1192 1193 case DeviationNotSupported: 1194 dp := deviatedNode.Parent 1195 if dp == nil { 1196 appendErr(fmt.Errorf("%s: node %s does not have a valid parent, but deviate not-supported references one", Source(e.Node), e.Name)) 1197 continue 1198 } 1199 if !hasIgnoreDeviateNotSupported(deviateOpts) { 1200 dp.delete(deviatedNode.Name) 1201 } 1202 case DeviationDelete: 1203 if devSpec.Config != TSUnset { 1204 deviatedNode.Config = TSUnset 1205 } 1206 1207 if len(devSpec.Default) > 0 { 1208 switch { 1209 case deviatedNode.IsLeafList(): 1210 // It is unclear from RFC7950 on how deviate delete works 1211 // when there are duplicate leaf-list values in config-false leafs. 1212 // TODO(wenbli): Add support for deleting default values when the leaf-list is a config leaf (duplicates are not allowed). 1213 appendErr(fmt.Errorf("%s: deviate delete on default statements unsupported for leaf-lists, please use replace instead", Source(e.Node))) 1214 case len(deviatedNode.Default) == 0: 1215 appendErr(fmt.Errorf("%s: tried to deviate delete a default statement that doesn't exist", Source(e.Node))) 1216 case devSpec.Default[0] != deviatedNode.Default[0]: 1217 appendErr(fmt.Errorf("%s: tried to deviate delete a default statement with a non-matching keyword", Source(e.Node))) 1218 default: 1219 deviatedNode.Default = nil 1220 } 1221 } 1222 1223 if devSpec.Mandatory != TSUnset { 1224 deviatedNode.Mandatory = TSUnset 1225 } 1226 1227 if devSpec.deviatePresence.hasMinElements { 1228 if !deviatedNode.IsList() && !deviatedNode.IsLeafList() { 1229 appendErr(fmt.Errorf("tried to deviate min-elements on a non-list type %s", deviatedNode.Kind)) 1230 continue 1231 } 1232 if deviatedNode.ListAttr.MinElements != devSpec.ListAttr.MinElements { 1233 // Argument value must match: 1234 // https://tools.ietf.org/html/rfc7950#section-7.20.3.2 1235 appendErr(fmt.Errorf("min-element value %d differs from deviation's min-element value %d for entry %v", devSpec.ListAttr.MinElements, deviatedNode.ListAttr.MinElements, d.DeviatedPath)) 1236 } 1237 deviatedNode.ListAttr.MinElements = 0 1238 } 1239 1240 if devSpec.deviatePresence.hasMaxElements { 1241 if !deviatedNode.IsList() && !deviatedNode.IsLeafList() { 1242 appendErr(fmt.Errorf("tried to deviate max-elements on a non-list type %s", deviatedNode.Kind)) 1243 continue 1244 } 1245 if deviatedNode.ListAttr.MaxElements != devSpec.ListAttr.MaxElements { 1246 appendErr(fmt.Errorf("max-element value %d differs from deviation's max-element value %d for entry %v", devSpec.ListAttr.MaxElements, deviatedNode.ListAttr.MaxElements, d.DeviatedPath)) 1247 } 1248 deviatedNode.ListAttr.MaxElements = math.MaxUint64 1249 } 1250 1251 default: 1252 appendErr(fmt.Errorf("invalid deviation type %s", dt)) 1253 } 1254 } 1255 } 1256 } 1257 1258 return errs 1259 } 1260 1261 // FixChoice inserts missing Case entries for non-case entries within a choice 1262 // entry. 1263 func (e *Entry) FixChoice() { 1264 if e.Kind == ChoiceEntry && len(e.Errors) == 0 { 1265 for k, ce := range e.Dir { 1266 if ce.Kind != CaseEntry { 1267 ne := &Entry{ 1268 Parent: e, 1269 Node: &Case{ 1270 Parent: ce.Node.ParentNode(), 1271 Name: ce.Node.NName(), 1272 Source: ce.Node.Statement(), 1273 Extensions: ce.Node.Exts(), 1274 }, 1275 Name: ce.Name, 1276 Kind: CaseEntry, 1277 Config: ce.Config, 1278 Prefix: ce.Prefix, 1279 Dir: map[string]*Entry{ce.Name: ce}, 1280 Extra: map[string][]interface{}{}, 1281 } 1282 ce.Parent = ne 1283 e.Dir[k] = ne 1284 } 1285 } 1286 } 1287 for _, ce := range e.Dir { 1288 ce.FixChoice() 1289 } 1290 } 1291 1292 // ReadOnly returns true if e is a read-only variable (config == false). 1293 // If Config is unset in e, then false is returned if e has no parent, 1294 // otherwise the value parent's ReadOnly is returned. 1295 func (e *Entry) ReadOnly() bool { 1296 switch { 1297 case e == nil: 1298 // We made it all the way to the root of the tree 1299 return false 1300 case e.Kind == OutputEntry: 1301 return true 1302 case e.Config == TSUnset: 1303 return e.Parent.ReadOnly() 1304 default: 1305 return !e.Config.Value() 1306 } 1307 } 1308 1309 // Find finds the Entry named by name relative to e. 1310 func (e *Entry) Find(name string) *Entry { 1311 if e == nil || name == "" { 1312 return nil 1313 } 1314 parts := strings.Split(name, "/") 1315 1316 // If parts[0] is "" then this path started with a / 1317 // and we need to find our parent. 1318 if parts[0] == "" { 1319 parts = parts[1:] 1320 contextNode := e.Node 1321 for e.Parent != nil { 1322 e = e.Parent 1323 } 1324 if prefix, _ := getPrefix(parts[0]); prefix != "" { 1325 mod := FindModuleByPrefix(contextNode, prefix) 1326 if mod == nil { 1327 e.addError(fmt.Errorf("cannot find module giving prefix %q within context entry %q", prefix, e.Path())) 1328 return nil 1329 } 1330 m := module(mod) 1331 if m == nil { 1332 e.addError(fmt.Errorf("cannot find which module %q belongs to within context entry %q", 1333 mod.NName(), e.Path())) 1334 return nil 1335 } 1336 if m != e.Node.(*Module) { 1337 e = ToEntry(m) 1338 } 1339 } 1340 } 1341 1342 for _, part := range parts { 1343 switch { 1344 case e == nil: 1345 return nil 1346 case part == ".": 1347 case part == "..": 1348 e = e.Parent 1349 case e.RPC != nil: 1350 _, part = getPrefix(part) 1351 switch part { 1352 case "input": 1353 if e.RPC.Input == nil { 1354 e.RPC.Input = &Entry{ 1355 Name: "input", 1356 Kind: InputEntry, 1357 Dir: make(map[string]*Entry), 1358 } 1359 } 1360 e = e.RPC.Input 1361 case "output": 1362 if e.RPC.Output == nil { 1363 e.RPC.Output = &Entry{ 1364 Name: "output", 1365 Kind: OutputEntry, 1366 Dir: make(map[string]*Entry), 1367 } 1368 } 1369 e = e.RPC.Output 1370 } 1371 default: 1372 _, part = getPrefix(part) 1373 switch part { 1374 case ".": 1375 case "", "..": 1376 return nil 1377 default: 1378 e = e.Dir[part] 1379 } 1380 } 1381 } 1382 return e 1383 } 1384 1385 // Path returns the path to e. A nil Entry returns "". 1386 func (e *Entry) Path() string { 1387 if e == nil { 1388 return "" 1389 } 1390 return e.Parent.Path() + "/" + e.Name 1391 } 1392 1393 // Namespace returns the YANG/XML namespace Value for e as mounted in the Entry 1394 // tree (e.g., as placed by grouping statements). 1395 // 1396 // Per RFC6020 section 7.12, the namespace on elements in the tree due to a 1397 // "uses" statement is that of the where the uses statement occurs, i.e., the 1398 // user, rather than creator (grouping) of those elements, so we follow the 1399 // usage (Entry) tree up to the parent before obtaining the (then adjacent) root 1400 // node for its namespace Value. 1401 func (e *Entry) Namespace() *Value { 1402 // Make e the root parent entry 1403 for ; e.Parent != nil; e = e.Parent { 1404 if e.namespace != nil { 1405 return e.namespace 1406 } 1407 } 1408 1409 // Return the namespace of a valid root parent entry 1410 if e != nil && e.Node != nil { 1411 if root := RootNode(e.Node); root != nil { 1412 if root.Kind() == "submodule" { 1413 root = root.Modules.Modules[root.BelongsTo.Name] 1414 if root == nil { 1415 return new(Value) 1416 } 1417 } 1418 return root.Namespace 1419 } 1420 } 1421 1422 // Otherwise return an empty namespace Value (rather than nil) 1423 return new(Value) 1424 } 1425 1426 // InstantiatingModule returns the YANG module which instantiated the Entry 1427 // within the schema tree - using the same rules described in the documentation 1428 // of the Namespace function. The namespace is resolved in the module name. This 1429 // approach to namespacing is used when serialising YANG-modelled data to JSON as 1430 // per RFC7951. 1431 func (e *Entry) InstantiatingModule() (string, error) { 1432 n := e.Namespace() 1433 if n == nil { 1434 return "", fmt.Errorf("entry %s had nil namespace", e.Name) 1435 } 1436 1437 module, err := e.Modules().FindModuleByNamespace(n.Name) 1438 if err != nil { 1439 return "", fmt.Errorf("could not find module %q when retrieving namespace for %s: %v", n.Name, e.Name, err) 1440 } 1441 return module.Name, nil 1442 } 1443 1444 // shallowDup makes a shallow duplicate of e (only direct children are 1445 // duplicated; grandchildren and deeper descendants are deleted). 1446 func (e *Entry) shallowDup() *Entry { 1447 // Warning: if we add any elements to Entry that should not be 1448 // copied we will have to explicitly uncopy them. 1449 ne := *e 1450 1451 // Now only copy direct children, clear their Dir, and fix up 1452 // Parent pointers. 1453 if e.Dir != nil { 1454 ne.Dir = make(map[string]*Entry, len(e.Dir)) 1455 for k, v := range e.Dir { 1456 de := *v 1457 de.Dir = nil 1458 de.Parent = &ne 1459 ne.Dir[k] = &de 1460 } 1461 } 1462 return &ne 1463 } 1464 1465 // dup makes a deep duplicate of e. 1466 func (e *Entry) dup() *Entry { 1467 // Warning: if we add any elements to Entry that should not be 1468 // copied we will have to explicitly uncopy them. 1469 // It is possible we may want to do a deep copy on some other fields, 1470 // such as Exts, Choice and Case, but it is not clear that we need 1471 // to do that. 1472 ne := *e 1473 1474 // Now recurse down to all of our children, fixing up Parent 1475 // pointers as we go. 1476 if e.Dir != nil { 1477 ne.Dir = make(map[string]*Entry, len(e.Dir)) 1478 for k, v := range e.Dir { 1479 de := v.dup() 1480 de.Parent = &ne 1481 ne.Dir[k] = de 1482 } 1483 } 1484 1485 ne.Extra = make(map[string][]interface{}) 1486 for k, v := range e.Extra { 1487 ne.Extra[k] = v 1488 } 1489 1490 return &ne 1491 } 1492 1493 // merge merges a duplicate of oe.Dir into e.Dir, setting the prefix of each 1494 // element to prefix, if not nil. It is an error if e and oe contain common 1495 // elements. 1496 func (e *Entry) merge(prefix *Value, namespace *Value, oe *Entry) { 1497 e.importErrors(oe) 1498 for k, v := range oe.Dir { 1499 v := v.dup() 1500 if prefix != nil { 1501 v.Prefix = prefix 1502 } 1503 if namespace != nil { 1504 v.namespace = namespace 1505 } 1506 if se := e.Dir[k]; se != nil { 1507 er := newError(oe.Node, `Duplicate node %q in %q from: 1508 %s: %s 1509 %s: %s`, k, e.Name, Source(v.Node), v.Name, Source(se.Node), se.Name) 1510 e.addError(er.Errors[0]) 1511 } else { 1512 v.Parent = e 1513 v.Exts = append(v.Exts, oe.Exts...) 1514 for lk := range oe.Extra { 1515 v.Extra[lk] = append(v.Extra[lk], oe.Extra[lk]...) 1516 } 1517 e.Dir[k] = v 1518 } 1519 } 1520 } 1521 1522 // nless returns -1 if a is less than b, 0 if a == b, and 1 if a > b. 1523 // If a and b are both numeric, then nless compares them as numbers, 1524 // otherwise they are compared lexicographically. 1525 func nless(a, b string) int { 1526 an, ae := strconv.Atoi(a) 1527 bn, be := strconv.Atoi(b) 1528 switch { 1529 case ae == nil && be == nil: 1530 switch { 1531 case an < bn: 1532 return -1 1533 case an > bn: 1534 return 1 1535 default: 1536 return 0 1537 } 1538 case a < b: 1539 return -1 1540 case a > b: 1541 return 1 1542 default: 1543 return 0 1544 } 1545 } 1546 1547 type sError struct { 1548 s string 1549 err error 1550 } 1551 1552 type sortedErrors []sError 1553 1554 func (s sortedErrors) Len() int { return len(s) } 1555 func (s sortedErrors) Swap(i, j int) { s[i], s[j] = s[j], s[i] } 1556 func (s sortedErrors) Less(i, j int) bool { 1557 // We expect the error strings to be composed of error messages, 1558 // line numbers, etc. delimited by ":". 1559 const errorSplitCount = 4 1560 fi := strings.SplitN(s[i].s, ":", errorSplitCount) 1561 fj := strings.SplitN(s[j].s, ":", errorSplitCount) 1562 // First, order the errors by the file name. 1563 if fi[0] < fj[0] { 1564 return true 1565 } 1566 if fi[0] > fj[0] { 1567 return false 1568 } 1569 1570 // compare remaining indices of the error string slices 1571 // in order to create a total ordering. 1572 for i := 1; i < errorSplitCount; i++ { 1573 switch { 1574 // Handle when an expected index doesn't exist. 1575 case len(fj) == i: 1576 return false 1577 case len(fi) == i: 1578 return true 1579 } 1580 1581 switch nless(fi[i], fj[i]) { 1582 case -1: 1583 return true 1584 case 1: 1585 return false 1586 } 1587 } 1588 return false 1589 } 1590 1591 // errorSort sorts the strings in the errors slice assuming each line starts 1592 // with file:line:col. Line and column number are sorted numerically. 1593 // Duplicate errors are stripped. 1594 func errorSort(errors []error) []error { 1595 switch len(errors) { 1596 case 0: 1597 return nil 1598 case 1: 1599 return errors 1600 } 1601 elist := make(sortedErrors, len(errors)) 1602 for x, err := range errors { 1603 elist[x] = sError{err.Error(), err} 1604 } 1605 sort.Sort(elist) 1606 errors = make([]error, len(errors)) 1607 i := 0 1608 for _, err := range elist { 1609 if i > 0 && reflect.DeepEqual(err.err, errors[i-1]) { 1610 continue 1611 } 1612 errors[i] = err.err 1613 i++ 1614 } 1615 return errors[:i] 1616 } 1617 1618 // SingleDefaultValue returns the single schema default value for e and a bool 1619 // indicating whether the entry contains one and only one default value. The 1620 // empty string is returned when the entry has zero or multiple default values. 1621 // This function is useful for determining the default values of a 1622 // non-leaf-list leaf entry. If the leaf has no explicit default, its type 1623 // default (if any) will be used. 1624 // 1625 // For a leaf-list entry, use DefaultValues() instead. 1626 func (e *Entry) SingleDefaultValue() (string, bool) { 1627 if dvals := e.DefaultValues(); len(dvals) == 1 { 1628 return dvals[0], true 1629 } 1630 return "", false 1631 } 1632 1633 // DefaultValues returns all default values for the leaf entry. This is useful 1634 // for determining the default values for a leaf-list, which may have more than 1635 // one default value. If the entry has no explicit default, its type default 1636 // (if any) will be used. nil is returned when no default value exists. 1637 // 1638 // For a leaf entry, use SingleDefaultValue() instead. 1639 func (e *Entry) DefaultValues() []string { 1640 if len(e.Default) > 0 { 1641 return append([]string{}, e.Default...) 1642 } 1643 1644 if typ := e.Type; typ != nil && typ.HasDefault { 1645 switch leaf := e.Node.(type) { 1646 case *Leaf: 1647 switch { 1648 case e.IsLeaf() && (leaf.Mandatory == nil || leaf.Mandatory.Name == "false"), e.IsLeafList() && e.ListAttr.MinElements == 0: 1649 return []string{typ.Default} 1650 } 1651 } 1652 } 1653 return nil 1654 }