blob: 76acf7419adbd3d048cb102984c72505ae024363 [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 Lekveishvili743fb432023-11-08 17:19:40 +04004 "archive/tar"
Giorgi Lekveishvili3f697b12024-01-04 00:56:06 +04005 "bytes"
Giorgi Lekveishvili743fb432023-11-08 17:19:40 +04006 "compress/gzip"
giolekva8aa73e82022-07-09 11:34:39 +04007 "embed"
Giorgi Lekveishvilibd6be7f2023-05-26 15:51:28 +04008 "fmt"
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +04009 htemplate "html/template"
Giorgi Lekveishvili743fb432023-11-08 17:19:40 +040010 "io"
giolekva8aa73e82022-07-09 11:34:39 +040011 "log"
Giorgi Lekveishvili743fb432023-11-08 17:19:40 +040012 "net/http"
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +040013 "strings"
giolekva8aa73e82022-07-09 11:34:39 +040014 "text/template"
Giorgi Lekveishvili0ccd1482023-06-21 15:02:24 +040015
16 "github.com/Masterminds/sprig/v3"
Giorgi Lekveishvili743fb432023-11-08 17:19:40 +040017 "github.com/go-git/go-billy/v5"
18 "sigs.k8s.io/yaml"
giolekva8aa73e82022-07-09 11:34:39 +040019)
giolekva050609f2021-12-29 15:51:40 +040020
Giorgi Lekveishvilibd6be7f2023-05-26 15:51:28 +040021//go:embed values-tmpl
22var valuesTmpls embed.FS
23
Giorgi Lekveishvili27b2b572023-06-30 10:44:45 +040024type Named interface {
25 Nam() string
26}
27
Giorgi Lekveishvili743fb432023-11-08 17:19:40 +040028type appConfig struct {
29 Name string `json:"name"`
30 Version string `json:"version"`
31 Description string `json:"description"`
32 Namespaces []string `json:"namespaces"`
33 Icon htemplate.HTML `json:"icon"`
34}
35
giolekva050609f2021-12-29 15:51:40 +040036type App struct {
Giorgi Lekveishvili7fb28bf2023-06-24 19:51:16 +040037 Name string
38 Namespaces []string
Giorgi Lekveishvili3f697b12024-01-04 00:56:06 +040039 templates []*template.Template
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +040040 schema Schema
Giorgi Lekveishvili7fb28bf2023-06-24 19:51:16 +040041 Readme *template.Template
giolekva050609f2021-12-29 15:51:40 +040042}
43
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +040044func (a App) Schema() Schema {
45 return a.schema
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +040046}
47
Giorgi Lekveishvili3f697b12024-01-04 00:56:06 +040048func (a App) Render(derived Derived) (map[string][]byte, error) {
49 ret := make(map[string][]byte)
50 for _, t := range a.templates {
51 var buf bytes.Buffer
52 if err := t.Execute(&buf, derived); err != nil {
53 return nil, err
54 }
55 ret[t.Name()] = buf.Bytes()
56 }
57 return ret, nil
58}
59
Giorgi Lekveishvili27b2b572023-06-30 10:44:45 +040060type StoreApp struct {
61 App
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +040062 Icon htemplate.HTML
Giorgi Lekveishvili27b2b572023-06-30 10:44:45 +040063 ShortDescription string
Giorgi Lekveishvilibd6be7f2023-05-26 15:51:28 +040064}
65
Giorgi Lekveishvili27b2b572023-06-30 10:44:45 +040066func (a App) Nam() string {
67 return a.Name
Giorgi Lekveishvilibd6be7f2023-05-26 15:51:28 +040068}
69
Giorgi Lekveishvili27b2b572023-06-30 10:44:45 +040070func (a StoreApp) Nam() string {
71 return a.Name
72}
73
74type AppRepository[A Named] interface {
75 GetAll() ([]A, error)
76 Find(name string) (*A, error)
77}
78
79type InMemoryAppRepository[A Named] struct {
80 apps []A
81}
82
Giorgi Lekveishvili743fb432023-11-08 17:19:40 +040083func NewInMemoryAppRepository[A Named](apps []A) InMemoryAppRepository[A] {
84 return InMemoryAppRepository[A]{
Giorgi Lekveishvilibd6be7f2023-05-26 15:51:28 +040085 apps,
86 }
87}
88
Giorgi Lekveishvili27b2b572023-06-30 10:44:45 +040089func (r InMemoryAppRepository[A]) Find(name string) (*A, error) {
Giorgi Lekveishvilibd6be7f2023-05-26 15:51:28 +040090 for _, a := range r.apps {
Giorgi Lekveishvili27b2b572023-06-30 10:44:45 +040091 if a.Nam() == name {
Giorgi Lekveishvilibd6be7f2023-05-26 15:51:28 +040092 return &a, nil
93 }
94 }
95 return nil, fmt.Errorf("Application not found: %s", name)
96}
giolekva8aa73e82022-07-09 11:34:39 +040097
Giorgi Lekveishvili27b2b572023-06-30 10:44:45 +040098func (r InMemoryAppRepository[A]) GetAll() ([]A, error) {
Giorgi Lekveishvili7efe22f2023-05-30 13:01:53 +040099 return r.apps, nil
100}
101
giolekva8aa73e82022-07-09 11:34:39 +0400102func CreateAllApps() []App {
Giorgi Lekveishvili0ccd1482023-06-21 15:02:24 +0400103 tmpls, err := template.New("root").Funcs(template.FuncMap(sprig.FuncMap())).ParseFS(valuesTmpls, "values-tmpl/*")
giolekva8aa73e82022-07-09 11:34:39 +0400104 if err != nil {
105 log.Fatal(err)
106 }
Giorgi Lekveishvili27b2b572023-06-30 10:44:45 +0400107 ret := []App{
Giorgi Lekveishvili7efe22f2023-05-30 13:01:53 +0400108 CreateAppIngressPrivate(valuesTmpls, tmpls),
Giorgi Lekveishvili12850ee2023-06-22 13:11:17 +0400109 CreateCertificateIssuerPublic(valuesTmpls, tmpls),
110 CreateCertificateIssuerPrivate(valuesTmpls, tmpls),
Giorgi Lekveishvili7efe22f2023-05-30 13:01:53 +0400111 CreateAppCoreAuth(valuesTmpls, tmpls),
Giorgi Lekveishvili7efe22f2023-05-30 13:01:53 +0400112 CreateAppHeadscale(valuesTmpls, tmpls),
Giorgi Lekveishvili39913692023-12-05 08:58:08 +0400113 CreateAppHeadscaleUser(valuesTmpls, tmpls),
Giorgi Lekveishvili4fc29432023-07-20 10:03:28 +0400114 CreateMetallbIPAddressPool(valuesTmpls, tmpls),
Giorgi Lekveishvili0ccd1482023-06-21 15:02:24 +0400115 CreateEnvManager(valuesTmpls, tmpls),
Giorgi Lekveishvili12850ee2023-06-22 13:11:17 +0400116 CreateWelcome(valuesTmpls, tmpls),
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400117 CreateAppManager(valuesTmpls, tmpls),
Giorgi Lekveishvili0ccd1482023-06-21 15:02:24 +0400118 CreateIngressPublic(valuesTmpls, tmpls),
119 CreateCertManager(valuesTmpls, tmpls),
120 CreateCertManagerWebhookGandi(valuesTmpls, tmpls),
Giorgi Lekveishvili0ccd1482023-06-21 15:02:24 +0400121 CreateCSIDriverSMB(valuesTmpls, tmpls),
122 CreateResourceRendererController(valuesTmpls, tmpls),
123 CreateHeadscaleController(valuesTmpls, tmpls),
Giorgi Lekveishvili106a9352023-12-04 11:20:11 +0400124 CreateDNSZoneManager(valuesTmpls, tmpls),
Giorgi Lekveishvili2df23db2023-12-14 07:55:22 +0400125 CreateFluxcdReconciler(valuesTmpls, tmpls),
giolekvaef76a3e2022-01-10 12:22:28 +0400126 }
Giorgi Lekveishvili27b2b572023-06-30 10:44:45 +0400127 for _, a := range CreateStoreApps() {
128 ret = append(ret, a.App)
129 }
130 return ret
131}
132
133func CreateStoreApps() []StoreApp {
134 tmpls, err := template.New("root").Funcs(template.FuncMap(sprig.FuncMap())).ParseFS(valuesTmpls, "values-tmpl/*")
135 if err != nil {
136 log.Fatal(err)
137 }
138 return []StoreApp{
139 CreateAppVaultwarden(valuesTmpls, tmpls),
140 CreateAppMatrix(valuesTmpls, tmpls),
141 CreateAppPihole(valuesTmpls, tmpls),
Giorgi Lekveishvili3fd5e4c2023-12-19 22:09:40 +0400142 CreateAppPenpot(valuesTmpls, tmpls),
Giorgi Lekveishvili27b2b572023-06-30 10:44:45 +0400143 CreateAppMaddy(valuesTmpls, tmpls),
144 CreateAppQBittorrent(valuesTmpls, tmpls),
145 CreateAppJellyfin(valuesTmpls, tmpls),
Giorgi Lekveishvili672af5d2023-07-12 11:57:51 +0400146 CreateAppSoftServe(valuesTmpls, tmpls),
Giorgi Lekveishvili27b2b572023-06-30 10:44:45 +0400147 CreateAppRpuppy(valuesTmpls, tmpls),
148 }
giolekvaef76a3e2022-01-10 12:22:28 +0400149}
150
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +0400151func readJSONSchemaFromFile(fs embed.FS, f string) (Schema, error) {
152 schema, err := fs.ReadFile(f)
153 if err != nil {
154 return nil, err
155 }
156 ret, err := NewJSONSchema(string(schema))
157 if err != nil {
158 return nil, err
159 }
160 return ret, nil
161}
162
Giorgi Lekveishvili4d2784d2023-06-01 14:27:32 +0400163// TODO(gio): service account needs permission to create/update secret
Giorgi Lekveishvili7efe22f2023-05-30 13:01:53 +0400164func CreateAppIngressPrivate(fs embed.FS, tmpls *template.Template) App {
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +0400165 schema, err := readJSONSchemaFromFile(fs, "values-tmpl/private-network.jsonschema")
Giorgi Lekveishvili7efe22f2023-05-30 13:01:53 +0400166 if err != nil {
167 panic(err)
168 }
giolekva050609f2021-12-29 15:51:40 +0400169 return App{
Giorgi Lekveishvili2dbce6c2023-12-05 15:16:27 +0400170 "private-network",
171 []string{"ingress-private"}, // TODO(gio): rename to private network
giolekva050609f2021-12-29 15:51:40 +0400172 []*template.Template{
giolekva050609f2021-12-29 15:51:40 +0400173 tmpls.Lookup("ingress-private.yaml"),
Giorgi Lekveishvili2dbce6c2023-12-05 15:16:27 +0400174 tmpls.Lookup("tailscale-proxy.yaml"),
giolekva050609f2021-12-29 15:51:40 +0400175 },
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +0400176 schema,
Giorgi Lekveishvili2dbce6c2023-12-05 15:16:27 +0400177 tmpls.Lookup("private-network.md"),
giolekva050609f2021-12-29 15:51:40 +0400178 }
179}
180
Giorgi Lekveishvili0ccd1482023-06-21 15:02:24 +0400181func CreateCertificateIssuerPrivate(fs embed.FS, tmpls *template.Template) App {
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +0400182 schema, err := readJSONSchemaFromFile(fs, "values-tmpl/certificate-issuer-private.jsonschema")
Giorgi Lekveishvili0ccd1482023-06-21 15:02:24 +0400183 if err != nil {
184 panic(err)
185 }
186 return App{
Giorgi Lekveishvili12850ee2023-06-22 13:11:17 +0400187 "certificate-issuer-private",
Giorgi Lekveishvili7fb28bf2023-06-24 19:51:16 +0400188 []string{},
Giorgi Lekveishvili0ccd1482023-06-21 15:02:24 +0400189 []*template.Template{
190 tmpls.Lookup("certificate-issuer-private.yaml"),
191 },
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +0400192 schema,
Giorgi Lekveishvili0ccd1482023-06-21 15:02:24 +0400193 tmpls.Lookup("certificate-issuer-private.md"),
194 }
195}
196
Giorgi Lekveishvili12850ee2023-06-22 13:11:17 +0400197func CreateCertificateIssuerPublic(fs embed.FS, tmpls *template.Template) App {
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +0400198 schema, err := readJSONSchemaFromFile(fs, "values-tmpl/certificate-issuer-public.jsonschema")
Giorgi Lekveishvili12850ee2023-06-22 13:11:17 +0400199 if err != nil {
200 panic(err)
201 }
202 return App{
203 "certificate-issuer-public",
Giorgi Lekveishvili7fb28bf2023-06-24 19:51:16 +0400204 []string{},
Giorgi Lekveishvili12850ee2023-06-22 13:11:17 +0400205 []*template.Template{
206 tmpls.Lookup("certificate-issuer-public.yaml"),
207 },
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +0400208 schema,
Giorgi Lekveishvili12850ee2023-06-22 13:11:17 +0400209 tmpls.Lookup("certificate-issuer-public.md"),
210 }
211}
212
Giorgi Lekveishvili7efe22f2023-05-30 13:01:53 +0400213func CreateAppCoreAuth(fs embed.FS, tmpls *template.Template) App {
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +0400214 schema, err := readJSONSchemaFromFile(fs, "values-tmpl/core-auth.jsonschema")
Giorgi Lekveishvili7efe22f2023-05-30 13:01:53 +0400215 if err != nil {
216 panic(err)
217 }
giolekva050609f2021-12-29 15:51:40 +0400218 return App{
219 "core-auth",
Giorgi Lekveishvili7fb28bf2023-06-24 19:51:16 +0400220 []string{"core-auth"},
giolekva050609f2021-12-29 15:51:40 +0400221 []*template.Template{
222 tmpls.Lookup("core-auth-storage.yaml"),
223 tmpls.Lookup("core-auth.yaml"),
224 },
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +0400225 schema,
Giorgi Lekveishvili3ca1f3f2023-05-30 14:33:02 +0400226 tmpls.Lookup("core-auth.md"),
giolekva050609f2021-12-29 15:51:40 +0400227 }
228}
229
Giorgi Lekveishvili27b2b572023-06-30 10:44:45 +0400230func CreateAppVaultwarden(fs embed.FS, tmpls *template.Template) StoreApp {
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +0400231 schema, err := readJSONSchemaFromFile(fs, "values-tmpl/vaultwarden.jsonschema")
Giorgi Lekveishvili7efe22f2023-05-30 13:01:53 +0400232 if err != nil {
233 panic(err)
234 }
Giorgi Lekveishvili27b2b572023-06-30 10:44:45 +0400235 return StoreApp{
236 App: App{
237 "vaultwarden",
238 []string{"app-vaultwarden"},
239 []*template.Template{
240 tmpls.Lookup("vaultwarden.yaml"),
241 },
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +0400242 schema,
Giorgi Lekveishvili27b2b572023-06-30 10:44:45 +0400243 tmpls.Lookup("vaultwarden.md"),
giolekva050609f2021-12-29 15:51:40 +0400244 },
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400245 Icon: `<svg xmlns="http://www.w3.org/2000/svg" width="50" height="50" viewBox="0 0 48 48"><path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" d="M35.38 25.63V9.37H24v28.87a34.93 34.93 0 0 0 5.41-3.48q6-4.66 6-9.14Zm4.87-19.5v19.5A11.58 11.58 0 0 1 39.4 30a16.22 16.22 0 0 1-2.11 3.81a23.52 23.52 0 0 1-3 3.24a34.87 34.87 0 0 1-3.22 2.62c-1 .69-2 1.35-3.07 2s-1.82 1-2.27 1.26l-1.08.51a1.53 1.53 0 0 1-1.32 0l-1.08-.51c-.45-.22-1.21-.64-2.27-1.26s-2.09-1.27-3.07-2A34.87 34.87 0 0 1 13.7 37a23.52 23.52 0 0 1-3-3.24A16.22 16.22 0 0 1 8.6 30a11.58 11.58 0 0 1-.85-4.32V6.13A1.64 1.64 0 0 1 9.38 4.5h29.24a1.64 1.64 0 0 1 1.63 1.63Z"/></svg>`,
Giorgi Lekveishvili27b2b572023-06-30 10:44:45 +0400246 ShortDescription: "Open source implementation of Bitwarden password manager. Can be used with official client applications.",
giolekva050609f2021-12-29 15:51:40 +0400247 }
248}
249
Giorgi Lekveishvili27b2b572023-06-30 10:44:45 +0400250func CreateAppMatrix(fs embed.FS, tmpls *template.Template) StoreApp {
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +0400251 schema, err := readJSONSchemaFromFile(fs, "values-tmpl/matrix.jsonschema")
Giorgi Lekveishvili7efe22f2023-05-30 13:01:53 +0400252 if err != nil {
253 panic(err)
254 }
Giorgi Lekveishvili27b2b572023-06-30 10:44:45 +0400255 return StoreApp{
256 App{
257 "matrix",
258 []string{"app-matrix"},
259 []*template.Template{
260 tmpls.Lookup("matrix-storage.yaml"),
261 tmpls.Lookup("matrix.yaml"),
262 },
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +0400263 schema,
Giorgi Lekveishvili27b2b572023-06-30 10:44:45 +0400264 nil,
giolekva050609f2021-12-29 15:51:40 +0400265 },
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400266 `<svg xmlns="http://www.w3.org/2000/svg" width="50" height="50" viewBox="0 0 24 24"><path fill="currentColor" d="M.632.55v22.9H2.28V24H0V0h2.28v.55zm7.043 7.26v1.157h.033a3.312 3.312 0 0 1 1.117-1.024c.433-.245.936-.365 1.5-.365c.54 0 1.033.107 1.481.314c.448.208.785.582 1.02 1.108c.254-.374.6-.706 1.034-.992c.434-.287.95-.43 1.546-.43c.453 0 .872.056 1.26.167c.388.11.716.286.993.53c.276.245.489.559.646.951c.152.392.23.863.23 1.417v5.728h-2.349V11.52c0-.286-.01-.559-.032-.812a1.755 1.755 0 0 0-.18-.66a1.106 1.106 0 0 0-.438-.448c-.194-.11-.457-.166-.785-.166c-.332 0-.6.064-.803.189a1.38 1.38 0 0 0-.48.499a1.946 1.946 0 0 0-.231.696a5.56 5.56 0 0 0-.06.785v4.768h-2.35v-4.8c0-.254-.004-.503-.018-.752a2.074 2.074 0 0 0-.143-.688a1.052 1.052 0 0 0-.415-.503c-.194-.125-.476-.19-.854-.19c-.111 0-.259.024-.439.074c-.18.051-.36.143-.53.282a1.637 1.637 0 0 0-.439.595c-.12.259-.18.6-.18 1.02v4.966H5.46V7.81zm15.693 15.64V.55H21.72V0H24v24h-2.28v-.55z"/></svg>`,
Giorgi Lekveishvili27b2b572023-06-30 10:44:45 +0400267 "An open network for secure, decentralised communication",
giolekva050609f2021-12-29 15:51:40 +0400268 }
269}
270
Giorgi Lekveishvili27b2b572023-06-30 10:44:45 +0400271func CreateAppPihole(fs embed.FS, tmpls *template.Template) StoreApp {
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +0400272 schema, err := readJSONSchemaFromFile(fs, "values-tmpl/pihole.jsonschema")
Giorgi Lekveishvili7efe22f2023-05-30 13:01:53 +0400273 if err != nil {
274 panic(err)
275 }
Giorgi Lekveishvili27b2b572023-06-30 10:44:45 +0400276 return StoreApp{
277 App{
278 "pihole",
279 []string{"app-pihole"},
280 []*template.Template{
281 tmpls.Lookup("pihole.yaml"),
282 },
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +0400283 schema,
Giorgi Lekveishvili27b2b572023-06-30 10:44:45 +0400284 tmpls.Lookup("pihole.md"),
giolekva050609f2021-12-29 15:51:40 +0400285 },
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400286 // "simple-icons:pihole",
287 `<svg xmlns="http://www.w3.org/2000/svg" width="50" height="50" viewBox="0 0 24 24"><path fill="currentColor" d="M4.344 0c.238 4.792 3.256 7.056 6.252 7.376c.165-1.692-4.319-5.6-4.319-5.6c-.008-.011.009-.025.019-.014c0 0 4.648 4.01 5.423 5.645c2.762-.15 5.196-1.947 5-4.912c0 0-4.12-.613-5 4.618C11.48 2.753 8.993 0 4.344 0zM12 7.682v.002a3.68 3.68 0 0 0-2.591 1.077L4.94 13.227a3.683 3.683 0 0 0-.86 1.356a3.31 3.31 0 0 0-.237 1.255A3.681 3.681 0 0 0 4.92 18.45l4.464 4.466a3.69 3.69 0 0 0 2.251 1.06l.002.001c.093.01.187.015.28.017l-.1-.008c.06.003.117.009.177.009l-.077-.001L12 24l-.004-.005a3.68 3.68 0 0 0 2.61-1.077l4.469-4.465a3.683 3.683 0 0 0 1.006-1.888l.012-.063a3.682 3.682 0 0 0 .057-.541l.003-.061c0-.017.003-.05.004-.06h-.002a3.683 3.683 0 0 0-1.077-2.607l-4.466-4.468a3.694 3.694 0 0 0-1.564-.927l-.07-.02a3.43 3.43 0 0 0-.946-.133L12 7.682zm3.165 3.357c.023 1.748-1.33 3.078-1.33 4.806c.164 2.227 1.733 3.207 3.266 3.146c-.035.003-.068.007-.104.009c-1.847.135-3.209-1.326-5.002-1.326c-2.23.164-3.21 1.736-3.147 3.27l-.008-.104c-.133-1.847 1.328-3.21 1.328-5.002c-.173-2.32-1.867-3.284-3.46-3.132c.1-.011.203-.021.31-.027c1.847-.133 3.209 1.328 5.002 1.328c2.082-.155 3.074-1.536 3.145-2.968zM4.344 0c.238 4.792 3.256 7.056 6.252 7.376c.165-1.692-4.319-5.6-4.319-5.6c-.008-.011.009-.025.019-.014c0 0 4.648 4.01 5.423 5.645c2.762-.15 5.196-1.947 5-4.912c0 0-4.12-.613-5 4.618C11.48 2.753 8.993 0 4.344 0zM12 7.682v.002a3.68 3.68 0 0 0-2.591 1.077L4.94 13.227a3.683 3.683 0 0 0-.86 1.356a3.31 3.31 0 0 0-.237 1.255A3.681 3.681 0 0 0 4.92 18.45l4.464 4.466a3.69 3.69 0 0 0 2.251 1.06l.002.001c.093.01.187.015.28.017l-.1-.008c.06.003.117.009.177.009l-.077-.001L12 24l-.004-.005a3.68 3.68 0 0 0 2.61-1.077l4.469-4.465a3.683 3.683 0 0 0 1.006-1.888l.012-.063a3.682 3.682 0 0 0 .057-.541l.003-.061c0-.017.003-.05.004-.06h-.002a3.683 3.683 0 0 0-1.077-2.607l-4.466-4.468a3.694 3.694 0 0 0-1.564-.927l-.07-.02a3.43 3.43 0 0 0-.946-.133L12 7.682zm3.165 3.357c.023 1.748-1.33 3.078-1.33 4.806c.164 2.227 1.733 3.207 3.266 3.146c-.035.003-.068.007-.104.009c-1.847.135-3.209-1.326-5.002-1.326c-2.23.164-3.21 1.736-3.147 3.27l-.008-.104c-.133-1.847 1.328-3.21 1.328-5.002c-.173-2.32-1.867-3.284-3.46-3.132c.1-.011.203-.021.31-.027c1.847-.133 3.209 1.328 5.002 1.328c2.082-.155 3.074-1.536 3.145-2.968z"/></svg>`,
Giorgi Lekveishvili27b2b572023-06-30 10:44:45 +0400288 "Pi-hole is a Linux network-level advertisement and Internet tracker blocking application which acts as a DNS sinkhole and optionally a DHCP server, intended for use on a private network.",
giolekva050609f2021-12-29 15:51:40 +0400289 }
290}
291
Giorgi Lekveishvili3fd5e4c2023-12-19 22:09:40 +0400292func CreateAppPenpot(fs embed.FS, tmpls *template.Template) StoreApp {
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +0400293 schema, err := readJSONSchemaFromFile(fs, "values-tmpl/penpot.jsonschema")
Giorgi Lekveishvili3fd5e4c2023-12-19 22:09:40 +0400294 if err != nil {
295 panic(err)
296 }
297 return StoreApp{
298 App{
299 "penpot",
300 []string{"app-penpot"},
301 []*template.Template{
302 tmpls.Lookup("penpot.yaml"),
303 },
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +0400304 schema,
Giorgi Lekveishvili3fd5e4c2023-12-19 22:09:40 +0400305 tmpls.Lookup("penpot.md"),
306 },
307 // "simple-icons:pihole",
308 `<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="currentColor" d="M7.654 0L5.13 3.554v2.01L2.934 6.608l-.02-.009v13.109l8.563 4.045L12 24l.523-.247l8.563-4.045V6.6l-.017.008l-2.196-1.045V3.555l-.077-.108L16.349.001l-2.524 3.554v.004L11.989.973l-1.823 2.566l-.065-.091zm.447 2.065l.976 1.374H6.232l.964-1.358zm8.694 0l.976 1.374h-2.845l.965-1.358zm-4.36.971l.976 1.375h-2.845l.965-1.359zM5.962 4.132h1.35v4.544l-1.35-.638Zm2.042 0h1.343v5.506l-1.343-.635zm6.652 0h1.35V9l-1.35.637zm2.042 0h1.343v3.905l-1.343.634zm-6.402.972h1.35v5.62l-1.35-.638zm2.042 0h1.343v4.993l-1.343.634zm6.534 1.493l1.188.486l-1.188.561zM5.13 6.6v1.047l-1.187-.561ZM3.96 8.251l7.517 3.55v10.795l-7.516-3.55zm16.08 0v10.794l-7.517 3.55V11.802z"/></svg>`,
309 "Penpot is the first Open Source design and prototyping platform meant for cross-domain teams. Non dependent on operating systems, Penpot is web based and works with open standards (SVG). Penpot invites designers all over the world to fall in love with open source while getting developers excited about the design process in return.",
310 }
311}
312
Giorgi Lekveishvili27b2b572023-06-30 10:44:45 +0400313func CreateAppMaddy(fs embed.FS, tmpls *template.Template) StoreApp {
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +0400314 schema, err := readJSONSchemaFromFile(fs, "values-tmpl/maddy.jsonschema")
Giorgi Lekveishvili7efe22f2023-05-30 13:01:53 +0400315 if err != nil {
316 panic(err)
317 }
Giorgi Lekveishvili27b2b572023-06-30 10:44:45 +0400318 return StoreApp{
319 App{
320 "maddy",
321 []string{"app-maddy"},
322 []*template.Template{
323 tmpls.Lookup("maddy.yaml"),
324 },
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +0400325 schema,
Giorgi Lekveishvili27b2b572023-06-30 10:44:45 +0400326 nil,
giolekva050609f2021-12-29 15:51:40 +0400327 },
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400328 `<svg xmlns="http://www.w3.org/2000/svg" width="50" height="50" viewBox="0 0 48 48"><path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" d="M9.5 13c13.687 13.574 14.825 13.09 29 0"/><rect width="37" height="31" x="5.5" y="8.5" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" rx="2"/></svg>`,
Giorgi Lekveishvili27b2b572023-06-30 10:44:45 +0400329 "SMPT/IMAP server to communicate via email.",
giolekva050609f2021-12-29 15:51:40 +0400330 }
331}
giolekvaef76a3e2022-01-10 12:22:28 +0400332
Giorgi Lekveishvili27b2b572023-06-30 10:44:45 +0400333func CreateAppQBittorrent(fs embed.FS, tmpls *template.Template) StoreApp {
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +0400334 schema, err := readJSONSchemaFromFile(fs, "values-tmpl/qbittorrent.jsonschema")
Giorgi Lekveishvili7efe22f2023-05-30 13:01:53 +0400335 if err != nil {
336 panic(err)
337 }
Giorgi Lekveishvili27b2b572023-06-30 10:44:45 +0400338 return StoreApp{
339 App{
340 "qbittorrent",
341 []string{"app-qbittorrent"},
342 []*template.Template{
343 tmpls.Lookup("qbittorrent.yaml"),
344 },
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +0400345 schema,
Giorgi Lekveishvili27b2b572023-06-30 10:44:45 +0400346 tmpls.Lookup("qbittorrent.md"),
giolekvaef76a3e2022-01-10 12:22:28 +0400347 },
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400348 `<svg xmlns="http://www.w3.org/2000/svg" width="50" height="50" viewBox="0 0 48 48"><circle cx="24" cy="24" r="21.5" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"/><path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" d="M26.651 22.364a5.034 5.034 0 0 1 5.035-5.035h0a5.034 5.034 0 0 1 5.034 5.035v3.272a5.034 5.034 0 0 1-5.034 5.035h0a5.034 5.034 0 0 1-5.035-5.035m0 5.035V10.533m-5.302 15.103a5.034 5.034 0 0 1-5.035 5.035h0a5.034 5.034 0 0 1-5.034-5.035v-3.272a5.034 5.034 0 0 1 5.034-5.035h0a5.034 5.034 0 0 1 5.035 5.035m0-5.035v20.138"/></svg>`,
Giorgi Lekveishvili27b2b572023-06-30 10:44:45 +0400349 "qBittorrent is a cross-platform free and open-source BitTorrent client written in native C++. It relies on Boost, Qt 6 toolkit and the libtorrent-rasterbar library, with an optional search engine written in Python.",
giolekvaef76a3e2022-01-10 12:22:28 +0400350 }
351}
352
Giorgi Lekveishvili27b2b572023-06-30 10:44:45 +0400353func CreateAppJellyfin(fs embed.FS, tmpls *template.Template) StoreApp {
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +0400354 schema, err := readJSONSchemaFromFile(fs, "values-tmpl/jellyfin.jsonschema")
Giorgi Lekveishvili7efe22f2023-05-30 13:01:53 +0400355 if err != nil {
356 panic(err)
357 }
Giorgi Lekveishvili27b2b572023-06-30 10:44:45 +0400358 return StoreApp{
359 App{
360 "jellyfin",
361 []string{"app-jellyfin"},
362 []*template.Template{
363 tmpls.Lookup("jellyfin.yaml"),
364 },
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +0400365 schema,
Giorgi Lekveishvili27b2b572023-06-30 10:44:45 +0400366 nil,
giolekvaef76a3e2022-01-10 12:22:28 +0400367 },
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400368 `<svg xmlns="http://www.w3.org/2000/svg" width="50" height="50" viewBox="0 0 48 48"><path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" d="M24 20c-1.62 0-6.85 9.48-6.06 11.08s11.33 1.59 12.12 0S25.63 20 24 20Z"/><path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" d="M24 5.5c-4.89 0-20.66 28.58-18.25 33.4s34.13 4.77 36.51 0S28.9 5.5 24 5.5Zm12 29.21c-1.56 3.13-22.35 3.17-23.93 0S20.8 12.83 24 12.83s13.52 18.76 12 21.88Z"/></svg>`,
Giorgi Lekveishvili27b2b572023-06-30 10:44:45 +0400369 "Jellyfin is a free and open-source media server and suite of multimedia applications designed to organize, manage, and share digital media files to networked devices.",
giolekvaef76a3e2022-01-10 12:22:28 +0400370 }
371}
Giorgi Lekveishvili23ef7f82023-05-26 11:57:48 +0400372
Giorgi Lekveishvili27b2b572023-06-30 10:44:45 +0400373func CreateAppRpuppy(fs embed.FS, tmpls *template.Template) StoreApp {
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +0400374 schema, err := readJSONSchemaFromFile(fs, "values-tmpl/rpuppy.jsonschema")
Giorgi Lekveishvili7efe22f2023-05-30 13:01:53 +0400375 if err != nil {
376 panic(err)
377 }
Giorgi Lekveishvili27b2b572023-06-30 10:44:45 +0400378 return StoreApp{
379 App{
380 "rpuppy",
381 []string{"app-rpuppy"},
382 []*template.Template{
383 tmpls.Lookup("rpuppy.yaml"),
384 },
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +0400385 schema,
Giorgi Lekveishvili27b2b572023-06-30 10:44:45 +0400386 tmpls.Lookup("rpuppy.md"),
Giorgi Lekveishvili23ef7f82023-05-26 11:57:48 +0400387 },
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400388 `<svg xmlns="http://www.w3.org/2000/svg" width="50" height="50" viewBox="0 0 256 256"><path fill="currentColor" d="M100 140a8 8 0 1 1-8-8a8 8 0 0 1 8 8Zm64 8a8 8 0 1 0-8-8a8 8 0 0 0 8 8Zm64.94-9.11a12.12 12.12 0 0 1-5 1.11a11.83 11.83 0 0 1-9.35-4.62l-2.59-3.29V184a36 36 0 0 1-36 36H80a36 36 0 0 1-36-36v-51.91l-2.53 3.27A11.88 11.88 0 0 1 32.1 140a12.08 12.08 0 0 1-5-1.11a11.82 11.82 0 0 1-6.84-13.14l16.42-88a12 12 0 0 1 14.7-9.43h.16L104.58 44h46.84l53.08-15.6h.16a12 12 0 0 1 14.7 9.43l16.42 88a11.81 11.81 0 0 1-6.84 13.06ZM97.25 50.18L49.34 36.1a4.18 4.18 0 0 0-.92-.1a4 4 0 0 0-3.92 3.26l-16.42 88a4 4 0 0 0 7.08 3.22ZM204 121.75L150 52h-44l-54 69.75V184a28 28 0 0 0 28 28h44v-18.34l-14.83-14.83a4 4 0 0 1 5.66-5.66L128 186.34l13.17-13.17a4 4 0 0 1 5.66 5.66L132 193.66V212h44a28 28 0 0 0 28-28Zm23.92 5.48l-16.42-88a4 4 0 0 0-4.84-3.16l-47.91 14.11l62.11 80.28a4 4 0 0 0 7.06-3.23Z"/></svg>`,
Giorgi Lekveishvili27b2b572023-06-30 10:44:45 +0400389 "Delights users with randomly generate puppy pictures. Can be configured to be reachable only from private network or publicly.",
Giorgi Lekveishvili23ef7f82023-05-26 11:57:48 +0400390 }
391}
392
Giorgi Lekveishvili672af5d2023-07-12 11:57:51 +0400393func CreateAppSoftServe(fs embed.FS, tmpls *template.Template) StoreApp {
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +0400394 schema, err := readJSONSchemaFromFile(fs, "values-tmpl/soft-serve.jsonschema")
Giorgi Lekveishvili672af5d2023-07-12 11:57:51 +0400395 if err != nil {
396 panic(err)
397 }
398 return StoreApp{
399 App{
400 "soft-serve",
401 []string{"app-soft-serve"},
402 []*template.Template{
403 tmpls.Lookup("soft-serve.yaml"),
404 },
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +0400405 schema,
Giorgi Lekveishvili672af5d2023-07-12 11:57:51 +0400406 tmpls.Lookup("soft-serve.md"),
407 },
408 `<svg xmlns="http://www.w3.org/2000/svg" width="50" height="50" viewBox="0 0 48 48"><g fill="none" stroke="currentColor" stroke-linecap="round" stroke-width="4"><path stroke-linejoin="round" d="M15.34 22.5L21 37l3 6l3-6l5.66-14.5"/><path d="M19 32h10"/><path stroke-linejoin="round" d="M24 3c-6 0-8 6-8 6s-6 2-6 7s5 7 5 7s3.5-2 9-2s9 2 9 2s5-2 5-7s-6-7-6-7s-2-6-8-6Z"/></g></svg>`,
409 "A tasty, self-hostable Git server for the command line. 🍦",
410 }
411}
412
Giorgi Lekveishvili7efe22f2023-05-30 13:01:53 +0400413func CreateAppHeadscale(fs embed.FS, tmpls *template.Template) App {
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +0400414 schema, err := readJSONSchemaFromFile(fs, "values-tmpl/headscale.jsonschema")
Giorgi Lekveishvili7efe22f2023-05-30 13:01:53 +0400415 if err != nil {
416 panic(err)
417 }
Giorgi Lekveishvili23ef7f82023-05-26 11:57:48 +0400418 return App{
419 "headscale",
Giorgi Lekveishvili7fb28bf2023-06-24 19:51:16 +0400420 []string{"app-headscale"},
Giorgi Lekveishvili23ef7f82023-05-26 11:57:48 +0400421 []*template.Template{
422 tmpls.Lookup("headscale.yaml"),
423 },
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +0400424 schema,
Giorgi Lekveishvili3a907052023-05-30 13:33:32 +0400425 tmpls.Lookup("headscale.md"),
Giorgi Lekveishvili23ef7f82023-05-26 11:57:48 +0400426 }
427}
Giorgi Lekveishvili0ccd1482023-06-21 15:02:24 +0400428
Giorgi Lekveishvili39913692023-12-05 08:58:08 +0400429func CreateAppHeadscaleUser(fs embed.FS, tmpls *template.Template) App {
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +0400430 schema, err := readJSONSchemaFromFile(fs, "values-tmpl/headscale-user.jsonschema")
Giorgi Lekveishvili39913692023-12-05 08:58:08 +0400431 if err != nil {
432 panic(err)
433 }
434 return App{
435 "headscale-user",
436 []string{"app-headscale"},
437 []*template.Template{
438 tmpls.Lookup("headscale-user.yaml"),
439 },
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +0400440 schema,
Giorgi Lekveishvili39913692023-12-05 08:58:08 +0400441 tmpls.Lookup("headscale-user.md"),
442 }
443}
444
Giorgi Lekveishvili4fc29432023-07-20 10:03:28 +0400445func CreateMetallbIPAddressPool(fs embed.FS, tmpls *template.Template) App {
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +0400446 schema, err := readJSONSchemaFromFile(fs, "values-tmpl/metallb-ipaddresspool.jsonschema")
Giorgi Lekveishvili4fc29432023-07-20 10:03:28 +0400447 if err != nil {
448 panic(err)
449 }
450 return App{
451 "metallb-ipaddresspool",
452 []string{"metallb-ipaddresspool"},
453 []*template.Template{
454 tmpls.Lookup("metallb-ipaddresspool.yaml"),
455 },
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +0400456 schema,
Giorgi Lekveishvili4fc29432023-07-20 10:03:28 +0400457 tmpls.Lookup("metallb-ipaddresspool.md"),
458 }
459}
460
Giorgi Lekveishvili0ccd1482023-06-21 15:02:24 +0400461func CreateEnvManager(fs embed.FS, tmpls *template.Template) App {
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +0400462 schema, err := readJSONSchemaFromFile(fs, "values-tmpl/env-manager.jsonschema")
Giorgi Lekveishvili0ccd1482023-06-21 15:02:24 +0400463 if err != nil {
464 panic(err)
465 }
466 return App{
467 "env-manager",
Giorgi Lekveishvili7fb28bf2023-06-24 19:51:16 +0400468 []string{"env-manager"},
Giorgi Lekveishvili0ccd1482023-06-21 15:02:24 +0400469 []*template.Template{
470 tmpls.Lookup("env-manager.yaml"),
471 },
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +0400472 schema,
Giorgi Lekveishvili0ccd1482023-06-21 15:02:24 +0400473 tmpls.Lookup("env-manager.md"),
474 }
475}
476
Giorgi Lekveishvili12850ee2023-06-22 13:11:17 +0400477func CreateWelcome(fs embed.FS, tmpls *template.Template) App {
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +0400478 schema, err := readJSONSchemaFromFile(fs, "values-tmpl/welcome.jsonschema")
Giorgi Lekveishvili12850ee2023-06-22 13:11:17 +0400479 if err != nil {
480 panic(err)
481 }
482 return App{
483 "welcome",
Giorgi Lekveishvili7fb28bf2023-06-24 19:51:16 +0400484 []string{"app-welcome"},
Giorgi Lekveishvili12850ee2023-06-22 13:11:17 +0400485 []*template.Template{
486 tmpls.Lookup("welcome.yaml"),
487 },
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +0400488 schema,
Giorgi Lekveishvili12850ee2023-06-22 13:11:17 +0400489 tmpls.Lookup("welcome.md"),
490 }
491}
492
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400493func CreateAppManager(fs embed.FS, tmpls *template.Template) App {
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +0400494 schema, err := readJSONSchemaFromFile(fs, "values-tmpl/appmanager.jsonschema")
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400495 if err != nil {
496 panic(err)
497 }
498 return App{
499 "app-manager",
500 []string{"core-appmanager"},
501 []*template.Template{
502 tmpls.Lookup("appmanager.yaml"),
503 },
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +0400504 schema,
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400505 tmpls.Lookup("appmanager.md"),
506 }
507}
508
Giorgi Lekveishvili0ccd1482023-06-21 15:02:24 +0400509func CreateIngressPublic(fs embed.FS, tmpls *template.Template) App {
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +0400510 schema, err := readJSONSchemaFromFile(fs, "values-tmpl/ingress-public.jsonschema")
Giorgi Lekveishvili0ccd1482023-06-21 15:02:24 +0400511 if err != nil {
512 panic(err)
513 }
514 return App{
515 "ingress-public",
Giorgi Lekveishvili7fb28bf2023-06-24 19:51:16 +0400516 []string{"ingress-public"},
Giorgi Lekveishvili0ccd1482023-06-21 15:02:24 +0400517 []*template.Template{
518 tmpls.Lookup("ingress-public.yaml"),
519 },
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +0400520 schema,
Giorgi Lekveishvili0ccd1482023-06-21 15:02:24 +0400521 tmpls.Lookup("ingress-public.md"),
522 }
523}
524
525func CreateCertManager(fs embed.FS, tmpls *template.Template) App {
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +0400526 schema, err := readJSONSchemaFromFile(fs, "values-tmpl/cert-manager.jsonschema")
Giorgi Lekveishvili0ccd1482023-06-21 15:02:24 +0400527 if err != nil {
528 panic(err)
529 }
530 return App{
531 "cert-manager",
Giorgi Lekveishvili7fb28bf2023-06-24 19:51:16 +0400532 []string{"cert-manager"},
Giorgi Lekveishvili0ccd1482023-06-21 15:02:24 +0400533 []*template.Template{
534 tmpls.Lookup("cert-manager.yaml"),
535 },
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +0400536 schema,
Giorgi Lekveishvili0ccd1482023-06-21 15:02:24 +0400537 tmpls.Lookup("cert-manager.md"),
538 }
539}
540
541func CreateCertManagerWebhookGandi(fs embed.FS, tmpls *template.Template) App {
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +0400542 schema, err := readJSONSchemaFromFile(fs, "values-tmpl/cert-manager-webhook-pcloud.jsonschema")
Giorgi Lekveishvili0ccd1482023-06-21 15:02:24 +0400543 if err != nil {
544 panic(err)
545 }
546 return App{
Giorgi Lekveishvili5c2c0b92023-12-07 17:35:40 +0400547 "cert-manager-webhook-pcloud",
Giorgi Lekveishvili7fb28bf2023-06-24 19:51:16 +0400548 []string{},
Giorgi Lekveishvili0ccd1482023-06-21 15:02:24 +0400549 []*template.Template{
Giorgi Lekveishvili5c2c0b92023-12-07 17:35:40 +0400550 tmpls.Lookup("cert-manager-webhook-pcloud.yaml"),
Giorgi Lekveishvili0ccd1482023-06-21 15:02:24 +0400551 },
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +0400552 schema,
Giorgi Lekveishvili5c2c0b92023-12-07 17:35:40 +0400553 tmpls.Lookup("cert-manager-webhook-pcloud.md"),
Giorgi Lekveishvili0ccd1482023-06-21 15:02:24 +0400554 }
555}
556
557func CreateCSIDriverSMB(fs embed.FS, tmpls *template.Template) App {
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +0400558 schema, err := readJSONSchemaFromFile(fs, "values-tmpl/csi-driver-smb.jsonschema")
Giorgi Lekveishvili0ccd1482023-06-21 15:02:24 +0400559 if err != nil {
560 panic(err)
561 }
562 return App{
563 "csi-driver-smb",
Giorgi Lekveishvili7fb28bf2023-06-24 19:51:16 +0400564 []string{"csi-driver-smb"},
Giorgi Lekveishvili0ccd1482023-06-21 15:02:24 +0400565 []*template.Template{
566 tmpls.Lookup("csi-driver-smb.yaml"),
567 },
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +0400568 schema,
Giorgi Lekveishvili0ccd1482023-06-21 15:02:24 +0400569 tmpls.Lookup("csi-driver-smb.md"),
570 }
571}
572
573func CreateResourceRendererController(fs embed.FS, tmpls *template.Template) App {
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +0400574 schema, err := readJSONSchemaFromFile(fs, "values-tmpl/resource-renderer-controller.jsonschema")
Giorgi Lekveishvili0ccd1482023-06-21 15:02:24 +0400575 if err != nil {
576 panic(err)
577 }
578 return App{
579 "resource-renderer-controller",
Giorgi Lekveishvili7fb28bf2023-06-24 19:51:16 +0400580 []string{"rr-controller"},
Giorgi Lekveishvili0ccd1482023-06-21 15:02:24 +0400581 []*template.Template{
582 tmpls.Lookup("resource-renderer-controller.yaml"),
583 },
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +0400584 schema,
Giorgi Lekveishvili0ccd1482023-06-21 15:02:24 +0400585 tmpls.Lookup("resource-renderer-controller.md"),
586 }
587}
588
589func CreateHeadscaleController(fs embed.FS, tmpls *template.Template) App {
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +0400590 schema, err := readJSONSchemaFromFile(fs, "values-tmpl/headscale-controller.jsonschema")
Giorgi Lekveishvili0ccd1482023-06-21 15:02:24 +0400591 if err != nil {
592 panic(err)
593 }
594 return App{
595 "headscale-controller",
Giorgi Lekveishvili7fb28bf2023-06-24 19:51:16 +0400596 []string{"headscale-controller"},
Giorgi Lekveishvili0ccd1482023-06-21 15:02:24 +0400597 []*template.Template{
598 tmpls.Lookup("headscale-controller.yaml"),
599 },
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +0400600 schema,
Giorgi Lekveishvili0ccd1482023-06-21 15:02:24 +0400601 tmpls.Lookup("headscale-controller.md"),
602 }
603}
Giorgi Lekveishvili743fb432023-11-08 17:19:40 +0400604
Giorgi Lekveishvili106a9352023-12-04 11:20:11 +0400605func CreateDNSZoneManager(fs embed.FS, tmpls *template.Template) App {
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +0400606 schema, err := readJSONSchemaFromFile(fs, "values-tmpl/dns-zone-controller.jsonschema")
Giorgi Lekveishvili106a9352023-12-04 11:20:11 +0400607 if err != nil {
608 panic(err)
609 }
610 return App{
611 "dns-zone-manager",
612 []string{"dns-zone-manager"},
613 []*template.Template{
614 tmpls.Lookup("dns-zone-storage.yaml"),
615 tmpls.Lookup("coredns.yaml"),
616 tmpls.Lookup("dns-zone-controller.yaml"),
617 },
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +0400618 schema,
Giorgi Lekveishvili106a9352023-12-04 11:20:11 +0400619 tmpls.Lookup("dns-zone-controller.md"),
620 }
621}
622
Giorgi Lekveishvili2df23db2023-12-14 07:55:22 +0400623func CreateFluxcdReconciler(fs embed.FS, tmpls *template.Template) App {
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +0400624 schema, err := readJSONSchemaFromFile(fs, "values-tmpl/fluxcd-reconciler.jsonschema")
Giorgi Lekveishvili2df23db2023-12-14 07:55:22 +0400625 if err != nil {
626 panic(err)
627 }
628 return App{
629 "fluxcd-reconciler",
630 []string{"fluxcd-reconciler"},
631 []*template.Template{
632 tmpls.Lookup("fluxcd-reconciler.yaml"),
633 },
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +0400634 schema,
Giorgi Lekveishvili2df23db2023-12-14 07:55:22 +0400635 tmpls.Lookup("fluxcd-reconciler.md"),
636 }
637}
638
Giorgi Lekveishvili743fb432023-11-08 17:19:40 +0400639type httpAppRepository struct {
640 apps []StoreApp
641}
642
643type appVersion struct {
644 Version string `json:"version"`
645 Urls []string `json:"urls"`
646}
647
648type allAppsResp struct {
649 ApiVersion string `json:"apiVersion"`
650 Entries map[string][]appVersion `json:"entries"`
651}
652
653func FetchAppsFromHTTPRepository(addr string, fs billy.Filesystem) error {
654 resp, err := http.Get(addr)
655 if err != nil {
656 return err
657 }
658 b, err := io.ReadAll(resp.Body)
659 if err != nil {
660 return err
661 }
662 var apps allAppsResp
663 if err := yaml.Unmarshal(b, &apps); err != nil {
664 return err
665 }
666 for name, conf := range apps.Entries {
667 for _, version := range conf {
668 resp, err := http.Get(version.Urls[0])
669 if err != nil {
670 return err
671 }
672 nameVersion := fmt.Sprintf("%s-%s", name, version.Version)
673 if err := fs.MkdirAll(nameVersion, 0700); err != nil {
674 return err
675 }
676 sub, err := fs.Chroot(nameVersion)
677 if err != nil {
678 return err
679 }
680 if err := extractApp(resp.Body, sub); err != nil {
681 return err
682 }
683 }
684 }
685 return nil
686}
687
688func extractApp(archive io.Reader, fs billy.Filesystem) error {
689 uncompressed, err := gzip.NewReader(archive)
690 if err != nil {
691 return err
692 }
693 tarReader := tar.NewReader(uncompressed)
694 for true {
695 header, err := tarReader.Next()
696 if err == io.EOF {
697 break
698 }
699 if err != nil {
700 return err
701 }
702 switch header.Typeflag {
703 case tar.TypeDir:
704 if err := fs.MkdirAll(header.Name, 0755); err != nil {
705 return err
706 }
707 case tar.TypeReg:
708 out, err := fs.Create(header.Name)
709 if err != nil {
710 return err
711 }
712 defer out.Close()
713 if _, err := io.Copy(out, tarReader); err != nil {
714 return err
715 }
716 default:
717 return fmt.Errorf("Uknown type: %s", header.Name)
718 }
719 }
720 return nil
721}
722
723type fsAppRepository struct {
724 InMemoryAppRepository[StoreApp]
725 fs billy.Filesystem
726}
727
728func NewFSAppRepository(fs billy.Filesystem) (AppRepository[StoreApp], error) {
729 all, err := fs.ReadDir(".")
730 if err != nil {
731 return nil, err
732 }
733 apps := make([]StoreApp, 0)
734 for _, e := range all {
735 if !e.IsDir() {
736 continue
737 }
738 appFS, err := fs.Chroot(e.Name())
739 if err != nil {
740 return nil, err
741 }
742 app, err := loadApp(appFS)
743 if err != nil {
744 log.Printf("Ignoring directory %s: %s", e.Name(), err)
745 continue
746 }
747 apps = append(apps, app)
748 }
749 return &fsAppRepository{
750 NewInMemoryAppRepository[StoreApp](apps),
751 fs,
752 }, nil
753}
754
755func loadApp(fs billy.Filesystem) (StoreApp, error) {
756 cfg, err := fs.Open("Chart.yaml")
757 if err != nil {
758 return StoreApp{}, err
759 }
760 defer cfg.Close()
761 b, err := io.ReadAll(cfg)
762 if err != nil {
763 return StoreApp{}, err
764 }
765 var appCfg appConfig
766 if err := yaml.Unmarshal(b, &appCfg); err != nil {
767 return StoreApp{}, err
768 }
769 rb, err := fs.Open("README.md")
770 if err != nil {
771 return StoreApp{}, err
772 }
773 defer rb.Close()
774 readme, err := io.ReadAll(rb)
775 if err != nil {
776 return StoreApp{}, err
777 }
778 readmeTmpl, err := template.New("README.md").Parse(string(readme))
779 if err != nil {
780 return StoreApp{}, err
781 }
782 sb, err := fs.Open("schema.json")
783 if err != nil {
784 return StoreApp{}, err
785 }
786 defer sb.Close()
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +0400787 scm, err := io.ReadAll(sb)
788 if err != nil {
789 return StoreApp{}, err
790 }
791 schema, err := NewJSONSchema(string(scm))
Giorgi Lekveishvili743fb432023-11-08 17:19:40 +0400792 if err != nil {
793 return StoreApp{}, err
794 }
795 tFiles, err := fs.ReadDir("templates")
796 if err != nil {
797 return StoreApp{}, err
798 }
799 tmpls := make([]*template.Template, 0)
800 for _, t := range tFiles {
801 if !strings.HasSuffix(t.Name(), ".yaml") {
802 continue
803 }
804 inp, err := fs.Open(fs.Join("templates", t.Name()))
805 if err != nil {
806 return StoreApp{}, err
807 }
808 b, err := io.ReadAll(inp)
809 if err != nil {
810 return StoreApp{}, err
811 }
812 tmpl, err := template.New(t.Name()).Parse(string(b))
813 if err != nil {
814 return StoreApp{}, err
815 }
816 tmpls = append(tmpls, tmpl)
817 }
818 return StoreApp{
819 App: App{
820 Name: appCfg.Name,
821 Readme: readmeTmpl,
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +0400822 schema: schema,
Giorgi Lekveishvili743fb432023-11-08 17:19:40 +0400823 Namespaces: appCfg.Namespaces,
Giorgi Lekveishvili3f697b12024-01-04 00:56:06 +0400824 templates: tmpls,
Giorgi Lekveishvili743fb432023-11-08 17:19:40 +0400825 },
826 ShortDescription: appCfg.Description,
827 Icon: appCfg.Icon,
828 }, nil
829}