installer: split up new env creation into chain of tasks
diff --git a/core/installer/tasks/dns.go b/core/installer/tasks/dns.go
new file mode 100644
index 0000000..60a8a9d
--- /dev/null
+++ b/core/installer/tasks/dns.go
@@ -0,0 +1,149 @@
+package tasks
+
+import (
+ "context"
+ "fmt"
+ "net"
+ "text/template"
+ "time"
+
+ "github.com/Masterminds/sprig/v3"
+
+ "github.com/giolekva/pcloud/core/installer"
+)
+
+type dnsResolver struct {
+ basicTask
+ name string
+ expected []net.IP
+ ctx context.Context
+ env Env
+ st *state
+}
+
+func NewDNSResolverTask(
+ name string,
+ expected []net.IP,
+ ctx context.Context,
+ env Env,
+ st *state,
+) Task {
+ return &dnsResolver{
+ basicTask: basicTask{
+ title: "Configure DNS",
+ },
+ name: name,
+ expected: expected,
+ ctx: ctx,
+ env: env,
+ st: st,
+ }
+}
+
+func (t *dnsResolver) Start() {
+ repo, err := t.st.ssClient.GetRepo("config")
+ if err != nil {
+ t.callDoneListeners(err)
+ return
+ }
+ r := installer.NewRepoIO(repo, t.st.ssClient.Signer)
+ {
+ key, err := newDNSSecKey(t.env.Domain)
+ if err != nil {
+ t.callDoneListeners(err)
+ return
+ }
+ out, err := r.Writer("dns-zone.yaml")
+ if err != nil {
+ t.callDoneListeners(err)
+ return
+ }
+ defer out.Close()
+ dnsZoneTmpl, err := template.New("config").Funcs(sprig.TxtFuncMap()).Parse(`
+apiVersion: dodo.cloud.dodo.cloud/v1
+kind: DNSZone
+metadata:
+ name: dns-zone
+ namespace: {{ .namespace }}
+spec:
+ zone: {{ .zone }}
+ privateIP: 10.1.0.1
+ publicIPs:
+{{ range .publicIPs }}
+ - {{ .String }}
+{{ end }}
+ nameservers:
+{{ range .publicIPs }}
+ - {{ .String }}
+{{ end }}
+ dnssec:
+ enabled: true
+ secretName: dnssec-key
+---
+apiVersion: v1
+kind: Secret
+metadata:
+ name: dnssec-key
+ namespace: {{ .namespace }}
+type: Opaque
+data:
+ basename: {{ .dnssec.Basename | b64enc }}
+ key: {{ .dnssec.Key | toString | b64enc }}
+ private: {{ .dnssec.Private | toString | b64enc }}
+ ds: {{ .dnssec.DS | toString | b64enc }}
+`)
+ if err != nil {
+ t.callDoneListeners(err)
+ return
+ }
+ if err := dnsZoneTmpl.Execute(out, map[string]any{
+ "namespace": t.env.Name,
+ "zone": t.env.Domain,
+ "dnssec": key,
+ "publicIPs": t.st.publicIPs,
+ }); err != nil {
+ t.callDoneListeners(err)
+ return
+ }
+ rootKust := installer.NewKustomization()
+ rootKust.AddResources("dns-zone.yaml")
+ if err := r.WriteKustomization("kustomization.yaml", rootKust); err != nil {
+ t.callDoneListeners(err)
+ return
+ }
+ r.CommitAndPush("configure dns zone")
+ }
+
+ gotExpectedIPs := func(actual []net.IP) bool {
+ for _, a := range actual {
+ found := false
+ for _, e := range t.expected {
+ if a.Equal(e) {
+ found = true
+ break
+ }
+ }
+ if !found {
+ return false
+ }
+ }
+ return true
+ }
+ check := func(check Check) {
+ addrs, err := net.LookupIP(t.name)
+ if err == nil && gotExpectedIPs(addrs) {
+ t.callDoneListeners(nil)
+ return
+ }
+ select {
+ case <-t.ctx.Done():
+ t.callDoneListeners(fmt.Errorf("deadline exceeded"))
+ return
+ case <-time.After(5 * time.Second):
+ check(check)
+ }
+ }
+ check(check)
+}
+
+type Check func(ch Check)