blob: cee8a5f98b8f7dbad1149f90c0434322966d758a [file] [log] [blame]
giolekva8aa73e82022-07-09 11:34:39 +04001package installer
giolekva050609f2021-12-29 15:51:40 +04002
giolekva8aa73e82022-07-09 11:34:39 +04003import (
Giorgi Lekveishvili3f697b12024-01-04 00:56:06 +04004 "bytes"
gio0eaf2712024-04-14 13:08:46 +04005 _ "embed"
Giorgi Lekveishvili9b52ab92024-01-05 13:12:48 +04006 "encoding/json"
Giorgi Lekveishvilibd6be7f2023-05-26 15:51:28 +04007 "fmt"
Giorgi Lekveishvili08af67a2024-01-18 08:53:05 +04008 template "html/template"
gio3cdee592024-04-17 10:15:56 +04009 "net"
gioe72b54f2024-04-22 10:44:41 +040010 "net/netip"
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +040011 "strings"
Giorgi Lekveishvili0ccd1482023-06-21 15:02:24 +040012
Giorgi Lekveishvili9b52ab92024-01-05 13:12:48 +040013 "cuelang.org/go/cue"
gio308105e2024-04-19 13:12:13 +040014 "cuelang.org/go/cue/build"
15 "cuelang.org/go/cue/cuecontext"
16 "cuelang.org/go/cue/load"
Giorgi Lekveishvili9b52ab92024-01-05 13:12:48 +040017 cueyaml "cuelang.org/go/encoding/yaml"
giof8843412024-05-22 16:38:05 +040018 helmv2 "github.com/fluxcd/helm-controller/api/v2"
giolekva8aa73e82022-07-09 11:34:39 +040019)
giolekva050609f2021-12-29 15:51:40 +040020
giof8843412024-05-22 16:38:05 +040021//go:embed app_configs/dodo_app.cue
22var dodoAppCue []byte
gio0eaf2712024-04-14 13:08:46 +040023
giof8843412024-05-22 16:38:05 +040024//go:embed app_configs/app_base.cue
25var cueBaseConfig []byte
gio0eaf2712024-04-14 13:08:46 +040026
giof8843412024-05-22 16:38:05 +040027//go:embed app_configs/app_global_env.cue
28var cueEnvAppGlobal []byte
Giorgi Lekveishvilie009a5d2024-01-05 14:10:11 +040029
giof8843412024-05-22 16:38:05 +040030//go:embed app_configs/app_global_infra.cue
31var cueInfraAppGlobal []byte
Giorgi Lekveishvilie009a5d2024-01-05 14:10:11 +040032
gioe72b54f2024-04-22 10:44:41 +040033type rendered struct {
giof8843412024-05-22 16:38:05 +040034 Name string
35 Readme string
36 Resources CueAppData
37 HelmCharts HelmCharts
38 ContainerImages map[string]ContainerImage
39 Ports []PortForward
40 Data CueAppData
41 URL string
42 Help []HelpDocument
43 Icon string
gio94904702024-07-26 16:58:34 +040044 Raw []byte
Davit Tabidze56f86a42024-04-09 19:15:25 +040045}
46
47type HelpDocument struct {
48 Title string
49 Contents string
50 Children []HelpDocument
Giorgi Lekveishvili9b52ab92024-01-05 13:12:48 +040051}
52
giof8843412024-05-22 16:38:05 +040053type ContainerImage struct {
54 Registry string `json:"registry"`
55 Repository string `json:"repository"`
56 Name string `json:"name"`
57 Tag string `json:"tag"`
58}
59
60type helmChartRef struct {
61 Kind string `json:"kind"`
62}
63
64type HelmCharts struct {
65 Git map[string]HelmChartGitRepo
66}
67
68type HelmChartGitRepo struct {
69 Address string `json:"address"`
70 Branch string `json:"branch"`
71 Path string `json:"path"`
72}
73
gioe72b54f2024-04-22 10:44:41 +040074type EnvAppRendered struct {
75 rendered
76 Config AppInstanceConfig
77}
78
79type InfraAppRendered struct {
80 rendered
81 Config InfraAppInstanceConfig
82}
83
gio3cdee592024-04-17 10:15:56 +040084type PortForward struct {
85 Allocator string `json:"allocator"`
gioefa0ed42024-06-13 12:31:43 +040086 ReserveAddr string `json:"reservator"`
giocdfa3722024-06-13 20:10:14 +040087 RemoveAddr string `json:"deallocator"`
gio3cdee592024-04-17 10:15:56 +040088 Protocol string `json:"protocol"`
89 SourcePort int `json:"sourcePort"`
90 TargetService string `json:"targetService"`
91 TargetPort int `json:"targetPort"`
92}
93
94type AppType int
95
96const (
97 AppTypeInfra AppType = iota
98 AppTypeEnv
99)
100
Giorgi Lekveishvili08af67a2024-01-18 08:53:05 +0400101type App interface {
102 Name() string
gio44f621b2024-04-29 09:44:38 +0400103 Type() AppType
104 Slug() string
Giorgi Lekveishvili08af67a2024-01-18 08:53:05 +0400105 Description() string
106 Icon() template.HTML
107 Schema() Schema
gioef01fbb2024-04-12 16:52:59 +0400108 Namespace() string
gio3cdee592024-04-17 10:15:56 +0400109}
110
111type InfraConfig struct {
gioe72b54f2024-04-22 10:44:41 +0400112 Name string `json:"pcloudEnvName,omitempty"` // #TODO(gio): change to name
113 PublicIP []net.IP `json:"publicIP,omitempty"`
114 InfraNamespacePrefix string `json:"namespacePrefix,omitempty"`
115 InfraAdminPublicKey []byte `json:"infraAdminPublicKey,omitempty"`
gio3cdee592024-04-17 10:15:56 +0400116}
117
gio7841f4f2024-07-26 19:53:49 +0400118type InfraNetwork struct {
119 Name string `json:"name,omitempty"`
120 IngressClass string `json:"ingressClass,omitempty"`
121 CertificateIssuer string `json:"certificateIssuer,omitempty"`
122 AllocatePortAddr string `json:"allocatePortAddr,omitempty"`
123 ReservePortAddr string `json:"reservePortAddr,omitempty"`
124 DeallocatePortAddr string `json:"deallocatePortAddr,omitempty"`
125}
126
gio3cdee592024-04-17 10:15:56 +0400127type InfraApp interface {
128 App
gio7841f4f2024-07-26 19:53:49 +0400129 Render(release Release, infra InfraConfig, networks []InfraNetwork, values map[string]any, charts map[string]helmv2.HelmChartTemplateSpec) (InfraAppRendered, error)
gioe72b54f2024-04-22 10:44:41 +0400130}
131
132type EnvNetwork struct {
133 DNS net.IP `json:"dns,omitempty"`
134 DNSInClusterIP net.IP `json:"dnsInClusterIP,omitempty"`
135 Ingress net.IP `json:"ingress,omitempty"`
136 Headscale net.IP `json:"headscale,omitempty"`
137 ServicesFrom net.IP `json:"servicesFrom,omitempty"`
138 ServicesTo net.IP `json:"servicesTo,omitempty"`
139}
140
141func NewEnvNetwork(subnet net.IP) (EnvNetwork, error) {
142 addr, err := netip.ParseAddr(subnet.String())
143 if err != nil {
144 return EnvNetwork{}, err
145 }
146 if !addr.Is4() {
147 return EnvNetwork{}, fmt.Errorf("Expected IPv4, got %s instead", addr)
148 }
149 dns := addr.Next()
150 ingress := dns.Next()
151 headscale := ingress.Next()
152 b := addr.AsSlice()
153 if b[3] != 0 {
154 return EnvNetwork{}, fmt.Errorf("Expected last byte to be zero, got %d instead", b[3])
155 }
156 b[3] = 10
157 servicesFrom, ok := netip.AddrFromSlice(b)
158 if !ok {
159 return EnvNetwork{}, fmt.Errorf("Must not reach")
160 }
161 b[3] = 254
162 servicesTo, ok := netip.AddrFromSlice(b)
163 if !ok {
164 return EnvNetwork{}, fmt.Errorf("Must not reach")
165 }
166 b[3] = b[2]
167 b[2] = b[1]
168 b[0] = 10
169 b[1] = 44
170 dnsInClusterIP, ok := netip.AddrFromSlice(b)
171 if !ok {
172 return EnvNetwork{}, fmt.Errorf("Must not reach")
173 }
174 return EnvNetwork{
175 DNS: net.ParseIP(dns.String()),
176 DNSInClusterIP: net.ParseIP(dnsInClusterIP.String()),
177 Ingress: net.ParseIP(ingress.String()),
178 Headscale: net.ParseIP(headscale.String()),
179 ServicesFrom: net.ParseIP(servicesFrom.String()),
180 ServicesTo: net.ParseIP(servicesTo.String()),
181 }, nil
gio3cdee592024-04-17 10:15:56 +0400182}
183
gioe72b54f2024-04-22 10:44:41 +0400184type EnvConfig struct {
185 Id string `json:"id,omitempty"`
186 InfraName string `json:"pcloudEnvName,omitempty"`
187 Domain string `json:"domain,omitempty"`
188 PrivateDomain string `json:"privateDomain,omitempty"`
189 ContactEmail string `json:"contactEmail,omitempty"`
190 AdminPublicKey string `json:"adminPublicKey,omitempty"`
191 PublicIP []net.IP `json:"publicIP,omitempty"`
192 NameserverIP []net.IP `json:"nameserverIP,omitempty"`
193 NamespacePrefix string `json:"namespacePrefix,omitempty"`
194 Network EnvNetwork `json:"network,omitempty"`
gio3cdee592024-04-17 10:15:56 +0400195}
196
197type EnvApp interface {
198 App
gio36b23b32024-08-25 12:20:54 +0400199 Render(
200 release Release,
201 env EnvConfig,
202 networks []Network,
203 values map[string]any,
204 charts map[string]helmv2.HelmChartTemplateSpec,
205 vpnKeyGen VPNAuthKeyGenerator,
206 ) (EnvAppRendered, error)
Giorgi Lekveishvilie009a5d2024-01-05 14:10:11 +0400207}
208
Giorgi Lekveishvili08af67a2024-01-18 08:53:05 +0400209type cueApp struct {
210 name string
211 description string
212 icon template.HTML
213 namespace string
214 schema Schema
gio308105e2024-04-19 13:12:13 +0400215 cfg cue.Value
216 data CueAppData
Giorgi Lekveishvili08af67a2024-01-18 08:53:05 +0400217}
218
gio308105e2024-04-19 13:12:13 +0400219type CueAppData map[string][]byte
220
221func ParseCueAppConfig(data CueAppData) (cue.Value, error) {
222 ctx := cuecontext.New()
223 buildCtx := build.NewContext()
224 cfg := &load.Config{
225 Context: buildCtx,
226 Overlay: map[string]load.Source{},
Giorgi Lekveishvili08af67a2024-01-18 08:53:05 +0400227 }
gio308105e2024-04-19 13:12:13 +0400228 names := make([]string, 0)
229 for n, b := range data {
230 a := fmt.Sprintf("/%s", n)
231 names = append(names, a)
232 cfg.Overlay[a] = load.FromString("package main\n\n" + string(b))
233 }
234 instances := load.Instances(names, cfg)
235 for _, inst := range instances {
236 if inst.Err != nil {
237 return cue.Value{}, inst.Err
238 }
239 }
240 if len(instances) != 1 {
241 return cue.Value{}, fmt.Errorf("invalid")
242 }
243 ret := ctx.BuildInstance(instances[0])
244 if ret.Err() != nil {
245 return cue.Value{}, ret.Err()
246 }
247 if err := ret.Validate(); err != nil {
248 return cue.Value{}, err
249 }
250 return ret, nil
251}
252
253func newCueApp(config cue.Value, data CueAppData) (cueApp, error) {
gio3cdee592024-04-17 10:15:56 +0400254 cfg := struct {
255 Name string `json:"name"`
256 Namespace string `json:"namespace"`
257 Description string `json:"description"`
258 Icon string `json:"icon"`
259 }{}
Giorgi Lekveishvili08af67a2024-01-18 08:53:05 +0400260 if err := config.Decode(&cfg); err != nil {
261 return cueApp{}, err
262 }
gio44f621b2024-04-29 09:44:38 +0400263 schema, err := NewCueSchema("input", config.LookupPath(cue.ParsePath("input")))
Giorgi Lekveishvili08af67a2024-01-18 08:53:05 +0400264 if err != nil {
265 return cueApp{}, err
266 }
267 return cueApp{
268 name: cfg.Name,
269 description: cfg.Description,
270 icon: template.HTML(cfg.Icon),
271 namespace: cfg.Namespace,
272 schema: schema,
273 cfg: config,
gio308105e2024-04-19 13:12:13 +0400274 data: data,
Giorgi Lekveishvili08af67a2024-01-18 08:53:05 +0400275 }, nil
276}
277
gio308105e2024-04-19 13:12:13 +0400278func ParseAndCreateNewCueApp(data CueAppData) (cueApp, error) {
279 config, err := ParseCueAppConfig(data)
280 if err != nil {
281 return cueApp{}, err
282 }
283 return newCueApp(config, data)
284}
285
Giorgi Lekveishvili08af67a2024-01-18 08:53:05 +0400286func (a cueApp) Name() string {
287 return a.name
288}
289
gio44f621b2024-04-29 09:44:38 +0400290func (a cueApp) Slug() string {
291 return strings.ReplaceAll(strings.ToLower(a.name), " ", "-")
292}
293
Giorgi Lekveishvili08af67a2024-01-18 08:53:05 +0400294func (a cueApp) Description() string {
295 return a.description
296}
297
298func (a cueApp) Icon() template.HTML {
299 return a.icon
300}
301
302func (a cueApp) Schema() Schema {
303 return a.schema
304}
305
gioef01fbb2024-04-12 16:52:59 +0400306func (a cueApp) Namespace() string {
307 return a.namespace
Giorgi Lekveishvili08af67a2024-01-18 08:53:05 +0400308}
309
gioe72b54f2024-04-22 10:44:41 +0400310func (a cueApp) render(values map[string]any) (rendered, error) {
311 ret := rendered{
gio44f621b2024-04-29 09:44:38 +0400312 Name: a.Slug(),
gio308105e2024-04-19 13:12:13 +0400313 Resources: make(CueAppData),
giof8843412024-05-22 16:38:05 +0400314 HelmCharts: HelmCharts{
315 Git: make(map[string]HelmChartGitRepo),
316 },
317 ContainerImages: make(map[string]ContainerImage),
318 Ports: make([]PortForward, 0),
319 Data: a.data,
Giorgi Lekveishvili9b52ab92024-01-05 13:12:48 +0400320 }
Giorgi Lekveishvili08af67a2024-01-18 08:53:05 +0400321 var buf bytes.Buffer
gio3cdee592024-04-17 10:15:56 +0400322 if err := json.NewEncoder(&buf).Encode(values); err != nil {
gioe72b54f2024-04-22 10:44:41 +0400323 return rendered{}, err
Giorgi Lekveishvili9b52ab92024-01-05 13:12:48 +0400324 }
Giorgi Lekveishvili08af67a2024-01-18 08:53:05 +0400325 ctx := a.cfg.Context()
326 d := ctx.CompileBytes(buf.Bytes())
327 res := a.cfg.Unify(d).Eval()
328 if err := res.Err(); err != nil {
gioe72b54f2024-04-22 10:44:41 +0400329 return rendered{}, err
Giorgi Lekveishvili08af67a2024-01-18 08:53:05 +0400330 }
331 if err := res.Validate(); err != nil {
gioe72b54f2024-04-22 10:44:41 +0400332 return rendered{}, err
Giorgi Lekveishvili08af67a2024-01-18 08:53:05 +0400333 }
gio308105e2024-04-19 13:12:13 +0400334 full, err := json.MarshalIndent(res, "", "\t")
335 if err != nil {
gioe72b54f2024-04-22 10:44:41 +0400336 return rendered{}, err
gio308105e2024-04-19 13:12:13 +0400337 }
gio94904702024-07-26 16:58:34 +0400338 ret.Raw = full
gio308105e2024-04-19 13:12:13 +0400339 ret.Data["rendered.json"] = full
Giorgi Lekveishvili08af67a2024-01-18 08:53:05 +0400340 readme, err := res.LookupPath(cue.ParsePath("readme")).String()
341 if err != nil {
gioe72b54f2024-04-22 10:44:41 +0400342 return rendered{}, err
Giorgi Lekveishvili08af67a2024-01-18 08:53:05 +0400343 }
344 ret.Readme = readme
Giorgi Lekveishvilib59b7c22024-04-03 22:17:50 +0400345 if err := res.LookupPath(cue.ParsePath("portForward")).Decode(&ret.Ports); err != nil {
gioe72b54f2024-04-22 10:44:41 +0400346 return rendered{}, err
Giorgi Lekveishvilib59b7c22024-04-03 22:17:50 +0400347 }
gio0eaf2712024-04-14 13:08:46 +0400348 {
giof8843412024-05-22 16:38:05 +0400349 charts := res.LookupPath(cue.ParsePath("charts"))
350 i, err := charts.Fields()
351 if err != nil {
352 return rendered{}, err
353 }
354 for i.Next() {
355 var chartRef helmChartRef
356 if err := i.Value().Decode(&chartRef); err != nil {
357 return rendered{}, err
358 }
359 if chartRef.Kind == "GitRepository" {
360 var chart HelmChartGitRepo
361 if err := i.Value().Decode(&chart); err != nil {
362 return rendered{}, err
363 }
364 ret.HelmCharts.Git[cleanName(i.Selector().String())] = chart
365 }
366 }
367 }
368 {
369 images := res.LookupPath(cue.ParsePath("images"))
370 i, err := images.Fields()
371 if err != nil {
372 return rendered{}, err
373 }
374 for i.Next() {
375 var img ContainerImage
376 if err := i.Value().Decode(&img); err != nil {
377 return rendered{}, err
378 }
379 ret.ContainerImages[cleanName(i.Selector().String())] = img
380 }
381 }
382 {
gio0eaf2712024-04-14 13:08:46 +0400383 output := res.LookupPath(cue.ParsePath("output"))
384 i, err := output.Fields()
385 if err != nil {
gioe72b54f2024-04-22 10:44:41 +0400386 return rendered{}, err
gio0eaf2712024-04-14 13:08:46 +0400387 }
388 for i.Next() {
389 if contents, err := cueyaml.Encode(i.Value()); err != nil {
390 return rendered{}, err
391 } else {
392 name := fmt.Sprintf("%s.yaml", cleanName(i.Selector().String()))
393 ret.Resources[name] = contents
394 }
395 }
396 }
397 {
398 resources := res.LookupPath(cue.ParsePath("resources"))
399 i, err := resources.Fields()
400 if err != nil {
401 return rendered{}, err
402 }
403 for i.Next() {
404 if contents, err := cueyaml.Encode(i.Value()); err != nil {
405 return rendered{}, err
406 } else {
407 name := fmt.Sprintf("%s.yaml", cleanName(i.Selector().String()))
408 ret.Resources[name] = contents
409 }
Giorgi Lekveishvili3f697b12024-01-04 00:56:06 +0400410 }
Giorgi Lekveishvili3f697b12024-01-04 00:56:06 +0400411 }
Davit Tabidze56f86a42024-04-09 19:15:25 +0400412 helpValue := res.LookupPath(cue.ParsePath("help"))
413 if helpValue.Exists() {
414 if err := helpValue.Decode(&ret.Help); err != nil {
gioe72b54f2024-04-22 10:44:41 +0400415 return rendered{}, err
Davit Tabidze56f86a42024-04-09 19:15:25 +0400416 }
417 }
418 url, err := res.LookupPath(cue.ParsePath("url")).String()
419 if err != nil {
gioe72b54f2024-04-22 10:44:41 +0400420 return rendered{}, err
Davit Tabidze56f86a42024-04-09 19:15:25 +0400421 }
gio09a3e5b2024-04-26 14:11:06 +0400422 ret.URL = url
Davit Tabidze56f86a42024-04-09 19:15:25 +0400423 icon, err := res.LookupPath(cue.ParsePath("icon")).String()
424 if err != nil {
gioe72b54f2024-04-22 10:44:41 +0400425 return rendered{}, err
Davit Tabidze56f86a42024-04-09 19:15:25 +0400426 }
427 ret.Icon = icon
Giorgi Lekveishvili3f697b12024-01-04 00:56:06 +0400428 return ret, nil
429}
430
gio3cdee592024-04-17 10:15:56 +0400431type cueEnvApp struct {
432 cueApp
Giorgi Lekveishvilibd6be7f2023-05-26 15:51:28 +0400433}
434
gio308105e2024-04-19 13:12:13 +0400435func NewCueEnvApp(data CueAppData) (EnvApp, error) {
436 app, err := ParseAndCreateNewCueApp(data)
Giorgi Lekveishvili743fb432023-11-08 17:19:40 +0400437 if err != nil {
438 return nil, err
439 }
gio3cdee592024-04-17 10:15:56 +0400440 return cueEnvApp{app}, nil
Giorgi Lekveishvili743fb432023-11-08 17:19:40 +0400441}
442
gio0eaf2712024-04-14 13:08:46 +0400443func NewDodoApp(appCfg []byte) (EnvApp, error) {
444 return NewCueEnvApp(CueAppData{
giofc9c4ea2024-06-26 13:46:53 +0400445 "app.cue": appCfg,
446 "base.cue": []byte(cueBaseConfig),
447 "dodo.cue": dodoAppCue,
448 "env.cue": []byte(cueEnvAppGlobal),
gio0eaf2712024-04-14 13:08:46 +0400449 })
450}
451
gio3cdee592024-04-17 10:15:56 +0400452func (a cueEnvApp) Type() AppType {
453 return AppTypeEnv
454}
455
giocb34ad22024-07-11 08:01:13 +0400456func (a cueEnvApp) Render(
457 release Release,
458 env EnvConfig,
459 networks []Network,
460 values map[string]any,
461 charts map[string]helmv2.HelmChartTemplateSpec,
gio36b23b32024-08-25 12:20:54 +0400462 vpnKeyGen VPNAuthKeyGenerator,
giocb34ad22024-07-11 08:01:13 +0400463) (EnvAppRendered, error) {
gio36b23b32024-08-25 12:20:54 +0400464 derived, err := deriveValues(values, values, a.Schema(), networks, vpnKeyGen)
gio3cdee592024-04-17 10:15:56 +0400465 if err != nil {
gioefa0ed42024-06-13 12:31:43 +0400466 return EnvAppRendered{}, err
gio3cdee592024-04-17 10:15:56 +0400467 }
giof8843412024-05-22 16:38:05 +0400468 if charts == nil {
469 charts = make(map[string]helmv2.HelmChartTemplateSpec)
470 }
gio3cdee592024-04-17 10:15:56 +0400471 ret, err := a.cueApp.render(map[string]any{
giof8843412024-05-22 16:38:05 +0400472 "global": env,
473 "release": release,
474 "input": derived,
475 "localCharts": charts,
gio5e49bb62024-07-20 10:43:19 +0400476 "networks": NetworkMap(networks),
gio3cdee592024-04-17 10:15:56 +0400477 })
478 if err != nil {
gioe72b54f2024-04-22 10:44:41 +0400479 return EnvAppRendered{}, err
gio3cdee592024-04-17 10:15:56 +0400480 }
gioe72b54f2024-04-22 10:44:41 +0400481 return EnvAppRendered{
482 rendered: ret,
483 Config: AppInstanceConfig{
gio44f621b2024-04-29 09:44:38 +0400484 AppId: a.Slug(),
gioe72b54f2024-04-22 10:44:41 +0400485 Env: env,
486 Release: release,
487 Values: values,
488 Input: derived,
gio09a3e5b2024-04-26 14:11:06 +0400489 URL: ret.URL,
gioe72b54f2024-04-22 10:44:41 +0400490 Help: ret.Help,
gio09a3e5b2024-04-26 14:11:06 +0400491 Icon: ret.Icon,
gioe72b54f2024-04-22 10:44:41 +0400492 },
493 }, nil
gio3cdee592024-04-17 10:15:56 +0400494}
495
496type cueInfraApp struct {
497 cueApp
498}
499
gio308105e2024-04-19 13:12:13 +0400500func NewCueInfraApp(data CueAppData) (InfraApp, error) {
501 app, err := ParseAndCreateNewCueApp(data)
Giorgi Lekveishvili743fb432023-11-08 17:19:40 +0400502 if err != nil {
Giorgi Lekveishvili08af67a2024-01-18 08:53:05 +0400503 return nil, err
Giorgi Lekveishvili743fb432023-11-08 17:19:40 +0400504 }
gio3cdee592024-04-17 10:15:56 +0400505 return cueInfraApp{app}, nil
506}
507
508func (a cueInfraApp) Type() AppType {
509 return AppTypeInfra
510}
511
gio7841f4f2024-07-26 19:53:49 +0400512func (a cueInfraApp) Render(release Release, infra InfraConfig, networks []InfraNetwork, values map[string]any, charts map[string]helmv2.HelmChartTemplateSpec) (InfraAppRendered, error) {
giof8843412024-05-22 16:38:05 +0400513 if charts == nil {
514 charts = make(map[string]helmv2.HelmChartTemplateSpec)
515 }
gioe72b54f2024-04-22 10:44:41 +0400516 ret, err := a.cueApp.render(map[string]any{
giof8843412024-05-22 16:38:05 +0400517 "global": infra,
518 "release": release,
519 "input": values,
520 "localCharts": charts,
gio7841f4f2024-07-26 19:53:49 +0400521 "networks": InfraNetworkMap(networks),
gio3cdee592024-04-17 10:15:56 +0400522 })
gioe72b54f2024-04-22 10:44:41 +0400523 if err != nil {
524 return InfraAppRendered{}, err
525 }
526 return InfraAppRendered{
527 rendered: ret,
528 Config: InfraAppInstanceConfig{
gio44f621b2024-04-29 09:44:38 +0400529 AppId: a.Slug(),
gioe72b54f2024-04-22 10:44:41 +0400530 Infra: infra,
531 Release: release,
532 Values: values,
533 Input: values,
gio09a3e5b2024-04-26 14:11:06 +0400534 URL: ret.URL,
535 Help: ret.Help,
gioe72b54f2024-04-22 10:44:41 +0400536 },
537 }, nil
Giorgi Lekveishvilief21c132024-01-17 18:57:58 +0400538}
539
Giorgi Lekveishvili08af67a2024-01-18 08:53:05 +0400540func cleanName(s string) string {
541 return strings.ReplaceAll(strings.ReplaceAll(s, "\"", ""), "'", "")
Giorgi Lekveishvilief21c132024-01-17 18:57:58 +0400542}
gioe72b54f2024-04-22 10:44:41 +0400543
544func join[T fmt.Stringer](items []T, sep string) string {
545 var tmp []string
546 for _, i := range items {
547 tmp = append(tmp, i.String())
548 }
549 return strings.Join(tmp, ",")
550}
gio0eaf2712024-04-14 13:08:46 +0400551
gio5e49bb62024-07-20 10:43:19 +0400552func NetworkMap(networks []Network) map[string]Network {
gio0eaf2712024-04-14 13:08:46 +0400553 ret := make(map[string]Network)
554 for _, n := range networks {
555 ret[strings.ToLower(n.Name)] = n
556 }
557 return ret
558}
gio7841f4f2024-07-26 19:53:49 +0400559
560func InfraNetworkMap(networks []InfraNetwork) map[string]InfraNetwork {
561 ret := make(map[string]InfraNetwork)
562 for _, n := range networks {
563 ret[strings.ToLower(n.Name)] = n
564 }
565 return ret
566}