blob: 384e54fb4c8d134c43cbd4c8d28f3b41bccb3e13 [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"
5 "compress/gzip"
giolekva8aa73e82022-07-09 11:34:39 +04006 "embed"
Giorgi Lekveishvilibd6be7f2023-05-26 15:51:28 +04007 "fmt"
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +04008 htemplate "html/template"
Giorgi Lekveishvili743fb432023-11-08 17:19:40 +04009 "io"
giolekva8aa73e82022-07-09 11:34:39 +040010 "log"
Giorgi Lekveishvili743fb432023-11-08 17:19:40 +040011 "net/http"
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +040012 "strings"
giolekva8aa73e82022-07-09 11:34:39 +040013 "text/template"
Giorgi Lekveishvili0ccd1482023-06-21 15:02:24 +040014
15 "github.com/Masterminds/sprig/v3"
Giorgi Lekveishvili743fb432023-11-08 17:19:40 +040016 "github.com/go-git/go-billy/v5"
17 "sigs.k8s.io/yaml"
giolekva8aa73e82022-07-09 11:34:39 +040018)
giolekva050609f2021-12-29 15:51:40 +040019
Giorgi Lekveishvilibd6be7f2023-05-26 15:51:28 +040020//go:embed values-tmpl
21var valuesTmpls embed.FS
22
Giorgi Lekveishvili27b2b572023-06-30 10:44:45 +040023type Named interface {
24 Nam() string
25}
26
Giorgi Lekveishvili743fb432023-11-08 17:19:40 +040027type appConfig struct {
28 Name string `json:"name"`
29 Version string `json:"version"`
30 Description string `json:"description"`
31 Namespaces []string `json:"namespaces"`
32 Icon htemplate.HTML `json:"icon"`
33}
34
giolekva050609f2021-12-29 15:51:40 +040035type App struct {
Giorgi Lekveishvili7fb28bf2023-06-24 19:51:16 +040036 Name string
37 Namespaces []string
38 Templates []*template.Template
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +040039 schema Schema
Giorgi Lekveishvili7fb28bf2023-06-24 19:51:16 +040040 Readme *template.Template
giolekva050609f2021-12-29 15:51:40 +040041}
42
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +040043func (a App) Schema() Schema {
44 return a.schema
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +040045}
46
Giorgi Lekveishvili27b2b572023-06-30 10:44:45 +040047type StoreApp struct {
48 App
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +040049 Icon htemplate.HTML
Giorgi Lekveishvili27b2b572023-06-30 10:44:45 +040050 ShortDescription string
Giorgi Lekveishvilibd6be7f2023-05-26 15:51:28 +040051}
52
Giorgi Lekveishvili27b2b572023-06-30 10:44:45 +040053func (a App) Nam() string {
54 return a.Name
Giorgi Lekveishvilibd6be7f2023-05-26 15:51:28 +040055}
56
Giorgi Lekveishvili27b2b572023-06-30 10:44:45 +040057func (a StoreApp) Nam() string {
58 return a.Name
59}
60
61type AppRepository[A Named] interface {
62 GetAll() ([]A, error)
63 Find(name string) (*A, error)
64}
65
66type InMemoryAppRepository[A Named] struct {
67 apps []A
68}
69
Giorgi Lekveishvili743fb432023-11-08 17:19:40 +040070func NewInMemoryAppRepository[A Named](apps []A) InMemoryAppRepository[A] {
71 return InMemoryAppRepository[A]{
Giorgi Lekveishvilibd6be7f2023-05-26 15:51:28 +040072 apps,
73 }
74}
75
Giorgi Lekveishvili27b2b572023-06-30 10:44:45 +040076func (r InMemoryAppRepository[A]) Find(name string) (*A, error) {
Giorgi Lekveishvilibd6be7f2023-05-26 15:51:28 +040077 for _, a := range r.apps {
Giorgi Lekveishvili27b2b572023-06-30 10:44:45 +040078 if a.Nam() == name {
Giorgi Lekveishvilibd6be7f2023-05-26 15:51:28 +040079 return &a, nil
80 }
81 }
82 return nil, fmt.Errorf("Application not found: %s", name)
83}
giolekva8aa73e82022-07-09 11:34:39 +040084
Giorgi Lekveishvili27b2b572023-06-30 10:44:45 +040085func (r InMemoryAppRepository[A]) GetAll() ([]A, error) {
Giorgi Lekveishvili7efe22f2023-05-30 13:01:53 +040086 return r.apps, nil
87}
88
giolekva8aa73e82022-07-09 11:34:39 +040089func CreateAllApps() []App {
Giorgi Lekveishvili0ccd1482023-06-21 15:02:24 +040090 tmpls, err := template.New("root").Funcs(template.FuncMap(sprig.FuncMap())).ParseFS(valuesTmpls, "values-tmpl/*")
giolekva8aa73e82022-07-09 11:34:39 +040091 if err != nil {
92 log.Fatal(err)
93 }
Giorgi Lekveishvili27b2b572023-06-30 10:44:45 +040094 ret := []App{
Giorgi Lekveishvili7efe22f2023-05-30 13:01:53 +040095 CreateAppIngressPrivate(valuesTmpls, tmpls),
Giorgi Lekveishvili12850ee2023-06-22 13:11:17 +040096 CreateCertificateIssuerPublic(valuesTmpls, tmpls),
97 CreateCertificateIssuerPrivate(valuesTmpls, tmpls),
Giorgi Lekveishvili7efe22f2023-05-30 13:01:53 +040098 CreateAppCoreAuth(valuesTmpls, tmpls),
Giorgi Lekveishvili7efe22f2023-05-30 13:01:53 +040099 CreateAppHeadscale(valuesTmpls, tmpls),
Giorgi Lekveishvili39913692023-12-05 08:58:08 +0400100 CreateAppHeadscaleUser(valuesTmpls, tmpls),
Giorgi Lekveishvili4fc29432023-07-20 10:03:28 +0400101 CreateMetallbIPAddressPool(valuesTmpls, tmpls),
Giorgi Lekveishvili0ccd1482023-06-21 15:02:24 +0400102 CreateEnvManager(valuesTmpls, tmpls),
Giorgi Lekveishvili12850ee2023-06-22 13:11:17 +0400103 CreateWelcome(valuesTmpls, tmpls),
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400104 CreateAppManager(valuesTmpls, tmpls),
Giorgi Lekveishvili0ccd1482023-06-21 15:02:24 +0400105 CreateIngressPublic(valuesTmpls, tmpls),
106 CreateCertManager(valuesTmpls, tmpls),
107 CreateCertManagerWebhookGandi(valuesTmpls, tmpls),
Giorgi Lekveishvili0ccd1482023-06-21 15:02:24 +0400108 CreateCSIDriverSMB(valuesTmpls, tmpls),
109 CreateResourceRendererController(valuesTmpls, tmpls),
110 CreateHeadscaleController(valuesTmpls, tmpls),
Giorgi Lekveishvili106a9352023-12-04 11:20:11 +0400111 CreateDNSZoneManager(valuesTmpls, tmpls),
Giorgi Lekveishvili2df23db2023-12-14 07:55:22 +0400112 CreateFluxcdReconciler(valuesTmpls, tmpls),
giolekvaef76a3e2022-01-10 12:22:28 +0400113 }
Giorgi Lekveishvili27b2b572023-06-30 10:44:45 +0400114 for _, a := range CreateStoreApps() {
115 ret = append(ret, a.App)
116 }
117 return ret
118}
119
120func CreateStoreApps() []StoreApp {
121 tmpls, err := template.New("root").Funcs(template.FuncMap(sprig.FuncMap())).ParseFS(valuesTmpls, "values-tmpl/*")
122 if err != nil {
123 log.Fatal(err)
124 }
125 return []StoreApp{
126 CreateAppVaultwarden(valuesTmpls, tmpls),
127 CreateAppMatrix(valuesTmpls, tmpls),
128 CreateAppPihole(valuesTmpls, tmpls),
Giorgi Lekveishvili3fd5e4c2023-12-19 22:09:40 +0400129 CreateAppPenpot(valuesTmpls, tmpls),
Giorgi Lekveishvili27b2b572023-06-30 10:44:45 +0400130 CreateAppMaddy(valuesTmpls, tmpls),
131 CreateAppQBittorrent(valuesTmpls, tmpls),
132 CreateAppJellyfin(valuesTmpls, tmpls),
Giorgi Lekveishvili672af5d2023-07-12 11:57:51 +0400133 CreateAppSoftServe(valuesTmpls, tmpls),
Giorgi Lekveishvili27b2b572023-06-30 10:44:45 +0400134 CreateAppRpuppy(valuesTmpls, tmpls),
135 }
giolekvaef76a3e2022-01-10 12:22:28 +0400136}
137
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +0400138func readJSONSchemaFromFile(fs embed.FS, f string) (Schema, error) {
139 schema, err := fs.ReadFile(f)
140 if err != nil {
141 return nil, err
142 }
143 ret, err := NewJSONSchema(string(schema))
144 if err != nil {
145 return nil, err
146 }
147 return ret, nil
148}
149
Giorgi Lekveishvili4d2784d2023-06-01 14:27:32 +0400150// TODO(gio): service account needs permission to create/update secret
Giorgi Lekveishvili7efe22f2023-05-30 13:01:53 +0400151func CreateAppIngressPrivate(fs embed.FS, tmpls *template.Template) App {
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +0400152 schema, err := readJSONSchemaFromFile(fs, "values-tmpl/private-network.jsonschema")
Giorgi Lekveishvili7efe22f2023-05-30 13:01:53 +0400153 if err != nil {
154 panic(err)
155 }
giolekva050609f2021-12-29 15:51:40 +0400156 return App{
Giorgi Lekveishvili2dbce6c2023-12-05 15:16:27 +0400157 "private-network",
158 []string{"ingress-private"}, // TODO(gio): rename to private network
giolekva050609f2021-12-29 15:51:40 +0400159 []*template.Template{
giolekva050609f2021-12-29 15:51:40 +0400160 tmpls.Lookup("ingress-private.yaml"),
Giorgi Lekveishvili2dbce6c2023-12-05 15:16:27 +0400161 tmpls.Lookup("tailscale-proxy.yaml"),
giolekva050609f2021-12-29 15:51:40 +0400162 },
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +0400163 schema,
Giorgi Lekveishvili2dbce6c2023-12-05 15:16:27 +0400164 tmpls.Lookup("private-network.md"),
giolekva050609f2021-12-29 15:51:40 +0400165 }
166}
167
Giorgi Lekveishvili0ccd1482023-06-21 15:02:24 +0400168func CreateCertificateIssuerPrivate(fs embed.FS, tmpls *template.Template) App {
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +0400169 schema, err := readJSONSchemaFromFile(fs, "values-tmpl/certificate-issuer-private.jsonschema")
Giorgi Lekveishvili0ccd1482023-06-21 15:02:24 +0400170 if err != nil {
171 panic(err)
172 }
173 return App{
Giorgi Lekveishvili12850ee2023-06-22 13:11:17 +0400174 "certificate-issuer-private",
Giorgi Lekveishvili7fb28bf2023-06-24 19:51:16 +0400175 []string{},
Giorgi Lekveishvili0ccd1482023-06-21 15:02:24 +0400176 []*template.Template{
177 tmpls.Lookup("certificate-issuer-private.yaml"),
178 },
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +0400179 schema,
Giorgi Lekveishvili0ccd1482023-06-21 15:02:24 +0400180 tmpls.Lookup("certificate-issuer-private.md"),
181 }
182}
183
Giorgi Lekveishvili12850ee2023-06-22 13:11:17 +0400184func CreateCertificateIssuerPublic(fs embed.FS, tmpls *template.Template) App {
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +0400185 schema, err := readJSONSchemaFromFile(fs, "values-tmpl/certificate-issuer-public.jsonschema")
Giorgi Lekveishvili12850ee2023-06-22 13:11:17 +0400186 if err != nil {
187 panic(err)
188 }
189 return App{
190 "certificate-issuer-public",
Giorgi Lekveishvili7fb28bf2023-06-24 19:51:16 +0400191 []string{},
Giorgi Lekveishvili12850ee2023-06-22 13:11:17 +0400192 []*template.Template{
193 tmpls.Lookup("certificate-issuer-public.yaml"),
194 },
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +0400195 schema,
Giorgi Lekveishvili12850ee2023-06-22 13:11:17 +0400196 tmpls.Lookup("certificate-issuer-public.md"),
197 }
198}
199
Giorgi Lekveishvili7efe22f2023-05-30 13:01:53 +0400200func CreateAppCoreAuth(fs embed.FS, tmpls *template.Template) App {
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +0400201 schema, err := readJSONSchemaFromFile(fs, "values-tmpl/core-auth.jsonschema")
Giorgi Lekveishvili7efe22f2023-05-30 13:01:53 +0400202 if err != nil {
203 panic(err)
204 }
giolekva050609f2021-12-29 15:51:40 +0400205 return App{
206 "core-auth",
Giorgi Lekveishvili7fb28bf2023-06-24 19:51:16 +0400207 []string{"core-auth"},
giolekva050609f2021-12-29 15:51:40 +0400208 []*template.Template{
209 tmpls.Lookup("core-auth-storage.yaml"),
210 tmpls.Lookup("core-auth.yaml"),
211 },
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +0400212 schema,
Giorgi Lekveishvili3ca1f3f2023-05-30 14:33:02 +0400213 tmpls.Lookup("core-auth.md"),
giolekva050609f2021-12-29 15:51:40 +0400214 }
215}
216
Giorgi Lekveishvili27b2b572023-06-30 10:44:45 +0400217func CreateAppVaultwarden(fs embed.FS, tmpls *template.Template) StoreApp {
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +0400218 schema, err := readJSONSchemaFromFile(fs, "values-tmpl/vaultwarden.jsonschema")
Giorgi Lekveishvili7efe22f2023-05-30 13:01:53 +0400219 if err != nil {
220 panic(err)
221 }
Giorgi Lekveishvili27b2b572023-06-30 10:44:45 +0400222 return StoreApp{
223 App: App{
224 "vaultwarden",
225 []string{"app-vaultwarden"},
226 []*template.Template{
227 tmpls.Lookup("vaultwarden.yaml"),
228 },
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +0400229 schema,
Giorgi Lekveishvili27b2b572023-06-30 10:44:45 +0400230 tmpls.Lookup("vaultwarden.md"),
giolekva050609f2021-12-29 15:51:40 +0400231 },
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400232 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 +0400233 ShortDescription: "Open source implementation of Bitwarden password manager. Can be used with official client applications.",
giolekva050609f2021-12-29 15:51:40 +0400234 }
235}
236
Giorgi Lekveishvili27b2b572023-06-30 10:44:45 +0400237func CreateAppMatrix(fs embed.FS, tmpls *template.Template) StoreApp {
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +0400238 schema, err := readJSONSchemaFromFile(fs, "values-tmpl/matrix.jsonschema")
Giorgi Lekveishvili7efe22f2023-05-30 13:01:53 +0400239 if err != nil {
240 panic(err)
241 }
Giorgi Lekveishvili27b2b572023-06-30 10:44:45 +0400242 return StoreApp{
243 App{
244 "matrix",
245 []string{"app-matrix"},
246 []*template.Template{
247 tmpls.Lookup("matrix-storage.yaml"),
248 tmpls.Lookup("matrix.yaml"),
249 },
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +0400250 schema,
Giorgi Lekveishvili27b2b572023-06-30 10:44:45 +0400251 nil,
giolekva050609f2021-12-29 15:51:40 +0400252 },
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400253 `<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 +0400254 "An open network for secure, decentralised communication",
giolekva050609f2021-12-29 15:51:40 +0400255 }
256}
257
Giorgi Lekveishvili27b2b572023-06-30 10:44:45 +0400258func CreateAppPihole(fs embed.FS, tmpls *template.Template) StoreApp {
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +0400259 schema, err := readJSONSchemaFromFile(fs, "values-tmpl/pihole.jsonschema")
Giorgi Lekveishvili7efe22f2023-05-30 13:01:53 +0400260 if err != nil {
261 panic(err)
262 }
Giorgi Lekveishvili27b2b572023-06-30 10:44:45 +0400263 return StoreApp{
264 App{
265 "pihole",
266 []string{"app-pihole"},
267 []*template.Template{
268 tmpls.Lookup("pihole.yaml"),
269 },
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +0400270 schema,
Giorgi Lekveishvili27b2b572023-06-30 10:44:45 +0400271 tmpls.Lookup("pihole.md"),
giolekva050609f2021-12-29 15:51:40 +0400272 },
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400273 // "simple-icons:pihole",
274 `<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 +0400275 "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 +0400276 }
277}
278
Giorgi Lekveishvili3fd5e4c2023-12-19 22:09:40 +0400279func CreateAppPenpot(fs embed.FS, tmpls *template.Template) StoreApp {
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +0400280 schema, err := readJSONSchemaFromFile(fs, "values-tmpl/penpot.jsonschema")
Giorgi Lekveishvili3fd5e4c2023-12-19 22:09:40 +0400281 if err != nil {
282 panic(err)
283 }
284 return StoreApp{
285 App{
286 "penpot",
287 []string{"app-penpot"},
288 []*template.Template{
289 tmpls.Lookup("penpot.yaml"),
290 },
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +0400291 schema,
Giorgi Lekveishvili3fd5e4c2023-12-19 22:09:40 +0400292 tmpls.Lookup("penpot.md"),
293 },
294 // "simple-icons:pihole",
295 `<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>`,
296 "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.",
297 }
298}
299
Giorgi Lekveishvili27b2b572023-06-30 10:44:45 +0400300func CreateAppMaddy(fs embed.FS, tmpls *template.Template) StoreApp {
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +0400301 schema, err := readJSONSchemaFromFile(fs, "values-tmpl/maddy.jsonschema")
Giorgi Lekveishvili7efe22f2023-05-30 13:01:53 +0400302 if err != nil {
303 panic(err)
304 }
Giorgi Lekveishvili27b2b572023-06-30 10:44:45 +0400305 return StoreApp{
306 App{
307 "maddy",
308 []string{"app-maddy"},
309 []*template.Template{
310 tmpls.Lookup("maddy.yaml"),
311 },
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +0400312 schema,
Giorgi Lekveishvili27b2b572023-06-30 10:44:45 +0400313 nil,
giolekva050609f2021-12-29 15:51:40 +0400314 },
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400315 `<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 +0400316 "SMPT/IMAP server to communicate via email.",
giolekva050609f2021-12-29 15:51:40 +0400317 }
318}
giolekvaef76a3e2022-01-10 12:22:28 +0400319
Giorgi Lekveishvili27b2b572023-06-30 10:44:45 +0400320func CreateAppQBittorrent(fs embed.FS, tmpls *template.Template) StoreApp {
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +0400321 schema, err := readJSONSchemaFromFile(fs, "values-tmpl/qbittorrent.jsonschema")
Giorgi Lekveishvili7efe22f2023-05-30 13:01:53 +0400322 if err != nil {
323 panic(err)
324 }
Giorgi Lekveishvili27b2b572023-06-30 10:44:45 +0400325 return StoreApp{
326 App{
327 "qbittorrent",
328 []string{"app-qbittorrent"},
329 []*template.Template{
330 tmpls.Lookup("qbittorrent.yaml"),
331 },
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +0400332 schema,
Giorgi Lekveishvili27b2b572023-06-30 10:44:45 +0400333 tmpls.Lookup("qbittorrent.md"),
giolekvaef76a3e2022-01-10 12:22:28 +0400334 },
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400335 `<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 +0400336 "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 +0400337 }
338}
339
Giorgi Lekveishvili27b2b572023-06-30 10:44:45 +0400340func CreateAppJellyfin(fs embed.FS, tmpls *template.Template) StoreApp {
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +0400341 schema, err := readJSONSchemaFromFile(fs, "values-tmpl/jellyfin.jsonschema")
Giorgi Lekveishvili7efe22f2023-05-30 13:01:53 +0400342 if err != nil {
343 panic(err)
344 }
Giorgi Lekveishvili27b2b572023-06-30 10:44:45 +0400345 return StoreApp{
346 App{
347 "jellyfin",
348 []string{"app-jellyfin"},
349 []*template.Template{
350 tmpls.Lookup("jellyfin.yaml"),
351 },
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +0400352 schema,
Giorgi Lekveishvili27b2b572023-06-30 10:44:45 +0400353 nil,
giolekvaef76a3e2022-01-10 12:22:28 +0400354 },
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400355 `<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 +0400356 "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 +0400357 }
358}
Giorgi Lekveishvili23ef7f82023-05-26 11:57:48 +0400359
Giorgi Lekveishvili27b2b572023-06-30 10:44:45 +0400360func CreateAppRpuppy(fs embed.FS, tmpls *template.Template) StoreApp {
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +0400361 schema, err := readJSONSchemaFromFile(fs, "values-tmpl/rpuppy.jsonschema")
Giorgi Lekveishvili7efe22f2023-05-30 13:01:53 +0400362 if err != nil {
363 panic(err)
364 }
Giorgi Lekveishvili27b2b572023-06-30 10:44:45 +0400365 return StoreApp{
366 App{
367 "rpuppy",
368 []string{"app-rpuppy"},
369 []*template.Template{
370 tmpls.Lookup("rpuppy.yaml"),
371 },
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +0400372 schema,
Giorgi Lekveishvili27b2b572023-06-30 10:44:45 +0400373 tmpls.Lookup("rpuppy.md"),
Giorgi Lekveishvili23ef7f82023-05-26 11:57:48 +0400374 },
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400375 `<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 +0400376 "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 +0400377 }
378}
379
Giorgi Lekveishvili672af5d2023-07-12 11:57:51 +0400380func CreateAppSoftServe(fs embed.FS, tmpls *template.Template) StoreApp {
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +0400381 schema, err := readJSONSchemaFromFile(fs, "values-tmpl/soft-serve.jsonschema")
Giorgi Lekveishvili672af5d2023-07-12 11:57:51 +0400382 if err != nil {
383 panic(err)
384 }
385 return StoreApp{
386 App{
387 "soft-serve",
388 []string{"app-soft-serve"},
389 []*template.Template{
390 tmpls.Lookup("soft-serve.yaml"),
391 },
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +0400392 schema,
Giorgi Lekveishvili672af5d2023-07-12 11:57:51 +0400393 tmpls.Lookup("soft-serve.md"),
394 },
395 `<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>`,
396 "A tasty, self-hostable Git server for the command line. 🍦",
397 }
398}
399
Giorgi Lekveishvili7efe22f2023-05-30 13:01:53 +0400400func CreateAppHeadscale(fs embed.FS, tmpls *template.Template) App {
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +0400401 schema, err := readJSONSchemaFromFile(fs, "values-tmpl/headscale.jsonschema")
Giorgi Lekveishvili7efe22f2023-05-30 13:01:53 +0400402 if err != nil {
403 panic(err)
404 }
Giorgi Lekveishvili23ef7f82023-05-26 11:57:48 +0400405 return App{
406 "headscale",
Giorgi Lekveishvili7fb28bf2023-06-24 19:51:16 +0400407 []string{"app-headscale"},
Giorgi Lekveishvili23ef7f82023-05-26 11:57:48 +0400408 []*template.Template{
409 tmpls.Lookup("headscale.yaml"),
410 },
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +0400411 schema,
Giorgi Lekveishvili3a907052023-05-30 13:33:32 +0400412 tmpls.Lookup("headscale.md"),
Giorgi Lekveishvili23ef7f82023-05-26 11:57:48 +0400413 }
414}
Giorgi Lekveishvili0ccd1482023-06-21 15:02:24 +0400415
Giorgi Lekveishvili39913692023-12-05 08:58:08 +0400416func CreateAppHeadscaleUser(fs embed.FS, tmpls *template.Template) App {
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +0400417 schema, err := readJSONSchemaFromFile(fs, "values-tmpl/headscale-user.jsonschema")
Giorgi Lekveishvili39913692023-12-05 08:58:08 +0400418 if err != nil {
419 panic(err)
420 }
421 return App{
422 "headscale-user",
423 []string{"app-headscale"},
424 []*template.Template{
425 tmpls.Lookup("headscale-user.yaml"),
426 },
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +0400427 schema,
Giorgi Lekveishvili39913692023-12-05 08:58:08 +0400428 tmpls.Lookup("headscale-user.md"),
429 }
430}
431
Giorgi Lekveishvili4fc29432023-07-20 10:03:28 +0400432func CreateMetallbIPAddressPool(fs embed.FS, tmpls *template.Template) App {
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +0400433 schema, err := readJSONSchemaFromFile(fs, "values-tmpl/metallb-ipaddresspool.jsonschema")
Giorgi Lekveishvili4fc29432023-07-20 10:03:28 +0400434 if err != nil {
435 panic(err)
436 }
437 return App{
438 "metallb-ipaddresspool",
439 []string{"metallb-ipaddresspool"},
440 []*template.Template{
441 tmpls.Lookup("metallb-ipaddresspool.yaml"),
442 },
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +0400443 schema,
Giorgi Lekveishvili4fc29432023-07-20 10:03:28 +0400444 tmpls.Lookup("metallb-ipaddresspool.md"),
445 }
446}
447
Giorgi Lekveishvili0ccd1482023-06-21 15:02:24 +0400448func CreateEnvManager(fs embed.FS, tmpls *template.Template) App {
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +0400449 schema, err := readJSONSchemaFromFile(fs, "values-tmpl/env-manager.jsonschema")
Giorgi Lekveishvili0ccd1482023-06-21 15:02:24 +0400450 if err != nil {
451 panic(err)
452 }
453 return App{
454 "env-manager",
Giorgi Lekveishvili7fb28bf2023-06-24 19:51:16 +0400455 []string{"env-manager"},
Giorgi Lekveishvili0ccd1482023-06-21 15:02:24 +0400456 []*template.Template{
457 tmpls.Lookup("env-manager.yaml"),
458 },
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +0400459 schema,
Giorgi Lekveishvili0ccd1482023-06-21 15:02:24 +0400460 tmpls.Lookup("env-manager.md"),
461 }
462}
463
Giorgi Lekveishvili12850ee2023-06-22 13:11:17 +0400464func CreateWelcome(fs embed.FS, tmpls *template.Template) App {
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +0400465 schema, err := readJSONSchemaFromFile(fs, "values-tmpl/welcome.jsonschema")
Giorgi Lekveishvili12850ee2023-06-22 13:11:17 +0400466 if err != nil {
467 panic(err)
468 }
469 return App{
470 "welcome",
Giorgi Lekveishvili7fb28bf2023-06-24 19:51:16 +0400471 []string{"app-welcome"},
Giorgi Lekveishvili12850ee2023-06-22 13:11:17 +0400472 []*template.Template{
473 tmpls.Lookup("welcome.yaml"),
474 },
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +0400475 schema,
Giorgi Lekveishvili12850ee2023-06-22 13:11:17 +0400476 tmpls.Lookup("welcome.md"),
477 }
478}
479
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400480func CreateAppManager(fs embed.FS, tmpls *template.Template) App {
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +0400481 schema, err := readJSONSchemaFromFile(fs, "values-tmpl/appmanager.jsonschema")
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400482 if err != nil {
483 panic(err)
484 }
485 return App{
486 "app-manager",
487 []string{"core-appmanager"},
488 []*template.Template{
489 tmpls.Lookup("appmanager.yaml"),
490 },
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +0400491 schema,
Giorgi Lekveishvili4257b902023-07-07 17:08:42 +0400492 tmpls.Lookup("appmanager.md"),
493 }
494}
495
Giorgi Lekveishvili0ccd1482023-06-21 15:02:24 +0400496func CreateIngressPublic(fs embed.FS, tmpls *template.Template) App {
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +0400497 schema, err := readJSONSchemaFromFile(fs, "values-tmpl/ingress-public.jsonschema")
Giorgi Lekveishvili0ccd1482023-06-21 15:02:24 +0400498 if err != nil {
499 panic(err)
500 }
501 return App{
502 "ingress-public",
Giorgi Lekveishvili7fb28bf2023-06-24 19:51:16 +0400503 []string{"ingress-public"},
Giorgi Lekveishvili0ccd1482023-06-21 15:02:24 +0400504 []*template.Template{
505 tmpls.Lookup("ingress-public.yaml"),
506 },
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +0400507 schema,
Giorgi Lekveishvili0ccd1482023-06-21 15:02:24 +0400508 tmpls.Lookup("ingress-public.md"),
509 }
510}
511
512func CreateCertManager(fs embed.FS, tmpls *template.Template) App {
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +0400513 schema, err := readJSONSchemaFromFile(fs, "values-tmpl/cert-manager.jsonschema")
Giorgi Lekveishvili0ccd1482023-06-21 15:02:24 +0400514 if err != nil {
515 panic(err)
516 }
517 return App{
518 "cert-manager",
Giorgi Lekveishvili7fb28bf2023-06-24 19:51:16 +0400519 []string{"cert-manager"},
Giorgi Lekveishvili0ccd1482023-06-21 15:02:24 +0400520 []*template.Template{
521 tmpls.Lookup("cert-manager.yaml"),
522 },
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +0400523 schema,
Giorgi Lekveishvili0ccd1482023-06-21 15:02:24 +0400524 tmpls.Lookup("cert-manager.md"),
525 }
526}
527
528func CreateCertManagerWebhookGandi(fs embed.FS, tmpls *template.Template) App {
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +0400529 schema, err := readJSONSchemaFromFile(fs, "values-tmpl/cert-manager-webhook-pcloud.jsonschema")
Giorgi Lekveishvili0ccd1482023-06-21 15:02:24 +0400530 if err != nil {
531 panic(err)
532 }
533 return App{
Giorgi Lekveishvili5c2c0b92023-12-07 17:35:40 +0400534 "cert-manager-webhook-pcloud",
Giorgi Lekveishvili7fb28bf2023-06-24 19:51:16 +0400535 []string{},
Giorgi Lekveishvili0ccd1482023-06-21 15:02:24 +0400536 []*template.Template{
Giorgi Lekveishvili5c2c0b92023-12-07 17:35:40 +0400537 tmpls.Lookup("cert-manager-webhook-pcloud.yaml"),
Giorgi Lekveishvili0ccd1482023-06-21 15:02:24 +0400538 },
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +0400539 schema,
Giorgi Lekveishvili5c2c0b92023-12-07 17:35:40 +0400540 tmpls.Lookup("cert-manager-webhook-pcloud.md"),
Giorgi Lekveishvili0ccd1482023-06-21 15:02:24 +0400541 }
542}
543
544func CreateCSIDriverSMB(fs embed.FS, tmpls *template.Template) App {
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +0400545 schema, err := readJSONSchemaFromFile(fs, "values-tmpl/csi-driver-smb.jsonschema")
Giorgi Lekveishvili0ccd1482023-06-21 15:02:24 +0400546 if err != nil {
547 panic(err)
548 }
549 return App{
550 "csi-driver-smb",
Giorgi Lekveishvili7fb28bf2023-06-24 19:51:16 +0400551 []string{"csi-driver-smb"},
Giorgi Lekveishvili0ccd1482023-06-21 15:02:24 +0400552 []*template.Template{
553 tmpls.Lookup("csi-driver-smb.yaml"),
554 },
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +0400555 schema,
Giorgi Lekveishvili0ccd1482023-06-21 15:02:24 +0400556 tmpls.Lookup("csi-driver-smb.md"),
557 }
558}
559
560func CreateResourceRendererController(fs embed.FS, tmpls *template.Template) App {
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +0400561 schema, err := readJSONSchemaFromFile(fs, "values-tmpl/resource-renderer-controller.jsonschema")
Giorgi Lekveishvili0ccd1482023-06-21 15:02:24 +0400562 if err != nil {
563 panic(err)
564 }
565 return App{
566 "resource-renderer-controller",
Giorgi Lekveishvili7fb28bf2023-06-24 19:51:16 +0400567 []string{"rr-controller"},
Giorgi Lekveishvili0ccd1482023-06-21 15:02:24 +0400568 []*template.Template{
569 tmpls.Lookup("resource-renderer-controller.yaml"),
570 },
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +0400571 schema,
Giorgi Lekveishvili0ccd1482023-06-21 15:02:24 +0400572 tmpls.Lookup("resource-renderer-controller.md"),
573 }
574}
575
576func CreateHeadscaleController(fs embed.FS, tmpls *template.Template) App {
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +0400577 schema, err := readJSONSchemaFromFile(fs, "values-tmpl/headscale-controller.jsonschema")
Giorgi Lekveishvili0ccd1482023-06-21 15:02:24 +0400578 if err != nil {
579 panic(err)
580 }
581 return App{
582 "headscale-controller",
Giorgi Lekveishvili7fb28bf2023-06-24 19:51:16 +0400583 []string{"headscale-controller"},
Giorgi Lekveishvili0ccd1482023-06-21 15:02:24 +0400584 []*template.Template{
585 tmpls.Lookup("headscale-controller.yaml"),
586 },
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +0400587 schema,
Giorgi Lekveishvili0ccd1482023-06-21 15:02:24 +0400588 tmpls.Lookup("headscale-controller.md"),
589 }
590}
Giorgi Lekveishvili743fb432023-11-08 17:19:40 +0400591
Giorgi Lekveishvili106a9352023-12-04 11:20:11 +0400592func CreateDNSZoneManager(fs embed.FS, tmpls *template.Template) App {
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +0400593 schema, err := readJSONSchemaFromFile(fs, "values-tmpl/dns-zone-controller.jsonschema")
Giorgi Lekveishvili106a9352023-12-04 11:20:11 +0400594 if err != nil {
595 panic(err)
596 }
597 return App{
598 "dns-zone-manager",
599 []string{"dns-zone-manager"},
600 []*template.Template{
601 tmpls.Lookup("dns-zone-storage.yaml"),
602 tmpls.Lookup("coredns.yaml"),
603 tmpls.Lookup("dns-zone-controller.yaml"),
604 },
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +0400605 schema,
Giorgi Lekveishvili106a9352023-12-04 11:20:11 +0400606 tmpls.Lookup("dns-zone-controller.md"),
607 }
608}
609
Giorgi Lekveishvili2df23db2023-12-14 07:55:22 +0400610func CreateFluxcdReconciler(fs embed.FS, tmpls *template.Template) App {
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +0400611 schema, err := readJSONSchemaFromFile(fs, "values-tmpl/fluxcd-reconciler.jsonschema")
Giorgi Lekveishvili2df23db2023-12-14 07:55:22 +0400612 if err != nil {
613 panic(err)
614 }
615 return App{
616 "fluxcd-reconciler",
617 []string{"fluxcd-reconciler"},
618 []*template.Template{
619 tmpls.Lookup("fluxcd-reconciler.yaml"),
620 },
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +0400621 schema,
Giorgi Lekveishvili2df23db2023-12-14 07:55:22 +0400622 tmpls.Lookup("fluxcd-reconciler.md"),
623 }
624}
625
Giorgi Lekveishvili743fb432023-11-08 17:19:40 +0400626type httpAppRepository struct {
627 apps []StoreApp
628}
629
630type appVersion struct {
631 Version string `json:"version"`
632 Urls []string `json:"urls"`
633}
634
635type allAppsResp struct {
636 ApiVersion string `json:"apiVersion"`
637 Entries map[string][]appVersion `json:"entries"`
638}
639
640func FetchAppsFromHTTPRepository(addr string, fs billy.Filesystem) error {
641 resp, err := http.Get(addr)
642 if err != nil {
643 return err
644 }
645 b, err := io.ReadAll(resp.Body)
646 if err != nil {
647 return err
648 }
649 var apps allAppsResp
650 if err := yaml.Unmarshal(b, &apps); err != nil {
651 return err
652 }
653 for name, conf := range apps.Entries {
654 for _, version := range conf {
655 resp, err := http.Get(version.Urls[0])
656 if err != nil {
657 return err
658 }
659 nameVersion := fmt.Sprintf("%s-%s", name, version.Version)
660 if err := fs.MkdirAll(nameVersion, 0700); err != nil {
661 return err
662 }
663 sub, err := fs.Chroot(nameVersion)
664 if err != nil {
665 return err
666 }
667 if err := extractApp(resp.Body, sub); err != nil {
668 return err
669 }
670 }
671 }
672 return nil
673}
674
675func extractApp(archive io.Reader, fs billy.Filesystem) error {
676 uncompressed, err := gzip.NewReader(archive)
677 if err != nil {
678 return err
679 }
680 tarReader := tar.NewReader(uncompressed)
681 for true {
682 header, err := tarReader.Next()
683 if err == io.EOF {
684 break
685 }
686 if err != nil {
687 return err
688 }
689 switch header.Typeflag {
690 case tar.TypeDir:
691 if err := fs.MkdirAll(header.Name, 0755); err != nil {
692 return err
693 }
694 case tar.TypeReg:
695 out, err := fs.Create(header.Name)
696 if err != nil {
697 return err
698 }
699 defer out.Close()
700 if _, err := io.Copy(out, tarReader); err != nil {
701 return err
702 }
703 default:
704 return fmt.Errorf("Uknown type: %s", header.Name)
705 }
706 }
707 return nil
708}
709
710type fsAppRepository struct {
711 InMemoryAppRepository[StoreApp]
712 fs billy.Filesystem
713}
714
715func NewFSAppRepository(fs billy.Filesystem) (AppRepository[StoreApp], error) {
716 all, err := fs.ReadDir(".")
717 if err != nil {
718 return nil, err
719 }
720 apps := make([]StoreApp, 0)
721 for _, e := range all {
722 if !e.IsDir() {
723 continue
724 }
725 appFS, err := fs.Chroot(e.Name())
726 if err != nil {
727 return nil, err
728 }
729 app, err := loadApp(appFS)
730 if err != nil {
731 log.Printf("Ignoring directory %s: %s", e.Name(), err)
732 continue
733 }
734 apps = append(apps, app)
735 }
736 return &fsAppRepository{
737 NewInMemoryAppRepository[StoreApp](apps),
738 fs,
739 }, nil
740}
741
742func loadApp(fs billy.Filesystem) (StoreApp, error) {
743 cfg, err := fs.Open("Chart.yaml")
744 if err != nil {
745 return StoreApp{}, err
746 }
747 defer cfg.Close()
748 b, err := io.ReadAll(cfg)
749 if err != nil {
750 return StoreApp{}, err
751 }
752 var appCfg appConfig
753 if err := yaml.Unmarshal(b, &appCfg); err != nil {
754 return StoreApp{}, err
755 }
756 rb, err := fs.Open("README.md")
757 if err != nil {
758 return StoreApp{}, err
759 }
760 defer rb.Close()
761 readme, err := io.ReadAll(rb)
762 if err != nil {
763 return StoreApp{}, err
764 }
765 readmeTmpl, err := template.New("README.md").Parse(string(readme))
766 if err != nil {
767 return StoreApp{}, err
768 }
769 sb, err := fs.Open("schema.json")
770 if err != nil {
771 return StoreApp{}, err
772 }
773 defer sb.Close()
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +0400774 scm, err := io.ReadAll(sb)
775 if err != nil {
776 return StoreApp{}, err
777 }
778 schema, err := NewJSONSchema(string(scm))
Giorgi Lekveishvili743fb432023-11-08 17:19:40 +0400779 if err != nil {
780 return StoreApp{}, err
781 }
782 tFiles, err := fs.ReadDir("templates")
783 if err != nil {
784 return StoreApp{}, err
785 }
786 tmpls := make([]*template.Template, 0)
787 for _, t := range tFiles {
788 if !strings.HasSuffix(t.Name(), ".yaml") {
789 continue
790 }
791 inp, err := fs.Open(fs.Join("templates", t.Name()))
792 if err != nil {
793 return StoreApp{}, err
794 }
795 b, err := io.ReadAll(inp)
796 if err != nil {
797 return StoreApp{}, err
798 }
799 tmpl, err := template.New(t.Name()).Parse(string(b))
800 if err != nil {
801 return StoreApp{}, err
802 }
803 tmpls = append(tmpls, tmpl)
804 }
805 return StoreApp{
806 App: App{
807 Name: appCfg.Name,
808 Readme: readmeTmpl,
Giorgi Lekveishvili7c427602024-01-04 00:13:55 +0400809 schema: schema,
Giorgi Lekveishvili743fb432023-11-08 17:19:40 +0400810 Namespaces: appCfg.Namespaces,
811 Templates: tmpls,
812 },
813 ShortDescription: appCfg.Description,
814 Icon: appCfg.Icon,
815 }, nil
816}