mirror of
https://github.com/kubernetes-sigs/node-feature-discovery.git
synced 2025-03-06 16:57:10 +00:00
Merge pull request #2038 from SonicInfra/sprig-template
Use Sprig template functions and add asLabelValue function
This commit is contained in:
commit
b62e7c1d29
6 changed files with 115 additions and 57 deletions
|
@ -1100,14 +1100,17 @@ these separate expansions would be created, i.e. the end result would be a
|
|||
union of all the individual expansions.
|
||||
|
||||
Rule templates use the Golang [text/template](https://pkg.go.dev/text/template)
|
||||
package and all its built-in functionality (e.g. pipelines and functions) can
|
||||
package along with [Sprig functions](https://masterminds.github.io/sprig/)
|
||||
and all their functionality (e.g. pipelines and functions) can
|
||||
be used. An example template taking use of the built-in `len` function,
|
||||
advertising the number of PCI network controllers from a specific vendor:
|
||||
advertising the number of PCI network controllers from a specific vendor,
|
||||
and using Sprig's `first`, `trim` and `substr` to advertise the first one's class:
|
||||
<!-- {% raw %} -->
|
||||
|
||||
```yaml
|
||||
labelsTemplate: |
|
||||
num-intel-network-controllers={{ .pci.device | len }}
|
||||
first-intel-network-controllers={{ (.pci.device | first).class | trim | substr 0 63 }}
|
||||
matchFeatures:
|
||||
- feature: pci.device
|
||||
matchExpressions:
|
||||
|
@ -1117,6 +1120,7 @@ advertising the number of PCI network controllers from a specific vendor:
|
|||
```
|
||||
|
||||
<!-- {% endraw %} -->
|
||||
|
||||
Imaginative template pipelines are possible, but care must be taken to
|
||||
produce understandable and maintainable rule sets.
|
||||
|
||||
|
|
9
go.mod
9
go.mod
|
@ -3,6 +3,7 @@ module sigs.k8s.io/node-feature-discovery
|
|||
go 1.24
|
||||
|
||||
require (
|
||||
github.com/Masterminds/sprig/v3 v3.3.0
|
||||
github.com/fsnotify/fsnotify v1.8.0
|
||||
github.com/google/go-cmp v0.6.0
|
||||
github.com/google/uuid v1.6.0
|
||||
|
@ -42,7 +43,10 @@ require (
|
|||
|
||||
require (
|
||||
cel.dev/expr v0.19.0 // indirect
|
||||
dario.cat/mergo v1.0.1 // indirect
|
||||
github.com/JeffAshton/win_pdh v0.0.0-20161109143554-76bb4ee9f0ab // indirect
|
||||
github.com/Masterminds/goutils v1.1.1 // indirect
|
||||
github.com/Masterminds/semver/v3 v3.3.0 // indirect
|
||||
github.com/Microsoft/go-winio v0.6.2 // indirect
|
||||
github.com/NYTimes/gziphandler v1.1.1 // indirect
|
||||
github.com/OneOfOne/xxhash v1.2.8 // indirect
|
||||
|
@ -87,6 +91,7 @@ require (
|
|||
github.com/gorilla/websocket v1.5.0 // indirect
|
||||
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 // indirect
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0 // indirect
|
||||
github.com/huandu/xstrings v1.5.0 // indirect
|
||||
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
||||
github.com/jaypipes/pcidb v1.0.1 // indirect
|
||||
github.com/josharian/intern v1.0.0 // indirect
|
||||
|
@ -96,7 +101,9 @@ require (
|
|||
github.com/mailru/easyjson v0.7.7 // indirect
|
||||
github.com/mattn/go-runewidth v0.0.16 // indirect
|
||||
github.com/mistifyio/go-zfs v2.1.2-0.20190413222219-f784269be439+incompatible // indirect
|
||||
github.com/mitchellh/copystructure v1.2.0 // indirect
|
||||
github.com/mitchellh/go-homedir v1.1.0 // indirect
|
||||
github.com/mitchellh/reflectwalk v1.0.2 // indirect
|
||||
github.com/moby/spdystream v0.5.0 // indirect
|
||||
github.com/moby/sys/mountinfo v0.7.2 // indirect
|
||||
github.com/moby/sys/userns v0.1.0 // indirect
|
||||
|
@ -113,8 +120,10 @@ require (
|
|||
github.com/prometheus/common v0.55.0 // indirect
|
||||
github.com/prometheus/procfs v0.15.1 // indirect
|
||||
github.com/rivo/uniseg v0.4.7 // indirect
|
||||
github.com/shopspring/decimal v1.4.0 // indirect
|
||||
github.com/sirupsen/logrus v1.9.3 // indirect
|
||||
github.com/smarty/assertions v1.15.1 // indirect
|
||||
github.com/spf13/cast v1.7.0 // indirect
|
||||
github.com/spf13/pflag v1.0.6 // indirect
|
||||
github.com/stoewer/go-strcase v1.3.0 // indirect
|
||||
github.com/stretchr/objx v0.5.2 // indirect
|
||||
|
|
20
go.sum
20
go.sum
|
@ -1,7 +1,15 @@
|
|||
cel.dev/expr v0.19.0 h1:lXuo+nDhpyJSpWxpPVi5cPUwzKb+dsdOiw6IreM5yt0=
|
||||
cel.dev/expr v0.19.0/go.mod h1:MrpN08Q+lEBs+bGYdLxxHkZoUSsCp0nSKTs0nTymJgw=
|
||||
dario.cat/mergo v1.0.1 h1:Ra4+bf83h2ztPIQYNP99R6m+Y7KfnARDfID+a+vLl4s=
|
||||
dario.cat/mergo v1.0.1/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk=
|
||||
github.com/JeffAshton/win_pdh v0.0.0-20161109143554-76bb4ee9f0ab h1:UKkYhof1njT1/xq4SEg5z+VpTgjmNeHwPGRQl7takDI=
|
||||
github.com/JeffAshton/win_pdh v0.0.0-20161109143554-76bb4ee9f0ab/go.mod h1:3VYc5hodBMJ5+l/7J4xAyMeuM2PNuepvHlGs8yilUCA=
|
||||
github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI=
|
||||
github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU=
|
||||
github.com/Masterminds/semver/v3 v3.3.0 h1:B8LGeaivUe71a5qox1ICM/JLl0NqZSW5CHyL+hmvYS0=
|
||||
github.com/Masterminds/semver/v3 v3.3.0/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM=
|
||||
github.com/Masterminds/sprig/v3 v3.3.0 h1:mQh0Yrg1XPo6vjYXgtf5OtijNAKJRNcTdOOGZe3tPhs=
|
||||
github.com/Masterminds/sprig/v3 v3.3.0/go.mod h1:Zy1iXRYNqNLUolqCpL4uhk6SHUMAOSCzdgBfDb35Lz0=
|
||||
github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY=
|
||||
github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU=
|
||||
github.com/NYTimes/gziphandler v1.1.1 h1:ZUDjpQae29j0ryrS0u/B8HZfJBtBQHjqw2rQ2cqUQ3I=
|
||||
|
@ -62,6 +70,8 @@ github.com/euank/go-kmsg-parser v2.0.0+incompatible h1:cHD53+PLQuuQyLZeriD1V/esu
|
|||
github.com/euank/go-kmsg-parser v2.0.0+incompatible/go.mod h1:MhmAMZ8V4CYH4ybgdRwPr2TU5ThnS43puaKEMpja1uw=
|
||||
github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
|
||||
github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
|
||||
github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
|
||||
github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
|
||||
github.com/fsnotify/fsnotify v1.8.0 h1:dAwr6QBTBZIkG8roQaJjGof0pp0EeF+tNV7YBP3F/8M=
|
||||
github.com/fsnotify/fsnotify v1.8.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=
|
||||
github.com/fxamacker/cbor/v2 v2.7.0 h1:iM5WgngdRBanHcxugY4JySA0nk1wZorNOpTgCMedv5E=
|
||||
|
@ -125,6 +135,8 @@ github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4
|
|||
github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0 h1:bkypFPDjIYGfCYD5mRBvpqxfYX1YCS1PXdKYWi8FsN0=
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0/go.mod h1:P+Lt/0by1T8bfcF3z737NnSbmxQAppXMRziHUxPOC8k=
|
||||
github.com/huandu/xstrings v1.5.0 h1:2ag3IFq9ZDANvthTwTiqSSZLjDc+BedvHPAp5tJy2TI=
|
||||
github.com/huandu/xstrings v1.5.0/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
|
||||
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
|
||||
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
|
||||
github.com/jaypipes/ghw v0.13.0 h1:log8MXuB8hzTNnSktqpXMHc0c/2k/WgjOMSUtnI1RV4=
|
||||
|
@ -165,8 +177,12 @@ github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6T
|
|||
github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
|
||||
github.com/mistifyio/go-zfs v2.1.2-0.20190413222219-f784269be439+incompatible h1:aKW/4cBs+yK6gpqU3K/oIwk9Q/XICqd3zOX/UFuvqmk=
|
||||
github.com/mistifyio/go-zfs v2.1.2-0.20190413222219-f784269be439+incompatible/go.mod h1:8AuVvqP/mXw1px98n46wfvcGfQ4ci2FwoAjKYxuo3Z4=
|
||||
github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw=
|
||||
github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s=
|
||||
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
|
||||
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||
github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ=
|
||||
github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
|
||||
github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0=
|
||||
github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo=
|
||||
github.com/moby/spdystream v0.5.0 h1:7r0J1Si3QO/kjRitvSLVVFUjxMEb/YLj6S9FF62JBCU=
|
||||
|
@ -217,6 +233,8 @@ github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUc
|
|||
github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8=
|
||||
github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4=
|
||||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/shopspring/decimal v1.4.0 h1:bxl37RwXBklmTi0C79JfXCEBD1cqqHt0bbgBAGFp81k=
|
||||
github.com/shopspring/decimal v1.4.0/go.mod h1:gawqmDU56v4yIKSwfBSFip1HdCCXN8/+DMd9qYNcwME=
|
||||
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
|
||||
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
||||
github.com/smarty/assertions v1.15.1 h1:812oFiXI+G55vxsFf+8bIZ1ux30qtkdqzKbEFwyX3Tk=
|
||||
|
@ -225,6 +243,8 @@ github.com/smartystreets/goconvey v1.8.1 h1:qGjIddxOk4grTu9JPOU31tVfq3cNdBlNa5sS
|
|||
github.com/smartystreets/goconvey v1.8.1/go.mod h1:+/u4qLyY6x1jReYOp7GOM2FSt8aP9CzCZL03bI28W60=
|
||||
github.com/soheilhy/cmux v0.1.5 h1:jjzc5WVemNEDTLwv9tlmemhC73tI08BNOIGwBOo10Js=
|
||||
github.com/soheilhy/cmux v0.1.5/go.mod h1:T7TcVDs9LWfQgPlPsdngu6I6QIoyIFZDDC6sNE1GqG0=
|
||||
github.com/spf13/cast v1.7.0 h1:ntdiHjuueXFgm5nzDRdOS4yfT43P5Fnud6DH50rz/7w=
|
||||
github.com/spf13/cast v1.7.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo=
|
||||
github.com/spf13/cobra v1.9.0 h1:Py5fIuq/lJsRYxcxfOtsJqpmwJWCMOUy2tMJYV8TNHE=
|
||||
github.com/spf13/cobra v1.9.0/go.mod h1:nDyEzZ8ogv936Cinf6g1RU9MRY64Ir93oCnqb9wxYW0=
|
||||
github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o=
|
||||
|
|
|
@ -17,17 +17,16 @@ limitations under the License.
|
|||
package nodefeaturerule
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"maps"
|
||||
"slices"
|
||||
"strings"
|
||||
"text/template"
|
||||
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
"k8s.io/klog/v2"
|
||||
|
||||
nfdv1alpha1 "sigs.k8s.io/node-feature-discovery/api/nfd/v1alpha1"
|
||||
"sigs.k8s.io/node-feature-discovery/pkg/apis/nfd/template"
|
||||
"sigs.k8s.io/node-feature-discovery/pkg/utils"
|
||||
)
|
||||
|
||||
|
@ -188,12 +187,12 @@ func executeLabelsTemplate(r *nfdv1alpha1.Rule, in matchedFeatures, out map[stri
|
|||
return nil
|
||||
}
|
||||
|
||||
th, err := newTemplateHelper(r.LabelsTemplate)
|
||||
th, err := template.NewHelper(r.LabelsTemplate)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to parse LabelsTemplate: %w", err)
|
||||
}
|
||||
|
||||
labels, err := th.expandMap(in)
|
||||
labels, err := th.ExpandMap(in)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to expand LabelsTemplate: %w", err)
|
||||
}
|
||||
|
@ -208,12 +207,12 @@ func executeVarsTemplate(r *nfdv1alpha1.Rule, in matchedFeatures, out map[string
|
|||
return nil
|
||||
}
|
||||
|
||||
th, err := newTemplateHelper(r.VarsTemplate)
|
||||
th, err := template.NewHelper(r.VarsTemplate)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
vars, err := th.expandMap(in)
|
||||
vars, err := th.ExpandMap(in)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -309,47 +308,3 @@ func evaluateFeatureMatcher(m *nfdv1alpha1.FeatureMatcher, features *nfdv1alpha1
|
|||
}
|
||||
return isMatch, status, nil
|
||||
}
|
||||
|
||||
type templateHelper struct {
|
||||
template *template.Template
|
||||
}
|
||||
|
||||
func newTemplateHelper(name string) (*templateHelper, error) {
|
||||
tmpl, err := template.New("").Option("missingkey=error").Parse(name)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid template: %w", err)
|
||||
}
|
||||
return &templateHelper{template: tmpl}, nil
|
||||
}
|
||||
|
||||
func (h *templateHelper) execute(data interface{}) (string, error) {
|
||||
var tmp bytes.Buffer
|
||||
if err := h.template.Execute(&tmp, data); err != nil {
|
||||
return "", err
|
||||
}
|
||||
return tmp.String(), nil
|
||||
}
|
||||
|
||||
// expandMap is a helper for expanding a template in to a map of strings. Data
|
||||
// after executing the template is expexted to be key=value pairs separated by
|
||||
// newlines.
|
||||
func (h *templateHelper) expandMap(data interface{}) (map[string]string, error) {
|
||||
expanded, err := h.execute(data)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Split out individual key-value pairs
|
||||
out := make(map[string]string)
|
||||
for _, item := range strings.Split(expanded, "\n") {
|
||||
// Remove leading/trailing whitespace and skip empty lines
|
||||
if trimmed := strings.TrimSpace(item); trimmed != "" {
|
||||
split := strings.SplitN(trimmed, "=", 2)
|
||||
if len(split) == 1 {
|
||||
return nil, fmt.Errorf("missing value in expanded template line %q, (format must be '<key>=<value>')", trimmed)
|
||||
}
|
||||
out[split[0]] = split[1]
|
||||
}
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
|
71
pkg/apis/nfd/template/template.go
Normal file
71
pkg/apis/nfd/template/template.go
Normal file
|
@ -0,0 +1,71 @@
|
|||
/*
|
||||
Copyright 2025 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package template
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"strings"
|
||||
"text/template"
|
||||
|
||||
"github.com/Masterminds/sprig/v3"
|
||||
)
|
||||
|
||||
type Helper struct {
|
||||
template *template.Template
|
||||
}
|
||||
|
||||
func NewHelper(name string) (*Helper, error) {
|
||||
tmpl := template.New("").Funcs(sprig.FuncMap()).Option("missingkey=error")
|
||||
tmpl, err := tmpl.Parse(name)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid template: %w", err)
|
||||
}
|
||||
return &Helper{template: tmpl}, nil
|
||||
}
|
||||
|
||||
func (h *Helper) execute(data interface{}) (string, error) {
|
||||
var tmp bytes.Buffer
|
||||
if err := h.template.Execute(&tmp, data); err != nil {
|
||||
return "", err
|
||||
}
|
||||
return tmp.String(), nil
|
||||
}
|
||||
|
||||
// ExpandMap is a helper for expanding a template in to a map of strings. Data
|
||||
// after executing the template is expected to be key=value pairs separated by
|
||||
// newlines.
|
||||
func (h *Helper) ExpandMap(data interface{}) (map[string]string, error) {
|
||||
expanded, err := h.execute(data)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Split out individual key-value pairs
|
||||
out := make(map[string]string)
|
||||
for _, item := range strings.Split(expanded, "\n") {
|
||||
// Remove leading/trailing whitespace and skip empty lines
|
||||
if trimmed := strings.TrimSpace(item); trimmed != "" {
|
||||
split := strings.SplitN(trimmed, "=", 2)
|
||||
if len(split) == 1 {
|
||||
return nil, fmt.Errorf("missing value in expanded template line %q, (format must be '<key>=<value>')", trimmed)
|
||||
}
|
||||
out[split[0]] = split[1]
|
||||
}
|
||||
}
|
||||
return out, nil
|
||||
}
|
|
@ -19,13 +19,13 @@ package validate
|
|||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"text/template"
|
||||
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
k8sQuantity "k8s.io/apimachinery/pkg/api/resource"
|
||||
k8svalidation "k8s.io/apimachinery/pkg/util/validation"
|
||||
|
||||
nfdv1alpha1 "sigs.k8s.io/node-feature-discovery/api/nfd/v1alpha1"
|
||||
"sigs.k8s.io/node-feature-discovery/pkg/apis/nfd/template"
|
||||
)
|
||||
|
||||
var (
|
||||
|
@ -70,11 +70,10 @@ func MatchFeatures(matchFeature nfdv1alpha1.FeatureMatcher) []error {
|
|||
// template is invalid.
|
||||
func Template(labelsTemplate string) []error {
|
||||
var validationErr []error
|
||||
|
||||
// Validate template
|
||||
_, err := template.New("").Option("missingkey=error").Parse(labelsTemplate)
|
||||
// Only validate template
|
||||
_, err := template.NewHelper(labelsTemplate)
|
||||
if err != nil {
|
||||
validationErr = append(validationErr, fmt.Errorf("invalid template: %w", err))
|
||||
validationErr = append(validationErr, err)
|
||||
}
|
||||
return validationErr
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue