1+ package namereference
2+
3+ import (
4+ "fmt"
5+
6+ "github.com/pkg/errors"
7+ "sigs.k8s.io/kustomize/api/filters/fieldspec"
8+ "sigs.k8s.io/kustomize/api/resmap"
9+ "sigs.k8s.io/kustomize/api/resource"
10+ "sigs.k8s.io/kustomize/api/types"
11+ "sigs.k8s.io/kustomize/kyaml/kio"
12+ "sigs.k8s.io/kustomize/kyaml/resid"
13+ "sigs.k8s.io/kustomize/kyaml/yaml"
14+ )
15+
16+ type UnlimitedNameRefFilter struct {
17+ Referrer * resource.Resource
18+ NameFieldToUpdate types.FieldSpec
19+ ReferralTarget resid.Gvk
20+ ReferralCandidates resmap.ResMap
21+
22+ }
23+
24+ func (f UnlimitedNameRefFilter ) Filter (nodes []* yaml.RNode ) ([]* yaml.RNode , error ) {
25+ return kio .FilterAll (yaml .FilterFunc (f .run )).Filter (nodes )
26+ }
27+
28+ func (f UnlimitedNameRefFilter ) run (node * yaml.RNode ) (* yaml.RNode , error ) {
29+ if node .GetNamespace () != f .Referrer .GetNamespace () {
30+ return nil , fmt .Errorf ("not in the same namespace" )
31+ }
32+ if err := node .PipeE (fieldspec.Filter {
33+ FieldSpec : f .NameFieldToUpdate ,
34+ SetValue : f .updateName ,
35+ }); err != nil {
36+ return nil , errors .Wrapf (
37+ err , "updating name reference in '%s' field of '%s'" ,
38+ f .NameFieldToUpdate .Path , f .Referrer .CurId ().String ())
39+ }
40+ return node , nil
41+ }
42+
43+ func (f UnlimitedNameRefFilter ) updateName (node * yaml.RNode ) error {
44+ if yaml .IsMissingOrNull (node ) {
45+ return nil
46+ }
47+ referrals := doSieve (f .ReferralCandidates .Resources (), f .sameCurrentNamespaceAsReferrer ())
48+ if len (referrals ) == 0 {
49+ return nil
50+ }
51+ referral := referrals [0 ]
52+ return node .PipeE (yaml.FieldSetter {StringValue : referral .GetName ()})
53+ }
54+
55+ type sieveFunc func (* resource.Resource ) bool
56+
57+ func doSieve (list []* resource.Resource , fn sieveFunc ) (s []* resource.Resource ) {
58+ for _ , r := range list {
59+ if fn (r ) {
60+ s = append (s , r )
61+ }
62+ }
63+ return
64+ }
65+
66+ func (f UnlimitedNameRefFilter ) sameCurrentNamespaceAsReferrer () sieveFunc {
67+ referrerCurId := f .Referrer .CurId ()
68+ if referrerCurId .IsClusterScoped () {
69+ // If the referrer is cluster-scoped, let anything through.
70+ return func (_ * resource.Resource ) bool {return true }
71+ }
72+ return func (r * resource.Resource ) bool {
73+ if r .CurId ().IsClusterScoped () {
74+ // Allow cluster-scoped through.
75+ return true
76+ }
77+ if r .GetKind () == "ServiceAccount" {
78+ // Allow service accounts through, even though they
79+ // are in a namespace. A RoleBinding in another namespace
80+ // can reference them.
81+ return true
82+ }
83+ return referrerCurId .IsNsEquals (r .CurId ())
84+ }
85+ }
0 commit comments