blob: e8b77ece6d88d03413013f95e0b458c2bdee636c [file] [log] [blame]
Giorgi Lekveishvili94cda9d2023-07-20 10:16:09 +04001package installer
2
3import (
4 "context"
5 _ "embed"
6 "fmt"
7 "log"
8 "net/netip"
9 "path/filepath"
Giorgi Lekveishvili724885f2023-11-29 16:18:42 +040010 "strings"
Giorgi Lekveishvili94cda9d2023-07-20 10:16:09 +040011 "time"
12
Giorgi Lekveishvili94cda9d2023-07-20 10:16:09 +040013 "helm.sh/helm/v3/pkg/action"
14 "helm.sh/helm/v3/pkg/chart"
15 "helm.sh/helm/v3/pkg/chart/loader"
16
gioe72b54f2024-04-22 10:44:41 +040017 "github.com/giolekva/pcloud/core/installer/io"
Giorgi Lekveishvili94cda9d2023-07-20 10:16:09 +040018 "github.com/giolekva/pcloud/core/installer/soft"
19)
20
21const IPAddressPoolLocal = "local"
22const IPAddressPoolConfigRepo = "config-repo"
23const IPAddressPoolIngressPublic = "ingress-public"
24
Giorgi Lekveishvili5c2c0b92023-12-07 17:35:40 +040025const dnsAPIConfigMapName = "api-config"
26
Giorgi Lekveishvili94cda9d2023-07-20 10:16:09 +040027type Bootstrapper struct {
gioe72b54f2024-04-22 10:44:41 +040028 cl ChartLoader
29 ns NamespaceCreator
30 ha HelmActionConfigFactory
31 appRepo AppRepository
32 repoClient soft.ClientGetter
Giorgi Lekveishvili94cda9d2023-07-20 10:16:09 +040033}
34
gioe72b54f2024-04-22 10:44:41 +040035func NewBootstrapper(cl ChartLoader, ns NamespaceCreator, ha HelmActionConfigFactory, appRepo AppRepository, repoClient soft.ClientGetter) Bootstrapper {
36 return Bootstrapper{cl, ns, ha, appRepo, repoClient}
Giorgi Lekveishvili94cda9d2023-07-20 10:16:09 +040037}
38
gio3cdee592024-04-17 10:15:56 +040039func (b Bootstrapper) findApp(name string) (InfraApp, error) {
40 app, err := b.appRepo.Find(name)
41 if err != nil {
42 return nil, err
43 }
44 if a, ok := app.(InfraApp); ok {
45 return a, nil
46 } else {
47 return nil, fmt.Errorf("not found")
48 }
49}
50
51func (b Bootstrapper) Run(env BootstrapConfig) error {
52 if err := b.ns.Create(env.InfraName); err != nil {
Giorgi Lekveishvili94cda9d2023-07-20 10:16:09 +040053 return err
54 }
55 if err := b.installMetallb(env); err != nil {
56 return err
57 }
gio3cdee592024-04-17 10:15:56 +040058 if err := b.installLonghorn(env.InfraName, env.StorageDir, env.VolumeDefaultReplicaCount); err != nil {
Giorgi Lekveishvili94cda9d2023-07-20 10:16:09 +040059 return err
60 }
Giorgi Lekveishvilia1e77902023-11-06 14:48:27 +040061 bootstrapJobKeys, err := NewSSHKeyPair("bootstrapper")
62 if err != nil {
63 return err
64 }
gio3cdee592024-04-17 10:15:56 +040065 if err := b.installSoftServe(bootstrapJobKeys.AuthorizedKey(), env.InfraName, env.ServiceIPs.ConfigRepo); err != nil {
Giorgi Lekveishvili94cda9d2023-07-20 10:16:09 +040066 return err
67 }
Giorgi Lekveishvili5c1b06e2024-03-28 15:19:44 +040068 time.Sleep(30 * time.Second)
gioe72b54f2024-04-22 10:44:41 +040069 ss, err := b.repoClient.Get(
Giorgi Lekveishvili724885f2023-11-29 16:18:42 +040070 netip.AddrPortFrom(env.ServiceIPs.ConfigRepo, 22).String(),
71 bootstrapJobKeys.RawPrivateKey(),
72 log.Default())
Giorgi Lekveishvili94cda9d2023-07-20 10:16:09 +040073 if err != nil {
74 return err
75 }
Giorgi Lekveishvili724885f2023-11-29 16:18:42 +040076 defer func() {
77 if ss.RemovePublicKey("admin", bootstrapJobKeys.AuthorizedKey()); err != nil {
78 fmt.Printf("Failed to remove admin public key: %s\n", err.Error())
79 }
80 }()
Giorgi Lekveishvili94cda9d2023-07-20 10:16:09 +040081 if ss.AddPublicKey("admin", string(env.AdminPublicKey)); err != nil {
82 return err
83 }
gio3cdee592024-04-17 10:15:56 +040084 if err := b.installFluxcd(ss, env.InfraName); err != nil {
Giorgi Lekveishvili94cda9d2023-07-20 10:16:09 +040085 return err
86 }
Giorgi Lekveishvili106a9352023-12-04 11:20:11 +040087 fmt.Println("Fluxcd installed")
gioe72b54f2024-04-22 10:44:41 +040088 repoIO, err := ss.GetRepo("config")
Giorgi Lekveishvili94cda9d2023-07-20 10:16:09 +040089 if err != nil {
Giorgi Lekveishvili106a9352023-12-04 11:20:11 +040090 fmt.Println("Failed to get config repo")
Giorgi Lekveishvili94cda9d2023-07-20 10:16:09 +040091 return err
92 }
gio3cdee592024-04-17 10:15:56 +040093 mgr, err := NewInfraAppManager(repoIO, b.ns)
94 if err != nil {
95 return err
96 }
Giorgi Lekveishvili106a9352023-12-04 11:20:11 +040097 fmt.Println("Configuring main repo")
Giorgi Lekveishvili94cda9d2023-07-20 10:16:09 +040098 if err := configureMainRepo(repoIO, env); err != nil {
99 return err
100 }
Giorgi Lekveishvili106a9352023-12-04 11:20:11 +0400101 fmt.Println("Installing infrastructure services")
gio3cdee592024-04-17 10:15:56 +0400102 if err := b.installInfrastructureServices(mgr, env); err != nil {
103 return err
104 }
105 fmt.Println("Installing public ingress")
106 if err := b.installIngressPublic(mgr, ss, env); err != nil {
Giorgi Lekveishvili94cda9d2023-07-20 10:16:09 +0400107 return err
108 }
Giorgi Lekveishvili106a9352023-12-04 11:20:11 +0400109 fmt.Println("Installing DNS Zone Manager")
gio3cdee592024-04-17 10:15:56 +0400110 if err := b.installDNSZoneManager(mgr, env); err != nil {
Giorgi Lekveishvili106a9352023-12-04 11:20:11 +0400111 return err
112 }
Giorgi Lekveishvili2df23db2023-12-14 07:55:22 +0400113 fmt.Println("Installing Fluxcd Reconciler")
gio3cdee592024-04-17 10:15:56 +0400114 if err := b.installFluxcdReconciler(mgr, ss, env); err != nil {
Giorgi Lekveishvili2df23db2023-12-14 07:55:22 +0400115 return err
116 }
Giorgi Lekveishvili106a9352023-12-04 11:20:11 +0400117 fmt.Println("Installing env manager")
gio3cdee592024-04-17 10:15:56 +0400118 if err := b.installEnvManager(mgr, ss, env); err != nil {
Giorgi Lekveishvili94cda9d2023-07-20 10:16:09 +0400119 return err
120 }
Giorgi Lekveishvili925f0de2024-03-14 18:51:56 +0400121 fmt.Println("Installing Ory Hydra Maester")
gio3cdee592024-04-17 10:15:56 +0400122 if err := b.installOryHydraMaester(mgr, env); err != nil {
Giorgi Lekveishvili925f0de2024-03-14 18:51:56 +0400123 return err
124 }
Giorgi Lekveishvili106a9352023-12-04 11:20:11 +0400125 fmt.Println("Environment ready to use")
Giorgi Lekveishvili94cda9d2023-07-20 10:16:09 +0400126 return nil
127}
128
gio3cdee592024-04-17 10:15:56 +0400129func (b Bootstrapper) installMetallb(env BootstrapConfig) error {
Giorgi Lekveishvili94cda9d2023-07-20 10:16:09 +0400130 if err := b.installMetallbNamespace(env); err != nil {
131 return err
132 }
133 if err := b.installMetallbService(); err != nil {
134 return err
135 }
136 if err := b.installMetallbIPAddressPool(IPAddressPoolLocal, true, env.ServiceIPs.From, env.ServiceIPs.To); err != nil {
137 return err
138 }
139 if err := b.installMetallbIPAddressPool(IPAddressPoolConfigRepo, false, env.ServiceIPs.ConfigRepo, env.ServiceIPs.ConfigRepo); err != nil {
140 return err
141 }
142 if err := b.installMetallbIPAddressPool(IPAddressPoolIngressPublic, false, env.ServiceIPs.IngressPublic, env.ServiceIPs.IngressPublic); err != nil {
143 return err
144 }
145 return nil
146}
147
gio3cdee592024-04-17 10:15:56 +0400148func (b Bootstrapper) installMetallbNamespace(env BootstrapConfig) error {
Giorgi Lekveishvili94cda9d2023-07-20 10:16:09 +0400149 fmt.Println("Installing metallb namespace")
gio3cdee592024-04-17 10:15:56 +0400150 config, err := b.ha.New(env.InfraName)
Giorgi Lekveishvili94cda9d2023-07-20 10:16:09 +0400151 if err != nil {
152 return err
153 }
154 chart, err := b.cl.Load("namespace")
155 if err != nil {
156 return err
157 }
158 values := map[string]any{
159 "namespace": "metallb-system",
160 "labels": []string{
161 "pod-security.kubernetes.io/audit: privileged",
162 "pod-security.kubernetes.io/enforce: privileged",
163 "pod-security.kubernetes.io/warn: privileged",
164 },
165 }
166 installer := action.NewInstall(config)
gio3cdee592024-04-17 10:15:56 +0400167 installer.Namespace = env.InfraName
Giorgi Lekveishvili94cda9d2023-07-20 10:16:09 +0400168 installer.ReleaseName = "metallb-ns"
169 installer.Wait = true
170 installer.WaitForJobs = true
171 if _, err := installer.RunWithContext(context.TODO(), chart, values); err != nil {
172 return err
173 }
174 return nil
175}
176
177func (b Bootstrapper) installMetallbService() error {
178 fmt.Println("Installing metallb")
179 config, err := b.ha.New("metallb-system")
180 if err != nil {
181 return err
182 }
183 chart, err := b.cl.Load("metallb")
184 if err != nil {
185 return err
186 }
187 values := map[string]any{ // TODO(giolekva): add loadBalancerClass?
188 "controller": map[string]any{
189 "image": map[string]any{
190 "repository": "quay.io/metallb/controller",
Giorgi Lekveishvilic06164d2023-11-22 13:51:29 +0400191 "tag": "v0.13.12",
Giorgi Lekveishvili94cda9d2023-07-20 10:16:09 +0400192 "pullPolicy": "IfNotPresent",
193 },
194 "logLevel": "info",
195 },
196 "speaker": map[string]any{
197 "image": map[string]any{
198 "repository": "quay.io/metallb/speaker",
Giorgi Lekveishvilic06164d2023-11-22 13:51:29 +0400199 "tag": "v0.13.12",
Giorgi Lekveishvili94cda9d2023-07-20 10:16:09 +0400200 "pullPolicy": "IfNotPresent",
201 },
202 "logLevel": "info",
203 },
204 }
205 installer := action.NewInstall(config)
206 installer.Namespace = "metallb-system"
207 installer.CreateNamespace = true
208 installer.ReleaseName = "metallb"
209 installer.IncludeCRDs = true
210 installer.Wait = true
211 installer.WaitForJobs = true
212 installer.Timeout = 20 * time.Minute
213 if _, err := installer.RunWithContext(context.TODO(), chart, values); err != nil {
214 return err
215 }
216 return nil
217}
218
219func (b Bootstrapper) installMetallbIPAddressPool(name string, autoAssign bool, from, to netip.Addr) error {
220 fmt.Printf("Installing metallb-ipaddresspool: %s\n", name)
221 config, err := b.ha.New("metallb-system")
222 if err != nil {
223 return err
224 }
225 chart, err := b.cl.Load("metallb-ipaddresspool")
226 if err != nil {
227 return err
228 }
229 values := map[string]any{
230 "name": name,
231 "autoAssign": autoAssign,
232 "from": from.String(),
233 "to": to.String(),
234 }
235 installer := action.NewInstall(config)
236 installer.Namespace = "metallb-system"
237 installer.CreateNamespace = true
238 installer.ReleaseName = name
239 installer.Wait = true
240 installer.WaitForJobs = true
241 installer.Timeout = 20 * time.Minute
242 if _, err := installer.RunWithContext(context.TODO(), chart, values); err != nil {
243 return err
244 }
245 return nil
246}
247
248func (b Bootstrapper) installLonghorn(envName string, storageDir string, volumeDefaultReplicaCount int) error {
249 fmt.Println("Installing Longhorn")
250 config, err := b.ha.New(envName)
251 if err != nil {
252 return err
253 }
254 chart, err := b.cl.Load("longhorn")
255 if err != nil {
256 return err
257 }
258 values := map[string]any{
259 "defaultSettings": map[string]any{
260 "defaultDataPath": storageDir,
261 },
262 "persistence": map[string]any{
263 "defaultClassReplicaCount": volumeDefaultReplicaCount,
264 },
265 "service": map[string]any{
266 "ui": map[string]any{
267 "type": "LoadBalancer",
268 },
269 },
270 "ingress": map[string]any{
271 "enabled": false,
272 },
273 }
274 installer := action.NewInstall(config)
275 installer.Namespace = "longhorn-system"
276 installer.CreateNamespace = true
277 installer.ReleaseName = "longhorn"
278 installer.Wait = true
279 installer.WaitForJobs = true
280 installer.Timeout = 20 * time.Minute
281 if _, err := installer.RunWithContext(context.TODO(), chart, values); err != nil {
282 return err
283 }
284 return nil
285}
286
Giorgi Lekveishvili724885f2023-11-29 16:18:42 +0400287func (b Bootstrapper) installSoftServe(adminPublicKey string, namespace string, repoIP netip.Addr) error {
Giorgi Lekveishvili94cda9d2023-07-20 10:16:09 +0400288 fmt.Println("Installing SoftServe")
Giorgi Lekveishvilia1e77902023-11-06 14:48:27 +0400289 keys, err := NewSSHKeyPair("soft-serve")
Giorgi Lekveishvili94cda9d2023-07-20 10:16:09 +0400290 if err != nil {
291 return err
292 }
Giorgi Lekveishvili724885f2023-11-29 16:18:42 +0400293 config, err := b.ha.New(namespace)
Giorgi Lekveishvili94cda9d2023-07-20 10:16:09 +0400294 if err != nil {
295 return err
296 }
297 chart, err := b.cl.Load("soft-serve")
298 if err != nil {
299 return err
300 }
301 values := map[string]any{
302 "image": map[string]any{
303 "repository": "charmcli/soft-serve",
Giorgi Lekveishvilic06164d2023-11-22 13:51:29 +0400304 "tag": "v0.7.1",
Giorgi Lekveishvili94cda9d2023-07-20 10:16:09 +0400305 "pullPolicy": "IfNotPresent",
306 },
Giorgi Lekveishvili724885f2023-11-29 16:18:42 +0400307 "privateKey": string(keys.RawPrivateKey()),
308 "publicKey": string(keys.RawAuthorizedKey()),
309 "adminKey": adminPublicKey,
310 "reservedIP": repoIP.String(),
311 "serviceType": "LoadBalancer",
Giorgi Lekveishvili94cda9d2023-07-20 10:16:09 +0400312 }
313 installer := action.NewInstall(config)
Giorgi Lekveishvili724885f2023-11-29 16:18:42 +0400314 installer.Namespace = namespace
Giorgi Lekveishvili94cda9d2023-07-20 10:16:09 +0400315 installer.CreateNamespace = true
316 installer.ReleaseName = "soft-serve"
317 installer.Wait = true
318 installer.WaitForJobs = true
319 installer.Timeout = 20 * time.Minute
320 if _, err := installer.RunWithContext(context.TODO(), chart, values); err != nil {
321 return err
322 }
323 return nil
324}
325
gioe72b54f2024-04-22 10:44:41 +0400326func (b Bootstrapper) installFluxcd(ss soft.Client, envName string) error {
Giorgi Lekveishvilia1e77902023-11-06 14:48:27 +0400327 keys, err := NewSSHKeyPair("fluxcd")
Giorgi Lekveishvili94cda9d2023-07-20 10:16:09 +0400328 if err != nil {
329 return err
330 }
Giorgi Lekveishvilia1e77902023-11-06 14:48:27 +0400331 if err := ss.AddUser("flux", keys.AuthorizedKey()); err != nil {
Giorgi Lekveishvili94cda9d2023-07-20 10:16:09 +0400332 return err
333 }
334 if err := ss.MakeUserAdmin("flux"); err != nil {
335 return err
336 }
Giorgi Lekveishvili724885f2023-11-29 16:18:42 +0400337 if err := ss.AddRepository("config"); err != nil {
338 return err
339 }
gioe72b54f2024-04-22 10:44:41 +0400340 repoIO, err := ss.GetRepo("config")
Giorgi Lekveishvili724885f2023-11-29 16:18:42 +0400341 if err != nil {
342 return err
343 }
gioe72b54f2024-04-22 10:44:41 +0400344 if err := repoIO.Do(func(r soft.RepoFS) (string, error) {
gio3af43942024-04-16 08:13:50 +0400345 w, err := r.Writer("README.md")
346 if err != nil {
347 return "", err
348 }
349 if _, err := fmt.Fprintf(w, "# %s systems", envName); err != nil {
350 return "", err
351 }
352 return "readme", nil
353 }); err != nil {
Giorgi Lekveishvili94cda9d2023-07-20 10:16:09 +0400354 return err
355 }
356 fmt.Println("Installing Flux")
Giorgi Lekveishvili106a9352023-12-04 11:20:11 +0400357 ssPublicKeys, err := ss.GetPublicKeys()
Giorgi Lekveishvili94cda9d2023-07-20 10:16:09 +0400358 if err != nil {
359 return err
360 }
gioe72b54f2024-04-22 10:44:41 +0400361 host := strings.Split(ss.Address(), ":")[0]
Giorgi Lekveishvili94cda9d2023-07-20 10:16:09 +0400362 if err := b.installFluxBootstrap(
Giorgi Lekveishvili724885f2023-11-29 16:18:42 +0400363 ss.GetRepoAddress("config"),
364 host,
Giorgi Lekveishvili106a9352023-12-04 11:20:11 +0400365 ssPublicKeys,
Giorgi Lekveishvilia1e77902023-11-06 14:48:27 +0400366 string(keys.RawPrivateKey()),
Giorgi Lekveishvili94cda9d2023-07-20 10:16:09 +0400367 envName,
368 ); err != nil {
369 return err
370 }
371 return nil
372}
373
Giorgi Lekveishvili106a9352023-12-04 11:20:11 +0400374func (b Bootstrapper) installFluxBootstrap(repoAddr, repoHost string, repoHostPubKeys []string, privateKey, envName string) error {
Giorgi Lekveishvili94cda9d2023-07-20 10:16:09 +0400375 config, err := b.ha.New(envName)
376 if err != nil {
377 return err
378 }
379 chart, err := b.cl.Load("flux-bootstrap")
380 if err != nil {
381 return err
382 }
Giorgi Lekveishvili106a9352023-12-04 11:20:11 +0400383 var lines []string
384 for _, k := range repoHostPubKeys {
385 lines = append(lines, fmt.Sprintf("%s %s", repoHost, k))
386 }
Giorgi Lekveishvili94cda9d2023-07-20 10:16:09 +0400387 values := map[string]any{
388 "image": map[string]any{
Giorgi Lekveishvilic06164d2023-11-22 13:51:29 +0400389 "repository": "fluxcd/flux-cli",
390 "tag": "v2.1.2",
Giorgi Lekveishvili94cda9d2023-07-20 10:16:09 +0400391 "pullPolicy": "IfNotPresent",
392 },
Giorgi Lekveishvili106a9352023-12-04 11:20:11 +0400393 "repositoryAddress": repoAddr,
394 "repositoryHost": repoHost,
395 "repositoryHostPublicKeys": strings.Join(lines, "\n"),
396 "privateKey": privateKey,
397 "installationNamespace": fmt.Sprintf("%s-flux", envName),
Giorgi Lekveishvili94cda9d2023-07-20 10:16:09 +0400398 }
399 installer := action.NewInstall(config)
400 installer.Namespace = envName
401 installer.CreateNamespace = true
402 installer.ReleaseName = "flux"
403 installer.Wait = true
404 installer.WaitForJobs = true
405 installer.Timeout = 20 * time.Minute
406 if _, err := installer.RunWithContext(context.TODO(), chart, values); err != nil {
407 return err
408 }
409 return nil
410}
411
gio3cdee592024-04-17 10:15:56 +0400412func (b Bootstrapper) installInfrastructureServices(mgr *InfraAppManager, env BootstrapConfig) error {
Giorgi Lekveishvili94cda9d2023-07-20 10:16:09 +0400413 install := func(name string) error {
Giorgi Lekveishvili5c1b06e2024-03-28 15:19:44 +0400414 fmt.Printf("Installing infrastructure service %s\n", name)
gio3cdee592024-04-17 10:15:56 +0400415 app, err := b.findApp(name)
Giorgi Lekveishvili94cda9d2023-07-20 10:16:09 +0400416 if err != nil {
417 return err
418 }
gio3cdee592024-04-17 10:15:56 +0400419 namespace := fmt.Sprintf("%s-%s", env.InfraName, app.Namespace())
gio44f621b2024-04-29 09:44:38 +0400420 appDir := filepath.Join("/infrastructure", app.Slug())
gio3cdee592024-04-17 10:15:56 +0400421 return mgr.Install(app, appDir, namespace, map[string]any{})
Giorgi Lekveishvili94cda9d2023-07-20 10:16:09 +0400422 }
423 appsToInstall := []string{
424 "resource-renderer-controller",
425 "headscale-controller",
426 "csi-driver-smb",
Giorgi Lekveishvili94cda9d2023-07-20 10:16:09 +0400427 "cert-manager",
Giorgi Lekveishvili94cda9d2023-07-20 10:16:09 +0400428 }
429 for _, name := range appsToInstall {
430 if err := install(name); err != nil {
431 return err
432 }
433 }
434 return nil
435}
436
gioe72b54f2024-04-22 10:44:41 +0400437func configureMainRepo(repo soft.RepoIO, bootstrap BootstrapConfig) error {
438 return repo.Do(func(r soft.RepoFS) (string, error) {
439 if err := soft.WriteYaml(r, "bootstrap-config.yaml", bootstrap); err != nil {
gio3cdee592024-04-17 10:15:56 +0400440 return "", err
441 }
442 infra := InfraConfig{
443 Name: bootstrap.InfraName,
444 PublicIP: bootstrap.PublicIP,
445 InfraNamespacePrefix: bootstrap.NamespacePrefix,
446 InfraAdminPublicKey: bootstrap.AdminPublicKey,
447 }
gioe72b54f2024-04-22 10:44:41 +0400448 if err := soft.WriteYaml(r, "config.yaml", infra); err != nil {
gio3af43942024-04-16 08:13:50 +0400449 return "", err
Giorgi Lekveishvili94cda9d2023-07-20 10:16:09 +0400450 }
gioe72b54f2024-04-22 10:44:41 +0400451 if err := soft.WriteYaml(r, "env-cidrs.yaml", EnvCIDRs{}); err != nil {
gio3af43942024-04-16 08:13:50 +0400452 return "", err
453 }
gioe72b54f2024-04-22 10:44:41 +0400454 kust := io.NewKustomization()
gio3af43942024-04-16 08:13:50 +0400455 kust.AddResources(
gio3cdee592024-04-17 10:15:56 +0400456 fmt.Sprintf("%s-flux", bootstrap.InfraName),
gio3af43942024-04-16 08:13:50 +0400457 "infrastructure",
458 "environments",
459 )
gioe72b54f2024-04-22 10:44:41 +0400460 if err := soft.WriteYaml(r, "kustomization.yaml", kust); err != nil {
gio3af43942024-04-16 08:13:50 +0400461 return "", err
462 }
463 {
464 out, err := r.Writer("infrastructure/pcloud-charts.yaml")
465 if err != nil {
466 return "", err
467 }
468 defer out.Close()
469 _, err = out.Write([]byte(fmt.Sprintf(`
Giorgi Lekveishvili94cda9d2023-07-20 10:16:09 +0400470apiVersion: source.toolkit.fluxcd.io/v1
471kind: GitRepository
472metadata:
473 name: pcloud # TODO(giolekva): use more generic name
474 namespace: %s
475spec:
476 interval: 1m0s
477 url: https://github.com/giolekva/pcloud
478 ref:
Giorgi Lekveishvili024757c2024-03-14 13:27:29 +0400479 branch: main
gio3cdee592024-04-17 10:15:56 +0400480`, bootstrap.InfraName)))
gio3af43942024-04-16 08:13:50 +0400481 if err != nil {
482 return "", err
483 }
Giorgi Lekveishvili94cda9d2023-07-20 10:16:09 +0400484 }
gioe72b54f2024-04-22 10:44:41 +0400485 infraKust := io.NewKustomization()
gio3af43942024-04-16 08:13:50 +0400486 infraKust.AddResources("pcloud-charts.yaml")
gioe72b54f2024-04-22 10:44:41 +0400487 if err := soft.WriteYaml(r, "infrastructure/kustomization.yaml", infraKust); err != nil {
gio3af43942024-04-16 08:13:50 +0400488 return "", err
489 }
gioe72b54f2024-04-22 10:44:41 +0400490 if err := soft.WriteYaml(r, "environments/kustomization.yaml", io.NewKustomization()); err != nil {
gio3af43942024-04-16 08:13:50 +0400491 return "", err
492 }
493 return "initialize pcloud directory structure", nil
494 })
Giorgi Lekveishvili94cda9d2023-07-20 10:16:09 +0400495}
496
gioe72b54f2024-04-22 10:44:41 +0400497func (b Bootstrapper) installEnvManager(mgr *InfraAppManager, ss soft.Client, env BootstrapConfig) error {
Giorgi Lekveishvilia1e77902023-11-06 14:48:27 +0400498 keys, err := NewSSHKeyPair("env-manager")
Giorgi Lekveishvili94cda9d2023-07-20 10:16:09 +0400499 if err != nil {
500 return err
501 }
gio3cdee592024-04-17 10:15:56 +0400502 user := fmt.Sprintf("%s-env-manager", env.InfraName)
Giorgi Lekveishvilia1e77902023-11-06 14:48:27 +0400503 if err := ss.AddUser(user, keys.AuthorizedKey()); err != nil {
Giorgi Lekveishvili94cda9d2023-07-20 10:16:09 +0400504 return err
505 }
506 if err := ss.MakeUserAdmin(user); err != nil {
507 return err
508 }
gio3cdee592024-04-17 10:15:56 +0400509 app, err := b.findApp("env-manager")
Giorgi Lekveishvili94cda9d2023-07-20 10:16:09 +0400510 if err != nil {
511 return err
512 }
gio3cdee592024-04-17 10:15:56 +0400513 namespace := fmt.Sprintf("%s-%s", env.InfraName, app.Namespace())
gio44f621b2024-04-29 09:44:38 +0400514 appDir := filepath.Join("/infrastructure", app.Slug())
gio3cdee592024-04-17 10:15:56 +0400515 return mgr.Install(app, appDir, namespace, map[string]any{
516 "repoIP": env.ServiceIPs.ConfigRepo,
517 "repoPort": 22,
518 "repoName": "config",
519 "sshPrivateKey": string(keys.RawPrivateKey()),
520 })
Giorgi Lekveishvili94cda9d2023-07-20 10:16:09 +0400521}
522
gioe72b54f2024-04-22 10:44:41 +0400523func (b Bootstrapper) installIngressPublic(mgr *InfraAppManager, ss soft.Client, env BootstrapConfig) error {
gio3cdee592024-04-17 10:15:56 +0400524 keys, err := NewSSHKeyPair("port-allocator")
Giorgi Lekveishvili925f0de2024-03-14 18:51:56 +0400525 if err != nil {
526 return err
527 }
gio3cdee592024-04-17 10:15:56 +0400528 user := fmt.Sprintf("%s-port-allocator", env.InfraName)
529 if err := ss.AddUser(user, keys.AuthorizedKey()); err != nil {
530 return err
Giorgi Lekveishvili925f0de2024-03-14 18:51:56 +0400531 }
gio3cdee592024-04-17 10:15:56 +0400532 if err := ss.AddReadWriteCollaborator("config", user); err != nil {
533 return err
534 }
535 app, err := b.findApp("ingress-public")
536 if err != nil {
537 return err
538 }
539 namespace := fmt.Sprintf("%s-%s", env.InfraName, app.Namespace())
gio44f621b2024-04-29 09:44:38 +0400540 appDir := filepath.Join("/infrastructure", app.Slug())
gio3cdee592024-04-17 10:15:56 +0400541 return mgr.Install(app, appDir, namespace, map[string]any{
542 "sshPrivateKey": string(keys.RawPrivateKey()),
543 })
Giorgi Lekveishvili925f0de2024-03-14 18:51:56 +0400544}
545
gio3cdee592024-04-17 10:15:56 +0400546func (b Bootstrapper) installOryHydraMaester(mgr *InfraAppManager, env BootstrapConfig) error {
547 app, err := b.findApp("hydra-maester")
548 if err != nil {
549 return err
550 }
551 namespace := fmt.Sprintf("%s-%s", env.InfraName, app.Namespace())
gio44f621b2024-04-29 09:44:38 +0400552 appDir := filepath.Join("/infrastructure", app.Slug())
gio3cdee592024-04-17 10:15:56 +0400553 return mgr.Install(app, appDir, namespace, map[string]any{})
554}
555
556func (b Bootstrapper) installDNSZoneManager(mgr *InfraAppManager, env BootstrapConfig) error {
gioe72b54f2024-04-22 10:44:41 +0400557 app, err := b.findApp("dns-gateway")
Giorgi Lekveishvili106a9352023-12-04 11:20:11 +0400558 if err != nil {
559 return err
560 }
gio3cdee592024-04-17 10:15:56 +0400561 namespace := fmt.Sprintf("%s-%s", env.InfraName, app.Namespace())
gio44f621b2024-04-29 09:44:38 +0400562 appDir := filepath.Join("/infrastructure", app.Slug())
gio3cdee592024-04-17 10:15:56 +0400563 return mgr.Install(app, appDir, namespace, map[string]any{
gioe72b54f2024-04-22 10:44:41 +0400564 "servers": []EnvDNS{},
gio3cdee592024-04-17 10:15:56 +0400565 })
gio3af43942024-04-16 08:13:50 +0400566}
567
gioe72b54f2024-04-22 10:44:41 +0400568func (b Bootstrapper) installFluxcdReconciler(mgr *InfraAppManager, ss soft.Client, env BootstrapConfig) error {
gio3cdee592024-04-17 10:15:56 +0400569 app, err := b.findApp("fluxcd-reconciler")
gio3af43942024-04-16 08:13:50 +0400570 if err != nil {
Giorgi Lekveishvili2df23db2023-12-14 07:55:22 +0400571 return err
572 }
gio3cdee592024-04-17 10:15:56 +0400573 namespace := fmt.Sprintf("%s-%s", env.InfraName, app.Namespace())
gio44f621b2024-04-29 09:44:38 +0400574 appDir := filepath.Join("/infrastructure", app.Slug())
gio3cdee592024-04-17 10:15:56 +0400575 return mgr.Install(app, appDir, namespace, map[string]any{})
Giorgi Lekveishvili2df23db2023-12-14 07:55:22 +0400576}
577
Giorgi Lekveishvili94cda9d2023-07-20 10:16:09 +0400578type HelmActionConfigFactory interface {
579 New(namespace string) (*action.Configuration, error)
580}
581
582type ChartLoader interface {
583 Load(name string) (*chart.Chart, error)
584}
585
586type fsChartLoader struct {
587 baseDir string
588}
589
590func NewFSChartLoader(baseDir string) ChartLoader {
591 return &fsChartLoader{baseDir}
592}
593
594func (l *fsChartLoader) Load(name string) (*chart.Chart, error) {
595 return loader.Load(filepath.Join(l.baseDir, name))
596}