Adding upstream version 1.34.4.
Signed-off-by: Daniel Baumann <daniel@debian.org>
This commit is contained in:
parent
e393c3af3f
commit
4978089aab
4963 changed files with 677545 additions and 0 deletions
403
plugins/inputs/gnmi/path.go
Normal file
403
plugins/inputs/gnmi/path.go
Normal file
|
@ -0,0 +1,403 @@
|
|||
package gnmi
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/openconfig/gnmi/proto/gnmi"
|
||||
)
|
||||
|
||||
type keySegment struct {
|
||||
name string
|
||||
path string
|
||||
kv map[string]string
|
||||
}
|
||||
|
||||
type segment struct {
|
||||
namespace string
|
||||
id string
|
||||
}
|
||||
|
||||
type pathInfo struct {
|
||||
origin string
|
||||
target string
|
||||
segments []segment
|
||||
keyValues []keySegment
|
||||
}
|
||||
|
||||
func newInfoFromString(path string) *pathInfo {
|
||||
if path == "" {
|
||||
return &pathInfo{}
|
||||
}
|
||||
|
||||
parts := strings.Split(path, "/")
|
||||
|
||||
var origin string
|
||||
if strings.HasSuffix(parts[0], ":") {
|
||||
origin = strings.TrimSuffix(parts[0], ":")
|
||||
parts = parts[1:]
|
||||
}
|
||||
|
||||
info := &pathInfo{origin: origin}
|
||||
for _, part := range parts {
|
||||
if part == "" {
|
||||
continue
|
||||
}
|
||||
info.segments = append(info.segments, segment{id: part})
|
||||
}
|
||||
info.normalize()
|
||||
|
||||
return info
|
||||
}
|
||||
|
||||
func newInfoFromPathWithoutKeys(path *gnmi.Path) *pathInfo {
|
||||
info := &pathInfo{
|
||||
origin: path.Origin,
|
||||
segments: make([]segment, 0, len(path.Elem)),
|
||||
}
|
||||
for _, elem := range path.Elem {
|
||||
if elem.Name == "" {
|
||||
continue
|
||||
}
|
||||
info.segments = append(info.segments, segment{id: elem.Name})
|
||||
}
|
||||
info.normalize()
|
||||
|
||||
return info
|
||||
}
|
||||
|
||||
func newInfoFromPath(paths ...*gnmi.Path) *pathInfo {
|
||||
if len(paths) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
info := &pathInfo{}
|
||||
if paths[0] != nil {
|
||||
info.origin = paths[0].Origin
|
||||
info.target = paths[0].Target
|
||||
}
|
||||
|
||||
for _, p := range paths {
|
||||
if p == nil {
|
||||
continue
|
||||
}
|
||||
for _, elem := range p.Elem {
|
||||
if elem.Name != "" {
|
||||
info.segments = append(info.segments, segment{id: elem.Name})
|
||||
}
|
||||
|
||||
if len(elem.Key) == 0 {
|
||||
continue
|
||||
}
|
||||
keyInfo := keySegment{
|
||||
name: elem.Name,
|
||||
path: info.String(),
|
||||
kv: make(map[string]string, len(elem.Key)),
|
||||
}
|
||||
for k, v := range elem.Key {
|
||||
keyInfo.kv[k] = v
|
||||
}
|
||||
info.keyValues = append(info.keyValues, keyInfo)
|
||||
}
|
||||
}
|
||||
info.normalize()
|
||||
|
||||
return info
|
||||
}
|
||||
|
||||
func (pi *pathInfo) empty() bool {
|
||||
return len(pi.segments) == 0
|
||||
}
|
||||
|
||||
func (pi *pathInfo) append(paths ...*gnmi.Path) *pathInfo {
|
||||
// Copy the existing info
|
||||
segments := make([]segment, 0, len(pi.segments))
|
||||
path := &pathInfo{
|
||||
origin: pi.origin,
|
||||
target: pi.target,
|
||||
segments: append(segments, pi.segments...),
|
||||
keyValues: make([]keySegment, 0, len(pi.keyValues)),
|
||||
}
|
||||
for _, elem := range pi.keyValues {
|
||||
keyInfo := keySegment{
|
||||
name: elem.name,
|
||||
path: elem.path,
|
||||
kv: make(map[string]string, len(elem.kv)),
|
||||
}
|
||||
for k, v := range elem.kv {
|
||||
keyInfo.kv[k] = v
|
||||
}
|
||||
path.keyValues = append(path.keyValues, keyInfo)
|
||||
}
|
||||
|
||||
// Add the new segments
|
||||
for _, p := range paths {
|
||||
for _, elem := range p.Elem {
|
||||
if elem.Name != "" {
|
||||
path.segments = append(path.segments, segment{id: elem.Name})
|
||||
}
|
||||
|
||||
if len(elem.Key) == 0 {
|
||||
continue
|
||||
}
|
||||
keyInfo := keySegment{
|
||||
name: elem.Name,
|
||||
path: path.String(),
|
||||
kv: make(map[string]string, len(elem.Key)),
|
||||
}
|
||||
for k, v := range elem.Key {
|
||||
keyInfo.kv[k] = v
|
||||
}
|
||||
path.keyValues = append(path.keyValues, keyInfo)
|
||||
}
|
||||
}
|
||||
path.normalize()
|
||||
|
||||
return path
|
||||
}
|
||||
|
||||
func (pi *pathInfo) appendSegments(segments ...string) *pathInfo {
|
||||
// Copy the existing info
|
||||
seg := make([]segment, 0, len(segments))
|
||||
path := &pathInfo{
|
||||
origin: pi.origin,
|
||||
target: pi.target,
|
||||
segments: append(seg, pi.segments...),
|
||||
keyValues: make([]keySegment, 0, len(pi.keyValues)),
|
||||
}
|
||||
for _, elem := range pi.keyValues {
|
||||
keyInfo := keySegment{
|
||||
name: elem.name,
|
||||
path: elem.path,
|
||||
kv: make(map[string]string, len(elem.kv)),
|
||||
}
|
||||
for k, v := range elem.kv {
|
||||
keyInfo.kv[k] = v
|
||||
}
|
||||
path.keyValues = append(path.keyValues, keyInfo)
|
||||
}
|
||||
|
||||
// Add the new segments
|
||||
for _, s := range segments {
|
||||
if s == "" {
|
||||
continue
|
||||
}
|
||||
path.segments = append(path.segments, segment{id: s})
|
||||
}
|
||||
path.normalize()
|
||||
|
||||
return path
|
||||
}
|
||||
|
||||
func (pi *pathInfo) normalize() {
|
||||
if len(pi.segments) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
// Extract namespaces from segments
|
||||
for i, s := range pi.segments {
|
||||
if ns, id, found := strings.Cut(s.id, ":"); found {
|
||||
pi.segments[i].namespace = ns
|
||||
pi.segments[i].id = id
|
||||
}
|
||||
}
|
||||
|
||||
// Remove empty segments
|
||||
segments := make([]segment, 0, len(pi.segments))
|
||||
for _, s := range pi.segments {
|
||||
if s.id != "" {
|
||||
segments = append(segments, s)
|
||||
}
|
||||
}
|
||||
pi.segments = segments
|
||||
}
|
||||
|
||||
func (pi *pathInfo) enforceFirstNamespaceAsOrigin() {
|
||||
if len(pi.segments) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
// Some devices supply the origin as part of the first path element,
|
||||
// so try to find and extract it there.
|
||||
if pi.segments[0].namespace != "" {
|
||||
pi.origin = pi.segments[0].namespace
|
||||
pi.segments[0].namespace = ""
|
||||
}
|
||||
}
|
||||
|
||||
func (pi *pathInfo) equalsPathNoKeys(path *gnmi.Path) bool {
|
||||
if len(pi.segments) != len(path.Elem) {
|
||||
return false
|
||||
}
|
||||
for i, s := range pi.segments {
|
||||
if s.id != path.Elem[i].Name {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (pi *pathInfo) isSubPathOf(path *pathInfo) bool {
|
||||
// If both set an origin it has to match. Otherwise we ignore the origin
|
||||
if pi.origin != "" && path.origin != "" && pi.origin != path.origin {
|
||||
return false
|
||||
}
|
||||
|
||||
// The "parent" path should have the same length or be shorter than the
|
||||
// sub-path to have a chance to match
|
||||
if len(pi.segments) > len(path.segments) {
|
||||
return false
|
||||
}
|
||||
|
||||
// Compare the elements and exit if we find a mismatch
|
||||
for i, p := range pi.segments {
|
||||
ps := path.segments[i]
|
||||
if p.namespace != "" && ps.namespace != "" && p.namespace != ps.namespace {
|
||||
return false
|
||||
}
|
||||
if p.id != ps.id {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func (pi *pathInfo) relative(path *pathInfo, withNamespace bool) string {
|
||||
if !pi.isSubPathOf(path) || len(pi.segments) == len(path.segments) {
|
||||
return ""
|
||||
}
|
||||
|
||||
segments := path.segments[len(pi.segments):len(path.segments)]
|
||||
var r string
|
||||
if withNamespace && segments[0].namespace != "" {
|
||||
r = segments[0].namespace + ":" + segments[0].id
|
||||
} else {
|
||||
r = segments[0].id
|
||||
}
|
||||
for _, s := range segments[1:] {
|
||||
if withNamespace && s.namespace != "" {
|
||||
r += "/" + s.namespace + ":" + s.id
|
||||
} else {
|
||||
r += "/" + s.id
|
||||
}
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
func (pi *pathInfo) keepCommonPart(path *pathInfo) {
|
||||
shortestLen := len(pi.segments)
|
||||
if len(path.segments) < shortestLen {
|
||||
shortestLen = len(path.segments)
|
||||
}
|
||||
|
||||
// Compare the elements and stop as soon as they do mismatch
|
||||
var matchLen int
|
||||
for i, p := range pi.segments[:shortestLen] {
|
||||
if p != path.segments[i] {
|
||||
break
|
||||
}
|
||||
matchLen = i + 1
|
||||
}
|
||||
if matchLen < 1 {
|
||||
pi.segments = nil
|
||||
return
|
||||
}
|
||||
pi.segments = pi.segments[:matchLen]
|
||||
}
|
||||
|
||||
func (pi *pathInfo) dir() string {
|
||||
if len(pi.segments) <= 1 {
|
||||
return ""
|
||||
}
|
||||
|
||||
var dir string
|
||||
if pi.origin != "" {
|
||||
dir = pi.origin + ":"
|
||||
}
|
||||
for _, s := range pi.segments[:len(pi.segments)-1] {
|
||||
if s.namespace != "" {
|
||||
dir += "/" + s.namespace + ":" + s.id
|
||||
} else {
|
||||
dir += "/" + s.id
|
||||
}
|
||||
}
|
||||
return dir
|
||||
}
|
||||
|
||||
func (pi *pathInfo) base() string {
|
||||
if len(pi.segments) == 0 {
|
||||
return ""
|
||||
}
|
||||
|
||||
s := pi.segments[len(pi.segments)-1]
|
||||
if s.namespace != "" {
|
||||
return s.namespace + ":" + s.id
|
||||
}
|
||||
return s.id
|
||||
}
|
||||
|
||||
func (pi *pathInfo) path() (origin, path string) {
|
||||
if len(pi.segments) == 0 {
|
||||
return pi.origin, "/"
|
||||
}
|
||||
|
||||
for _, s := range pi.segments {
|
||||
path += "/" + s.id
|
||||
}
|
||||
|
||||
return pi.origin, path
|
||||
}
|
||||
|
||||
func (pi *pathInfo) fullPath() string {
|
||||
var path string
|
||||
if pi.origin != "" {
|
||||
path = pi.origin + ":"
|
||||
}
|
||||
if len(pi.segments) == 0 {
|
||||
return path
|
||||
}
|
||||
|
||||
for _, s := range pi.segments {
|
||||
if s.namespace != "" {
|
||||
path += "/" + s.namespace + ":" + s.id
|
||||
} else {
|
||||
path += "/" + s.id
|
||||
}
|
||||
}
|
||||
|
||||
return path
|
||||
}
|
||||
|
||||
func (pi *pathInfo) String() string {
|
||||
if len(pi.segments) == 0 {
|
||||
return ""
|
||||
}
|
||||
|
||||
origin, path := pi.path()
|
||||
if origin != "" {
|
||||
return origin + ":" + path
|
||||
}
|
||||
return path
|
||||
}
|
||||
|
||||
func (pi *pathInfo) tags(pathPrefix bool) map[string]string {
|
||||
tags := make(map[string]string, len(pi.keyValues))
|
||||
for _, s := range pi.keyValues {
|
||||
var prefix string
|
||||
if pathPrefix && s.name != "" {
|
||||
prefix = s.name + "_"
|
||||
}
|
||||
for k, v := range s.kv {
|
||||
key := strings.ReplaceAll(prefix+k, "-", "_")
|
||||
|
||||
// Use short-form of key if possible
|
||||
if _, exists := tags[key]; !exists {
|
||||
tags[key] = v
|
||||
continue
|
||||
}
|
||||
tags[s.path+"/"+key] = v
|
||||
}
|
||||
}
|
||||
|
||||
return tags
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue