From e7d27bbf1572c19d3ea45400e42c7eb18ddf4a59 Mon Sep 17 00:00:00 2001 From: Jesse Haka Date: Wed, 17 May 2023 20:23:45 +0300 Subject: [PATCH] openstack designate changes --- dns-controller/cmd/dns-controller/main.go | 3 +- .../openstack/designate/designate.go | 20 ++++++------ pkg/resources/openstack/dns.go | 32 +++++++++---------- .../k8s-1.12.yaml.template | 4 +++ upup/pkg/fi/cloudup/openstack/cloud.go | 13 ++++---- upup/pkg/fi/cloudup/openstack/dns.go | 22 +++++++++++++ upup/pkg/fi/cloudup/openstack/mock_cloud.go | 4 +++ upup/pkg/fi/cloudup/template_functions.go | 17 ++++++++++ 8 files changed, 80 insertions(+), 35 deletions(-) diff --git a/dns-controller/cmd/dns-controller/main.go b/dns-controller/cmd/dns-controller/main.go index 265bd2fd07c24..d38c2de86e95e 100644 --- a/dns-controller/cmd/dns-controller/main.go +++ b/dns-controller/cmd/dns-controller/main.go @@ -37,6 +37,7 @@ import ( "k8s.io/kops/dnsprovider/pkg/dnsprovider/providers/aws/route53" _ "k8s.io/kops/dnsprovider/pkg/dnsprovider/providers/do" _ "k8s.io/kops/dnsprovider/pkg/dnsprovider/providers/google/clouddns" + _ "k8s.io/kops/dnsprovider/pkg/dnsprovider/providers/openstack/designate" "k8s.io/kops/pkg/wellknownports" "k8s.io/kops/protokube/pkg/gossip" gossipdns "k8s.io/kops/protokube/pkg/gossip/dns" @@ -66,7 +67,7 @@ func main() { flags.BoolVar(&watchIngress, "watch-ingress", true, "Configure hostnames found in ingress resources") flags.StringSliceVar(&gossipSeeds, "gossip-seed", gossipSeeds, "If set, will enable gossip zones and seed using the provided addresses") flags.StringSliceVarP(&zones, "zone", "z", []string{}, "Configure permitted zones and their mappings") - flags.StringVar(&dnsProviderID, "dns", "aws-route53", "DNS provider we should use (aws-route53, google-clouddns, digitalocean, gossip)") + flags.StringVar(&dnsProviderID, "dns", "aws-route53", "DNS provider we should use (aws-route53, google-clouddns, digitalocean, gossip, openstack-designate)") flag.StringVar(&gossipProtocol, "gossip-protocol", "mesh", "mesh/memberlist") flags.StringVar(&gossipListen, "gossip-listen", fmt.Sprintf("0.0.0.0:%d", wellknownports.DNSControllerGossipWeaveMesh), "The address on which to listen if gossip is enabled") flags.StringVar(&gossipSecret, "gossip-secret", gossipSecret, "Secret to use to secure gossip") diff --git a/dnsprovider/pkg/dnsprovider/providers/openstack/designate/designate.go b/dnsprovider/pkg/dnsprovider/providers/openstack/designate/designate.go index 2461839758d49..fae53a1c0ab15 100644 --- a/dnsprovider/pkg/dnsprovider/providers/openstack/designate/designate.go +++ b/dnsprovider/pkg/dnsprovider/providers/openstack/designate/designate.go @@ -42,17 +42,16 @@ func init() { func newDesignate(_ io.Reader) (*Interface, error) { oc := vfs.OpenstackConfig{} + region, err := oc.GetRegion() + if err != nil { + return nil, fmt.Errorf("error finding openstack region: %v", err) + } + ao, err := oc.GetCredential() if err != nil { return nil, err } - /* - pc, err := openstack.AuthenticatedClient(ao) - if err != nil { - return nil, fmt.Errorf("error building openstack authenticated client: %v", err) - }*/ - provider, err := openstack.NewClient(ao.IdentityEndpoint) if err != nil { return nil, fmt.Errorf("error building openstack provider client: %v", err) @@ -76,11 +75,10 @@ func newDesignate(_ io.Reader) (*Interface, error) { return nil, fmt.Errorf("error building openstack authenticated client: %v", err) } - endpointOpt, err := oc.GetServiceConfig("Designate") - if err != nil { - return nil, err - } - sc, err := openstack.NewDNSV2(provider, endpointOpt) + sc, err := openstack.NewDNSV2(provider, gophercloud.EndpointOpts{ + Type: "dns", + Region: region, + }) if err != nil { return nil, fmt.Errorf("error creating a ServiceClient: %v", err) } diff --git a/pkg/resources/openstack/dns.go b/pkg/resources/openstack/dns.go index 0b8799ffbfe51..26fa3b2fc9c74 100644 --- a/pkg/resources/openstack/dns.go +++ b/pkg/resources/openstack/dns.go @@ -18,18 +18,17 @@ package openstack import ( "fmt" + "strings" "k8s.io/kops/pkg/dns" - "github.com/gophercloud/gophercloud/openstack/dns/v2/recordsets" "github.com/gophercloud/gophercloud/openstack/dns/v2/zones" "k8s.io/kops/pkg/resources" "k8s.io/kops/upup/pkg/fi" - "k8s.io/kops/upup/pkg/fi/cloudup/openstack" ) const ( - typeDNSRecord = "dNSRecord" + typeDNSRecord = "DNSRecord" ) func (os *clusterDiscoveryOS) ListDNSRecordsets() ([]*resources.Resource, error) { @@ -38,29 +37,31 @@ func (os *clusterDiscoveryOS) ListDNSRecordsets() ([]*resources.Resource, error) return nil, nil } - zopts := zones.ListOpts{ - Name: os.clusterName, - } - - zs, err := os.osCloud.ListDNSZones(zopts) + zs, err := os.osCloud.ListDNSZones(zones.ListOpts{}) if err != nil { return nil, fmt.Errorf("failed to list dns zones: %s", err) } - if len(zs) == 0 { - return nil, fmt.Errorf("dns zone not found: %s", os.clusterName) + var clusterZone zones.Zone + for _, zone := range zs { + if strings.HasSuffix(os.clusterName, strings.TrimSuffix(zone.Name, ".")) { + clusterZone = zone + break + } } - z := zs[0] + if clusterZone.ID == "" { + return nil, fmt.Errorf("failed to find cluster dns zone") + } - rrs, err := os.osCloud.ListDNSRecordsets(z.ID, nil) + rrs, err := os.osCloud.ListDNSRecordsets(clusterZone.ID, nil) if err != nil { - return nil, fmt.Errorf("failed to extract recordsets pages for zone %s: %v", z.Name, err) + return nil, fmt.Errorf("failed to extract recordsets pages for zone %s: %v", clusterZone.Name, err) } var resourceTrackers []*resources.Resource for _, rr := range rrs { - if rr.Type != "A" { + if rr.Type != "A" || !strings.HasSuffix(strings.TrimSuffix(rr.Name, "."), os.clusterName) { continue } @@ -69,8 +70,7 @@ func (os *clusterDiscoveryOS) ListDNSRecordsets() ([]*resources.Resource, error) ID: rr.ID, Type: typeDNSRecord, Deleter: func(cloud fi.Cloud, r *resources.Resource) error { - // TODO: not tested and this should have retry similar to what we have in another resources - return recordsets.Delete(cloud.(openstack.OpenstackCloud).DNSClient(), z.ID, rr.ID).ExtractErr() + return os.osCloud.DeleteDNSRecordset(clusterZone.ID, r.ID) }, Obj: rr, } diff --git a/upup/models/cloudup/resources/addons/dns-controller.addons.k8s.io/k8s-1.12.yaml.template b/upup/models/cloudup/resources/addons/dns-controller.addons.k8s.io/k8s-1.12.yaml.template index 24c90e85e6b8d..ae1143d60bc6f 100644 --- a/upup/models/cloudup/resources/addons/dns-controller.addons.k8s.io/k8s-1.12.yaml.template +++ b/upup/models/cloudup/resources/addons/dns-controller.addons.k8s.io/k8s-1.12.yaml.template @@ -56,6 +56,10 @@ spec: env: - name: KUBERNETES_SERVICE_HOST value: "127.0.0.1" +{{ range $name, $value := DNSControllerEnvs }} + - name: {{ $name }} + value: {{ $value }} +{{ end }} {{- if .Networking.EgressProxy }} {{ range $name, $value := ProxyEnv }} - name: {{ $name }} diff --git a/upup/pkg/fi/cloudup/openstack/cloud.go b/upup/pkg/fi/cloudup/openstack/cloud.go index 97fdde182f116..a43ba78d3e9a4 100644 --- a/upup/pkg/fi/cloudup/openstack/cloud.go +++ b/upup/pkg/fi/cloudup/openstack/cloud.go @@ -252,6 +252,8 @@ type OpenstackCloud interface { // ListDNSRecordsets will list the DNS recordsets for the given zone id ListDNSRecordsets(zoneID string, opt recordsets.ListOptsBuilder) ([]recordsets.RecordSet, error) + DeleteDNSRecordset(zoneID string, rrsetID string) error + GetLB(loadbalancerID string) (*loadbalancers.LoadBalancer, error) GetLBStats(loadbalancerID string) (*loadbalancers.Stats, error) CreateLB(opt loadbalancers.CreateOptsBuilder) (*loadbalancers.LoadBalancer, error) @@ -412,13 +414,10 @@ func buildClients(provider *gophercloud.ProviderClient, tags map[string]string, var dnsClient *gophercloud.ServiceClient if hasDNS { - // TODO: This should be replaced with the environment variable methods as done above - endpointOpt, err := config.GetServiceConfig("Designate") - if err != nil { - return nil, fmt.Errorf("failed to get service config: %w", err) - } - - dnsClient, err = openstack.NewDNSV2(provider, endpointOpt) + dnsClient, err = openstack.NewDNSV2(provider, gophercloud.EndpointOpts{ + Type: "dns", + Region: region, + }) if err != nil { return nil, fmt.Errorf("error building dns client: %w", err) } diff --git a/upup/pkg/fi/cloudup/openstack/dns.go b/upup/pkg/fi/cloudup/openstack/dns.go index 3d973ecfe14e6..ae1c2c4b76999 100644 --- a/upup/pkg/fi/cloudup/openstack/dns.go +++ b/upup/pkg/fi/cloudup/openstack/dns.go @@ -54,6 +54,28 @@ func listDNSZones(c OpenstackCloud, opt zones.ListOptsBuilder) ([]zones.Zone, er } } +func deleteDNSRecordset(c OpenstackCloud, zoneID string, rrsetID string) error { + done, err := vfs.RetryWithBackoff(writeBackoff, func() (bool, error) { + err := recordsets.Delete(c.DNSClient(), zoneID, rrsetID).ExtractErr() + if err != nil { + return false, fmt.Errorf("failed to delete dns recordset: %s", err) + } + return true, nil + }) + if err != nil { + return err + } else if done { + return nil + } else { + return wait.ErrWaitTimeout + } +} + +// DeleteDNSRecordset will delete single DNS recordset in zone +func (c *openstackCloud) DeleteDNSRecordset(zoneID string, rrsetID string) error { + return deleteDNSRecordset(c, zoneID, rrsetID) +} + // ListDNSRecordsets will list DNS recordsets func (c *openstackCloud) ListDNSRecordsets(zoneID string, opt recordsets.ListOptsBuilder) ([]recordsets.RecordSet, error) { return listDNSRecordsets(c, zoneID, opt) diff --git a/upup/pkg/fi/cloudup/openstack/mock_cloud.go b/upup/pkg/fi/cloudup/openstack/mock_cloud.go index 61cfa615a51d6..99f3e3e90d31c 100644 --- a/upup/pkg/fi/cloudup/openstack/mock_cloud.go +++ b/upup/pkg/fi/cloudup/openstack/mock_cloud.go @@ -405,6 +405,10 @@ func (c *MockCloud) ListDNSRecordsets(zoneID string, opt recordsets.ListOptsBuil return listDNSRecordsets(c, zoneID, opt) } +func (c *MockCloud) DeleteDNSRecordset(zoneID string, rrsetID string) error { + return deleteDNSRecordset(c, zoneID, rrsetID) +} + func (c *MockCloud) ListInstances(opt servers.ListOptsBuilder) ([]servers.Server, error) { return listInstances(c, opt) } diff --git a/upup/pkg/fi/cloudup/template_functions.go b/upup/pkg/fi/cloudup/template_functions.go index fc4db4bee3416..0c0eff93d0c5e 100644 --- a/upup/pkg/fi/cloudup/template_functions.go +++ b/upup/pkg/fi/cloudup/template_functions.go @@ -166,6 +166,7 @@ func (tf *TemplateFunctions) AddTo(dest template.FuncMap, secretStore fi.SecretS // will return openstack external ccm image location for current kubernetes version dest["OpenStackCCMTag"] = tf.OpenStackCCMTag dest["OpenStackCSITag"] = tf.OpenStackCSITag + dest["DNSControllerEnvs"] = tf.DNSControllerEnvs dest["ProxyEnv"] = tf.ProxyEnv dest["KopsSystemEnv"] = tf.KopsSystemEnv @@ -610,6 +611,8 @@ func (tf *TemplateFunctions) DNSControllerArgv() ([]string, error) { argv = append(argv, "--dns=google-clouddns") case kops.CloudProviderDO: argv = append(argv, "--dns=digitalocean") + case kops.CloudProviderOpenstack: + argv = append(argv, "--dns=openstack-designate") default: return nil, fmt.Errorf("unhandled cloudprovider %q", cluster.Spec.GetCloudProvider()) @@ -807,6 +810,20 @@ func (tf *TemplateFunctions) ExternalDNSArgv() ([]string, error) { return argv, nil } +func (tf *TemplateFunctions) DNSControllerEnvs() map[string]string { + if tf.Cluster.Spec.GetCloudProvider() != kops.CloudProviderOpenstack { + return nil + } + envs := env.BuildSystemComponentEnvVars(&tf.Cluster.Spec) + out := make(map[string]string) + for k, v := range envs { + if strings.HasPrefix(k, "OS_") { + out[k] = v + } + } + return out +} + func (tf *TemplateFunctions) ProxyEnv() map[string]string { cluster := tf.Cluster