diff --git a/plan/plan.go b/plan/plan.go index 9fafd7329..cee2dadc2 100644 --- a/plan/plan.go +++ b/plan/plan.go @@ -17,7 +17,12 @@ limitations under the License. package plan import ( + "fmt" + "regexp" + "strings" + "github.com/kubernetes-incubator/external-dns/endpoint" + log "github.com/sirupsen/logrus" ) // Plan can convert a list of desired and current records to a series of create, @@ -77,17 +82,27 @@ type planTableRow struct { } func (t planTable) addCurrent(e *endpoint.Endpoint) { - if _, ok := t.rows[e.DNSName]; !ok { - t.rows[e.DNSName] = &planTableRow{} + dnsName, err := stripLowerName(e.DNSName) + if err != nil { + log.Errorf("Skipping endpoint %v", err) + return } - t.rows[e.DNSName].current = e + if _, ok := t.rows[dnsName]; !ok { + t.rows[dnsName] = &planTableRow{} + } + t.rows[dnsName].current = e } func (t planTable) addCandidate(e *endpoint.Endpoint) { - if _, ok := t.rows[e.DNSName]; !ok { - t.rows[e.DNSName] = &planTableRow{} + dnsName, err := stripLowerName(e.DNSName) + if err != nil { + log.Errorf("Skipping endpoint %v", err) + return } - t.rows[e.DNSName].candidates = append(t.rows[e.DNSName].candidates, e) + if _, ok := t.rows[dnsName]; !ok { + t.rows[dnsName] = &planTableRow{} + } + t.rows[dnsName].candidates = append(t.rows[dnsName].candidates, e) } // TODO: allows record type change, which might not be supported by all dns providers @@ -175,3 +190,16 @@ func shouldUpdateTTL(desired, current *endpoint.Endpoint) bool { } return desired.RecordTTL != current.RecordTTL } + +func stripLowerName(dnsName string) (string, error) { + dnsName = strings.ToLower(dnsName) + dnsName = strings.TrimSpace(dnsName) + reg, err := regexp.Compile(`^(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)*([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9\-]*[A-Za-z0-9])$`) + if err != nil { + return "", err + } + if !reg.MatchString(dnsName) { + return "", fmt.Errorf("%s because dns record is invalid", dnsName) + } + return dnsName, nil +} diff --git a/plan/plan_test.go b/plan/plan_test.go index fc6bb6ade..c3046ca88 100644 --- a/plan/plan_test.go +++ b/plan/plan_test.go @@ -34,6 +34,8 @@ type PlanTestSuite struct { bar127A *endpoint.Endpoint bar127AWithTTL *endpoint.Endpoint bar192A *endpoint.Endpoint + invalidV2Cname *endpoint.Endpoint + invalidWithTTL *endpoint.Endpoint } func (suite *PlanTestSuite) SetupTest() { @@ -102,6 +104,17 @@ func (suite *PlanTestSuite) SetupTest() { endpoint.ResourceLabelKey: "ingress/default/bar-192", }, } + suite.invalidV2Cname = &endpoint.Endpoint{ + DNSName: "IamInvalid!", + Targets: endpoint.Targets{"v2"}, + RecordType: "CNAME", + } + suite.invalidWithTTL = &endpoint.Endpoint{ + DNSName: "5HW598OVOMBY!!!.cluster.juni.io", + Targets: endpoint.Targets{"127.0.0.1"}, + RecordType: "A", + RecordTTL: 300, + } } func (suite *PlanTestSuite) TestSyncFirstRound() { @@ -147,7 +160,7 @@ func (suite *PlanTestSuite) TestSyncSecondRound() { } func (suite *PlanTestSuite) TestSyncSecondRoundMigration() { - current := []*endpoint.Endpoint{suite.fooV2CnameNoLabel} + current := []*endpoint.Endpoint{suite.fooV2CnameNoLabel, suite.invalidWithTTL} desired := []*endpoint.Endpoint{suite.fooV2Cname, suite.fooV1Cname, suite.bar127A} expectedCreate := []*endpoint.Endpoint{suite.bar127A} expectedUpdateOld := []*endpoint.Endpoint{suite.fooV2CnameNoLabel} @@ -241,8 +254,8 @@ func (suite *PlanTestSuite) TestIdempotency() { } func (suite *PlanTestSuite) TestDifferentTypes() { - current := []*endpoint.Endpoint{suite.fooV1Cname} - desired := []*endpoint.Endpoint{suite.fooV2Cname, suite.fooA5} + current := []*endpoint.Endpoint{suite.fooV1Cname, suite.invalidV2Cname} + desired := []*endpoint.Endpoint{suite.fooV2Cname, suite.fooA5, suite.invalidV2Cname} expectedCreate := []*endpoint.Endpoint{} expectedUpdateOld := []*endpoint.Endpoint{suite.fooV1Cname} expectedUpdateNew := []*endpoint.Endpoint{suite.fooA5} @@ -327,8 +340,8 @@ func (suite *PlanTestSuite) TestDuplicatedEndpointsForSameResourceReplace() { //TODO: remove once multiple-target per endpoint is supported func (suite *PlanTestSuite) TestDuplicatedEndpointsForSameResourceRetain() { - current := []*endpoint.Endpoint{suite.fooV1Cname, suite.bar192A} - desired := []*endpoint.Endpoint{suite.fooV1Cname, suite.fooV3CnameSameResource} + current := []*endpoint.Endpoint{suite.fooV1Cname, suite.bar192A, suite.invalidV2Cname} + desired := []*endpoint.Endpoint{suite.fooV1Cname, suite.fooV3CnameSameResource, suite.invalidV2Cname} expectedCreate := []*endpoint.Endpoint{} expectedUpdateOld := []*endpoint.Endpoint{} expectedUpdateNew := []*endpoint.Endpoint{}