Merge pull request #1 from alena1108/reviewcomments_oct14

Addressing review comments:
This commit is contained in:
Alena Prokharchyk
2015-10-14 14:59:58 -07:00
6 changed files with 242 additions and 241 deletions
+1
View File
@@ -0,0 +1 @@
/external-dns
+211
View File
@@ -0,0 +1,211 @@
package main
import (
"fmt"
"github.com/Sirupsen/logrus"
"github.com/rancher/external-dns/metadata"
"github.com/rancher/external-dns/providers"
"strings"
"sync"
)
func UpdateDnsRecords(m metadata.MetadataHandler) error {
metadataRecs, err := getMetadataDnsRecords(m)
if err != nil {
return fmt.Errorf("Error reading external dns entries: %v", err)
}
logrus.Debugf("DNS records from metadata: %v", metadataRecs)
providerRecs, err := getProviderDnsRecords()
if err != nil {
return fmt.Errorf("Provider error reading dns entries: %v", err)
}
logrus.Debugf("DNS records from provider: %v", providerRecs)
if err = addMissingRecords(metadataRecs, providerRecs); err != nil {
return fmt.Errorf("Failed to add missing records: %v", err)
}
if err = removeExtraRecords(metadataRecs, providerRecs); err != nil {
return fmt.Errorf("Failed to remove extra records: %v", err)
}
if err = updateExistingRecords(metadataRecs, providerRecs); err != nil {
return fmt.Errorf("Failed to update existing records records: %v", err)
}
return nil
}
func addMissingRecords(metadataRecs map[string]providers.DnsRecord, providerRecs map[string]providers.DnsRecord) error {
var toAdd []providers.DnsRecord
for key, _ := range metadataRecs {
if _, ok := providerRecs[key]; !ok {
toAdd = append(toAdd, metadataRecs[key])
}
}
if len(toAdd) == 0 {
logrus.Debug("No DNS records to add")
return nil
} else {
logrus.Infof("DNS records to add: %v", toAdd)
}
return updateRecords(toAdd, &Add)
}
func updateRecords(toChange []providers.DnsRecord, op *Op) error {
values := make(chan providers.DnsRecord)
var wg sync.WaitGroup
wg.Add(len(toChange))
for _, value := range toChange {
go func(value providers.DnsRecord) {
defer wg.Done()
values <- value
}(value)
}
go func() error {
for value := range values {
switch *op {
case Add:
logrus.Infof("Adding dns record: %v", value)
if err := provider.AddRecord(value); err != nil {
return fmt.Errorf("Failed to add DNS record %v: %v", value, err)
}
case Remove:
logrus.Infof("Removing dns record: %v", value)
if err := provider.RemoveRecord(value); err != nil {
return fmt.Errorf("Failed to remove DNS record %v: %v", value, err)
}
case Update:
logrus.Infof("Updating dns record: %v", value)
if err := provider.UpdateRecord(value); err != nil {
return fmt.Errorf("Failed to update DNS record %v: %v", value, err)
}
}
}
return nil
}()
wg.Wait()
return nil
}
func updateExistingRecords(metadataRecs map[string]providers.DnsRecord, providerRecs map[string]providers.DnsRecord) error {
var toUpdate []providers.DnsRecord
for key, _ := range metadataRecs {
if _, ok := providerRecs[key]; ok {
metadataR := make(map[string]struct{}, len(metadataRecs[key].Records))
for _, s := range metadataRecs[key].Records {
metadataR[s] = struct{}{}
}
providerR := make(map[string]struct{}, len(providerRecs[key].Records))
for _, s := range providerRecs[key].Records {
providerR[s] = struct{}{}
}
var update bool
if len(metadataR) != len(providerR) {
update = true
} else {
for key, _ := range metadataR {
if _, ok := providerR[key]; !ok {
update = true
}
}
for key, _ := range providerR {
if _, ok := metadataR[key]; !ok {
update = true
}
}
}
if update {
toUpdate = append(toUpdate, metadataRecs[key])
}
}
}
if len(toUpdate) == 0 {
logrus.Debug("No DNS records to update")
return nil
} else {
logrus.Infof("DNS records to update: %v", toUpdate)
}
return updateRecords(toUpdate, &Update)
}
func removeExtraRecords(metadataRecs map[string]providers.DnsRecord, providerRecs map[string]providers.DnsRecord) error {
var toRemove []providers.DnsRecord
for key, _ := range providerRecs {
if _, ok := metadataRecs[key]; !ok {
toRemove = append(toRemove, providerRecs[key])
}
}
if len(toRemove) == 0 {
logrus.Debug("No DNS records to remove")
return nil
} else {
logrus.Infof("DNS records to remove: %v", toRemove)
}
return updateRecords(toRemove, &Remove)
}
func getProviderDnsRecords() (map[string]providers.DnsRecord, error) {
allRecords, err := provider.GetRecords()
if err != nil {
return nil, err
}
ourRecords := make(map[string]providers.DnsRecord, len(allRecords))
joins := []string{stack.EnvironmentName, providers.RootDomainName}
suffix := strings.ToLower(strings.Join(joins, "."))
for _, value := range allRecords {
if strings.HasSuffix(value.DomainName, suffix) {
ourRecords[value.DomainName] = value
}
}
return ourRecords, nil
}
func getMetadataDnsRecords(m metadata.MetadataHandler) (map[string]providers.DnsRecord, error) {
containers, err := m.GetContainers()
if err != nil {
return nil, err
}
dnsEntries := make(map[string]providers.DnsRecord)
for _, container := range containers {
if container.StackName == stack.Name {
hostUUID := container.HostUUID
if len(hostUUID) == 0 {
logrus.Debugf("Container's %v host_uuid is empty", container.Name)
continue
}
host, err := m.GetHost(hostUUID)
if err != nil {
logrus.Infof("%v", err)
continue
}
ip := host.AgentIP
domainNameEntries := []string{container.ServiceName, container.StackName, stack.EnvironmentName, providers.RootDomainName}
domainName := strings.ToLower(strings.Join(domainNameEntries, "."))
var dnsEntry providers.DnsRecord
var records []string
if _, ok := dnsEntries[domainName]; ok {
records = []string{ip}
} else {
records = dnsEntries[domainName].Records
records = append(records, ip)
}
dnsEntry = providers.DnsRecord{domainName, records, "A", 300}
dnsEntries[domainName] = dnsEntry
}
}
records := make(map[string]providers.DnsRecord, len(dnsEntries))
for _, value := range dnsEntries {
records[value.DomainName] = value
}
return records, nil
}
+14 -222
View File
@@ -2,13 +2,10 @@ package main
import (
"flag"
"fmt"
log "github.com/Sirupsen/logrus"
"github.com/Sirupsen/logrus"
"github.com/rancher/external-dns/metadata"
"github.com/rancher/external-dns/providers"
"os"
"strings"
"sync"
"time"
)
@@ -41,252 +38,47 @@ func setEnv() {
flag.Parse()
provider = providers.GetProvider(*providerName)
if *debug {
log.SetLevel(log.DebugLevel)
logrus.SetLevel(logrus.DebugLevel)
}
if *logFile != "" {
if output, err := os.OpenFile(*logFile, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666); err != nil {
log.Fatalf("Failed to log to file %s: %v", *logFile, err)
logrus.Fatalf("Failed to log to file %s: %v", *logFile, err)
} else {
log.SetOutput(output)
formatter := &log.TextFormatter{
logrus.SetOutput(output)
formatter := &logrus.TextFormatter{
FullTimestamp: true,
}
log.SetFormatter(formatter)
logrus.SetFormatter(formatter)
}
}
m = metadata.NewHandler(metadataUrl)
selfStack, err := m.GetSelfStack()
if err != nil {
log.Errorf("Error reading stack info: %v", err)
logrus.Fatalf("Error reading stack info: %v", err)
}
stack = selfStack
}
func main() {
log.Infof("Starting Rancher External DNS service")
logrus.Infof("Starting Rancher External DNS service")
setEnv()
log.Infof("Powered by %s", provider.GetName())
logrus.Infof("Powered by %s", provider.GetName())
version := "init"
for {
newVersion, err := m.GetVersion()
if err != nil {
log.Errorf("Error reading version: %v", err)
logrus.Errorf("Error reading version: %v", err)
} else if version == newVersion {
log.Debug("No changes in version: %s", newVersion)
logrus.Debug("No changes in version: %s", newVersion)
} else {
log.Debug("Version has been changed. Old version: %s. New version: %s.", version, newVersion)
err := updateDnsRecords(m)
if err != nil {
log.Errorf("Failed to update DNS records: %v", err)
logrus.Debug("Version has been changed. Old version: %s. New version: %s.", version, newVersion)
if err := UpdateDnsRecords(m); err != nil {
logrus.Errorf("Failed to update DNS records: %v", err)
}
version = newVersion
}
time.Sleep(time.Duration(poll) * time.Millisecond)
}
}
func updateDnsRecords(m metadata.MetadataHandler) error {
metadataRecs, err := getMetadataDnsRecords(m)
if err != nil {
log.Errorf("Error reading external dns entries: %v", err)
}
log.Debugf("DNS records from metadata: %v", metadataRecs)
providerRecs, err := getProviderDnsRecords()
if err != nil {
log.Errorf("Provider error reading dns entries: %v", err)
}
log.Debugf("DNS records from provider: %v", providerRecs)
err = addMissingRecords(metadataRecs, providerRecs)
if err != nil {
log.Errorf("Failed to add missing records: %v", err)
}
err = removeExtraRecords(metadataRecs, providerRecs)
if err != nil {
log.Errorf("Failed to remove extra records: %v", err)
}
err = updateExistingRecords(metadataRecs, providerRecs)
if err != nil {
log.Errorf("Failed to update existing records records: %v", err)
}
return nil
}
func addMissingRecords(metadataRecs map[string]providers.DnsRecord, providerRecs map[string]providers.DnsRecord) error {
var toAdd []providers.DnsRecord
for key, _ := range metadataRecs {
if _, ok := providerRecs[key]; !ok {
toAdd = append(toAdd, metadataRecs[key])
}
}
if len(toAdd) == 0 {
log.Debug("No DNS records to add")
return nil
} else {
log.Infof("DNS records to add: %v", toAdd)
}
return updateRecords(toAdd, &Add)
}
func updateRecords(toChange []providers.DnsRecord, op *Op) error {
values := make(chan providers.DnsRecord)
var wg sync.WaitGroup
wg.Add(len(toChange))
for _, value := range toChange {
go func(value providers.DnsRecord) {
defer wg.Done()
values <- value
}(value)
}
go func() error {
for value := range values {
switch *op {
case Add:
log.Infof("Adding dns record: %v", value)
err := provider.AddRecord(value)
if err != nil {
return fmt.Errorf("Failed to add DNS record %v: %v", value, err)
}
case Remove:
log.Infof("Removing dns record: %v", value)
err := provider.RemoveRecord(value)
if err != nil {
return fmt.Errorf("Failed to remove DNS record %v: %v", value, err)
}
case Update:
log.Infof("Updating dns record: %v", value)
err := provider.UpdateRecord(value)
if err != nil {
return fmt.Errorf("Failed to update DNS record %v: %v", value, err)
}
}
}
return nil
}()
wg.Wait()
return nil
}
func updateExistingRecords(metadataRecs map[string]providers.DnsRecord, providerRecs map[string]providers.DnsRecord) error {
var toUpdate []providers.DnsRecord
for key, _ := range metadataRecs {
if _, ok := providerRecs[key]; ok {
metadataR := make(map[string]struct{}, len(metadataRecs[key].Records))
for _, s := range metadataRecs[key].Records {
metadataR[s] = struct{}{}
}
providerR := make(map[string]struct{}, len(providerRecs[key].Records))
for _, s := range providerRecs[key].Records {
providerR[s] = struct{}{}
}
var update bool
if len(metadataR) != len(providerR) {
update = true
} else {
for key, _ := range metadataR {
if _, ok := providerR[key]; !ok {
update = true
}
}
for key, _ := range providerR {
if _, ok := metadataR[key]; !ok {
update = true
}
}
}
if update {
toUpdate = append(toUpdate, metadataRecs[key])
}
}
}
if len(toUpdate) == 0 {
log.Debug("No DNS records to update")
return nil
} else {
log.Infof("DNS records to update: %v", toUpdate)
}
return updateRecords(toUpdate, &Update)
}
func removeExtraRecords(metadataRecs map[string]providers.DnsRecord, providerRecs map[string]providers.DnsRecord) error {
var toRemove []providers.DnsRecord
for key, _ := range providerRecs {
if _, ok := metadataRecs[key]; !ok {
toRemove = append(toRemove, providerRecs[key])
}
}
if len(toRemove) == 0 {
log.Debug("No DNS records to remove")
return nil
} else {
log.Infof("DNS records to remove: %v", toRemove)
}
return updateRecords(toRemove, &Remove)
}
func getProviderDnsRecords() (map[string]providers.DnsRecord, error) {
allRecords, err := provider.GetRecords()
if err != nil {
return nil, err
}
ourRecords := make(map[string]providers.DnsRecord, len(allRecords))
joins := []string{stack.EnvironmentName, providers.RootDomainName}
suffix := strings.ToLower(strings.Join(joins, "."))
for _, value := range allRecords {
if strings.HasSuffix(value.DomainName, suffix) {
ourRecords[value.DomainName] = value
}
}
return ourRecords, nil
}
func getMetadataDnsRecords(m metadata.MetadataHandler) (map[string]providers.DnsRecord, error) {
containers, err := m.GetContainers()
if err != nil {
return nil, err
}
dnsEntries := make(map[string]providers.DnsRecord)
for _, container := range containers {
if container.StackName == stack.Name {
hostUUID := container.HostUUID
if len(hostUUID) == 0 {
log.Debugf("Container's %v host_uuid is empty", container.Name)
continue
}
host, err := m.GetHost(hostUUID)
if err != nil {
log.Infof("%v", err)
continue
}
ip := host.AgentIP
domainNameEntries := []string{container.ServiceName, container.StackName, stack.EnvironmentName, providers.RootDomainName}
domainName := strings.ToLower(strings.Join(domainNameEntries, "."))
var dnsEntry providers.DnsRecord
var records []string
if _, ok := dnsEntries[domainName]; ok {
records = []string{ip}
} else {
records = dnsEntries[domainName].Records
records = append(records, ip)
}
dnsEntry = providers.DnsRecord{domainName, records, "A", 300}
dnsEntries[domainName] = dnsEntry
}
}
records := make(map[string]providers.DnsRecord, len(dnsEntries))
for _, value := range dnsEntries {
records[value.DomainName] = value
}
return records, nil
}
+5 -8
View File
@@ -45,8 +45,8 @@ func (m *MetadataHandler) GetSelfStack() (Stack, error) {
if err != nil {
return stack, err
}
err = json.Unmarshal(resp, &stack)
if err != nil {
if err = json.Unmarshal(resp, &stack); err != nil {
return stack, err
}
@@ -60,8 +60,7 @@ func (m *MetadataHandler) GetServices() ([]Service, error) {
return services, err
}
err = json.Unmarshal(resp, &services)
if err != nil {
if err = json.Unmarshal(resp, &services); err != nil {
return services, err
}
return services, nil
@@ -74,8 +73,7 @@ func (m *MetadataHandler) GetContainers() ([]Container, error) {
return containers, err
}
err = json.Unmarshal(resp, &containers)
if err != nil {
if err = json.Unmarshal(resp, &containers); err != nil {
return containers, err
}
return containers, nil
@@ -88,8 +86,7 @@ func (m *MetadataHandler) GetHosts() ([]Host, error) {
return hosts, err
}
err = json.Unmarshal(resp, &hosts)
if err != nil {
if err = json.Unmarshal(resp, &hosts); err != nil {
return hosts, err
}
return hosts, nil
+2 -2
View File
@@ -2,7 +2,7 @@ package providers
import (
"fmt"
log "github.com/Sirupsen/logrus"
"github.com/Sirupsen/logrus"
"os"
)
@@ -32,7 +32,7 @@ var (
func init() {
name := os.Getenv("EXTERNAL_DNS_ROOT_DOMAIN")
if len(name) == 0 {
log.Fatalf("EXTERNAL_DNS_ROOT_DOMAIN is not set")
logrus.Fatalf("EXTERNAL_DNS_ROOT_DOMAIN is not set")
}
RootDomainName = name
}
+9 -9
View File
@@ -2,7 +2,7 @@ package providers
import (
"fmt"
log "github.com/Sirupsen/logrus"
"github.com/Sirupsen/logrus"
"github.com/mitchellh/goamz/aws"
"github.com/mitchellh/goamz/route53"
"math"
@@ -19,21 +19,21 @@ var (
region aws.Region
)
func init() {
func main() {
route53Handler := &Route53Handler{}
if err := RegisterProvider("route53", route53Handler); err != nil {
log.Fatal("Could not register route53 provider")
logrus.Fatal("Could not register route53 provider")
}
if err := setRegion(); err != nil {
log.Fatalf("Failed to set region: %v", err)
logrus.Fatalf("Failed to set region: %v", err)
}
if err := setHostedZone(); err != nil {
log.Fatalf("Failed to set hosted zone for root domain %s: %v", RootDomainName, err)
logrus.Fatalf("Failed to set hosted zone for root domain %s: %v", RootDomainName, err)
}
log.Infof("Configured %s with hosted zone \"%s\" in region \"%s\" ", route53Handler.GetName(), RootDomainName, region.Name)
logrus.Infof("Configured %s with hosted zone \"%s\" in region \"%s\" ", route53Handler.GetName(), RootDomainName, region.Name)
}
func setRegion() error {
@@ -50,7 +50,7 @@ func setRegion() error {
region = r
auth, err := aws.EnvAuth()
if err != nil {
log.Fatal("AWS failed to authenticate: %v", err)
logrus.Fatal("AWS failed to authenticate: %v", err)
}
client = route53.New(auth, region)
@@ -60,7 +60,7 @@ func setRegion() error {
func setHostedZone() error {
zoneResp, err := client.ListHostedZones("", math.MaxInt64)
if err != nil {
log.Fatalf("Failed to list hosted zones: %v", err)
logrus.Fatalf("Failed to list hosted zones: %v", err)
}
for _, zone := range zoneResp.HostedZones {
if zone.Name == RootDomainName {
@@ -69,7 +69,7 @@ func setHostedZone() error {
}
}
if hostedZone == nil {
log.Infof("Creating missing hosting zone for root domain %s ", RootDomainName)
logrus.Infof("Creating missing hosting zone for root domain %s ", RootDomainName)
req := route53.CreateHostedZoneRequest{Name: RootDomainName, Comment: "Updated by Rancher"}
resp, err := client.CreateHostedZone(&req)
if err != nil {