func createRoute53Delete(r53Api *route53.Route53, s serviceStatus) (*route53.ChangeResourceRecordSetsInput, error) { domainParts := strings.Split(s.dnsName, ".") segments := len(domainParts) tld := strings.Join(domainParts[segments-2:], ".") subdomain := strings.Join(domainParts[:segments-2], ".") listHostedZoneInput := route53.ListHostedZonesByNameInput{ DNSName: &tld, } hzOut, err := r53Api.ListHostedZonesByName(&listHostedZoneInput) if err != nil { glog.Warningf("No zone found for %s: %v", tld, err) return nil, err } zones := hzOut.HostedZones if len(zones) < 1 { glog.Warningf("No zone found for %s", tld) return nil, err } // The AWS API may return more than one zone, the first zone should be the relevant one tldWithDot := fmt.Sprint(tld, ".") if *zones[0].Name != tldWithDot { glog.Warningf("Zone found %s does not match tld given %s", *zones[0].Name, tld) return nil, err } zoneId := *zones[0].ID zoneParts := strings.Split(zoneId, "/") zoneId = zoneParts[len(zoneParts)-1] at := route53.AliasTarget{ DNSName: &s.lb.Hostname, EvaluateTargetHealth: aws.Boolean(false), HostedZoneID: &s.hzId, } rrs := route53.ResourceRecordSet{ AliasTarget: &at, Name: &s.dnsName, Type: aws.String("A"), } change := route53.Change{ Action: aws.String("DELETE"), ResourceRecordSet: &rrs, } batch := route53.ChangeBatch{ Changes: []*route53.Change{&change}, Comment: aws.String("Kubernetes Update to Service"), } crrsInput := route53.ChangeResourceRecordSetsInput{ ChangeBatch: &batch, HostedZoneID: &zoneId, } glog.Infof("Created dns delete record set: tld=%s, subdomain=%s, zoneId=%s", tld, subdomain, zoneId) return &crrsInput, nil }
func getHostedZone(service *route53.Route53, domain string) (*route53.HostedZone, error) { params := &route53.ListHostedZonesByNameInput{ DNSName: aws.String(domain), MaxItems: aws.String("1"), } resp, err := service.ListHostedZonesByName(params) if err != nil { return nil, err } zone := resp.HostedZones[0] return zone, nil }
func getHostedZoneID(fqdn string, client *route53.Route53) (string, error) { authZone, err := acme.FindZoneByFqdn(fqdn, acme.RecursiveNameservers) if err != nil { return "", err } // .DNSName should not have a trailing dot reqParams := &route53.ListHostedZonesByNameInput{ DNSName: aws.String(acme.UnFqdn(authZone)), } resp, err := client.ListHostedZonesByName(reqParams) if err != nil { return "", err } var hostedZoneID string for _, hostedZone := range resp.HostedZones { // .Name has a trailing dot if !*hostedZone.Config.PrivateZone && *hostedZone.Name == authZone { hostedZoneID = *hostedZone.Id break } } if len(hostedZoneID) == 0 { return "", fmt.Errorf("Zone %s not found in Route 53 for domain %s", authZone, fqdn) } if strings.HasPrefix(hostedZoneID, "/hostedzone/") { hostedZoneID = strings.TrimPrefix(hostedZoneID, "/hostedzone/") } return hostedZoneID, nil }
func upsertRecordOnRoute53(ipAddress string, fqdn string, svc *route53.Route53, verbose bool) { // Extract the domain from the fully qualified domain name r, _ := regexp.Compile("^([^\x2E]*)\x2E(.*)$") toks := r.FindStringSubmatch(fqdn) domain := toks[2] // http://docs.aws.amazon.com/sdk-for-go/api/service/route53/Route53.html#ListHostedZonesByName-instance_method resources, err := svc.ListHostedZonesByName(&route53.ListHostedZonesByNameInput{ DNSName: aws.String(domain + "."), MaxItems: aws.String("1"), }) if err != nil { fmt.Println("ERR: err.Error()", err) os.Exit(1) } if len(resources.HostedZones) != 1 { fmt.Printf("ERR: Could not find the domain %s\n", domain) os.Exit(1) } if *resources.DNSName != domain+"." { fmt.Printf("ERR: Could not find the domain %s - %s \n", domain, *resources.DNSName) os.Exit(1) } zoneIDToks := strings.Split(*resources.HostedZones[0].Id, "/") zoneID := zoneIDToks[len(zoneIDToks)-1] resp, err := svc.ListResourceRecordSets(&route53.ListResourceRecordSetsInput{ StartRecordName: aws.String(fqdn), StartRecordType: aws.String("A"), HostedZoneId: aws.String(zoneID), MaxItems: aws.String("1"), }) if err != nil { fmt.Println(err.Error()) os.Exit(1) } var foundResource bool if len(resp.ResourceRecordSets) != 1 { foundResource = false } else { foundResource = *resp.ResourceRecordSets[0].Name == fqdn+"." if foundResource { for _, record := range resp.ResourceRecordSets[0].ResourceRecords { if *record.Value == ipAddress { if verbose { fmt.Printf("INFO: %s already registered in route53 as %s\n", ipAddress, fqdn) } return } } } } // Make an A-record: resourceRecordSet := &route53.ResourceRecordSet{ Name: aws.String(fqdn + "."), Type: aws.String("A"), ResourceRecords: []*route53.ResourceRecord{ &route53.ResourceRecord{ Value: aws.String(ipAddress), }, }, TTL: aws.Int64(300), } // Wrap it as an UPSERT upsert := []*route53.Change{&route53.Change{ Action: aws.String("UPSERT"), ResourceRecordSet: resourceRecordSet, }} // Put it into a pretty envelope with a stamp for route53#zoneId and change ticket params := route53.ChangeResourceRecordSetsInput{ ChangeBatch: &route53.ChangeBatch{ Changes: upsert, }, HostedZoneId: aws.String(zoneID), } // Post it changeResp, err := svc.ChangeResourceRecordSets(¶ms) if err != nil { fmt.Println("ERR: ", err.Error(), changeResp) os.Exit(1) } // Done if verbose { fmt.Printf("INFO: Submitted change for zoneId %s to register %s as %s\n", zoneID, ipAddress, fqdn) } }
func createRoute53Upsert(r53Api *route53.Route53, elbApi *elb.ELB, domain string, hn string) (*route53.ChangeResourceRecordSetsInput, error) { domainParts := strings.Split(domain, ".") segments := len(domainParts) tld := strings.Join(domainParts[segments-2:], ".") // subdomain := strings.Join(domainParts[:segments-2], ".") elbName := strings.Split(hn, "-")[0] lbInput := &elb.DescribeLoadBalancersInput{ LoadBalancerNames: []*string{ &elbName, }, } resp, err := elbApi.DescribeLoadBalancers(lbInput) if err != nil { glog.Warningf("Could not describe load balancer: %v", err) return nil, err } descs := resp.LoadBalancerDescriptions if len(descs) < 1 { glog.Warningf("No lb found for %s: %v", tld, err) return nil, err } if len(descs) > 1 { glog.Warningf("Multiple lbs found for %s: %v", tld, err) return nil, err } hzId := descs[0].CanonicalHostedZoneNameID listHostedZoneInput := route53.ListHostedZonesByNameInput{ DNSName: &tld, } hzOut, err := r53Api.ListHostedZonesByName(&listHostedZoneInput) if err != nil { glog.Warningf("No zone found for %s: %v", tld, err) return nil, err } zones := hzOut.HostedZones if len(zones) < 1 { glog.Warningf("No zone found for %s", tld) return nil, err } // The AWS API may return more than one zone, the first zone should be the relevant one tldWithDot := fmt.Sprint(tld, ".") if *zones[0].Name != tldWithDot { glog.Warningf("Zone found %s does not match tld given %s", *zones[0].Name, tld) return nil, err } zoneId := *zones[0].ID zoneParts := strings.Split(zoneId, "/") zoneId = zoneParts[len(zoneParts)-1] at := route53.AliasTarget{ DNSName: &hn, EvaluateTargetHealth: aws.Boolean(false), HostedZoneID: hzId, } rrs := route53.ResourceRecordSet{ AliasTarget: &at, Name: &domain, Type: aws.String("A"), } change := route53.Change{ Action: aws.String("UPSERT"), ResourceRecordSet: &rrs, } batch := route53.ChangeBatch{ Changes: []*route53.Change{&change}, Comment: aws.String("Kubernetes Update to Service"), } crrsInput := route53.ChangeResourceRecordSetsInput{ ChangeBatch: &batch, HostedZoneID: &zoneId, } //glog.Infof("Created dns record set: tld=%s, subdomain=%s, zoneId=%s", tld, subdomain, zoneId) return &crrsInput, nil }