...
1
2
3
4 package starlark
5
6 import (
7 "bytes"
8 "fmt"
9 "io"
10 "net/http"
11 "os"
12
13 "go.starlark.net/starlark"
14 "sigs.k8s.io/kustomize/kyaml/errors"
15 "sigs.k8s.io/kustomize/kyaml/fn/runtime/runtimeutil"
16 "sigs.k8s.io/kustomize/kyaml/internal/forked/github.com/qri-io/starlib/util"
17 "sigs.k8s.io/kustomize/kyaml/kio/filters"
18 "sigs.k8s.io/kustomize/kyaml/yaml"
19 )
20
21
22 type Filter struct {
23 Name string
24
25
26 Program string
27
28
29 URL string
30
31
32 Path string
33
34 runtimeutil.FunctionFilter
35 }
36
37 func (sf *Filter) String() string {
38 return fmt.Sprintf(
39 "name: %v path: %v url: %v program: %v", sf.Name, sf.Path, sf.URL, sf.Program)
40 }
41
42 func (sf *Filter) Filter(nodes []*yaml.RNode) ([]*yaml.RNode, error) {
43 if err := sf.setup(); err != nil {
44 return nil, err
45 }
46 sf.FunctionFilter.Run = sf.Run
47
48 return sf.FunctionFilter.Filter(nodes)
49 }
50
51 func (sf *Filter) setup() error {
52 if (sf.URL != "" && sf.Path != "") ||
53 (sf.URL != "" && sf.Program != "") ||
54 (sf.Path != "" && sf.Program != "") {
55 return errors.Errorf("Filter Path, Program and URL are mutually exclusive")
56 }
57
58
59 if sf.Path != "" {
60 b, err := os.ReadFile(sf.Path)
61 if err != nil {
62 return err
63 }
64 sf.Program = string(b)
65 }
66
67
68 if sf.URL != "" {
69 err := func() error {
70 resp, err := http.Get(sf.URL)
71 if err != nil {
72 return err
73 }
74 defer resp.Body.Close()
75 b, err := io.ReadAll(resp.Body)
76 if err != nil {
77 return err
78 }
79 sf.Program = string(b)
80 return nil
81 }()
82 if err != nil {
83 return err
84 }
85 }
86
87 return nil
88 }
89
90 func (sf *Filter) Run(reader io.Reader, writer io.Writer) error {
91
92
93 value, err := sf.readResourceList(reader)
94 if err != nil {
95 return errors.Wrap(err)
96 }
97
98
99 thread := &starlark.Thread{Name: sf.Name}
100
101 ctx := &Context{resourceList: value}
102 pd, err := ctx.predeclared()
103 if err != nil {
104 return errors.Wrap(err)
105 }
106 _, err = starlark.ExecFile(thread, sf.Name, sf.Program, pd)
107 if err != nil {
108 return errors.Wrap(err)
109 }
110
111 return sf.writeResourceList(value, writer)
112 }
113
114
115 func (sf *Filter) readResourceList(reader io.Reader) (starlark.Value, error) {
116
117 rl := bytes.Buffer{}
118 _, err := rl.ReadFrom(reader)
119 if err != nil {
120 return nil, errors.Wrap(err)
121 }
122 rn, err := yaml.Parse(rl.String())
123 if err != nil {
124 return nil, errors.Wrap(err)
125 }
126
127
128 b, err := yaml.Marshal(rn.Document())
129 if err != nil {
130 return nil, errors.Wrap(err)
131 }
132 var in map[string]interface{}
133 err = yaml.Unmarshal(b, &in)
134 if err != nil {
135 return nil, errors.Wrap(err)
136 }
137 return util.Marshal(in)
138 }
139
140
141 func (sf *Filter) writeResourceList(value starlark.Value, writer io.Writer) error {
142
143
144 out, err := util.Unmarshal(value)
145 if err != nil {
146 return errors.Wrap(err)
147 }
148 b, err := yaml.Marshal(out)
149 if err != nil {
150 return errors.Wrap(err)
151 }
152
153 rl, err := yaml.Parse(string(b))
154 if err != nil {
155 return errors.Wrap(err)
156 }
157
158
159 items, err := rl.Pipe(yaml.Lookup("items"))
160 if err != nil {
161 return errors.Wrap(err)
162 }
163 err = items.VisitElements(func(node *yaml.RNode) error {
164
165
166 _, err := filters.FormatFilter{}.Filter([]*yaml.RNode{node})
167 return err
168 })
169 if err != nil {
170 return errors.Wrap(err)
171 }
172
173 s, err := rl.String()
174 if err != nil {
175 return errors.Wrap(err)
176 }
177
178 _, err = writer.Write([]byte(s))
179 return err
180 }
181
View as plain text