pkg/controller/dns/external_dns.go (164 lines of code) (raw):
package dns
import (
"fmt"
"time"
"github.com/Azure/aks-app-routing-operator/pkg/config"
"github.com/Azure/aks-app-routing-operator/pkg/controller/common"
"github.com/Azure/aks-app-routing-operator/pkg/controller/controllername"
"github.com/Azure/aks-app-routing-operator/pkg/manifests"
"github.com/Azure/aks-app-routing-operator/pkg/util"
"github.com/Azure/azure-sdk-for-go/sdk/azcore/to"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/runtime/schema"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/client"
)
const (
reconcileInterval = time.Minute * 3
)
// addExternalDnsReconciler creates a reconciler that manages external dns resources
func addExternalDnsReconciler(manager ctrl.Manager, resources []client.Object) error {
return common.NewResourceReconciler(manager, controllername.New("external", "dns", "reconciler"), resources, reconcileInterval)
}
func addExternalDnsCleaner(manager ctrl.Manager, instances []instance) error {
return nil // disable cleaner until we have better test coverage
objs := cleanObjs(instances)
retriever := common.RetrieverEmpty()
for _, obj := range objs {
retriever = retriever.Add(common.RetrieverFromObjs(obj.resources, obj.labels)) // clean up entire unused external dns applications
}
for _, instance := range instances {
labels := util.MergeMaps(instance.config.Labels(), manifests.GetTopLevelLabels())
retriever = retriever.Add(common.RetrieverFromGk(labels, manifests.OldExternalDnsGks...)) // clean up unused types from previous versions of app routing
}
retriever = retriever.Remove(common.RetrieverFromGk(
nil, // our compare strat is ignore labels
schema.GroupKind{
Group: corev1.GroupName,
Kind: "Namespace",
}),
common.RemoveOpt{
CompareStrat: common.IgnoreLabels, // ignore labels, we never want to clean namespaces
})
return common.NewCleaner(manager, controllername.New("external", "dns", "cleaner"), retriever)
}
// NewExternalDns starts all resources required for external dns
func NewExternalDns(manager ctrl.Manager, conf *config.Config) error {
instances, err := instances(conf)
if err != nil {
return fmt.Errorf("failed to create instances: %w", err)
}
deployInstances := filterAction(instances, deploy)
deployRes := getResources(deployInstances)
if err := addExternalDnsReconciler(manager, deployRes); err != nil {
return err
}
if err := addExternalDnsCleaner(manager, instances); err != nil {
return err
}
return nil
}
func instances(conf *config.Config) ([]instance, error) {
// public
publicCfg, err := publicConfigForIngress(conf)
if err != nil {
return nil, err
}
publicAction := actionFromConfig(publicCfg)
publicResources := publicCfg.Resources()
// private
privateCfg, err := privateConfigForIngress(conf)
if err != nil {
return nil, err
}
privateAction := actionFromConfig(privateCfg)
privateResources := privateCfg.Resources()
return []instance{
{
config: publicCfg,
resources: publicResources,
action: publicAction,
},
{
config: privateCfg,
resources: privateResources,
action: privateAction,
},
}, nil
}
func publicConfigForIngress(conf *config.Config) (*manifests.ExternalDnsConfig, error) {
publicconfig, err := manifests.NewExternalDNSConfig(
conf,
manifests.InputExternalDNSConfig{
TenantId: conf.TenantID,
ClientId: conf.MSIClientID,
Namespace: conf.NS,
IdentityType: manifests.IdentityTypeMSI,
ResourceTypes: map[manifests.ResourceType]struct{}{manifests.ResourceTypeIngress: struct{}{}},
DnsZoneresourceIDs: util.Keys(conf.PublicZoneConfig.ZoneIds),
Provider: to.Ptr(manifests.PublicProvider),
})
if err != nil {
return nil, err
}
return publicconfig, nil
}
func privateConfigForIngress(conf *config.Config) (*manifests.ExternalDnsConfig, error) {
privateconfig, err := manifests.NewExternalDNSConfig(
conf,
manifests.InputExternalDNSConfig{
TenantId: conf.TenantID,
ClientId: conf.MSIClientID,
Namespace: conf.NS,
IdentityType: manifests.IdentityTypeMSI,
ResourceTypes: map[manifests.ResourceType]struct{}{manifests.ResourceTypeIngress: struct{}{}},
DnsZoneresourceIDs: util.Keys(conf.PrivateZoneConfig.ZoneIds),
Provider: to.Ptr(manifests.PrivateProvider),
},
)
if err != nil {
return nil, err
}
return privateconfig, nil
}
func filterAction(instances []instance, action action) []instance {
var ret []instance
for _, i := range instances {
if i.action == action {
ret = append(ret, i)
}
}
return ret
}
func getResources(instances []instance) []client.Object {
var ret []client.Object
for _, i := range instances {
ret = append(ret, i.resources...)
}
return ret
}
func getLabels(instances ...instance) map[string]string {
l := map[string]string{}
for k, v := range manifests.GetTopLevelLabels() {
l[k] = v
}
for _, i := range instances {
for k, v := range i.config.Labels() {
l[k] = v
}
}
return l
}
func cleanObjs(instances []instance) []cleanObj {
var cleanObjs []cleanObj
for _, instance := range filterAction(instances, clean) {
obj := cleanObj{
resources: instance.resources,
labels: getLabels(instance),
}
cleanObjs = append(cleanObjs, obj)
}
return cleanObjs
}
func actionFromConfig(conf *manifests.ExternalDnsConfig) action {
if len(conf.DnsZoneResourceIds()) == 0 {
return clean
}
return deploy
}