| giolekva | 8aa73e8 | 2022-07-09 11:34:39 +0400 | [diff] [blame] | 1 | package installer |
| giolekva | 050609f | 2021-12-29 15:51:40 +0400 | [diff] [blame] | 2 | |
| giolekva | 8aa73e8 | 2022-07-09 11:34:39 +0400 | [diff] [blame] | 3 | import ( |
| Giorgi Lekveishvili | 743fb43 | 2023-11-08 17:19:40 +0400 | [diff] [blame] | 4 | "archive/tar" |
| 5 | "compress/gzip" |
| giolekva | 8aa73e8 | 2022-07-09 11:34:39 +0400 | [diff] [blame] | 6 | "embed" |
| Giorgi Lekveishvili | bd6be7f | 2023-05-26 15:51:28 +0400 | [diff] [blame] | 7 | "fmt" |
| Giorgi Lekveishvili | 4257b90 | 2023-07-07 17:08:42 +0400 | [diff] [blame] | 8 | htemplate "html/template" |
| Giorgi Lekveishvili | 743fb43 | 2023-11-08 17:19:40 +0400 | [diff] [blame] | 9 | "io" |
| giolekva | 8aa73e8 | 2022-07-09 11:34:39 +0400 | [diff] [blame] | 10 | "log" |
| Giorgi Lekveishvili | 743fb43 | 2023-11-08 17:19:40 +0400 | [diff] [blame] | 11 | "net/http" |
| Giorgi Lekveishvili | 4257b90 | 2023-07-07 17:08:42 +0400 | [diff] [blame] | 12 | "strings" |
| giolekva | 8aa73e8 | 2022-07-09 11:34:39 +0400 | [diff] [blame] | 13 | "text/template" |
| Giorgi Lekveishvili | 0ccd148 | 2023-06-21 15:02:24 +0400 | [diff] [blame] | 14 | |
| 15 | "github.com/Masterminds/sprig/v3" |
| Giorgi Lekveishvili | 743fb43 | 2023-11-08 17:19:40 +0400 | [diff] [blame] | 16 | "github.com/go-git/go-billy/v5" |
| 17 | "sigs.k8s.io/yaml" |
| giolekva | 8aa73e8 | 2022-07-09 11:34:39 +0400 | [diff] [blame] | 18 | ) |
| giolekva | 050609f | 2021-12-29 15:51:40 +0400 | [diff] [blame] | 19 | |
| Giorgi Lekveishvili | bd6be7f | 2023-05-26 15:51:28 +0400 | [diff] [blame] | 20 | //go:embed values-tmpl |
| 21 | var valuesTmpls embed.FS |
| 22 | |
| Giorgi Lekveishvili | 27b2b57 | 2023-06-30 10:44:45 +0400 | [diff] [blame] | 23 | type Named interface { |
| 24 | Nam() string |
| 25 | } |
| 26 | |
| Giorgi Lekveishvili | 743fb43 | 2023-11-08 17:19:40 +0400 | [diff] [blame] | 27 | type 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 | |
| giolekva | 050609f | 2021-12-29 15:51:40 +0400 | [diff] [blame] | 35 | type App struct { |
| Giorgi Lekveishvili | 7fb28bf | 2023-06-24 19:51:16 +0400 | [diff] [blame] | 36 | Name string |
| 37 | Namespaces []string |
| 38 | Templates []*template.Template |
| Giorgi Lekveishvili | 7c42760 | 2024-01-04 00:13:55 +0400 | [diff] [blame^] | 39 | schema Schema |
| Giorgi Lekveishvili | 7fb28bf | 2023-06-24 19:51:16 +0400 | [diff] [blame] | 40 | Readme *template.Template |
| giolekva | 050609f | 2021-12-29 15:51:40 +0400 | [diff] [blame] | 41 | } |
| 42 | |
| Giorgi Lekveishvili | 7c42760 | 2024-01-04 00:13:55 +0400 | [diff] [blame^] | 43 | func (a App) Schema() Schema { |
| 44 | return a.schema |
| Giorgi Lekveishvili | 4257b90 | 2023-07-07 17:08:42 +0400 | [diff] [blame] | 45 | } |
| 46 | |
| Giorgi Lekveishvili | 27b2b57 | 2023-06-30 10:44:45 +0400 | [diff] [blame] | 47 | type StoreApp struct { |
| 48 | App |
| Giorgi Lekveishvili | 4257b90 | 2023-07-07 17:08:42 +0400 | [diff] [blame] | 49 | Icon htemplate.HTML |
| Giorgi Lekveishvili | 27b2b57 | 2023-06-30 10:44:45 +0400 | [diff] [blame] | 50 | ShortDescription string |
| Giorgi Lekveishvili | bd6be7f | 2023-05-26 15:51:28 +0400 | [diff] [blame] | 51 | } |
| 52 | |
| Giorgi Lekveishvili | 27b2b57 | 2023-06-30 10:44:45 +0400 | [diff] [blame] | 53 | func (a App) Nam() string { |
| 54 | return a.Name |
| Giorgi Lekveishvili | bd6be7f | 2023-05-26 15:51:28 +0400 | [diff] [blame] | 55 | } |
| 56 | |
| Giorgi Lekveishvili | 27b2b57 | 2023-06-30 10:44:45 +0400 | [diff] [blame] | 57 | func (a StoreApp) Nam() string { |
| 58 | return a.Name |
| 59 | } |
| 60 | |
| 61 | type AppRepository[A Named] interface { |
| 62 | GetAll() ([]A, error) |
| 63 | Find(name string) (*A, error) |
| 64 | } |
| 65 | |
| 66 | type InMemoryAppRepository[A Named] struct { |
| 67 | apps []A |
| 68 | } |
| 69 | |
| Giorgi Lekveishvili | 743fb43 | 2023-11-08 17:19:40 +0400 | [diff] [blame] | 70 | func NewInMemoryAppRepository[A Named](apps []A) InMemoryAppRepository[A] { |
| 71 | return InMemoryAppRepository[A]{ |
| Giorgi Lekveishvili | bd6be7f | 2023-05-26 15:51:28 +0400 | [diff] [blame] | 72 | apps, |
| 73 | } |
| 74 | } |
| 75 | |
| Giorgi Lekveishvili | 27b2b57 | 2023-06-30 10:44:45 +0400 | [diff] [blame] | 76 | func (r InMemoryAppRepository[A]) Find(name string) (*A, error) { |
| Giorgi Lekveishvili | bd6be7f | 2023-05-26 15:51:28 +0400 | [diff] [blame] | 77 | for _, a := range r.apps { |
| Giorgi Lekveishvili | 27b2b57 | 2023-06-30 10:44:45 +0400 | [diff] [blame] | 78 | if a.Nam() == name { |
| Giorgi Lekveishvili | bd6be7f | 2023-05-26 15:51:28 +0400 | [diff] [blame] | 79 | return &a, nil |
| 80 | } |
| 81 | } |
| 82 | return nil, fmt.Errorf("Application not found: %s", name) |
| 83 | } |
| giolekva | 8aa73e8 | 2022-07-09 11:34:39 +0400 | [diff] [blame] | 84 | |
| Giorgi Lekveishvili | 27b2b57 | 2023-06-30 10:44:45 +0400 | [diff] [blame] | 85 | func (r InMemoryAppRepository[A]) GetAll() ([]A, error) { |
| Giorgi Lekveishvili | 7efe22f | 2023-05-30 13:01:53 +0400 | [diff] [blame] | 86 | return r.apps, nil |
| 87 | } |
| 88 | |
| giolekva | 8aa73e8 | 2022-07-09 11:34:39 +0400 | [diff] [blame] | 89 | func CreateAllApps() []App { |
| Giorgi Lekveishvili | 0ccd148 | 2023-06-21 15:02:24 +0400 | [diff] [blame] | 90 | tmpls, err := template.New("root").Funcs(template.FuncMap(sprig.FuncMap())).ParseFS(valuesTmpls, "values-tmpl/*") |
| giolekva | 8aa73e8 | 2022-07-09 11:34:39 +0400 | [diff] [blame] | 91 | if err != nil { |
| 92 | log.Fatal(err) |
| 93 | } |
| Giorgi Lekveishvili | 27b2b57 | 2023-06-30 10:44:45 +0400 | [diff] [blame] | 94 | ret := []App{ |
| Giorgi Lekveishvili | 7efe22f | 2023-05-30 13:01:53 +0400 | [diff] [blame] | 95 | CreateAppIngressPrivate(valuesTmpls, tmpls), |
| Giorgi Lekveishvili | 12850ee | 2023-06-22 13:11:17 +0400 | [diff] [blame] | 96 | CreateCertificateIssuerPublic(valuesTmpls, tmpls), |
| 97 | CreateCertificateIssuerPrivate(valuesTmpls, tmpls), |
| Giorgi Lekveishvili | 7efe22f | 2023-05-30 13:01:53 +0400 | [diff] [blame] | 98 | CreateAppCoreAuth(valuesTmpls, tmpls), |
| Giorgi Lekveishvili | 7efe22f | 2023-05-30 13:01:53 +0400 | [diff] [blame] | 99 | CreateAppHeadscale(valuesTmpls, tmpls), |
| Giorgi Lekveishvili | 3991369 | 2023-12-05 08:58:08 +0400 | [diff] [blame] | 100 | CreateAppHeadscaleUser(valuesTmpls, tmpls), |
| Giorgi Lekveishvili | 4fc2943 | 2023-07-20 10:03:28 +0400 | [diff] [blame] | 101 | CreateMetallbIPAddressPool(valuesTmpls, tmpls), |
| Giorgi Lekveishvili | 0ccd148 | 2023-06-21 15:02:24 +0400 | [diff] [blame] | 102 | CreateEnvManager(valuesTmpls, tmpls), |
| Giorgi Lekveishvili | 12850ee | 2023-06-22 13:11:17 +0400 | [diff] [blame] | 103 | CreateWelcome(valuesTmpls, tmpls), |
| Giorgi Lekveishvili | 4257b90 | 2023-07-07 17:08:42 +0400 | [diff] [blame] | 104 | CreateAppManager(valuesTmpls, tmpls), |
| Giorgi Lekveishvili | 0ccd148 | 2023-06-21 15:02:24 +0400 | [diff] [blame] | 105 | CreateIngressPublic(valuesTmpls, tmpls), |
| 106 | CreateCertManager(valuesTmpls, tmpls), |
| 107 | CreateCertManagerWebhookGandi(valuesTmpls, tmpls), |
| Giorgi Lekveishvili | 0ccd148 | 2023-06-21 15:02:24 +0400 | [diff] [blame] | 108 | CreateCSIDriverSMB(valuesTmpls, tmpls), |
| 109 | CreateResourceRendererController(valuesTmpls, tmpls), |
| 110 | CreateHeadscaleController(valuesTmpls, tmpls), |
| Giorgi Lekveishvili | 106a935 | 2023-12-04 11:20:11 +0400 | [diff] [blame] | 111 | CreateDNSZoneManager(valuesTmpls, tmpls), |
| Giorgi Lekveishvili | 2df23db | 2023-12-14 07:55:22 +0400 | [diff] [blame] | 112 | CreateFluxcdReconciler(valuesTmpls, tmpls), |
| giolekva | ef76a3e | 2022-01-10 12:22:28 +0400 | [diff] [blame] | 113 | } |
| Giorgi Lekveishvili | 27b2b57 | 2023-06-30 10:44:45 +0400 | [diff] [blame] | 114 | for _, a := range CreateStoreApps() { |
| 115 | ret = append(ret, a.App) |
| 116 | } |
| 117 | return ret |
| 118 | } |
| 119 | |
| 120 | func 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 Lekveishvili | 3fd5e4c | 2023-12-19 22:09:40 +0400 | [diff] [blame] | 129 | CreateAppPenpot(valuesTmpls, tmpls), |
| Giorgi Lekveishvili | 27b2b57 | 2023-06-30 10:44:45 +0400 | [diff] [blame] | 130 | CreateAppMaddy(valuesTmpls, tmpls), |
| 131 | CreateAppQBittorrent(valuesTmpls, tmpls), |
| 132 | CreateAppJellyfin(valuesTmpls, tmpls), |
| Giorgi Lekveishvili | 672af5d | 2023-07-12 11:57:51 +0400 | [diff] [blame] | 133 | CreateAppSoftServe(valuesTmpls, tmpls), |
| Giorgi Lekveishvili | 27b2b57 | 2023-06-30 10:44:45 +0400 | [diff] [blame] | 134 | CreateAppRpuppy(valuesTmpls, tmpls), |
| 135 | } |
| giolekva | ef76a3e | 2022-01-10 12:22:28 +0400 | [diff] [blame] | 136 | } |
| 137 | |
| Giorgi Lekveishvili | 7c42760 | 2024-01-04 00:13:55 +0400 | [diff] [blame^] | 138 | func 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 Lekveishvili | 4d2784d | 2023-06-01 14:27:32 +0400 | [diff] [blame] | 150 | // TODO(gio): service account needs permission to create/update secret |
| Giorgi Lekveishvili | 7efe22f | 2023-05-30 13:01:53 +0400 | [diff] [blame] | 151 | func CreateAppIngressPrivate(fs embed.FS, tmpls *template.Template) App { |
| Giorgi Lekveishvili | 7c42760 | 2024-01-04 00:13:55 +0400 | [diff] [blame^] | 152 | schema, err := readJSONSchemaFromFile(fs, "values-tmpl/private-network.jsonschema") |
| Giorgi Lekveishvili | 7efe22f | 2023-05-30 13:01:53 +0400 | [diff] [blame] | 153 | if err != nil { |
| 154 | panic(err) |
| 155 | } |
| giolekva | 050609f | 2021-12-29 15:51:40 +0400 | [diff] [blame] | 156 | return App{ |
| Giorgi Lekveishvili | 2dbce6c | 2023-12-05 15:16:27 +0400 | [diff] [blame] | 157 | "private-network", |
| 158 | []string{"ingress-private"}, // TODO(gio): rename to private network |
| giolekva | 050609f | 2021-12-29 15:51:40 +0400 | [diff] [blame] | 159 | []*template.Template{ |
| giolekva | 050609f | 2021-12-29 15:51:40 +0400 | [diff] [blame] | 160 | tmpls.Lookup("ingress-private.yaml"), |
| Giorgi Lekveishvili | 2dbce6c | 2023-12-05 15:16:27 +0400 | [diff] [blame] | 161 | tmpls.Lookup("tailscale-proxy.yaml"), |
| giolekva | 050609f | 2021-12-29 15:51:40 +0400 | [diff] [blame] | 162 | }, |
| Giorgi Lekveishvili | 7c42760 | 2024-01-04 00:13:55 +0400 | [diff] [blame^] | 163 | schema, |
| Giorgi Lekveishvili | 2dbce6c | 2023-12-05 15:16:27 +0400 | [diff] [blame] | 164 | tmpls.Lookup("private-network.md"), |
| giolekva | 050609f | 2021-12-29 15:51:40 +0400 | [diff] [blame] | 165 | } |
| 166 | } |
| 167 | |
| Giorgi Lekveishvili | 0ccd148 | 2023-06-21 15:02:24 +0400 | [diff] [blame] | 168 | func CreateCertificateIssuerPrivate(fs embed.FS, tmpls *template.Template) App { |
| Giorgi Lekveishvili | 7c42760 | 2024-01-04 00:13:55 +0400 | [diff] [blame^] | 169 | schema, err := readJSONSchemaFromFile(fs, "values-tmpl/certificate-issuer-private.jsonschema") |
| Giorgi Lekveishvili | 0ccd148 | 2023-06-21 15:02:24 +0400 | [diff] [blame] | 170 | if err != nil { |
| 171 | panic(err) |
| 172 | } |
| 173 | return App{ |
| Giorgi Lekveishvili | 12850ee | 2023-06-22 13:11:17 +0400 | [diff] [blame] | 174 | "certificate-issuer-private", |
| Giorgi Lekveishvili | 7fb28bf | 2023-06-24 19:51:16 +0400 | [diff] [blame] | 175 | []string{}, |
| Giorgi Lekveishvili | 0ccd148 | 2023-06-21 15:02:24 +0400 | [diff] [blame] | 176 | []*template.Template{ |
| 177 | tmpls.Lookup("certificate-issuer-private.yaml"), |
| 178 | }, |
| Giorgi Lekveishvili | 7c42760 | 2024-01-04 00:13:55 +0400 | [diff] [blame^] | 179 | schema, |
| Giorgi Lekveishvili | 0ccd148 | 2023-06-21 15:02:24 +0400 | [diff] [blame] | 180 | tmpls.Lookup("certificate-issuer-private.md"), |
| 181 | } |
| 182 | } |
| 183 | |
| Giorgi Lekveishvili | 12850ee | 2023-06-22 13:11:17 +0400 | [diff] [blame] | 184 | func CreateCertificateIssuerPublic(fs embed.FS, tmpls *template.Template) App { |
| Giorgi Lekveishvili | 7c42760 | 2024-01-04 00:13:55 +0400 | [diff] [blame^] | 185 | schema, err := readJSONSchemaFromFile(fs, "values-tmpl/certificate-issuer-public.jsonschema") |
| Giorgi Lekveishvili | 12850ee | 2023-06-22 13:11:17 +0400 | [diff] [blame] | 186 | if err != nil { |
| 187 | panic(err) |
| 188 | } |
| 189 | return App{ |
| 190 | "certificate-issuer-public", |
| Giorgi Lekveishvili | 7fb28bf | 2023-06-24 19:51:16 +0400 | [diff] [blame] | 191 | []string{}, |
| Giorgi Lekveishvili | 12850ee | 2023-06-22 13:11:17 +0400 | [diff] [blame] | 192 | []*template.Template{ |
| 193 | tmpls.Lookup("certificate-issuer-public.yaml"), |
| 194 | }, |
| Giorgi Lekveishvili | 7c42760 | 2024-01-04 00:13:55 +0400 | [diff] [blame^] | 195 | schema, |
| Giorgi Lekveishvili | 12850ee | 2023-06-22 13:11:17 +0400 | [diff] [blame] | 196 | tmpls.Lookup("certificate-issuer-public.md"), |
| 197 | } |
| 198 | } |
| 199 | |
| Giorgi Lekveishvili | 7efe22f | 2023-05-30 13:01:53 +0400 | [diff] [blame] | 200 | func CreateAppCoreAuth(fs embed.FS, tmpls *template.Template) App { |
| Giorgi Lekveishvili | 7c42760 | 2024-01-04 00:13:55 +0400 | [diff] [blame^] | 201 | schema, err := readJSONSchemaFromFile(fs, "values-tmpl/core-auth.jsonschema") |
| Giorgi Lekveishvili | 7efe22f | 2023-05-30 13:01:53 +0400 | [diff] [blame] | 202 | if err != nil { |
| 203 | panic(err) |
| 204 | } |
| giolekva | 050609f | 2021-12-29 15:51:40 +0400 | [diff] [blame] | 205 | return App{ |
| 206 | "core-auth", |
| Giorgi Lekveishvili | 7fb28bf | 2023-06-24 19:51:16 +0400 | [diff] [blame] | 207 | []string{"core-auth"}, |
| giolekva | 050609f | 2021-12-29 15:51:40 +0400 | [diff] [blame] | 208 | []*template.Template{ |
| 209 | tmpls.Lookup("core-auth-storage.yaml"), |
| 210 | tmpls.Lookup("core-auth.yaml"), |
| 211 | }, |
| Giorgi Lekveishvili | 7c42760 | 2024-01-04 00:13:55 +0400 | [diff] [blame^] | 212 | schema, |
| Giorgi Lekveishvili | 3ca1f3f | 2023-05-30 14:33:02 +0400 | [diff] [blame] | 213 | tmpls.Lookup("core-auth.md"), |
| giolekva | 050609f | 2021-12-29 15:51:40 +0400 | [diff] [blame] | 214 | } |
| 215 | } |
| 216 | |
| Giorgi Lekveishvili | 27b2b57 | 2023-06-30 10:44:45 +0400 | [diff] [blame] | 217 | func CreateAppVaultwarden(fs embed.FS, tmpls *template.Template) StoreApp { |
| Giorgi Lekveishvili | 7c42760 | 2024-01-04 00:13:55 +0400 | [diff] [blame^] | 218 | schema, err := readJSONSchemaFromFile(fs, "values-tmpl/vaultwarden.jsonschema") |
| Giorgi Lekveishvili | 7efe22f | 2023-05-30 13:01:53 +0400 | [diff] [blame] | 219 | if err != nil { |
| 220 | panic(err) |
| 221 | } |
| Giorgi Lekveishvili | 27b2b57 | 2023-06-30 10:44:45 +0400 | [diff] [blame] | 222 | return StoreApp{ |
| 223 | App: App{ |
| 224 | "vaultwarden", |
| 225 | []string{"app-vaultwarden"}, |
| 226 | []*template.Template{ |
| 227 | tmpls.Lookup("vaultwarden.yaml"), |
| 228 | }, |
| Giorgi Lekveishvili | 7c42760 | 2024-01-04 00:13:55 +0400 | [diff] [blame^] | 229 | schema, |
| Giorgi Lekveishvili | 27b2b57 | 2023-06-30 10:44:45 +0400 | [diff] [blame] | 230 | tmpls.Lookup("vaultwarden.md"), |
| giolekva | 050609f | 2021-12-29 15:51:40 +0400 | [diff] [blame] | 231 | }, |
| Giorgi Lekveishvili | 4257b90 | 2023-07-07 17:08:42 +0400 | [diff] [blame] | 232 | 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 Lekveishvili | 27b2b57 | 2023-06-30 10:44:45 +0400 | [diff] [blame] | 233 | ShortDescription: "Open source implementation of Bitwarden password manager. Can be used with official client applications.", |
| giolekva | 050609f | 2021-12-29 15:51:40 +0400 | [diff] [blame] | 234 | } |
| 235 | } |
| 236 | |
| Giorgi Lekveishvili | 27b2b57 | 2023-06-30 10:44:45 +0400 | [diff] [blame] | 237 | func CreateAppMatrix(fs embed.FS, tmpls *template.Template) StoreApp { |
| Giorgi Lekveishvili | 7c42760 | 2024-01-04 00:13:55 +0400 | [diff] [blame^] | 238 | schema, err := readJSONSchemaFromFile(fs, "values-tmpl/matrix.jsonschema") |
| Giorgi Lekveishvili | 7efe22f | 2023-05-30 13:01:53 +0400 | [diff] [blame] | 239 | if err != nil { |
| 240 | panic(err) |
| 241 | } |
| Giorgi Lekveishvili | 27b2b57 | 2023-06-30 10:44:45 +0400 | [diff] [blame] | 242 | 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 Lekveishvili | 7c42760 | 2024-01-04 00:13:55 +0400 | [diff] [blame^] | 250 | schema, |
| Giorgi Lekveishvili | 27b2b57 | 2023-06-30 10:44:45 +0400 | [diff] [blame] | 251 | nil, |
| giolekva | 050609f | 2021-12-29 15:51:40 +0400 | [diff] [blame] | 252 | }, |
| Giorgi Lekveishvili | 4257b90 | 2023-07-07 17:08:42 +0400 | [diff] [blame] | 253 | `<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 Lekveishvili | 27b2b57 | 2023-06-30 10:44:45 +0400 | [diff] [blame] | 254 | "An open network for secure, decentralised communication", |
| giolekva | 050609f | 2021-12-29 15:51:40 +0400 | [diff] [blame] | 255 | } |
| 256 | } |
| 257 | |
| Giorgi Lekveishvili | 27b2b57 | 2023-06-30 10:44:45 +0400 | [diff] [blame] | 258 | func CreateAppPihole(fs embed.FS, tmpls *template.Template) StoreApp { |
| Giorgi Lekveishvili | 7c42760 | 2024-01-04 00:13:55 +0400 | [diff] [blame^] | 259 | schema, err := readJSONSchemaFromFile(fs, "values-tmpl/pihole.jsonschema") |
| Giorgi Lekveishvili | 7efe22f | 2023-05-30 13:01:53 +0400 | [diff] [blame] | 260 | if err != nil { |
| 261 | panic(err) |
| 262 | } |
| Giorgi Lekveishvili | 27b2b57 | 2023-06-30 10:44:45 +0400 | [diff] [blame] | 263 | return StoreApp{ |
| 264 | App{ |
| 265 | "pihole", |
| 266 | []string{"app-pihole"}, |
| 267 | []*template.Template{ |
| 268 | tmpls.Lookup("pihole.yaml"), |
| 269 | }, |
| Giorgi Lekveishvili | 7c42760 | 2024-01-04 00:13:55 +0400 | [diff] [blame^] | 270 | schema, |
| Giorgi Lekveishvili | 27b2b57 | 2023-06-30 10:44:45 +0400 | [diff] [blame] | 271 | tmpls.Lookup("pihole.md"), |
| giolekva | 050609f | 2021-12-29 15:51:40 +0400 | [diff] [blame] | 272 | }, |
| Giorgi Lekveishvili | 4257b90 | 2023-07-07 17:08:42 +0400 | [diff] [blame] | 273 | // "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 Lekveishvili | 27b2b57 | 2023-06-30 10:44:45 +0400 | [diff] [blame] | 275 | "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.", |
| giolekva | 050609f | 2021-12-29 15:51:40 +0400 | [diff] [blame] | 276 | } |
| 277 | } |
| 278 | |
| Giorgi Lekveishvili | 3fd5e4c | 2023-12-19 22:09:40 +0400 | [diff] [blame] | 279 | func CreateAppPenpot(fs embed.FS, tmpls *template.Template) StoreApp { |
| Giorgi Lekveishvili | 7c42760 | 2024-01-04 00:13:55 +0400 | [diff] [blame^] | 280 | schema, err := readJSONSchemaFromFile(fs, "values-tmpl/penpot.jsonschema") |
| Giorgi Lekveishvili | 3fd5e4c | 2023-12-19 22:09:40 +0400 | [diff] [blame] | 281 | 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 Lekveishvili | 7c42760 | 2024-01-04 00:13:55 +0400 | [diff] [blame^] | 291 | schema, |
| Giorgi Lekveishvili | 3fd5e4c | 2023-12-19 22:09:40 +0400 | [diff] [blame] | 292 | 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 Lekveishvili | 27b2b57 | 2023-06-30 10:44:45 +0400 | [diff] [blame] | 300 | func CreateAppMaddy(fs embed.FS, tmpls *template.Template) StoreApp { |
| Giorgi Lekveishvili | 7c42760 | 2024-01-04 00:13:55 +0400 | [diff] [blame^] | 301 | schema, err := readJSONSchemaFromFile(fs, "values-tmpl/maddy.jsonschema") |
| Giorgi Lekveishvili | 7efe22f | 2023-05-30 13:01:53 +0400 | [diff] [blame] | 302 | if err != nil { |
| 303 | panic(err) |
| 304 | } |
| Giorgi Lekveishvili | 27b2b57 | 2023-06-30 10:44:45 +0400 | [diff] [blame] | 305 | return StoreApp{ |
| 306 | App{ |
| 307 | "maddy", |
| 308 | []string{"app-maddy"}, |
| 309 | []*template.Template{ |
| 310 | tmpls.Lookup("maddy.yaml"), |
| 311 | }, |
| Giorgi Lekveishvili | 7c42760 | 2024-01-04 00:13:55 +0400 | [diff] [blame^] | 312 | schema, |
| Giorgi Lekveishvili | 27b2b57 | 2023-06-30 10:44:45 +0400 | [diff] [blame] | 313 | nil, |
| giolekva | 050609f | 2021-12-29 15:51:40 +0400 | [diff] [blame] | 314 | }, |
| Giorgi Lekveishvili | 4257b90 | 2023-07-07 17:08:42 +0400 | [diff] [blame] | 315 | `<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 Lekveishvili | 27b2b57 | 2023-06-30 10:44:45 +0400 | [diff] [blame] | 316 | "SMPT/IMAP server to communicate via email.", |
| giolekva | 050609f | 2021-12-29 15:51:40 +0400 | [diff] [blame] | 317 | } |
| 318 | } |
| giolekva | ef76a3e | 2022-01-10 12:22:28 +0400 | [diff] [blame] | 319 | |
| Giorgi Lekveishvili | 27b2b57 | 2023-06-30 10:44:45 +0400 | [diff] [blame] | 320 | func CreateAppQBittorrent(fs embed.FS, tmpls *template.Template) StoreApp { |
| Giorgi Lekveishvili | 7c42760 | 2024-01-04 00:13:55 +0400 | [diff] [blame^] | 321 | schema, err := readJSONSchemaFromFile(fs, "values-tmpl/qbittorrent.jsonschema") |
| Giorgi Lekveishvili | 7efe22f | 2023-05-30 13:01:53 +0400 | [diff] [blame] | 322 | if err != nil { |
| 323 | panic(err) |
| 324 | } |
| Giorgi Lekveishvili | 27b2b57 | 2023-06-30 10:44:45 +0400 | [diff] [blame] | 325 | return StoreApp{ |
| 326 | App{ |
| 327 | "qbittorrent", |
| 328 | []string{"app-qbittorrent"}, |
| 329 | []*template.Template{ |
| 330 | tmpls.Lookup("qbittorrent.yaml"), |
| 331 | }, |
| Giorgi Lekveishvili | 7c42760 | 2024-01-04 00:13:55 +0400 | [diff] [blame^] | 332 | schema, |
| Giorgi Lekveishvili | 27b2b57 | 2023-06-30 10:44:45 +0400 | [diff] [blame] | 333 | tmpls.Lookup("qbittorrent.md"), |
| giolekva | ef76a3e | 2022-01-10 12:22:28 +0400 | [diff] [blame] | 334 | }, |
| Giorgi Lekveishvili | 4257b90 | 2023-07-07 17:08:42 +0400 | [diff] [blame] | 335 | `<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 Lekveishvili | 27b2b57 | 2023-06-30 10:44:45 +0400 | [diff] [blame] | 336 | "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.", |
| giolekva | ef76a3e | 2022-01-10 12:22:28 +0400 | [diff] [blame] | 337 | } |
| 338 | } |
| 339 | |
| Giorgi Lekveishvili | 27b2b57 | 2023-06-30 10:44:45 +0400 | [diff] [blame] | 340 | func CreateAppJellyfin(fs embed.FS, tmpls *template.Template) StoreApp { |
| Giorgi Lekveishvili | 7c42760 | 2024-01-04 00:13:55 +0400 | [diff] [blame^] | 341 | schema, err := readJSONSchemaFromFile(fs, "values-tmpl/jellyfin.jsonschema") |
| Giorgi Lekveishvili | 7efe22f | 2023-05-30 13:01:53 +0400 | [diff] [blame] | 342 | if err != nil { |
| 343 | panic(err) |
| 344 | } |
| Giorgi Lekveishvili | 27b2b57 | 2023-06-30 10:44:45 +0400 | [diff] [blame] | 345 | return StoreApp{ |
| 346 | App{ |
| 347 | "jellyfin", |
| 348 | []string{"app-jellyfin"}, |
| 349 | []*template.Template{ |
| 350 | tmpls.Lookup("jellyfin.yaml"), |
| 351 | }, |
| Giorgi Lekveishvili | 7c42760 | 2024-01-04 00:13:55 +0400 | [diff] [blame^] | 352 | schema, |
| Giorgi Lekveishvili | 27b2b57 | 2023-06-30 10:44:45 +0400 | [diff] [blame] | 353 | nil, |
| giolekva | ef76a3e | 2022-01-10 12:22:28 +0400 | [diff] [blame] | 354 | }, |
| Giorgi Lekveishvili | 4257b90 | 2023-07-07 17:08:42 +0400 | [diff] [blame] | 355 | `<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 Lekveishvili | 27b2b57 | 2023-06-30 10:44:45 +0400 | [diff] [blame] | 356 | "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.", |
| giolekva | ef76a3e | 2022-01-10 12:22:28 +0400 | [diff] [blame] | 357 | } |
| 358 | } |
| Giorgi Lekveishvili | 23ef7f8 | 2023-05-26 11:57:48 +0400 | [diff] [blame] | 359 | |
| Giorgi Lekveishvili | 27b2b57 | 2023-06-30 10:44:45 +0400 | [diff] [blame] | 360 | func CreateAppRpuppy(fs embed.FS, tmpls *template.Template) StoreApp { |
| Giorgi Lekveishvili | 7c42760 | 2024-01-04 00:13:55 +0400 | [diff] [blame^] | 361 | schema, err := readJSONSchemaFromFile(fs, "values-tmpl/rpuppy.jsonschema") |
| Giorgi Lekveishvili | 7efe22f | 2023-05-30 13:01:53 +0400 | [diff] [blame] | 362 | if err != nil { |
| 363 | panic(err) |
| 364 | } |
| Giorgi Lekveishvili | 27b2b57 | 2023-06-30 10:44:45 +0400 | [diff] [blame] | 365 | return StoreApp{ |
| 366 | App{ |
| 367 | "rpuppy", |
| 368 | []string{"app-rpuppy"}, |
| 369 | []*template.Template{ |
| 370 | tmpls.Lookup("rpuppy.yaml"), |
| 371 | }, |
| Giorgi Lekveishvili | 7c42760 | 2024-01-04 00:13:55 +0400 | [diff] [blame^] | 372 | schema, |
| Giorgi Lekveishvili | 27b2b57 | 2023-06-30 10:44:45 +0400 | [diff] [blame] | 373 | tmpls.Lookup("rpuppy.md"), |
| Giorgi Lekveishvili | 23ef7f8 | 2023-05-26 11:57:48 +0400 | [diff] [blame] | 374 | }, |
| Giorgi Lekveishvili | 4257b90 | 2023-07-07 17:08:42 +0400 | [diff] [blame] | 375 | `<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 Lekveishvili | 27b2b57 | 2023-06-30 10:44:45 +0400 | [diff] [blame] | 376 | "Delights users with randomly generate puppy pictures. Can be configured to be reachable only from private network or publicly.", |
| Giorgi Lekveishvili | 23ef7f8 | 2023-05-26 11:57:48 +0400 | [diff] [blame] | 377 | } |
| 378 | } |
| 379 | |
| Giorgi Lekveishvili | 672af5d | 2023-07-12 11:57:51 +0400 | [diff] [blame] | 380 | func CreateAppSoftServe(fs embed.FS, tmpls *template.Template) StoreApp { |
| Giorgi Lekveishvili | 7c42760 | 2024-01-04 00:13:55 +0400 | [diff] [blame^] | 381 | schema, err := readJSONSchemaFromFile(fs, "values-tmpl/soft-serve.jsonschema") |
| Giorgi Lekveishvili | 672af5d | 2023-07-12 11:57:51 +0400 | [diff] [blame] | 382 | 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 Lekveishvili | 7c42760 | 2024-01-04 00:13:55 +0400 | [diff] [blame^] | 392 | schema, |
| Giorgi Lekveishvili | 672af5d | 2023-07-12 11:57:51 +0400 | [diff] [blame] | 393 | 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 Lekveishvili | 7efe22f | 2023-05-30 13:01:53 +0400 | [diff] [blame] | 400 | func CreateAppHeadscale(fs embed.FS, tmpls *template.Template) App { |
| Giorgi Lekveishvili | 7c42760 | 2024-01-04 00:13:55 +0400 | [diff] [blame^] | 401 | schema, err := readJSONSchemaFromFile(fs, "values-tmpl/headscale.jsonschema") |
| Giorgi Lekveishvili | 7efe22f | 2023-05-30 13:01:53 +0400 | [diff] [blame] | 402 | if err != nil { |
| 403 | panic(err) |
| 404 | } |
| Giorgi Lekveishvili | 23ef7f8 | 2023-05-26 11:57:48 +0400 | [diff] [blame] | 405 | return App{ |
| 406 | "headscale", |
| Giorgi Lekveishvili | 7fb28bf | 2023-06-24 19:51:16 +0400 | [diff] [blame] | 407 | []string{"app-headscale"}, |
| Giorgi Lekveishvili | 23ef7f8 | 2023-05-26 11:57:48 +0400 | [diff] [blame] | 408 | []*template.Template{ |
| 409 | tmpls.Lookup("headscale.yaml"), |
| 410 | }, |
| Giorgi Lekveishvili | 7c42760 | 2024-01-04 00:13:55 +0400 | [diff] [blame^] | 411 | schema, |
| Giorgi Lekveishvili | 3a90705 | 2023-05-30 13:33:32 +0400 | [diff] [blame] | 412 | tmpls.Lookup("headscale.md"), |
| Giorgi Lekveishvili | 23ef7f8 | 2023-05-26 11:57:48 +0400 | [diff] [blame] | 413 | } |
| 414 | } |
| Giorgi Lekveishvili | 0ccd148 | 2023-06-21 15:02:24 +0400 | [diff] [blame] | 415 | |
| Giorgi Lekveishvili | 3991369 | 2023-12-05 08:58:08 +0400 | [diff] [blame] | 416 | func CreateAppHeadscaleUser(fs embed.FS, tmpls *template.Template) App { |
| Giorgi Lekveishvili | 7c42760 | 2024-01-04 00:13:55 +0400 | [diff] [blame^] | 417 | schema, err := readJSONSchemaFromFile(fs, "values-tmpl/headscale-user.jsonschema") |
| Giorgi Lekveishvili | 3991369 | 2023-12-05 08:58:08 +0400 | [diff] [blame] | 418 | 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 Lekveishvili | 7c42760 | 2024-01-04 00:13:55 +0400 | [diff] [blame^] | 427 | schema, |
| Giorgi Lekveishvili | 3991369 | 2023-12-05 08:58:08 +0400 | [diff] [blame] | 428 | tmpls.Lookup("headscale-user.md"), |
| 429 | } |
| 430 | } |
| 431 | |
| Giorgi Lekveishvili | 4fc2943 | 2023-07-20 10:03:28 +0400 | [diff] [blame] | 432 | func CreateMetallbIPAddressPool(fs embed.FS, tmpls *template.Template) App { |
| Giorgi Lekveishvili | 7c42760 | 2024-01-04 00:13:55 +0400 | [diff] [blame^] | 433 | schema, err := readJSONSchemaFromFile(fs, "values-tmpl/metallb-ipaddresspool.jsonschema") |
| Giorgi Lekveishvili | 4fc2943 | 2023-07-20 10:03:28 +0400 | [diff] [blame] | 434 | 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 Lekveishvili | 7c42760 | 2024-01-04 00:13:55 +0400 | [diff] [blame^] | 443 | schema, |
| Giorgi Lekveishvili | 4fc2943 | 2023-07-20 10:03:28 +0400 | [diff] [blame] | 444 | tmpls.Lookup("metallb-ipaddresspool.md"), |
| 445 | } |
| 446 | } |
| 447 | |
| Giorgi Lekveishvili | 0ccd148 | 2023-06-21 15:02:24 +0400 | [diff] [blame] | 448 | func CreateEnvManager(fs embed.FS, tmpls *template.Template) App { |
| Giorgi Lekveishvili | 7c42760 | 2024-01-04 00:13:55 +0400 | [diff] [blame^] | 449 | schema, err := readJSONSchemaFromFile(fs, "values-tmpl/env-manager.jsonschema") |
| Giorgi Lekveishvili | 0ccd148 | 2023-06-21 15:02:24 +0400 | [diff] [blame] | 450 | if err != nil { |
| 451 | panic(err) |
| 452 | } |
| 453 | return App{ |
| 454 | "env-manager", |
| Giorgi Lekveishvili | 7fb28bf | 2023-06-24 19:51:16 +0400 | [diff] [blame] | 455 | []string{"env-manager"}, |
| Giorgi Lekveishvili | 0ccd148 | 2023-06-21 15:02:24 +0400 | [diff] [blame] | 456 | []*template.Template{ |
| 457 | tmpls.Lookup("env-manager.yaml"), |
| 458 | }, |
| Giorgi Lekveishvili | 7c42760 | 2024-01-04 00:13:55 +0400 | [diff] [blame^] | 459 | schema, |
| Giorgi Lekveishvili | 0ccd148 | 2023-06-21 15:02:24 +0400 | [diff] [blame] | 460 | tmpls.Lookup("env-manager.md"), |
| 461 | } |
| 462 | } |
| 463 | |
| Giorgi Lekveishvili | 12850ee | 2023-06-22 13:11:17 +0400 | [diff] [blame] | 464 | func CreateWelcome(fs embed.FS, tmpls *template.Template) App { |
| Giorgi Lekveishvili | 7c42760 | 2024-01-04 00:13:55 +0400 | [diff] [blame^] | 465 | schema, err := readJSONSchemaFromFile(fs, "values-tmpl/welcome.jsonschema") |
| Giorgi Lekveishvili | 12850ee | 2023-06-22 13:11:17 +0400 | [diff] [blame] | 466 | if err != nil { |
| 467 | panic(err) |
| 468 | } |
| 469 | return App{ |
| 470 | "welcome", |
| Giorgi Lekveishvili | 7fb28bf | 2023-06-24 19:51:16 +0400 | [diff] [blame] | 471 | []string{"app-welcome"}, |
| Giorgi Lekveishvili | 12850ee | 2023-06-22 13:11:17 +0400 | [diff] [blame] | 472 | []*template.Template{ |
| 473 | tmpls.Lookup("welcome.yaml"), |
| 474 | }, |
| Giorgi Lekveishvili | 7c42760 | 2024-01-04 00:13:55 +0400 | [diff] [blame^] | 475 | schema, |
| Giorgi Lekveishvili | 12850ee | 2023-06-22 13:11:17 +0400 | [diff] [blame] | 476 | tmpls.Lookup("welcome.md"), |
| 477 | } |
| 478 | } |
| 479 | |
| Giorgi Lekveishvili | 4257b90 | 2023-07-07 17:08:42 +0400 | [diff] [blame] | 480 | func CreateAppManager(fs embed.FS, tmpls *template.Template) App { |
| Giorgi Lekveishvili | 7c42760 | 2024-01-04 00:13:55 +0400 | [diff] [blame^] | 481 | schema, err := readJSONSchemaFromFile(fs, "values-tmpl/appmanager.jsonschema") |
| Giorgi Lekveishvili | 4257b90 | 2023-07-07 17:08:42 +0400 | [diff] [blame] | 482 | 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 Lekveishvili | 7c42760 | 2024-01-04 00:13:55 +0400 | [diff] [blame^] | 491 | schema, |
| Giorgi Lekveishvili | 4257b90 | 2023-07-07 17:08:42 +0400 | [diff] [blame] | 492 | tmpls.Lookup("appmanager.md"), |
| 493 | } |
| 494 | } |
| 495 | |
| Giorgi Lekveishvili | 0ccd148 | 2023-06-21 15:02:24 +0400 | [diff] [blame] | 496 | func CreateIngressPublic(fs embed.FS, tmpls *template.Template) App { |
| Giorgi Lekveishvili | 7c42760 | 2024-01-04 00:13:55 +0400 | [diff] [blame^] | 497 | schema, err := readJSONSchemaFromFile(fs, "values-tmpl/ingress-public.jsonschema") |
| Giorgi Lekveishvili | 0ccd148 | 2023-06-21 15:02:24 +0400 | [diff] [blame] | 498 | if err != nil { |
| 499 | panic(err) |
| 500 | } |
| 501 | return App{ |
| 502 | "ingress-public", |
| Giorgi Lekveishvili | 7fb28bf | 2023-06-24 19:51:16 +0400 | [diff] [blame] | 503 | []string{"ingress-public"}, |
| Giorgi Lekveishvili | 0ccd148 | 2023-06-21 15:02:24 +0400 | [diff] [blame] | 504 | []*template.Template{ |
| 505 | tmpls.Lookup("ingress-public.yaml"), |
| 506 | }, |
| Giorgi Lekveishvili | 7c42760 | 2024-01-04 00:13:55 +0400 | [diff] [blame^] | 507 | schema, |
| Giorgi Lekveishvili | 0ccd148 | 2023-06-21 15:02:24 +0400 | [diff] [blame] | 508 | tmpls.Lookup("ingress-public.md"), |
| 509 | } |
| 510 | } |
| 511 | |
| 512 | func CreateCertManager(fs embed.FS, tmpls *template.Template) App { |
| Giorgi Lekveishvili | 7c42760 | 2024-01-04 00:13:55 +0400 | [diff] [blame^] | 513 | schema, err := readJSONSchemaFromFile(fs, "values-tmpl/cert-manager.jsonschema") |
| Giorgi Lekveishvili | 0ccd148 | 2023-06-21 15:02:24 +0400 | [diff] [blame] | 514 | if err != nil { |
| 515 | panic(err) |
| 516 | } |
| 517 | return App{ |
| 518 | "cert-manager", |
| Giorgi Lekveishvili | 7fb28bf | 2023-06-24 19:51:16 +0400 | [diff] [blame] | 519 | []string{"cert-manager"}, |
| Giorgi Lekveishvili | 0ccd148 | 2023-06-21 15:02:24 +0400 | [diff] [blame] | 520 | []*template.Template{ |
| 521 | tmpls.Lookup("cert-manager.yaml"), |
| 522 | }, |
| Giorgi Lekveishvili | 7c42760 | 2024-01-04 00:13:55 +0400 | [diff] [blame^] | 523 | schema, |
| Giorgi Lekveishvili | 0ccd148 | 2023-06-21 15:02:24 +0400 | [diff] [blame] | 524 | tmpls.Lookup("cert-manager.md"), |
| 525 | } |
| 526 | } |
| 527 | |
| 528 | func CreateCertManagerWebhookGandi(fs embed.FS, tmpls *template.Template) App { |
| Giorgi Lekveishvili | 7c42760 | 2024-01-04 00:13:55 +0400 | [diff] [blame^] | 529 | schema, err := readJSONSchemaFromFile(fs, "values-tmpl/cert-manager-webhook-pcloud.jsonschema") |
| Giorgi Lekveishvili | 0ccd148 | 2023-06-21 15:02:24 +0400 | [diff] [blame] | 530 | if err != nil { |
| 531 | panic(err) |
| 532 | } |
| 533 | return App{ |
| Giorgi Lekveishvili | 5c2c0b9 | 2023-12-07 17:35:40 +0400 | [diff] [blame] | 534 | "cert-manager-webhook-pcloud", |
| Giorgi Lekveishvili | 7fb28bf | 2023-06-24 19:51:16 +0400 | [diff] [blame] | 535 | []string{}, |
| Giorgi Lekveishvili | 0ccd148 | 2023-06-21 15:02:24 +0400 | [diff] [blame] | 536 | []*template.Template{ |
| Giorgi Lekveishvili | 5c2c0b9 | 2023-12-07 17:35:40 +0400 | [diff] [blame] | 537 | tmpls.Lookup("cert-manager-webhook-pcloud.yaml"), |
| Giorgi Lekveishvili | 0ccd148 | 2023-06-21 15:02:24 +0400 | [diff] [blame] | 538 | }, |
| Giorgi Lekveishvili | 7c42760 | 2024-01-04 00:13:55 +0400 | [diff] [blame^] | 539 | schema, |
| Giorgi Lekveishvili | 5c2c0b9 | 2023-12-07 17:35:40 +0400 | [diff] [blame] | 540 | tmpls.Lookup("cert-manager-webhook-pcloud.md"), |
| Giorgi Lekveishvili | 0ccd148 | 2023-06-21 15:02:24 +0400 | [diff] [blame] | 541 | } |
| 542 | } |
| 543 | |
| 544 | func CreateCSIDriverSMB(fs embed.FS, tmpls *template.Template) App { |
| Giorgi Lekveishvili | 7c42760 | 2024-01-04 00:13:55 +0400 | [diff] [blame^] | 545 | schema, err := readJSONSchemaFromFile(fs, "values-tmpl/csi-driver-smb.jsonschema") |
| Giorgi Lekveishvili | 0ccd148 | 2023-06-21 15:02:24 +0400 | [diff] [blame] | 546 | if err != nil { |
| 547 | panic(err) |
| 548 | } |
| 549 | return App{ |
| 550 | "csi-driver-smb", |
| Giorgi Lekveishvili | 7fb28bf | 2023-06-24 19:51:16 +0400 | [diff] [blame] | 551 | []string{"csi-driver-smb"}, |
| Giorgi Lekveishvili | 0ccd148 | 2023-06-21 15:02:24 +0400 | [diff] [blame] | 552 | []*template.Template{ |
| 553 | tmpls.Lookup("csi-driver-smb.yaml"), |
| 554 | }, |
| Giorgi Lekveishvili | 7c42760 | 2024-01-04 00:13:55 +0400 | [diff] [blame^] | 555 | schema, |
| Giorgi Lekveishvili | 0ccd148 | 2023-06-21 15:02:24 +0400 | [diff] [blame] | 556 | tmpls.Lookup("csi-driver-smb.md"), |
| 557 | } |
| 558 | } |
| 559 | |
| 560 | func CreateResourceRendererController(fs embed.FS, tmpls *template.Template) App { |
| Giorgi Lekveishvili | 7c42760 | 2024-01-04 00:13:55 +0400 | [diff] [blame^] | 561 | schema, err := readJSONSchemaFromFile(fs, "values-tmpl/resource-renderer-controller.jsonschema") |
| Giorgi Lekveishvili | 0ccd148 | 2023-06-21 15:02:24 +0400 | [diff] [blame] | 562 | if err != nil { |
| 563 | panic(err) |
| 564 | } |
| 565 | return App{ |
| 566 | "resource-renderer-controller", |
| Giorgi Lekveishvili | 7fb28bf | 2023-06-24 19:51:16 +0400 | [diff] [blame] | 567 | []string{"rr-controller"}, |
| Giorgi Lekveishvili | 0ccd148 | 2023-06-21 15:02:24 +0400 | [diff] [blame] | 568 | []*template.Template{ |
| 569 | tmpls.Lookup("resource-renderer-controller.yaml"), |
| 570 | }, |
| Giorgi Lekveishvili | 7c42760 | 2024-01-04 00:13:55 +0400 | [diff] [blame^] | 571 | schema, |
| Giorgi Lekveishvili | 0ccd148 | 2023-06-21 15:02:24 +0400 | [diff] [blame] | 572 | tmpls.Lookup("resource-renderer-controller.md"), |
| 573 | } |
| 574 | } |
| 575 | |
| 576 | func CreateHeadscaleController(fs embed.FS, tmpls *template.Template) App { |
| Giorgi Lekveishvili | 7c42760 | 2024-01-04 00:13:55 +0400 | [diff] [blame^] | 577 | schema, err := readJSONSchemaFromFile(fs, "values-tmpl/headscale-controller.jsonschema") |
| Giorgi Lekveishvili | 0ccd148 | 2023-06-21 15:02:24 +0400 | [diff] [blame] | 578 | if err != nil { |
| 579 | panic(err) |
| 580 | } |
| 581 | return App{ |
| 582 | "headscale-controller", |
| Giorgi Lekveishvili | 7fb28bf | 2023-06-24 19:51:16 +0400 | [diff] [blame] | 583 | []string{"headscale-controller"}, |
| Giorgi Lekveishvili | 0ccd148 | 2023-06-21 15:02:24 +0400 | [diff] [blame] | 584 | []*template.Template{ |
| 585 | tmpls.Lookup("headscale-controller.yaml"), |
| 586 | }, |
| Giorgi Lekveishvili | 7c42760 | 2024-01-04 00:13:55 +0400 | [diff] [blame^] | 587 | schema, |
| Giorgi Lekveishvili | 0ccd148 | 2023-06-21 15:02:24 +0400 | [diff] [blame] | 588 | tmpls.Lookup("headscale-controller.md"), |
| 589 | } |
| 590 | } |
| Giorgi Lekveishvili | 743fb43 | 2023-11-08 17:19:40 +0400 | [diff] [blame] | 591 | |
| Giorgi Lekveishvili | 106a935 | 2023-12-04 11:20:11 +0400 | [diff] [blame] | 592 | func CreateDNSZoneManager(fs embed.FS, tmpls *template.Template) App { |
| Giorgi Lekveishvili | 7c42760 | 2024-01-04 00:13:55 +0400 | [diff] [blame^] | 593 | schema, err := readJSONSchemaFromFile(fs, "values-tmpl/dns-zone-controller.jsonschema") |
| Giorgi Lekveishvili | 106a935 | 2023-12-04 11:20:11 +0400 | [diff] [blame] | 594 | 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 Lekveishvili | 7c42760 | 2024-01-04 00:13:55 +0400 | [diff] [blame^] | 605 | schema, |
| Giorgi Lekveishvili | 106a935 | 2023-12-04 11:20:11 +0400 | [diff] [blame] | 606 | tmpls.Lookup("dns-zone-controller.md"), |
| 607 | } |
| 608 | } |
| 609 | |
| Giorgi Lekveishvili | 2df23db | 2023-12-14 07:55:22 +0400 | [diff] [blame] | 610 | func CreateFluxcdReconciler(fs embed.FS, tmpls *template.Template) App { |
| Giorgi Lekveishvili | 7c42760 | 2024-01-04 00:13:55 +0400 | [diff] [blame^] | 611 | schema, err := readJSONSchemaFromFile(fs, "values-tmpl/fluxcd-reconciler.jsonschema") |
| Giorgi Lekveishvili | 2df23db | 2023-12-14 07:55:22 +0400 | [diff] [blame] | 612 | 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 Lekveishvili | 7c42760 | 2024-01-04 00:13:55 +0400 | [diff] [blame^] | 621 | schema, |
| Giorgi Lekveishvili | 2df23db | 2023-12-14 07:55:22 +0400 | [diff] [blame] | 622 | tmpls.Lookup("fluxcd-reconciler.md"), |
| 623 | } |
| 624 | } |
| 625 | |
| Giorgi Lekveishvili | 743fb43 | 2023-11-08 17:19:40 +0400 | [diff] [blame] | 626 | type httpAppRepository struct { |
| 627 | apps []StoreApp |
| 628 | } |
| 629 | |
| 630 | type appVersion struct { |
| 631 | Version string `json:"version"` |
| 632 | Urls []string `json:"urls"` |
| 633 | } |
| 634 | |
| 635 | type allAppsResp struct { |
| 636 | ApiVersion string `json:"apiVersion"` |
| 637 | Entries map[string][]appVersion `json:"entries"` |
| 638 | } |
| 639 | |
| 640 | func 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 | |
| 675 | func 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 | |
| 710 | type fsAppRepository struct { |
| 711 | InMemoryAppRepository[StoreApp] |
| 712 | fs billy.Filesystem |
| 713 | } |
| 714 | |
| 715 | func 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 | |
| 742 | func 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 Lekveishvili | 7c42760 | 2024-01-04 00:13:55 +0400 | [diff] [blame^] | 774 | scm, err := io.ReadAll(sb) |
| 775 | if err != nil { |
| 776 | return StoreApp{}, err |
| 777 | } |
| 778 | schema, err := NewJSONSchema(string(scm)) |
| Giorgi Lekveishvili | 743fb43 | 2023-11-08 17:19:40 +0400 | [diff] [blame] | 779 | 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 Lekveishvili | 7c42760 | 2024-01-04 00:13:55 +0400 | [diff] [blame^] | 809 | schema: schema, |
| Giorgi Lekveishvili | 743fb43 | 2023-11-08 17:19:40 +0400 | [diff] [blame] | 810 | Namespaces: appCfg.Namespaces, |
| 811 | Templates: tmpls, |
| 812 | }, |
| 813 | ShortDescription: appCfg.Description, |
| 814 | Icon: appCfg.Icon, |
| 815 | }, nil |
| 816 | } |