mirror of
https://github.com/kubernetes-sigs/kustomize.git
synced 2026-05-17 18:25:26 +00:00
* feat: Add regex support for Replacement selectors * Add new tests for regex support * Earlier exit with rejectAny, and fix linting * Add example Use cases using regex
138 lines
3.7 KiB
Go
138 lines
3.7 KiB
Go
// Copyright 2021 The Kubernetes Authors.
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
|
|
package types
|
|
|
|
import (
|
|
"fmt"
|
|
"strings"
|
|
|
|
"sigs.k8s.io/kustomize/kyaml/resid"
|
|
)
|
|
|
|
const DefaultReplacementFieldPath = "metadata.name"
|
|
|
|
// Replacement defines how to perform a substitution
|
|
// where it is from and where it is to.
|
|
type Replacement struct {
|
|
// The source of the value.
|
|
Source *SourceSelector `json:"source,omitempty" yaml:"source,omitempty"`
|
|
|
|
// The N fields to write the value to.
|
|
Targets []*TargetSelector `json:"targets,omitempty" yaml:"targets,omitempty"`
|
|
|
|
// Used to define an static value
|
|
SourceValue *string `json:"sourceValue,omitempty" yaml:"sourceValue,omitempty"`
|
|
}
|
|
|
|
// SourceSelector is the source of the replacement transformer.
|
|
type SourceSelector struct {
|
|
// A specific object to read it from.
|
|
resid.ResId `json:",inline,omitempty" yaml:",inline,omitempty"`
|
|
|
|
// Structured field path expected in the allowed object.
|
|
FieldPath string `json:"fieldPath,omitempty" yaml:"fieldPath,omitempty"`
|
|
|
|
// Used to refine the interpretation of the field.
|
|
Options *FieldOptions `json:"options,omitempty" yaml:"options,omitempty"`
|
|
}
|
|
|
|
func (s *SourceSelector) String() string {
|
|
if s == nil {
|
|
return ""
|
|
}
|
|
result := []string{s.ResId.String()}
|
|
if s.FieldPath != "" {
|
|
result = append(result, s.FieldPath)
|
|
}
|
|
if opts := s.Options.String(); opts != "" {
|
|
result = append(result, opts)
|
|
}
|
|
return strings.Join(result, ":")
|
|
}
|
|
|
|
// TargetSelector specifies fields in one or more objects.
|
|
type TargetSelector struct {
|
|
// Include objects that match this.
|
|
Select *Selector `json:"select" yaml:"select"`
|
|
|
|
// From the allowed set, remove objects that match this.
|
|
Reject []*Selector `json:"reject,omitempty" yaml:"reject,omitempty"`
|
|
|
|
// Structured field paths expected in each allowed object.
|
|
FieldPaths []string `json:"fieldPaths,omitempty" yaml:"fieldPaths,omitempty"`
|
|
|
|
// Used to refine the interpretation of the field.
|
|
Options *FieldOptions `json:"options,omitempty" yaml:"options,omitempty"`
|
|
}
|
|
|
|
type TargetSelectorRegex struct {
|
|
targetSelector *TargetSelector
|
|
selectRegex *SelectorRegex
|
|
rejectRegex []*SelectorRegex
|
|
}
|
|
|
|
func NewTargetSelectorRegex(ts *TargetSelector) (*TargetSelectorRegex, error) {
|
|
tsr := new(TargetSelectorRegex)
|
|
tsr.targetSelector = ts
|
|
var err error
|
|
|
|
tsr.selectRegex, err = NewSelectorRegex(ts.Select)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
rej := []*SelectorRegex{}
|
|
for _, r := range ts.Reject {
|
|
rr, err := NewSelectorRegex(r)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
rej = append(rej, rr)
|
|
}
|
|
tsr.rejectRegex = rej
|
|
|
|
return tsr, nil
|
|
}
|
|
|
|
func (tsr *TargetSelectorRegex) Selects(id resid.ResId) bool {
|
|
return tsr.selectRegex.MatchGvk(id.Gvk) && tsr.selectRegex.MatchName(id.Name) && tsr.selectRegex.MatchNamespace(id.Namespace)
|
|
}
|
|
|
|
func (tsr *TargetSelectorRegex) RejectsAny(ids []resid.ResId) bool {
|
|
for _, r := range tsr.rejectRegex {
|
|
if r.selector.ResId.IsEmpty() {
|
|
continue
|
|
}
|
|
for _, id := range ids {
|
|
if r.MatchGvk(id.Gvk) && r.MatchName(id.Name) && r.MatchNamespace(id.Namespace) {
|
|
return true
|
|
}
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
// FieldOptions refine the interpretation of FieldPaths.
|
|
type FieldOptions struct {
|
|
// Used to split/join the field.
|
|
Delimiter string `json:"delimiter,omitempty" yaml:"delimiter,omitempty"`
|
|
|
|
// Which position in the split to consider.
|
|
Index int `json:"index,omitempty" yaml:"index,omitempty"`
|
|
|
|
// TODO (#3492): Implement use of this option
|
|
// None, Base64, URL, Hex, etc
|
|
Encoding string `json:"encoding,omitempty" yaml:"encoding,omitempty"`
|
|
|
|
// If field missing, add it.
|
|
Create bool `json:"create,omitempty" yaml:"create,omitempty"`
|
|
}
|
|
|
|
func (fo *FieldOptions) String() string {
|
|
if fo == nil || (fo.Delimiter == "" && !fo.Create) {
|
|
return ""
|
|
}
|
|
return fmt.Sprintf("%s(%d), create=%t", fo.Delimiter, fo.Index, fo.Create)
|
|
}
|