blob: 7db2c3a067777e0244aa40002f868cf468f3d316 [file] [log] [blame]
package tasks
import (
"context"
"encoding/json"
"fmt"
"net"
"strings"
"time"
"github.com/giolekva/pcloud/core/installer"
"github.com/giolekva/pcloud/core/installer/dns"
)
type Check func(ch Check) error
func SetupZoneTask(env installer.EnvConfig, mgr *installer.InfraAppManager, st *state) Task {
ret := newSequentialParentTask(
"Configure DNS",
true,
SetupDNSServer(env, st),
WaitToPropagate(st.dnsClient, env.Domain, env.PublicIP),
)
ret.beforeStart = func() {
st.infoListener(fmt.Sprintf("Generating DNS zone records for %s", env.Domain))
}
ret.afterDone = func() {
st.infoListener("DNS zone records have been propagated.")
}
return ret
}
func join[T fmt.Stringer](items []T, sep string) string {
var tmp []string
for _, i := range items {
tmp = append(tmp, i.String())
}
return strings.Join(tmp, ",")
}
func SetupDNSServer(env installer.EnvConfig, st *state) Task {
t := newLeafTask("Start up DNS server", func() error {
addressPool := fmt.Sprintf("%s-dns", env.Id)
{
app, err := installer.FindEnvApp(st.appsRepo, "env-dns")
if err != nil {
return err
}
instanceId := app.Slug()
appDir := fmt.Sprintf("/apps/%s", instanceId)
namespace := fmt.Sprintf("%s%s", env.NamespacePrefix, app.Namespace())
if _, err := st.appManager.Install(app, instanceId, appDir, namespace, map[string]any{
"addressPool": addressPool,
"inClusterIP": env.Network.DNSInClusterIP.String(),
"publicIP": join(env.PublicIP, ","),
"privateIP": env.Network.Ingress.String(),
"nameserverIP": join(env.NameserverIP, ","),
}); err != nil {
return err
}
}
{
cfg, err := st.infraAppManager.FindInstance("dns-gateway")
if err != nil {
return err
}
serversJSON, ok := cfg.Values["servers"]
if !ok {
serversJSON = []installer.EnvDNS{}
}
serversTmp, err := json.Marshal(serversJSON)
if err != nil {
return err
}
servers := []installer.EnvDNS{}
if err := json.Unmarshal(serversTmp, &servers); err != nil {
return err
}
servers = append(servers, installer.EnvDNS{
env.Domain,
env.Network.DNSInClusterIP.String(),
})
if _, err := st.infraAppManager.Update("dns-gateway", map[string]any{
"servers": servers,
}); err != nil {
return err
}
}
{
for {
if _, err := st.dnsFetcher.Fetch(fmt.Sprintf("http://dns-api.%sdns.svc.cluster.local/records-to-publish", env.NamespacePrefix)); err != nil {
time.Sleep(5 * time.Second)
} else {
break
}
}
}
return nil
})
return &t
}
func WaitToPropagate(
client dns.Client,
name string,
expected []net.IP,
) Task {
t := newLeafTask("Wait to propagate", func() error {
ctx := context.TODO()
gotExpectedIPs := func(actual []net.IP) bool {
for _, a := range actual {
found := false
for _, e := range expected {
if a.Equal(e) {
found = true
break
}
}
if !found {
return false
}
}
return true
}
check := func(check Check) error {
addrs, err := client.Lookup(name)
fmt.Printf("DNS LOOKUP: %+v\n", addrs)
if err == nil && gotExpectedIPs(addrs) {
return err
}
select {
case <-ctx.Done():
return nil
case <-time.After(5 * time.Second):
return check(check)
}
}
return check(check)
})
return &t
}