blob: d43809c335cf94aa616ddbbe5738e856993af9ba [file] [log] [blame]
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +04001package installer
2
3import (
4 "bytes"
5 "context"
6 _ "embed"
7 "encoding/json"
8 "fmt"
9 "io"
10 "net/http"
11 "strings"
12 "testing"
13 "time"
14
15 "cuelang.org/go/cue"
16 "cuelang.org/go/cue/cuecontext"
17 fluxcd "github.com/fluxcd/source-controller/api/v1beta2"
18 "helm.sh/helm/v3/pkg/registry"
19 // "github.com/go-git/go-billy/v5/memfs"
20 "github.com/go-git/go-billy/v5/osfs"
21 "helm.sh/helm/v3/pkg/action"
22 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
23 "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
24 "k8s.io/apimachinery/pkg/runtime/schema"
25 "k8s.io/client-go/dynamic"
26 "k8s.io/client-go/rest"
27 "k8s.io/client-go/tools/clientcmd"
28)
29
30//go:embed values-tmpl/rpuppy.cue
31var rpuppyConfig []byte
32
33type ContainerImage struct {
34 Repository string
35 Tag string
36 PullPolicy string
37}
38
39type Chart struct {
40 Source ChartSource
41 Chart string
42}
43
44type ChartSource struct {
45 Kind string
46 Address string
47}
48
49type ApplicationConfig struct {
50 Images map[string]ContainerImage
51 Charts map[string]Chart
52}
53
54type client struct {
55 clientset dynamic.Interface
56}
57
58func (c *client) CreateHelmChart(chart fluxcd.HelmChart) error {
59 var buf bytes.Buffer
60 if err := json.NewEncoder(&buf).Encode(chart); err != nil {
61 return nil
62 }
63 var u unstructured.Unstructured
64 if err := json.NewDecoder(&buf).Decode(&u.Object); err != nil {
65 return err
66 }
67 _, err := c.clientset.Resource(schema.GroupVersionResource{Group: fluxcd.GroupVersion.Group, Version: fluxcd.GroupVersion.Version, Resource: "helmcharts"}).Namespace(chart.Namespace).Create(context.TODO(), &u, metav1.CreateOptions{})
68 return err
69}
70
71func NewClient(kubeconfig string) (*client, error) {
72 if kubeconfig == "" {
73 config, err := rest.InClusterConfig()
74 if err != nil {
75 return nil, err
76 }
77 c, err := dynamic.NewForConfig(config)
78 if err != nil {
79 return nil, err
80 }
81 return &client{c}, nil
82
83 } else {
84 config, err := clientcmd.BuildConfigFromFlags("", kubeconfig)
85 if err != nil {
86 return nil, err
87 }
88 c, err := dynamic.NewForConfig(config)
89 if err != nil {
90 return nil, err
91 }
92 return &client{c}, nil
93 }
94}
95
96const networkSchema = `
97#Network: {
98 IngressClass: string
99 CertificateIssuer: string
100 Domain: string
101}
102
103value: %s
104
105valid: #Network & value
106`
107
108type StringFormatter struct {
109 s strings.Builder
110}
111
112func (f *StringFormatter) Write(b []byte) (n int, err error) {
113 return f.s.Write(b)
114}
115
116func (f *StringFormatter) Width() (wid int, ok bool) {
117 return 4, true
118}
119
120func (f *StringFormatter) Precision() (prec int, ok bool) {
121 return 4, true
122}
123
124func (f *StringFormatter) Flag(c int) bool {
125 return false
126}
127
128func IsNetwork(v cue.Value) bool {
129 if v.Value().Kind() != cue.StructKind {
130 return false
131 }
132 value := fmt.Sprintf("%#v", v)
133 s := fmt.Sprintf(networkSchema, value)
134 c := cuecontext.New()
135 u := c.CompileString(s)
136 return u.Err() == nil && u.Validate() == nil
137}
138
139func PrintSchema(v cue.Value) {
140 f, _ := v.Fields()
141 for f.Next() {
142 fmt.Printf("%s\n", f.Selector())
143 if IsNetwork(f.Value()) {
144 fmt.Println("network")
145 }
146 PrintSchema(f.Value())
147 }
148}
149
150func TestInput(t *testing.T) {
151 c := cuecontext.New()
152 cfg := c.CompileBytes(rpuppyConfig)
153 input := c.CompileString(`
154global: {
155 id: "foo"
156}
157input: {
158 network: {
159 name: "public"
160 ingressClass: "dodo-ingress-public"
161 certificateIssuer: "rpuppu-public"
162 domain: "lekva.me"
163 }
164 subdomain: "rpuppy"
165}
166`)
167 if cfg.Err() != nil {
168 panic(cfg.Err())
169 }
170 if err := cfg.Validate(); err != nil {
171 panic(err)
172 }
173 PrintSchema(cfg.Eval().LookupPath(cue.ParsePath("input")))
174 out := cfg.Unify(input)
175 if out.Err() != nil {
176 panic(out.Err())
177 }
178 if err := out.Validate(); err != nil {
179 panic(err)
180 }
181 fmt.Printf("%#v\n", out)
182 e := out.Eval()
183 if e.Err() != nil {
184 panic(out.Err())
185 }
186 if err := e.Validate(); err != nil {
187 panic(err)
188 }
189 fmt.Printf("%#v\n", e)
190 fmt.Println(e.IsConcrete())
191}
192
193func TestParseApplicationConfig(t *testing.T) {
194 return
195 var r cue.Runtime
196 i, err := r.Compile("rpuppy", rpuppyConfig)
197 if err != nil {
198 panic(err)
199 }
200 var cfg ApplicationConfig
201 if err := i.Value().Decode(&cfg); err != nil {
202 panic(err)
203 }
204 fmt.Printf("%+v\n", cfg)
205 _, err = NewClient("/Users/lekva/dev/src/pcloud/priv/kubeconfig-hetzner")
206 if err != nil {
207 panic(err)
208 }
209
210 for name, c := range cfg.Charts {
211 chart := fluxcd.HelmChart{
212 TypeMeta: metav1.TypeMeta{
213 APIVersion: fluxcd.GroupVersion.String(),
214 Kind: "HelmChart",
215 },
216 ObjectMeta: metav1.ObjectMeta{
217 Name: name,
218 Namespace: "dodo",
219 },
220 Spec: fluxcd.HelmChartSpec{
221 Chart: c.Chart,
222 SourceRef: fluxcd.LocalHelmChartSourceReference{
223 Kind: c.Source.Kind,
224 Name: c.Source.Address,
225 },
226 Interval: metav1.Duration{time.Hour},
227 },
228 }
229 fmt.Printf("%+v\n", chart)
230 // if err := client.CreateHelmChart(chart); err != nil {
231 // panic(err)
232 // }
233 }
234}
235
236type downloader struct {
237 client *http.Client
238}
239
240func NewDownloader() *downloader {
241 return &downloader{
242 client: http.DefaultClient,
243 }
244}
245
246func (d *downloader) Download(addr string, out io.Writer) error {
247 resp, err := d.client.Get(addr)
248 if err != nil {
249 return err
250 }
251 if _, err := io.Copy(out, resp.Body); err != nil {
252 return err
253 }
254 return nil
255}
256
257func TestDownload(t *testing.T) {
258 return
259 // fs := memfs.New()
260 fs := osfs.New("/tmp")
261 func() {
262 f, err := fs.Create("/chart")
263 if err != nil {
264 panic(err)
265 }
266 defer f.Close()
267 d := NewDownloader()
268 if err := d.Download("http://localhost:9090/helmchart/dodo/rpuppy/rpuppy-0.0.1.tgz", f); err != nil {
269 panic(err)
270 }
271 }()
272 client, err := registry.NewClient()
273 if err != nil {
274 panic(err)
275 }
276 if err := client.Login("https://harbor.t46.lekva.me", registry.LoginOptBasicAuth("admin", "Harbor12345")); err != nil {
277 panic(err)
278 }
279 defer client.Logout("https://harbor.t46.lekva.me")
280 push := action.NewPushWithOpts(action.WithPushConfig(&action.Configuration{
281 RegistryClient: client,
282 }))
283 fmt.Printf("%+v\n", push)
284 res, err := push.Run("/tmp/chart", "oci://harbor.t46.lekva.me/library/charts")
285 fmt.Println(res)
286 if err != nil {
287 panic(err)
288 }
289 // cfg, err := ActionConfigFactory{"/Users/lekva/dev/src/pcloud/priv/kubeconfig-hetzner"}.New("")
290 // installer := action.NewInstall(config)
291 // installer.Namespace = env.Name
292 // installer.ReleaseName = "metallb-ns"
293 // installer.Wait = true
294 // installer.WaitForJobs = true
295
296}