blob: f855adf4cedc3dc43e471ab2a381ef5100b9a17f [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 }
giof8843412024-05-22 16:38:05 +040021 appManager, err := installer.NewAppManager(r, st.nsCreator, st.jc, st.hf, "/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 {
gio7841f4f2024-07-26 19:53:49 +040036 tasks := []Task{
gioe72b54f2024-04-22 10:44:41 +040037 SetupNetwork(env, st),
Giorgi Lekveishvili5c1b06e2024-03-28 15:19:44 +040038 SetupCertificateIssuers(env, st),
39 SetupAuth(env, st),
40 SetupGroupMemberships(env, st),
Giorgi Lekveishvili5c1b06e2024-03-28 15:19:44 +040041 SetupWelcome(env, st),
42 SetupAppStore(env, st),
Davit Tabidze56f86a42024-04-09 19:15:25 +040043 SetupLauncher(env, st),
gio7841f4f2024-07-26 19:53:49 +040044 }
45 if env.PrivateDomain != "" {
46 tasks = append(tasks, SetupHeadscale(env, st))
47 }
48 return newConcurrentParentTask(
49 "Setup core services",
50 true,
51 tasks...,
Giorgi Lekveishvili5c1b06e2024-03-28 15:19:44 +040052 )
Giorgi Lekveishvili378ea882023-12-12 13:59:18 +040053}
54
gioe72b54f2024-04-22 10:44:41 +040055func CommitEnvironmentConfiguration(env installer.EnvConfig, st *state) Task {
Giorgi Lekveishvili5c1b06e2024-03-28 15:19:44 +040056 t := newLeafTask("commit config", func() error {
gioe72b54f2024-04-22 10:44:41 +040057 r, err := st.ssClient.GetRepo("config")
Giorgi Lekveishvili378ea882023-12-12 13:59:18 +040058 if err != nil {
Giorgi Lekveishvili77ee2dc2023-12-11 16:51:10 +040059 return err
60 }
gioe72b54f2024-04-22 10:44:41 +040061 r.Do(func(r soft.RepoFS) (string, error) {
62 if err := soft.WriteYaml(r, "config.yaml", env); err != nil {
63 return "", err
gio3af43942024-04-16 08:13:50 +040064 }
gioe72b54f2024-04-22 10:44:41 +040065 rootKust, err := soft.ReadKustomization(r, "kustomization.yaml")
Giorgi Lekveishvili378ea882023-12-12 13:59:18 +040066 if err != nil {
gio3af43942024-04-16 08:13:50 +040067 return "", err
Giorgi Lekveishvili378ea882023-12-12 13:59:18 +040068 }
gioe72b54f2024-04-22 10:44:41 +040069 if err := soft.WriteYaml(r, "kustomization.yaml", rootKust); err != nil {
gio3af43942024-04-16 08:13:50 +040070 return "", err
Giorgi Lekveishvili378ea882023-12-12 13:59:18 +040071 }
gio3af43942024-04-16 08:13:50 +040072 return "configure charts repo", nil
73 })
Giorgi Lekveishvili378ea882023-12-12 13:59:18 +040074 return nil
75 })
76 return &t
77}
78
Giorgi Lekveishvilid542b732024-03-25 18:17:39 +040079type firstAccount struct {
80 Created bool `json:"created"`
81 Groups []string `json:"groups"`
82}
83
gioe72b54f2024-04-22 10:44:41 +040084func ConfigureFirstAccount(env installer.EnvConfig, st *state) Task {
Giorgi Lekveishvilid542b732024-03-25 18:17:39 +040085 t := newLeafTask("Configure first account settings", func() error {
gioe72b54f2024-04-22 10:44:41 +040086 r, err := st.ssClient.GetRepo("config")
Giorgi Lekveishvilid542b732024-03-25 18:17:39 +040087 if err != nil {
88 return err
89 }
gioe72b54f2024-04-22 10:44:41 +040090 return r.Do(func(r soft.RepoFS) (string, error) {
gio3af43942024-04-16 08:13:50 +040091 fa := firstAccount{false, initGroups}
gioe72b54f2024-04-22 10:44:41 +040092 if err := soft.WriteYaml(r, "first-account.yaml", fa); err != nil {
gio3af43942024-04-16 08:13:50 +040093 return "", err
94 }
95 return "first account membership configuration", nil
96 })
Giorgi Lekveishvilid542b732024-03-25 18:17:39 +040097 })
98 return &t
99}
100
gioe72b54f2024-04-22 10:44:41 +0400101func SetupNetwork(env installer.EnvConfig, st *state) Task {
gio7841f4f2024-07-26 19:53:49 +0400102 t := newLeafTask("Setup networks", func() error {
Giorgi Lekveishvili77ee2dc2023-12-11 16:51:10 +0400103 {
gio3cdee592024-04-17 10:15:56 +0400104 app, err := installer.FindEnvApp(st.appsRepo, "metallb-ipaddresspool")
Giorgi Lekveishvili77ee2dc2023-12-11 16:51:10 +0400105 if err != nil {
106 return err
107 }
gio3af43942024-04-16 08:13:50 +0400108 {
gio44f621b2024-04-29 09:44:38 +0400109 instanceId := fmt.Sprintf("%s-ingress-private", app.Slug())
gio3cdee592024-04-17 10:15:56 +0400110 appDir := fmt.Sprintf("/apps/%s", instanceId)
gio3af43942024-04-16 08:13:50 +0400111 namespace := fmt.Sprintf("%s%s-ingress-private", env.NamespacePrefix, app.Namespace())
gio778577f2024-04-29 09:44:38 +0400112 if _, err := st.appManager.Install(app, instanceId, appDir, namespace, map[string]any{
gioe72b54f2024-04-22 10:44:41 +0400113 "name": fmt.Sprintf("%s-ingress-private", env.Id),
114 "from": env.Network.Ingress.String(),
115 "to": env.Network.Ingress.String(),
gio3af43942024-04-16 08:13:50 +0400116 "autoAssign": false,
117 "namespace": "metallb-system",
118 }); err != nil {
119 return err
120 }
Giorgi Lekveishvili77ee2dc2023-12-11 16:51:10 +0400121 }
gio3af43942024-04-16 08:13:50 +0400122 {
gio44f621b2024-04-29 09:44:38 +0400123 instanceId := fmt.Sprintf("%s-headscale", app.Slug())
gio3cdee592024-04-17 10:15:56 +0400124 appDir := fmt.Sprintf("/apps/%s", instanceId)
gio3af43942024-04-16 08:13:50 +0400125 namespace := fmt.Sprintf("%s%s-ingress-private", env.NamespacePrefix, app.Namespace())
gio778577f2024-04-29 09:44:38 +0400126 if _, err := st.appManager.Install(app, instanceId, appDir, namespace, map[string]any{
gioe72b54f2024-04-22 10:44:41 +0400127 "name": fmt.Sprintf("%s-headscale", env.Id),
128 "from": env.Network.Headscale.String(),
129 "to": env.Network.Headscale.String(),
gio3af43942024-04-16 08:13:50 +0400130 "autoAssign": false,
131 "namespace": "metallb-system",
132 }); err != nil {
133 return err
134 }
Giorgi Lekveishvili77ee2dc2023-12-11 16:51:10 +0400135 }
gio3af43942024-04-16 08:13:50 +0400136 {
gio44f621b2024-04-29 09:44:38 +0400137 instanceId := app.Slug()
gio3cdee592024-04-17 10:15:56 +0400138 appDir := fmt.Sprintf("/apps/%s", instanceId)
gio3af43942024-04-16 08:13:50 +0400139 namespace := fmt.Sprintf("%s%s", env.NamespacePrefix, app.Namespace())
gio778577f2024-04-29 09:44:38 +0400140 if _, err := st.appManager.Install(app, instanceId, appDir, namespace, map[string]any{
gioe72b54f2024-04-22 10:44:41 +0400141 "name": env.Id,
142 "from": env.Network.ServicesFrom.String(),
143 "to": env.Network.ServicesTo.String(),
gio3af43942024-04-16 08:13:50 +0400144 "autoAssign": false,
145 "namespace": "metallb-system",
146 }); err != nil {
147 return err
148 }
Giorgi Lekveishvili77ee2dc2023-12-11 16:51:10 +0400149 }
Giorgi Lekveishvili46743d42023-12-10 15:47:23 +0400150 }
gio7841f4f2024-07-26 19:53:49 +0400151 if env.PrivateDomain != "" {
Giorgi Lekveishvilib59b7c22024-04-03 22:17:50 +0400152 keys, err := installer.NewSSHKeyPair("port-allocator")
153 if err != nil {
154 return err
155 }
gioe72b54f2024-04-22 10:44:41 +0400156 user := fmt.Sprintf("%s-port-allocator", env.Id)
Giorgi Lekveishvilib59b7c22024-04-03 22:17:50 +0400157 if err := st.ssClient.AddUser(user, keys.AuthorizedKey()); err != nil {
158 return err
159 }
160 if err := st.ssClient.AddReadWriteCollaborator("config", user); err != nil {
161 return err
162 }
gio3cdee592024-04-17 10:15:56 +0400163 app, err := installer.FindEnvApp(st.appsRepo, "private-network")
Giorgi Lekveishvili77ee2dc2023-12-11 16:51:10 +0400164 if err != nil {
165 return err
166 }
gio44f621b2024-04-29 09:44:38 +0400167 instanceId := app.Slug()
gio3cdee592024-04-17 10:15:56 +0400168 appDir := fmt.Sprintf("/apps/%s", instanceId)
gio3af43942024-04-16 08:13:50 +0400169 namespace := fmt.Sprintf("%s%s", env.NamespacePrefix, app.Namespace())
gio778577f2024-04-29 09:44:38 +0400170 if _, err := st.appManager.Install(app, instanceId, appDir, namespace, map[string]any{
Giorgi Lekveishvilie009a5d2024-01-05 14:10:11 +0400171 "privateNetwork": map[string]any{
172 "hostname": "private-network-proxy",
173 "username": "private-network-proxy",
gioe72b54f2024-04-22 10:44:41 +0400174 "ipSubnet": fmt.Sprintf("%s.0/24", strings.Join(strings.Split(env.Network.DNS.String(), ".")[:3], ".")),
Giorgi Lekveishvili77ee2dc2023-12-11 16:51:10 +0400175 },
Giorgi Lekveishvilib59b7c22024-04-03 22:17:50 +0400176 "sshPrivateKey": string(keys.RawPrivateKey()),
Giorgi Lekveishvili77ee2dc2023-12-11 16:51:10 +0400177 }); err != nil {
178 return err
179 }
Giorgi Lekveishvili46743d42023-12-10 15:47:23 +0400180 }
Giorgi Lekveishvili378ea882023-12-12 13:59:18 +0400181 return nil
182 })
183 return &t
184}
185
gioe72b54f2024-04-22 10:44:41 +0400186func SetupCertificateIssuers(env installer.EnvConfig, st *state) Task {
Giorgi Lekveishvili378ea882023-12-12 13:59:18 +0400187 pub := newLeafTask(fmt.Sprintf("Public %s", env.Domain), func() error {
gio3cdee592024-04-17 10:15:56 +0400188 app, err := installer.FindEnvApp(st.appsRepo, "certificate-issuer-public")
Giorgi Lekveishvili378ea882023-12-12 13:59:18 +0400189 if err != nil {
190 return err
Giorgi Lekveishvili46743d42023-12-10 15:47:23 +0400191 }
gio44f621b2024-04-29 09:44:38 +0400192 instanceId := app.Slug()
gio3cdee592024-04-17 10:15:56 +0400193 appDir := fmt.Sprintf("/apps/%s", instanceId)
gio3af43942024-04-16 08:13:50 +0400194 namespace := fmt.Sprintf("%s%s", env.NamespacePrefix, app.Namespace())
gio7841f4f2024-07-26 19:53:49 +0400195 if _, err := st.appManager.Install(app, instanceId, appDir, namespace, map[string]any{
196 "network": "Public",
197 }); err != nil {
Giorgi Lekveishvili378ea882023-12-12 13:59:18 +0400198 return err
Giorgi Lekveishvili46743d42023-12-10 15:47:23 +0400199 }
Giorgi Lekveishvili378ea882023-12-12 13:59:18 +0400200 return nil
201 })
gio7841f4f2024-07-26 19:53:49 +0400202 tasks := []Task{&pub}
203 if env.PrivateDomain != "" {
204 priv := newLeafTask(fmt.Sprintf("Private p.%s", env.Domain), func() error {
205 app, err := installer.FindEnvApp(st.appsRepo, "certificate-issuer-private")
206 if err != nil {
207 return err
208 }
209 instanceId := app.Slug()
210 appDir := fmt.Sprintf("/apps/%s", instanceId)
211 namespace := fmt.Sprintf("%s%s", env.NamespacePrefix, app.Namespace())
212 if _, err := st.appManager.Install(app, instanceId, appDir, namespace, map[string]any{}); err != nil {
213 return err
214 }
215 return nil
216 })
217 tasks = append(tasks, &priv)
218 }
219 return newSequentialParentTask("Configure TLS certificate issuers", false, tasks...)
Giorgi Lekveishvili378ea882023-12-12 13:59:18 +0400220}
221
gioe72b54f2024-04-22 10:44:41 +0400222func SetupAuth(env installer.EnvConfig, st *state) Task {
Giorgi Lekveishvili378ea882023-12-12 13:59:18 +0400223 t := newLeafTask("Setup", func() error {
gio3cdee592024-04-17 10:15:56 +0400224 app, err := installer.FindEnvApp(st.appsRepo, "core-auth")
Giorgi Lekveishvili378ea882023-12-12 13:59:18 +0400225 if err != nil {
226 return err
Giorgi Lekveishvili46743d42023-12-10 15:47:23 +0400227 }
gio44f621b2024-04-29 09:44:38 +0400228 instanceId := app.Slug()
gio3cdee592024-04-17 10:15:56 +0400229 appDir := fmt.Sprintf("/apps/%s", instanceId)
gio3af43942024-04-16 08:13:50 +0400230 namespace := fmt.Sprintf("%s%s", env.NamespacePrefix, app.Namespace())
gio778577f2024-04-29 09:44:38 +0400231 if _, err := st.appManager.Install(app, instanceId, appDir, namespace, map[string]any{
gio7841f4f2024-07-26 19:53:49 +0400232 "network": "Public",
Giorgi Lekveishvilie009a5d2024-01-05 14:10:11 +0400233 "subdomain": "test", // TODO(giolekva): make core-auth chart actually use this
Giorgi Lekveishvili378ea882023-12-12 13:59:18 +0400234 }); err != nil {
235 return err
236 }
237 return nil
238 })
239 return newSequentialParentTask(
240 "Authentication services",
Giorgi Lekveishvili5c1b06e2024-03-28 15:19:44 +0400241 false,
Giorgi Lekveishvili378ea882023-12-12 13:59:18 +0400242 &t,
gioe72b54f2024-04-22 10:44:41 +0400243 waitForAddr(st.httpClient, fmt.Sprintf("https://accounts-ui.%s", env.Domain)),
Giorgi Lekveishvili378ea882023-12-12 13:59:18 +0400244 )
245}
246
gioe72b54f2024-04-22 10:44:41 +0400247func SetupGroupMemberships(env installer.EnvConfig, st *state) Task {
Giorgi Lekveishvilia09fad72024-03-21 15:24:35 +0400248 t := newLeafTask("Setup", func() error {
gio3cdee592024-04-17 10:15:56 +0400249 app, err := installer.FindEnvApp(st.appsRepo, "memberships")
Giorgi Lekveishvilia09fad72024-03-21 15:24:35 +0400250 if err != nil {
251 return err
252 }
gio44f621b2024-04-29 09:44:38 +0400253 instanceId := app.Slug()
gio3cdee592024-04-17 10:15:56 +0400254 appDir := fmt.Sprintf("/apps/%s", instanceId)
gio3af43942024-04-16 08:13:50 +0400255 namespace := fmt.Sprintf("%s%s", env.NamespacePrefix, app.Namespace())
gio7841f4f2024-07-26 19:53:49 +0400256 network := "Public"
257 if env.PrivateDomain != "" {
258 network = "Private"
259 }
gio778577f2024-04-29 09:44:38 +0400260 if _, err := st.appManager.Install(app, instanceId, appDir, namespace, map[string]any{
gio7841f4f2024-07-26 19:53:49 +0400261 "network": network,
Giorgi Lekveishvilid542b732024-03-25 18:17:39 +0400262 "authGroups": strings.Join(initGroups, ","),
263 }); err != nil {
Giorgi Lekveishvilia09fad72024-03-21 15:24:35 +0400264 return err
265 }
266 return nil
267 })
giob79db3a2024-08-01 14:20:42 +0400268 var addr string
269 if env.PrivateDomain != "" {
270 addr = fmt.Sprintf("https://memberships.%s", env.PrivateDomain)
271 } else {
272 addr = fmt.Sprintf("https://memberships.%s", env.Domain)
273 }
Giorgi Lekveishvilia09fad72024-03-21 15:24:35 +0400274 return newSequentialParentTask(
Giorgi Lekveishvili5c1b06e2024-03-28 15:19:44 +0400275 "Group membership",
276 false,
Giorgi Lekveishvilia09fad72024-03-21 15:24:35 +0400277 &t,
giob79db3a2024-08-01 14:20:42 +0400278 waitForAddr(st.httpClient, addr),
Giorgi Lekveishvilia09fad72024-03-21 15:24:35 +0400279 )
280}
281
gio09a3e5b2024-04-26 14:11:06 +0400282func SetupLauncher(env installer.EnvConfig, st *state) Task {
283 t := newLeafTask("Setup", func() error {
284 user := fmt.Sprintf("%s-launcher", env.Id)
285 keys, err := installer.NewSSHKeyPair(user)
286 if err != nil {
287 return err
288 }
289 if err := st.ssClient.AddUser(user, keys.AuthorizedKey()); err != nil {
290 return err
291 }
292 if err := st.ssClient.AddReadWriteCollaborator("config", user); err != nil {
293 return err
294 }
295 app, err := installer.FindEnvApp(st.appsRepo, "launcher")
296 if err != nil {
297 return err
298 }
299 instanceId := app.Slug()
300 appDir := fmt.Sprintf("/apps/%s", instanceId)
301 namespace := fmt.Sprintf("%s%s", env.NamespacePrefix, app.Namespace())
302 if _, err := st.appManager.Install(app, instanceId, appDir, namespace, map[string]any{
gio7841f4f2024-07-26 19:53:49 +0400303 "network": "Public",
gio09a3e5b2024-04-26 14:11:06 +0400304 "repoAddr": st.ssClient.GetRepoAddress("config"),
305 "sshPrivateKey": string(keys.RawPrivateKey()),
306 }); err != nil {
307 return err
308 }
309 return nil
310 })
311 return newSequentialParentTask(
312 "Launcher",
313 false,
314 &t,
315 waitForAddr(st.httpClient, fmt.Sprintf("https://launcher.%s", env.Domain)),
316 )
317}
318
gioe72b54f2024-04-22 10:44:41 +0400319func SetupHeadscale(env installer.EnvConfig, st *state) Task {
Giorgi Lekveishvili378ea882023-12-12 13:59:18 +0400320 t := newLeafTask("Setup", func() error {
gio3cdee592024-04-17 10:15:56 +0400321 app, err := installer.FindEnvApp(st.appsRepo, "headscale")
Giorgi Lekveishvili378ea882023-12-12 13:59:18 +0400322 if err != nil {
323 return err
324 }
gio44f621b2024-04-29 09:44:38 +0400325 instanceId := app.Slug()
gio3cdee592024-04-17 10:15:56 +0400326 appDir := fmt.Sprintf("/apps/%s", instanceId)
gio3af43942024-04-16 08:13:50 +0400327 namespace := fmt.Sprintf("%s%s", env.NamespacePrefix, app.Namespace())
gio778577f2024-04-29 09:44:38 +0400328 if _, err := st.appManager.Install(app, instanceId, appDir, namespace, map[string]any{
gio7841f4f2024-07-26 19:53:49 +0400329 "network": "Public",
Giorgi Lekveishvilie009a5d2024-01-05 14:10:11 +0400330 "subdomain": "headscale",
gioe72b54f2024-04-22 10:44:41 +0400331 "ipSubnet": fmt.Sprintf("%s/24", env.Network.DNS.String()),
Giorgi Lekveishvili378ea882023-12-12 13:59:18 +0400332 }); err != nil {
333 return err
334 }
335 return nil
336 })
337 return newSequentialParentTask(
Giorgi Lekveishvili5c1b06e2024-03-28 15:19:44 +0400338 "Setup mesh VPN",
339 false,
Giorgi Lekveishvili378ea882023-12-12 13:59:18 +0400340 &t,
gioe72b54f2024-04-22 10:44:41 +0400341 waitForAddr(st.httpClient, fmt.Sprintf("https://headscale.%s/apple", env.Domain)),
Giorgi Lekveishvili378ea882023-12-12 13:59:18 +0400342 )
343}
344
gioe72b54f2024-04-22 10:44:41 +0400345func SetupWelcome(env installer.EnvConfig, st *state) Task {
Giorgi Lekveishvili378ea882023-12-12 13:59:18 +0400346 t := newLeafTask("Setup", func() error {
347 keys, err := installer.NewSSHKeyPair("welcome")
348 if err != nil {
349 return err
350 }
gioe72b54f2024-04-22 10:44:41 +0400351 user := fmt.Sprintf("%s-welcome", env.Id)
Giorgi Lekveishvili378ea882023-12-12 13:59:18 +0400352 if err := st.ssClient.AddUser(user, keys.AuthorizedKey()); err != nil {
353 return err
354 }
355 if err := st.ssClient.AddReadWriteCollaborator("config", user); err != nil {
356 return err
357 }
gio3cdee592024-04-17 10:15:56 +0400358 app, err := installer.FindEnvApp(st.appsRepo, "welcome")
Giorgi Lekveishvili378ea882023-12-12 13:59:18 +0400359 if err != nil {
360 return err
361 }
gio44f621b2024-04-29 09:44:38 +0400362 instanceId := app.Slug()
gio3cdee592024-04-17 10:15:56 +0400363 appDir := fmt.Sprintf("/apps/%s", instanceId)
gio3af43942024-04-16 08:13:50 +0400364 namespace := fmt.Sprintf("%s%s", env.NamespacePrefix, app.Namespace())
gio778577f2024-04-29 09:44:38 +0400365 if _, err := st.appManager.Install(app, instanceId, appDir, namespace, map[string]any{
gio7841f4f2024-07-26 19:53:49 +0400366 "network": "Public",
Giorgi Lekveishvilie009a5d2024-01-05 14:10:11 +0400367 "repoAddr": st.ssClient.GetRepoAddress("config"),
368 "sshPrivateKey": string(keys.RawPrivateKey()),
Giorgi Lekveishvili378ea882023-12-12 13:59:18 +0400369 }); err != nil {
370 return err
371 }
372 return nil
373 })
374 return newSequentialParentTask(
375 "Welcome service",
Giorgi Lekveishvili5c1b06e2024-03-28 15:19:44 +0400376 false,
Giorgi Lekveishvili378ea882023-12-12 13:59:18 +0400377 &t,
gioe72b54f2024-04-22 10:44:41 +0400378 waitForAddr(st.httpClient, fmt.Sprintf("https://welcome.%s", env.Domain)),
Giorgi Lekveishvili378ea882023-12-12 13:59:18 +0400379 )
380}
381
gioe72b54f2024-04-22 10:44:41 +0400382func SetupAppStore(env installer.EnvConfig, st *state) Task {
giob79db3a2024-08-01 14:20:42 +0400383 t := newLeafTask("Setup", func() error {
gioe72b54f2024-04-22 10:44:41 +0400384 user := fmt.Sprintf("%s-appmanager", env.Id)
Giorgi Lekveishvili378ea882023-12-12 13:59:18 +0400385 keys, err := installer.NewSSHKeyPair(user)
386 if err != nil {
387 return err
388 }
389 if err := st.ssClient.AddUser(user, keys.AuthorizedKey()); err != nil {
390 return err
391 }
392 if err := st.ssClient.AddReadWriteCollaborator("config", user); err != nil {
393 return err
394 }
gio3cdee592024-04-17 10:15:56 +0400395 app, err := installer.FindEnvApp(st.appsRepo, "app-manager") // TODO(giolekva): configure
Giorgi Lekveishvili378ea882023-12-12 13:59:18 +0400396 if err != nil {
397 return err
398 }
gio44f621b2024-04-29 09:44:38 +0400399 instanceId := app.Slug()
gio3cdee592024-04-17 10:15:56 +0400400 appDir := fmt.Sprintf("/apps/%s", instanceId)
gio3af43942024-04-16 08:13:50 +0400401 namespace := fmt.Sprintf("%s%s", env.NamespacePrefix, app.Namespace())
gio7841f4f2024-07-26 19:53:49 +0400402 network := "Public"
403 if env.PrivateDomain != "" {
404 network = "Private"
405 }
gio778577f2024-04-29 09:44:38 +0400406 if _, err := st.appManager.Install(app, instanceId, appDir, namespace, map[string]any{
gio7841f4f2024-07-26 19:53:49 +0400407 "network": network,
Giorgi Lekveishvilie009a5d2024-01-05 14:10:11 +0400408 "repoAddr": st.ssClient.GetRepoAddress("config"),
409 "sshPrivateKey": string(keys.RawPrivateKey()),
Giorgi Lekveishvili3c91e8b2024-03-25 20:20:14 +0400410 "authGroups": strings.Join(initGroups, ","),
Giorgi Lekveishvili378ea882023-12-12 13:59:18 +0400411 }); err != nil {
412 return err
Giorgi Lekveishvili46743d42023-12-10 15:47:23 +0400413 }
Giorgi Lekveishvili77ee2dc2023-12-11 16:51:10 +0400414 return nil
415 })
giob79db3a2024-08-01 14:20:42 +0400416 var addr string
417 if env.PrivateDomain != "" {
418 addr = fmt.Sprintf("https://apps.%s", env.PrivateDomain)
419 } else {
420 addr = fmt.Sprintf("https://apps.%s", env.Domain)
421 }
422 return newSequentialParentTask(
423 "Application marketplace",
424 false,
425 &t,
426 waitForAddr(st.httpClient, addr),
427 )
Giorgi Lekveishvili46743d42023-12-10 15:47:23 +0400428}
429
gioe72b54f2024-04-22 10:44:41 +0400430// TODO(gio-dns): remove
Giorgi Lekveishvili46743d42023-12-10 15:47:23 +0400431type DNSSecKey struct {
432 Basename string `json:"basename,omitempty"`
433 Key []byte `json:"key,omitempty"`
434 Private []byte `json:"private,omitempty"`
435 DS []byte `json:"ds,omitempty"`
436}
437
438func newDNSSecKey(zone string) (DNSSecKey, error) {
439 key := &dns.DNSKEY{
440 Hdr: dns.RR_Header{Name: dns.Fqdn(zone), Class: dns.ClassINET, Ttl: 3600, Rrtype: dns.TypeDNSKEY},
441 Algorithm: dns.ECDSAP256SHA256, Flags: 257, Protocol: 3,
442 }
443 priv, err := key.Generate(256)
444 if err != nil {
445 return DNSSecKey{}, err
446 }
447 return DNSSecKey{
448 Basename: fmt.Sprintf("K%s+%03d+%05d", key.Header().Name, key.Algorithm, key.KeyTag()),
449 Key: []byte(key.String()),
450 Private: []byte(key.PrivateKeyString(priv)),
451 DS: []byte(key.ToDS(dns.SHA256).String()),
452 }, nil
453}