blob: 65ef787663c2b7c8b95bf68073489f31791256a0 [file] [log] [blame]
Giorgi Lekveishvili46743d42023-12-10 15:47:23 +04001package tasks
2
3import (
4 "context"
Giorgi Lekveishvili378ea882023-12-12 13:59:18 +04005 "fmt"
Giorgi Lekveishvili46743d42023-12-10 15:47:23 +04006 "net"
7 "text/template"
8 "time"
9
10 "github.com/Masterminds/sprig/v3"
11
12 "github.com/giolekva/pcloud/core/installer"
13)
14
Giorgi Lekveishvili77ee2dc2023-12-11 16:51:10 +040015type Check func(ch Check) error
Giorgi Lekveishvili46743d42023-12-10 15:47:23 +040016
Giorgi Lekveishvili9d5e3f52024-03-13 15:02:50 +040017func SetupZoneTask(env Env, ingressIP net.IP, st *state) Task {
Giorgi Lekveishviliab7ff6e2024-03-29 13:11:30 +040018 ret := newSequentialParentTask(
Giorgi Lekveishvili5c1b06e2024-03-28 15:19:44 +040019 "Configure DNS",
20 true,
Giorgi Lekveishvili9d5e3f52024-03-13 15:02:50 +040021 CreateZoneRecords(env.Domain, st.publicIPs, ingressIP, env, st),
Giorgi Lekveishvili378ea882023-12-12 13:59:18 +040022 WaitToPropagate(env.Domain, st.publicIPs),
23 )
Giorgi Lekveishviliab7ff6e2024-03-29 13:11:30 +040024 ret.beforeStart = func() {
25 st.infoListener(fmt.Sprintf("Generating DNS zone records for %s", env.Domain))
26 }
27 ret.afterDone = func() {
28 st.infoListener("DNS zone records have been propagated.")
29 }
30 return ret
Giorgi Lekveishvili378ea882023-12-12 13:59:18 +040031}
32
33func CreateZoneRecords(
Giorgi Lekveishvili46743d42023-12-10 15:47:23 +040034 name string,
35 expected []net.IP,
Giorgi Lekveishvili9d5e3f52024-03-13 15:02:50 +040036 ingressIP net.IP,
Giorgi Lekveishvili46743d42023-12-10 15:47:23 +040037 env Env,
38 st *state,
39) Task {
Giorgi Lekveishvili5c1b06e2024-03-28 15:19:44 +040040 t := newLeafTask("Generate and publish DNS records", func() error {
gio3af43942024-04-16 08:13:50 +040041 key, err := newDNSSecKey(env.Domain)
42 if err != nil {
43 return err
44 }
Giorgi Lekveishvili77ee2dc2023-12-11 16:51:10 +040045 repo, err := st.ssClient.GetRepo("config")
Giorgi Lekveishvili46743d42023-12-10 15:47:23 +040046 if err != nil {
Giorgi Lekveishvili77ee2dc2023-12-11 16:51:10 +040047 return err
Giorgi Lekveishvili46743d42023-12-10 15:47:23 +040048 }
gio3af43942024-04-16 08:13:50 +040049 r, err := installer.NewRepoIO(repo, st.ssClient.Signer)
50 if err != nil {
51 return err
52 }
53 return r.Atomic(func(r installer.RepoFS) (string, error) {
54 {
55 out, err := r.Writer("dns-zone.yaml")
56 if err != nil {
57 return "", err
58 }
59 defer out.Close()
60 dnsZoneTmpl, err := template.New("config").Funcs(sprig.TxtFuncMap()).Parse(`
Giorgi Lekveishvili46743d42023-12-10 15:47:23 +040061apiVersion: dodo.cloud.dodo.cloud/v1
62kind: DNSZone
63metadata:
64 name: dns-zone
65 namespace: {{ .namespace }}
66spec:
67 zone: {{ .zone }}
Giorgi Lekveishvili9d5e3f52024-03-13 15:02:50 +040068 privateIP: {{ .ingressIP }}
Giorgi Lekveishvili46743d42023-12-10 15:47:23 +040069 publicIPs:
70{{ range .publicIPs }}
71 - {{ .String }}
72{{ end }}
73 nameservers:
74{{ range .publicIPs }}
75 - {{ .String }}
76{{ end }}
77 dnssec:
78 enabled: true
79 secretName: dnssec-key
80---
81apiVersion: v1
82kind: Secret
83metadata:
84 name: dnssec-key
85 namespace: {{ .namespace }}
86type: Opaque
87data:
88 basename: {{ .dnssec.Basename | b64enc }}
89 key: {{ .dnssec.Key | toString | b64enc }}
90 private: {{ .dnssec.Private | toString | b64enc }}
91 ds: {{ .dnssec.DS | toString | b64enc }}
92`)
gio3af43942024-04-16 08:13:50 +040093 if err != nil {
94 return "", err
95 }
96 if err := dnsZoneTmpl.Execute(out, map[string]any{
97 "namespace": env.Name,
98 "zone": env.Domain,
99 "dnssec": key,
100 "publicIPs": st.publicIPs,
101 "ingressIP": ingressIP.String(),
102 }); err != nil {
103 return "", err
104 }
105 rootKust, err := installer.ReadKustomization(r, "kustomization.yaml")
106 if err != nil {
107 return "", err
108 }
109 rootKust.AddResources("dns-zone.yaml")
110 if err := installer.WriteYaml(r, "kustomization.yaml", rootKust); err != nil {
111 return "", err
112 }
113 return "configure dns zone", nil
Giorgi Lekveishvili77ee2dc2023-12-11 16:51:10 +0400114 }
gio3af43942024-04-16 08:13:50 +0400115 })
Giorgi Lekveishvili378ea882023-12-12 13:59:18 +0400116 })
117 return &t
118}
Giorgi Lekveishvili46743d42023-12-10 15:47:23 +0400119
Giorgi Lekveishvili378ea882023-12-12 13:59:18 +0400120func WaitToPropagate(
121 name string,
122 expected []net.IP,
123) Task {
Giorgi Lekveishvili5c1b06e2024-03-28 15:19:44 +0400124 t := newLeafTask("Wait to propagate", func() error {
Giorgi Lekveishvilib59b7c22024-04-03 22:17:50 +0400125 time.Sleep(2 * time.Minute)
126 return nil
Giorgi Lekveishvili378ea882023-12-12 13:59:18 +0400127 ctx := context.TODO()
Giorgi Lekveishvili77ee2dc2023-12-11 16:51:10 +0400128 gotExpectedIPs := func(actual []net.IP) bool {
129 for _, a := range actual {
130 found := false
131 for _, e := range expected {
132 if a.Equal(e) {
133 found = true
134 break
135 }
136 }
137 if !found {
138 return false
Giorgi Lekveishvili46743d42023-12-10 15:47:23 +0400139 }
140 }
Giorgi Lekveishvili77ee2dc2023-12-11 16:51:10 +0400141 return true
142 }
143 check := func(check Check) error {
144 addrs, err := net.LookupIP(name)
Giorgi Lekveishvili1caed362023-12-13 16:29:43 +0400145 fmt.Printf("DNS LOOKUP: %+v\n", addrs)
Giorgi Lekveishvili77ee2dc2023-12-11 16:51:10 +0400146 if err == nil && gotExpectedIPs(addrs) {
147 return err
148 }
149 select {
150 case <-ctx.Done():
151 return nil
152 case <-time.After(5 * time.Second):
153 return check(check)
Giorgi Lekveishvili46743d42023-12-10 15:47:23 +0400154 }
155 }
Giorgi Lekveishvili77ee2dc2023-12-11 16:51:10 +0400156 return check(check)
157 })
158 return &t
Giorgi Lekveishvili46743d42023-12-10 15:47:23 +0400159}