blob: e71de44105f697e77911ceffafcd584ebe5e125a [file] [log] [blame]
Giorgi Lekveishvili46743d42023-12-10 15:47:23 +04001package tasks
2
3import (
4 "fmt"
Giorgi Lekveishvilid542b732024-03-25 18:17:39 +04005 "strings"
Giorgi Lekveishvili46743d42023-12-10 15:47:23 +04006
7 "github.com/miekg/dns"
8
9 "github.com/giolekva/pcloud/core/installer"
gioe72b54f2024-04-22 10:44:41 +040010 "github.com/giolekva/pcloud/core/installer/soft"
Giorgi Lekveishvili46743d42023-12-10 15:47:23 +040011)
12
Giorgi Lekveishvilid542b732024-03-25 18:17:39 +040013var initGroups = []string{"admin"}
14
gioe72b54f2024-04-22 10:44:41 +040015func CreateRepoClient(env installer.EnvConfig, st *state) Task {
Giorgi Lekveishvili5c1b06e2024-03-28 15:19:44 +040016 t := newLeafTask("Create repo client", func() error {
gioe72b54f2024-04-22 10:44:41 +040017 r, err := st.ssClient.GetRepo("config")
gio3af43942024-04-16 08:13:50 +040018 if err != nil {
19 return err
20 }
gio308105e2024-04-19 13:12:13 +040021 appManager, err := installer.NewAppManager(r, st.nsCreator, "/apps")
Giorgi Lekveishvili77ee2dc2023-12-11 16:51:10 +040022 if err != nil {
23 return err
24 }
Giorgi Lekveishvili378ea882023-12-12 13:59:18 +040025 st.appManager = appManager
26 st.appsRepo = installer.NewInMemoryAppRepository(installer.CreateAllApps())
Giorgi Lekveishvili378ea882023-12-12 13:59:18 +040027 return nil
28 })
Giorgi Lekveishviliab7ff6e2024-03-29 13:11:30 +040029 t.beforeStart = func() {
30 st.infoListener("Setting up core infrastructure services.")
31 }
Giorgi Lekveishvili5c1b06e2024-03-28 15:19:44 +040032 return &t
33}
34
gioe72b54f2024-04-22 10:44:41 +040035func SetupInfra(env installer.EnvConfig, st *state) Task {
Giorgi Lekveishvili5c1b06e2024-03-28 15:19:44 +040036 return newConcurrentParentTask(
37 "Setup core services",
38 true,
gioe72b54f2024-04-22 10:44:41 +040039 SetupNetwork(env, st),
Giorgi Lekveishvili5c1b06e2024-03-28 15:19:44 +040040 SetupCertificateIssuers(env, st),
41 SetupAuth(env, st),
42 SetupGroupMemberships(env, st),
gioe72b54f2024-04-22 10:44:41 +040043 SetupHeadscale(env, st),
Giorgi Lekveishvili5c1b06e2024-03-28 15:19:44 +040044 SetupWelcome(env, st),
45 SetupAppStore(env, st),
Davit Tabidze56f86a42024-04-09 19:15:25 +040046 SetupLauncher(env, st),
Giorgi Lekveishvili5c1b06e2024-03-28 15:19:44 +040047 )
Giorgi Lekveishvili378ea882023-12-12 13:59:18 +040048}
49
gioe72b54f2024-04-22 10:44:41 +040050func CommitEnvironmentConfiguration(env installer.EnvConfig, st *state) Task {
Giorgi Lekveishvili5c1b06e2024-03-28 15:19:44 +040051 t := newLeafTask("commit config", func() error {
gioe72b54f2024-04-22 10:44:41 +040052 r, err := st.ssClient.GetRepo("config")
Giorgi Lekveishvili378ea882023-12-12 13:59:18 +040053 if err != nil {
Giorgi Lekveishvili77ee2dc2023-12-11 16:51:10 +040054 return err
55 }
gioe72b54f2024-04-22 10:44:41 +040056 r.Do(func(r soft.RepoFS) (string, error) {
57 if err := soft.WriteYaml(r, "config.yaml", env); err != nil {
58 return "", err
gio3af43942024-04-16 08:13:50 +040059 }
Giorgi Lekveishvili77ee2dc2023-12-11 16:51:10 +040060 out, err := r.Writer("pcloud-charts.yaml")
61 if err != nil {
gio3af43942024-04-16 08:13:50 +040062 return "", err
Giorgi Lekveishvili77ee2dc2023-12-11 16:51:10 +040063 }
64 defer out.Close()
65 _, err = fmt.Fprintf(out, `
Giorgi Lekveishvili46743d42023-12-10 15:47:23 +040066apiVersion: source.toolkit.fluxcd.io/v1
67kind: GitRepository
68metadata:
69 name: pcloud
70 namespace: %s
71spec:
72 interval: 1m0s
73 url: https://github.com/giolekva/pcloud
74 ref:
gio3cdee592024-04-17 10:15:56 +040075 branch: main
gioe72b54f2024-04-22 10:44:41 +040076`, env.Id)
Giorgi Lekveishvili77ee2dc2023-12-11 16:51:10 +040077 if err != nil {
gio3af43942024-04-16 08:13:50 +040078 return "", err
Giorgi Lekveishvili77ee2dc2023-12-11 16:51:10 +040079 }
gioe72b54f2024-04-22 10:44:41 +040080 rootKust, err := soft.ReadKustomization(r, "kustomization.yaml")
Giorgi Lekveishvili378ea882023-12-12 13:59:18 +040081 if err != nil {
gio3af43942024-04-16 08:13:50 +040082 return "", err
Giorgi Lekveishvili378ea882023-12-12 13:59:18 +040083 }
84 rootKust.AddResources("pcloud-charts.yaml")
gioe72b54f2024-04-22 10:44:41 +040085 if err := soft.WriteYaml(r, "kustomization.yaml", rootKust); err != nil {
gio3af43942024-04-16 08:13:50 +040086 return "", err
Giorgi Lekveishvili378ea882023-12-12 13:59:18 +040087 }
gio3af43942024-04-16 08:13:50 +040088 return "configure charts repo", nil
89 })
Giorgi Lekveishvili378ea882023-12-12 13:59:18 +040090 return nil
91 })
92 return &t
93}
94
Giorgi Lekveishvilid542b732024-03-25 18:17:39 +040095type firstAccount struct {
96 Created bool `json:"created"`
97 Groups []string `json:"groups"`
98}
99
gioe72b54f2024-04-22 10:44:41 +0400100func ConfigureFirstAccount(env installer.EnvConfig, st *state) Task {
Giorgi Lekveishvilid542b732024-03-25 18:17:39 +0400101 t := newLeafTask("Configure first account settings", func() error {
gioe72b54f2024-04-22 10:44:41 +0400102 r, err := st.ssClient.GetRepo("config")
Giorgi Lekveishvilid542b732024-03-25 18:17:39 +0400103 if err != nil {
104 return err
105 }
gioe72b54f2024-04-22 10:44:41 +0400106 return r.Do(func(r soft.RepoFS) (string, error) {
gio3af43942024-04-16 08:13:50 +0400107 fa := firstAccount{false, initGroups}
gioe72b54f2024-04-22 10:44:41 +0400108 if err := soft.WriteYaml(r, "first-account.yaml", fa); err != nil {
gio3af43942024-04-16 08:13:50 +0400109 return "", err
110 }
111 return "first account membership configuration", nil
112 })
Giorgi Lekveishvilid542b732024-03-25 18:17:39 +0400113 })
114 return &t
115}
116
gioe72b54f2024-04-22 10:44:41 +0400117func SetupNetwork(env installer.EnvConfig, st *state) Task {
Giorgi Lekveishvili5c1b06e2024-03-28 15:19:44 +0400118 t := newLeafTask("Setup private and public networks", func() error {
Giorgi Lekveishvili77ee2dc2023-12-11 16:51:10 +0400119 {
gio3cdee592024-04-17 10:15:56 +0400120 app, err := installer.FindEnvApp(st.appsRepo, "metallb-ipaddresspool")
Giorgi Lekveishvili77ee2dc2023-12-11 16:51:10 +0400121 if err != nil {
122 return err
123 }
gio3af43942024-04-16 08:13:50 +0400124 {
gio44f621b2024-04-29 09:44:38 +0400125 instanceId := fmt.Sprintf("%s-ingress-private", app.Slug())
gio3cdee592024-04-17 10:15:56 +0400126 appDir := fmt.Sprintf("/apps/%s", instanceId)
gio3af43942024-04-16 08:13:50 +0400127 namespace := fmt.Sprintf("%s%s-ingress-private", env.NamespacePrefix, app.Namespace())
gio778577f2024-04-29 09:44:38 +0400128 if _, err := st.appManager.Install(app, instanceId, appDir, namespace, map[string]any{
gioe72b54f2024-04-22 10:44:41 +0400129 "name": fmt.Sprintf("%s-ingress-private", env.Id),
130 "from": env.Network.Ingress.String(),
131 "to": env.Network.Ingress.String(),
gio3af43942024-04-16 08:13:50 +0400132 "autoAssign": false,
133 "namespace": "metallb-system",
134 }); err != nil {
135 return err
136 }
Giorgi Lekveishvili77ee2dc2023-12-11 16:51:10 +0400137 }
gio3af43942024-04-16 08:13:50 +0400138 {
gio44f621b2024-04-29 09:44:38 +0400139 instanceId := fmt.Sprintf("%s-headscale", app.Slug())
gio3cdee592024-04-17 10:15:56 +0400140 appDir := fmt.Sprintf("/apps/%s", instanceId)
gio3af43942024-04-16 08:13:50 +0400141 namespace := fmt.Sprintf("%s%s-ingress-private", env.NamespacePrefix, app.Namespace())
gio778577f2024-04-29 09:44:38 +0400142 if _, err := st.appManager.Install(app, instanceId, appDir, namespace, map[string]any{
gioe72b54f2024-04-22 10:44:41 +0400143 "name": fmt.Sprintf("%s-headscale", env.Id),
144 "from": env.Network.Headscale.String(),
145 "to": env.Network.Headscale.String(),
gio3af43942024-04-16 08:13:50 +0400146 "autoAssign": false,
147 "namespace": "metallb-system",
148 }); err != nil {
149 return err
150 }
Giorgi Lekveishvili77ee2dc2023-12-11 16:51:10 +0400151 }
gio3af43942024-04-16 08:13:50 +0400152 {
gio44f621b2024-04-29 09:44:38 +0400153 instanceId := app.Slug()
gio3cdee592024-04-17 10:15:56 +0400154 appDir := fmt.Sprintf("/apps/%s", instanceId)
gio3af43942024-04-16 08:13:50 +0400155 namespace := fmt.Sprintf("%s%s", env.NamespacePrefix, app.Namespace())
gio778577f2024-04-29 09:44:38 +0400156 if _, err := st.appManager.Install(app, instanceId, appDir, namespace, map[string]any{
gioe72b54f2024-04-22 10:44:41 +0400157 "name": env.Id,
158 "from": env.Network.ServicesFrom.String(),
159 "to": env.Network.ServicesTo.String(),
gio3af43942024-04-16 08:13:50 +0400160 "autoAssign": false,
161 "namespace": "metallb-system",
162 }); err != nil {
163 return err
164 }
Giorgi Lekveishvili77ee2dc2023-12-11 16:51:10 +0400165 }
Giorgi Lekveishvili46743d42023-12-10 15:47:23 +0400166 }
Giorgi Lekveishvili77ee2dc2023-12-11 16:51:10 +0400167 {
Giorgi Lekveishvilib59b7c22024-04-03 22:17:50 +0400168 keys, err := installer.NewSSHKeyPair("port-allocator")
169 if err != nil {
170 return err
171 }
gioe72b54f2024-04-22 10:44:41 +0400172 user := fmt.Sprintf("%s-port-allocator", env.Id)
Giorgi Lekveishvilib59b7c22024-04-03 22:17:50 +0400173 if err := st.ssClient.AddUser(user, keys.AuthorizedKey()); err != nil {
174 return err
175 }
176 if err := st.ssClient.AddReadWriteCollaborator("config", user); err != nil {
177 return err
178 }
gio3cdee592024-04-17 10:15:56 +0400179 app, err := installer.FindEnvApp(st.appsRepo, "private-network")
Giorgi Lekveishvili77ee2dc2023-12-11 16:51:10 +0400180 if err != nil {
181 return err
182 }
gio44f621b2024-04-29 09:44:38 +0400183 instanceId := app.Slug()
gio3cdee592024-04-17 10:15:56 +0400184 appDir := fmt.Sprintf("/apps/%s", instanceId)
gio3af43942024-04-16 08:13:50 +0400185 namespace := fmt.Sprintf("%s%s", env.NamespacePrefix, app.Namespace())
gio778577f2024-04-29 09:44:38 +0400186 if _, err := st.appManager.Install(app, instanceId, appDir, namespace, map[string]any{
Giorgi Lekveishvilie009a5d2024-01-05 14:10:11 +0400187 "privateNetwork": map[string]any{
188 "hostname": "private-network-proxy",
189 "username": "private-network-proxy",
gioe72b54f2024-04-22 10:44:41 +0400190 "ipSubnet": fmt.Sprintf("%s.0/24", strings.Join(strings.Split(env.Network.DNS.String(), ".")[:3], ".")),
Giorgi Lekveishvili77ee2dc2023-12-11 16:51:10 +0400191 },
Giorgi Lekveishvilib59b7c22024-04-03 22:17:50 +0400192 "sshPrivateKey": string(keys.RawPrivateKey()),
Giorgi Lekveishvili77ee2dc2023-12-11 16:51:10 +0400193 }); err != nil {
194 return err
195 }
Giorgi Lekveishvili46743d42023-12-10 15:47:23 +0400196 }
Giorgi Lekveishvili378ea882023-12-12 13:59:18 +0400197 return nil
198 })
199 return &t
200}
201
gioe72b54f2024-04-22 10:44:41 +0400202func SetupCertificateIssuers(env installer.EnvConfig, st *state) Task {
Giorgi Lekveishvili378ea882023-12-12 13:59:18 +0400203 pub := newLeafTask(fmt.Sprintf("Public %s", env.Domain), func() error {
gio3cdee592024-04-17 10:15:56 +0400204 app, err := installer.FindEnvApp(st.appsRepo, "certificate-issuer-public")
Giorgi Lekveishvili378ea882023-12-12 13:59:18 +0400205 if err != nil {
206 return err
Giorgi Lekveishvili46743d42023-12-10 15:47:23 +0400207 }
gio44f621b2024-04-29 09:44:38 +0400208 instanceId := app.Slug()
gio3cdee592024-04-17 10:15:56 +0400209 appDir := fmt.Sprintf("/apps/%s", instanceId)
gio3af43942024-04-16 08:13:50 +0400210 namespace := fmt.Sprintf("%s%s", env.NamespacePrefix, app.Namespace())
gio778577f2024-04-29 09:44:38 +0400211 if _, err := st.appManager.Install(app, instanceId, appDir, namespace, map[string]any{}); err != nil {
Giorgi Lekveishvili378ea882023-12-12 13:59:18 +0400212 return err
Giorgi Lekveishvili46743d42023-12-10 15:47:23 +0400213 }
Giorgi Lekveishvili378ea882023-12-12 13:59:18 +0400214 return nil
215 })
216 priv := newLeafTask(fmt.Sprintf("Private p.%s", env.Domain), func() error {
gio3cdee592024-04-17 10:15:56 +0400217 app, err := installer.FindEnvApp(st.appsRepo, "certificate-issuer-private")
Giorgi Lekveishvili378ea882023-12-12 13:59:18 +0400218 if err != nil {
219 return err
Giorgi Lekveishvili46743d42023-12-10 15:47:23 +0400220 }
gio44f621b2024-04-29 09:44:38 +0400221 instanceId := app.Slug()
gio3cdee592024-04-17 10:15:56 +0400222 appDir := fmt.Sprintf("/apps/%s", instanceId)
gio3af43942024-04-16 08:13:50 +0400223 namespace := fmt.Sprintf("%s%s", env.NamespacePrefix, app.Namespace())
gio778577f2024-04-29 09:44:38 +0400224 if _, err := st.appManager.Install(app, instanceId, appDir, namespace, map[string]any{}); err != nil {
Giorgi Lekveishvili378ea882023-12-12 13:59:18 +0400225 return err
Giorgi Lekveishvili46743d42023-12-10 15:47:23 +0400226 }
Giorgi Lekveishvili378ea882023-12-12 13:59:18 +0400227 return nil
228 })
Giorgi Lekveishvili5c1b06e2024-03-28 15:19:44 +0400229 return newSequentialParentTask("Configure TLS certificate issuers", false, &pub, &priv)
Giorgi Lekveishvili378ea882023-12-12 13:59:18 +0400230}
231
gioe72b54f2024-04-22 10:44:41 +0400232func SetupAuth(env installer.EnvConfig, st *state) Task {
Giorgi Lekveishvili378ea882023-12-12 13:59:18 +0400233 t := newLeafTask("Setup", func() error {
gio3cdee592024-04-17 10:15:56 +0400234 app, err := installer.FindEnvApp(st.appsRepo, "core-auth")
Giorgi Lekveishvili378ea882023-12-12 13:59:18 +0400235 if err != nil {
236 return err
Giorgi Lekveishvili46743d42023-12-10 15:47:23 +0400237 }
gio44f621b2024-04-29 09:44:38 +0400238 instanceId := app.Slug()
gio3cdee592024-04-17 10:15:56 +0400239 appDir := fmt.Sprintf("/apps/%s", instanceId)
gio3af43942024-04-16 08:13:50 +0400240 namespace := fmt.Sprintf("%s%s", env.NamespacePrefix, app.Namespace())
gio778577f2024-04-29 09:44:38 +0400241 if _, err := st.appManager.Install(app, instanceId, appDir, namespace, map[string]any{
Giorgi Lekveishvilie009a5d2024-01-05 14:10:11 +0400242 "subdomain": "test", // TODO(giolekva): make core-auth chart actually use this
Giorgi Lekveishvili378ea882023-12-12 13:59:18 +0400243 }); err != nil {
244 return err
245 }
246 return nil
247 })
248 return newSequentialParentTask(
249 "Authentication services",
Giorgi Lekveishvili5c1b06e2024-03-28 15:19:44 +0400250 false,
Giorgi Lekveishvili378ea882023-12-12 13:59:18 +0400251 &t,
gioe72b54f2024-04-22 10:44:41 +0400252 waitForAddr(st.httpClient, fmt.Sprintf("https://accounts-ui.%s", env.Domain)),
Giorgi Lekveishvili378ea882023-12-12 13:59:18 +0400253 )
254}
255
gioe72b54f2024-04-22 10:44:41 +0400256func SetupGroupMemberships(env installer.EnvConfig, st *state) Task {
Giorgi Lekveishvilia09fad72024-03-21 15:24:35 +0400257 t := newLeafTask("Setup", func() error {
gio3cdee592024-04-17 10:15:56 +0400258 app, err := installer.FindEnvApp(st.appsRepo, "memberships")
Giorgi Lekveishvilia09fad72024-03-21 15:24:35 +0400259 if err != nil {
260 return err
261 }
gio44f621b2024-04-29 09:44:38 +0400262 instanceId := app.Slug()
gio3cdee592024-04-17 10:15:56 +0400263 appDir := fmt.Sprintf("/apps/%s", instanceId)
gio3af43942024-04-16 08:13:50 +0400264 namespace := fmt.Sprintf("%s%s", env.NamespacePrefix, app.Namespace())
gio778577f2024-04-29 09:44:38 +0400265 if _, err := st.appManager.Install(app, instanceId, appDir, namespace, map[string]any{
Giorgi Lekveishvilid542b732024-03-25 18:17:39 +0400266 "authGroups": strings.Join(initGroups, ","),
267 }); err != nil {
Giorgi Lekveishvilia09fad72024-03-21 15:24:35 +0400268 return err
269 }
270 return nil
271 })
272 return newSequentialParentTask(
Giorgi Lekveishvili5c1b06e2024-03-28 15:19:44 +0400273 "Group membership",
274 false,
Giorgi Lekveishvilia09fad72024-03-21 15:24:35 +0400275 &t,
gioe72b54f2024-04-22 10:44:41 +0400276 waitForAddr(st.httpClient, fmt.Sprintf("https://memberships.p.%s", env.Domain)),
Giorgi Lekveishvilia09fad72024-03-21 15:24:35 +0400277 )
278}
279
gio09a3e5b2024-04-26 14:11:06 +0400280func SetupLauncher(env installer.EnvConfig, st *state) Task {
281 t := newLeafTask("Setup", func() error {
282 user := fmt.Sprintf("%s-launcher", env.Id)
283 keys, err := installer.NewSSHKeyPair(user)
284 if err != nil {
285 return err
286 }
287 if err := st.ssClient.AddUser(user, keys.AuthorizedKey()); err != nil {
288 return err
289 }
290 if err := st.ssClient.AddReadWriteCollaborator("config", user); err != nil {
291 return err
292 }
293 app, err := installer.FindEnvApp(st.appsRepo, "launcher")
294 if err != nil {
295 return err
296 }
297 instanceId := app.Slug()
298 appDir := fmt.Sprintf("/apps/%s", instanceId)
299 namespace := fmt.Sprintf("%s%s", env.NamespacePrefix, app.Namespace())
300 if _, err := st.appManager.Install(app, instanceId, appDir, namespace, map[string]any{
301 "repoAddr": st.ssClient.GetRepoAddress("config"),
302 "sshPrivateKey": string(keys.RawPrivateKey()),
303 }); err != nil {
304 return err
305 }
306 return nil
307 })
308 return newSequentialParentTask(
309 "Launcher",
310 false,
311 &t,
312 waitForAddr(st.httpClient, fmt.Sprintf("https://launcher.%s", env.Domain)),
313 )
314}
315
gioe72b54f2024-04-22 10:44:41 +0400316func SetupHeadscale(env installer.EnvConfig, st *state) Task {
Giorgi Lekveishvili378ea882023-12-12 13:59:18 +0400317 t := newLeafTask("Setup", func() error {
gio3cdee592024-04-17 10:15:56 +0400318 app, err := installer.FindEnvApp(st.appsRepo, "headscale")
Giorgi Lekveishvili378ea882023-12-12 13:59:18 +0400319 if err != nil {
320 return err
321 }
gio44f621b2024-04-29 09:44:38 +0400322 instanceId := app.Slug()
gio3cdee592024-04-17 10:15:56 +0400323 appDir := fmt.Sprintf("/apps/%s", instanceId)
gio3af43942024-04-16 08:13:50 +0400324 namespace := fmt.Sprintf("%s%s", env.NamespacePrefix, app.Namespace())
gio778577f2024-04-29 09:44:38 +0400325 if _, err := st.appManager.Install(app, instanceId, appDir, namespace, map[string]any{
Giorgi Lekveishvilie009a5d2024-01-05 14:10:11 +0400326 "subdomain": "headscale",
gioe72b54f2024-04-22 10:44:41 +0400327 "ipSubnet": fmt.Sprintf("%s/24", env.Network.DNS.String()),
Giorgi Lekveishvili378ea882023-12-12 13:59:18 +0400328 }); err != nil {
329 return err
330 }
331 return nil
332 })
333 return newSequentialParentTask(
Giorgi Lekveishvili5c1b06e2024-03-28 15:19:44 +0400334 "Setup mesh VPN",
335 false,
Giorgi Lekveishvili378ea882023-12-12 13:59:18 +0400336 &t,
gioe72b54f2024-04-22 10:44:41 +0400337 waitForAddr(st.httpClient, fmt.Sprintf("https://headscale.%s/apple", env.Domain)),
Giorgi Lekveishvili378ea882023-12-12 13:59:18 +0400338 )
339}
340
gioe72b54f2024-04-22 10:44:41 +0400341func SetupWelcome(env installer.EnvConfig, st *state) Task {
Giorgi Lekveishvili378ea882023-12-12 13:59:18 +0400342 t := newLeafTask("Setup", func() error {
343 keys, err := installer.NewSSHKeyPair("welcome")
344 if err != nil {
345 return err
346 }
gioe72b54f2024-04-22 10:44:41 +0400347 user := fmt.Sprintf("%s-welcome", env.Id)
Giorgi Lekveishvili378ea882023-12-12 13:59:18 +0400348 if err := st.ssClient.AddUser(user, keys.AuthorizedKey()); err != nil {
349 return err
350 }
351 if err := st.ssClient.AddReadWriteCollaborator("config", user); err != nil {
352 return err
353 }
gio3cdee592024-04-17 10:15:56 +0400354 app, err := installer.FindEnvApp(st.appsRepo, "welcome")
Giorgi Lekveishvili378ea882023-12-12 13:59:18 +0400355 if err != nil {
356 return err
357 }
gio44f621b2024-04-29 09:44:38 +0400358 instanceId := app.Slug()
gio3cdee592024-04-17 10:15:56 +0400359 appDir := fmt.Sprintf("/apps/%s", instanceId)
gio3af43942024-04-16 08:13:50 +0400360 namespace := fmt.Sprintf("%s%s", env.NamespacePrefix, app.Namespace())
gio778577f2024-04-29 09:44:38 +0400361 if _, err := st.appManager.Install(app, instanceId, appDir, namespace, map[string]any{
Giorgi Lekveishvilie009a5d2024-01-05 14:10:11 +0400362 "repoAddr": st.ssClient.GetRepoAddress("config"),
363 "sshPrivateKey": string(keys.RawPrivateKey()),
Giorgi Lekveishvili378ea882023-12-12 13:59:18 +0400364 }); err != nil {
365 return err
366 }
367 return nil
368 })
369 return newSequentialParentTask(
370 "Welcome service",
Giorgi Lekveishvili5c1b06e2024-03-28 15:19:44 +0400371 false,
Giorgi Lekveishvili378ea882023-12-12 13:59:18 +0400372 &t,
gioe72b54f2024-04-22 10:44:41 +0400373 waitForAddr(st.httpClient, fmt.Sprintf("https://welcome.%s", env.Domain)),
Giorgi Lekveishvili378ea882023-12-12 13:59:18 +0400374 )
375}
376
gioe72b54f2024-04-22 10:44:41 +0400377func SetupAppStore(env installer.EnvConfig, st *state) Task {
Giorgi Lekveishvili378ea882023-12-12 13:59:18 +0400378 t := newLeafTask("Application marketplace", func() error {
gioe72b54f2024-04-22 10:44:41 +0400379 user := fmt.Sprintf("%s-appmanager", env.Id)
Giorgi Lekveishvili378ea882023-12-12 13:59:18 +0400380 keys, err := installer.NewSSHKeyPair(user)
381 if err != nil {
382 return err
383 }
384 if err := st.ssClient.AddUser(user, keys.AuthorizedKey()); err != nil {
385 return err
386 }
387 if err := st.ssClient.AddReadWriteCollaborator("config", user); err != nil {
388 return err
389 }
gio3cdee592024-04-17 10:15:56 +0400390 app, err := installer.FindEnvApp(st.appsRepo, "app-manager") // TODO(giolekva): configure
Giorgi Lekveishvili378ea882023-12-12 13:59:18 +0400391 if err != nil {
392 return err
393 }
gio44f621b2024-04-29 09:44:38 +0400394 instanceId := app.Slug()
gio3cdee592024-04-17 10:15:56 +0400395 appDir := fmt.Sprintf("/apps/%s", instanceId)
gio3af43942024-04-16 08:13:50 +0400396 namespace := fmt.Sprintf("%s%s", env.NamespacePrefix, app.Namespace())
gio778577f2024-04-29 09:44:38 +0400397 if _, err := st.appManager.Install(app, instanceId, appDir, namespace, map[string]any{
Giorgi Lekveishvilie009a5d2024-01-05 14:10:11 +0400398 "repoAddr": st.ssClient.GetRepoAddress("config"),
399 "sshPrivateKey": string(keys.RawPrivateKey()),
Giorgi Lekveishvili3c91e8b2024-03-25 20:20:14 +0400400 "authGroups": strings.Join(initGroups, ","),
Giorgi Lekveishvili378ea882023-12-12 13:59:18 +0400401 }); err != nil {
402 return err
Giorgi Lekveishvili46743d42023-12-10 15:47:23 +0400403 }
Giorgi Lekveishvili77ee2dc2023-12-11 16:51:10 +0400404 return nil
405 })
406 return &t
Giorgi Lekveishvili46743d42023-12-10 15:47:23 +0400407}
408
gioe72b54f2024-04-22 10:44:41 +0400409// TODO(gio-dns): remove
Giorgi Lekveishvili46743d42023-12-10 15:47:23 +0400410type DNSSecKey struct {
411 Basename string `json:"basename,omitempty"`
412 Key []byte `json:"key,omitempty"`
413 Private []byte `json:"private,omitempty"`
414 DS []byte `json:"ds,omitempty"`
415}
416
417func newDNSSecKey(zone string) (DNSSecKey, error) {
418 key := &dns.DNSKEY{
419 Hdr: dns.RR_Header{Name: dns.Fqdn(zone), Class: dns.ClassINET, Ttl: 3600, Rrtype: dns.TypeDNSKEY},
420 Algorithm: dns.ECDSAP256SHA256, Flags: 257, Protocol: 3,
421 }
422 priv, err := key.Generate(256)
423 if err != nil {
424 return DNSSecKey{}, err
425 }
426 return DNSSecKey{
427 Basename: fmt.Sprintf("K%s+%03d+%05d", key.Header().Name, key.Algorithm, key.KeyTag()),
428 Key: []byte(key.String()),
429 Private: []byte(key.PrivateKeyString(priv)),
430 DS: []byte(key.ToDS(dns.SHA256).String()),
431 }, nil
432}