blob: 13c4b58318fd5d407d7261b9d7021bf7ee152cba [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 {
Giorgi Lekveishvili77ee2dc2023-12-11 16:51:10 +040041 repo, err := st.ssClient.GetRepo("config")
Giorgi Lekveishvili46743d42023-12-10 15:47:23 +040042 if err != nil {
Giorgi Lekveishvili77ee2dc2023-12-11 16:51:10 +040043 return err
Giorgi Lekveishvili46743d42023-12-10 15:47:23 +040044 }
Giorgi Lekveishvili77ee2dc2023-12-11 16:51:10 +040045 r := installer.NewRepoIO(repo, st.ssClient.Signer)
46 {
47 key, err := newDNSSecKey(env.Domain)
48 if err != nil {
49 return err
50 }
51 out, err := r.Writer("dns-zone.yaml")
52 if err != nil {
53 return err
54 }
55 defer out.Close()
56 dnsZoneTmpl, err := template.New("config").Funcs(sprig.TxtFuncMap()).Parse(`
Giorgi Lekveishvili46743d42023-12-10 15:47:23 +040057apiVersion: dodo.cloud.dodo.cloud/v1
58kind: DNSZone
59metadata:
60 name: dns-zone
61 namespace: {{ .namespace }}
62spec:
63 zone: {{ .zone }}
Giorgi Lekveishvili9d5e3f52024-03-13 15:02:50 +040064 privateIP: {{ .ingressIP }}
Giorgi Lekveishvili46743d42023-12-10 15:47:23 +040065 publicIPs:
66{{ range .publicIPs }}
67 - {{ .String }}
68{{ end }}
69 nameservers:
70{{ range .publicIPs }}
71 - {{ .String }}
72{{ end }}
73 dnssec:
74 enabled: true
75 secretName: dnssec-key
76---
77apiVersion: v1
78kind: Secret
79metadata:
80 name: dnssec-key
81 namespace: {{ .namespace }}
82type: Opaque
83data:
84 basename: {{ .dnssec.Basename | b64enc }}
85 key: {{ .dnssec.Key | toString | b64enc }}
86 private: {{ .dnssec.Private | toString | b64enc }}
87 ds: {{ .dnssec.DS | toString | b64enc }}
88`)
Giorgi Lekveishvili77ee2dc2023-12-11 16:51:10 +040089 if err != nil {
90 return err
91 }
92 if err := dnsZoneTmpl.Execute(out, map[string]any{
93 "namespace": env.Name,
94 "zone": env.Domain,
95 "dnssec": key,
96 "publicIPs": st.publicIPs,
Giorgi Lekveishvili9d5e3f52024-03-13 15:02:50 +040097 "ingressIP": ingressIP.String(),
Giorgi Lekveishvili77ee2dc2023-12-11 16:51:10 +040098 }); err != nil {
99 return err
100 }
Giorgi Lekveishvili5c1b06e2024-03-28 15:19:44 +0400101 rootKust, err := r.ReadKustomization("kustomization.yaml")
102 if err != nil {
Giorgi Lekveishvili77ee2dc2023-12-11 16:51:10 +0400103 return err
104 }
Giorgi Lekveishvili5c1b06e2024-03-28 15:19:44 +0400105 rootKust.AddResources("dns-zone.yaml")
106 if err := r.WriteKustomization("kustomization.yaml", *rootKust); err != nil {
107 return err
108 }
109 if err := r.CommitAndPush("configure dns zone"); err != nil {
110 return err
111 }
Giorgi Lekveishvili46743d42023-12-10 15:47:23 +0400112 }
Giorgi Lekveishvili378ea882023-12-12 13:59:18 +0400113 return nil
114 })
115 return &t
116}
Giorgi Lekveishvili46743d42023-12-10 15:47:23 +0400117
Giorgi Lekveishvili378ea882023-12-12 13:59:18 +0400118func WaitToPropagate(
119 name string,
120 expected []net.IP,
121) Task {
Giorgi Lekveishvili5c1b06e2024-03-28 15:19:44 +0400122 t := newLeafTask("Wait to propagate", func() error {
Giorgi Lekveishvilib59b7c22024-04-03 22:17:50 +0400123 time.Sleep(2 * time.Minute)
124 return nil
Giorgi Lekveishvili378ea882023-12-12 13:59:18 +0400125 ctx := context.TODO()
Giorgi Lekveishvili77ee2dc2023-12-11 16:51:10 +0400126 gotExpectedIPs := func(actual []net.IP) bool {
127 for _, a := range actual {
128 found := false
129 for _, e := range expected {
130 if a.Equal(e) {
131 found = true
132 break
133 }
134 }
135 if !found {
136 return false
Giorgi Lekveishvili46743d42023-12-10 15:47:23 +0400137 }
138 }
Giorgi Lekveishvili77ee2dc2023-12-11 16:51:10 +0400139 return true
140 }
141 check := func(check Check) error {
142 addrs, err := net.LookupIP(name)
Giorgi Lekveishvili1caed362023-12-13 16:29:43 +0400143 fmt.Printf("DNS LOOKUP: %+v\n", addrs)
Giorgi Lekveishvili77ee2dc2023-12-11 16:51:10 +0400144 if err == nil && gotExpectedIPs(addrs) {
145 return err
146 }
147 select {
148 case <-ctx.Done():
149 return nil
150 case <-time.After(5 * time.Second):
151 return check(check)
Giorgi Lekveishvili46743d42023-12-10 15:47:23 +0400152 }
153 }
Giorgi Lekveishvili77ee2dc2023-12-11 16:51:10 +0400154 return check(check)
155 })
156 return &t
Giorgi Lekveishvili46743d42023-12-10 15:47:23 +0400157}