mitchell852 closed pull request #2217: Fix Traffic Ops Go CRConfig to implement maxmind override logic URL: https://github.com/apache/incubator-trafficcontrol/pull/2217
This is a PR merged from a forked repository. As GitHub hides the original diff on merge, it is displayed below for the sake of provenance: As this is a foreign pull request (from a fork), the diff is supplied below (as it won't show otherwise due to GitHub magic): diff --git a/traffic_ops/traffic_ops_golang/crconfig/config.go b/traffic_ops/traffic_ops_golang/crconfig/config.go index 0d3eb4501..d0e549099 100644 --- a/traffic_ops/traffic_ops_golang/crconfig/config.go +++ b/traffic_ops/traffic_ops_golang/crconfig/config.go @@ -22,6 +22,7 @@ package crconfig import ( "database/sql" "errors" + "strconv" "strings" ) @@ -30,28 +31,41 @@ func makeCRConfigConfig(cdn string, db *sql.DB, dnssecEnabled bool, domain strin if err != nil { return nil, errors.New("Error getting router params: " + err.Error()) } - configParams["domain_name"] = domain soa := map[string]string{} ttl := map[string]string{} + maxmindDefaultOverrides := []CRConfigConfigMaxmindDefaultOverride{} + const soaPrefix = "tld.soa." - ttlPrefix := "tld.ttls." + const ttlPrefix = "tld.ttls." + const maxmindDefaultOverrideParameterName = "maxmind.default.override" crConfigConfig := map[string]interface{}{} - for k, v := range configParams { + for _, param := range configParams { + k := param.Name + v := param.Value if strings.HasPrefix(k, soaPrefix) { soa[k[len(soaPrefix):]] = v } else if strings.HasPrefix(k, ttlPrefix) { ttl[k[len(ttlPrefix):]] = v + } else if k == maxmindDefaultOverrideParameterName { + overrideObj, err := createMaxmindDefaultOverrideObj(v) + if err != nil { + return nil, errors.New("Error parsing " + maxmindDefaultOverrideParameterName + " parameter: " + err.Error()) + } + maxmindDefaultOverrides = append(maxmindDefaultOverrides, overrideObj) } else { crConfigConfig[k] = v } } + crConfigConfig["domain_name"] = domain if len(soa) > 0 { crConfigConfig["soa"] = soa } if len(ttl) > 0 { crConfigConfig["ttls"] = ttl } - + if len(maxmindDefaultOverrides) > 0 { + crConfigConfig[maxmindDefaultOverrideParameterName] = maxmindDefaultOverrides + } dnssecStr := "false" if dnssecEnabled { dnssecStr = "true" @@ -61,7 +75,12 @@ func makeCRConfigConfig(cdn string, db *sql.DB, dnssecEnabled bool, domain strin return crConfigConfig, nil } -func getConfigParams(cdn string, db *sql.DB) (map[string]string, error) { +type CRConfigConfigParameter struct { + Name string + Value string +} + +func getConfigParams(cdn string, db *sql.DB) ([]CRConfigConfigParameter, error) { // TODO change to []struct{string,string} ? Speed might matter. q := ` select name, value from parameter where id in ( @@ -79,17 +98,51 @@ and config_file = 'CRConfig.json' } defer rows.Close() - params := map[string]string{} + params := []CRConfigConfigParameter{} for rows.Next() { name := "" val := "" if err := rows.Scan(&name, &val); err != nil { return nil, errors.New("Error scanning router param: " + err.Error()) } - params[name] = val + params = append(params, CRConfigConfigParameter{Name: name, Value: val}) } if err := rows.Err(); err != nil { return nil, errors.New("Error iterating router param rows: " + err.Error()) } return params, nil } + +type CRConfigConfigMaxmindDefaultOverride struct { + CountryCode string `json:"countryCode"` + Lat float64 `json:"lat"` + Lon float64 `json:"long"` +} + +func createMaxmindDefaultOverrideObj(maxmindDefaultOverrideParamVal string) (CRConfigConfigMaxmindDefaultOverride, error) { + countryCodeCoords := strings.Split(maxmindDefaultOverrideParamVal, ";") + if len(countryCodeCoords) < 2 { + return CRConfigConfigMaxmindDefaultOverride{}, errors.New("malformed maxmind.default.override parameter: '" + maxmindDefaultOverrideParamVal + "'") + } + countryCode := countryCodeCoords[0] + coords := countryCodeCoords[1] + latLon := strings.Split(coords, ",") + if len(latLon) < 2 { + return CRConfigConfigMaxmindDefaultOverride{}, errors.New("malformed maxmind.default.override parameter coordinates '" + maxmindDefaultOverrideParamVal + "'") + } + latStr := latLon[0] + lonStr := latLon[1] + lat, err := strconv.ParseFloat(latStr, 64) + if err != nil { + return CRConfigConfigMaxmindDefaultOverride{}, errors.New("malformed maxmind.default.override parameter coordinates, latitude not a number: '" + maxmindDefaultOverrideParamVal + "'") + } + lon, err := strconv.ParseFloat(lonStr, 64) + if err != nil { + return CRConfigConfigMaxmindDefaultOverride{}, errors.New("malformed maxmind.default.override parameter coordinates, longitude not an number: '" + maxmindDefaultOverrideParamVal + "'") + } + return CRConfigConfigMaxmindDefaultOverride{ + CountryCode: countryCode, + Lat: lat, + Lon: lon, + }, nil +} diff --git a/traffic_ops/traffic_ops_golang/crconfig/config_test.go b/traffic_ops/traffic_ops_golang/crconfig/config_test.go index 86f209e8a..d8e135d41 100644 --- a/traffic_ops/traffic_ops_golang/crconfig/config_test.go +++ b/traffic_ops/traffic_ops_golang/crconfig/config_test.go @@ -27,16 +27,19 @@ import ( "gopkg.in/DATA-DOG/go-sqlmock.v1" ) -func ExpectedGetConfigParams() map[string]string { - return map[string]string{ - "tld.ttls.foo" + *randStr(): *randStr(), - "tld.soa.bar" + *randStr(): *randStr(), +func ExpectedGetConfigParams(domain string) []CRConfigConfigParameter{ + return []CRConfigConfigParameter{ + {"tld.ttls.foo" + *randStr(), *randStr()}, + {"tld.soa.bar" + *randStr(), *randStr()}, + {"domain_name", domain}, } } -func MockGetConfigParams(mock sqlmock.Sqlmock, expected map[string]string, cdn string) { +func MockGetConfigParams(mock sqlmock.Sqlmock, expected []CRConfigConfigParameter, cdn string) { rows := sqlmock.NewRows([]string{"name", "value"}) - for n, v := range expected { + for _, param := range expected { + n := param.Name + v := param.Value rows = rows.AddRow(n, v) } mock.ExpectQuery("select").WithArgs(cdn).WillReturnRows(rows) @@ -50,8 +53,9 @@ func TestGetConfigParams(t *testing.T) { defer db.Close() cdn := "mycdn" + domain := "mycdn.invalid" - expected := ExpectedGetConfigParams() + expected := ExpectedGetConfigParams(domain) MockGetConfigParams(mock, expected, cdn) actual, err := getConfigParams(cdn, db) @@ -67,11 +71,13 @@ func TestGetConfigParams(t *testing.T) { const soaPrefix = "tld.soa." const ttlPrefix = "tld.ttls." -func ExpectedMakeCRConfigConfig(expectedGetConfigParams map[string]string, expectedDNSSECEnabled bool) map[string]interface{} { +func ExpectedMakeCRConfigConfig(expectedGetConfigParams []CRConfigConfigParameter, expectedDNSSECEnabled bool) map[string]interface{} { m := map[string]interface{}{} soa := map[string]string{} ttl := map[string]string{} - for n, v := range expectedGetConfigParams { + for _, param := range expectedGetConfigParams { + n := param.Name + v := param.Value if strings.HasPrefix(n, soaPrefix) { soa[n[len(soaPrefix):]] = v } else if strings.HasPrefix(n, ttlPrefix) { @@ -98,14 +104,15 @@ func TestMakeCRConfigConfig(t *testing.T) { defer db.Close() cdn := "mycdn" + domain := "mycdn.invalid" dnssecEnabled := true - expectedGetConfigParams := ExpectedGetConfigParams() + expectedGetConfigParams := ExpectedGetConfigParams(domain) MockGetConfigParams(mock, expectedGetConfigParams, cdn) expected := ExpectedMakeCRConfigConfig(expectedGetConfigParams, dnssecEnabled) - actual, err := makeCRConfigConfig(cdn, db, dnssecEnabled) + actual, err := makeCRConfigConfig(cdn, db, dnssecEnabled, domain) if err != nil { t.Fatalf("makeCRConfigConfig err expected: nil, actual: %v", err) diff --git a/traffic_ops/traffic_ops_golang/crconfig/deliveryservice_test.go b/traffic_ops/traffic_ops_golang/crconfig/deliveryservice_test.go index fe066b443..b5795e2b0 100644 --- a/traffic_ops/traffic_ops_golang/crconfig/deliveryservice_test.go +++ b/traffic_ops/traffic_ops_golang/crconfig/deliveryservice_test.go @@ -169,6 +169,7 @@ func TestMakeDSes(t *testing.T) { defer db.Close() cdn := "mycdn" + domain := "mycdn.invalid" expected := ExpectedMakeDSes() MockMakeDSes(mock, expected, cdn) @@ -186,7 +187,7 @@ func TestMakeDSes(t *testing.T) { expectedStaticDNSEntries := ExpectedGetStaticDNSEntries(expected) MockGetStaticDNSEntries(mock, expectedStaticDNSEntries, cdn) - actual, err := makeDSes(cdn, db) + actual, err := makeDSes(cdn, domain, db) if err != nil { t.Fatalf("makeDSes expected: nil error, actual: %v", err) } @@ -310,6 +311,7 @@ func TestGetDSRegexesDomains(t *testing.T) { defer db.Close() cdn := "mycdn" + domain := "mycdn.invalid" expectedMakeDSes := ExpectedMakeDSes() expectedServerProfileParams := ExpectedGetServerProfileParams(expectedMakeDSes) @@ -320,7 +322,7 @@ func TestGetDSRegexesDomains(t *testing.T) { expectedMatchsets, expectedDomains := ExpectedGetDSRegexesDomains(expectedDSParams) MockGetDSRegexesDomains(mock, expectedMatchsets, expectedDomains, cdn) - actualMatchsets, actualDomains, err := getDSRegexesDomains(cdn, db, expectedDSParams) + actualMatchsets, actualDomains, err := getDSRegexesDomains(cdn, domain, db) if err != nil { t.Fatalf("getDSRegexesDomains expected: nil error, actual: %v", err) } diff --git a/traffic_ops/traffic_ops_golang/crconfig/handler.go b/traffic_ops/traffic_ops_golang/crconfig/handler.go index 3c11d5e4b..0c4453c93 100644 --- a/traffic_ops/traffic_ops_golang/crconfig/handler.go +++ b/traffic_ops/traffic_ops_golang/crconfig/handler.go @@ -113,6 +113,34 @@ func SnapshotGetHandler(db *sqlx.DB, cfg config.Config) http.HandlerFunc { } } +// SnapshotOldGetHandler gets and serves the CRConfig from the snapshot table, not wrapped in response to match the old non-API CRConfig-Snapshots endpoint +func SnapshotOldGetHandler(db *sqlx.DB, cfg config.Config) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + handleErrs := tc.GetHandleErrorsFunc(w, r) + params, err := api.GetCombinedParams(r) + if err != nil { + handleErrs(http.StatusInternalServerError, err) + return + } + cdn, ok := params["cdn"] + if !ok { + handleErrs(http.StatusInternalServerError, errors.New("params missing CDN")) + return + } + snapshot, cdnExists, err := GetSnapshot(db.DB, cdn) + if err != nil { + handleErrs(http.StatusInternalServerError, errors.New("getting snapshot: "+err.Error())) + return + } + if !cdnExists { + handleErrs(http.StatusNotFound, errors.New("CDN not found")) + return + } + w.Header().Set("Content-Type", "application/json") + w.Write([]byte(snapshot)) + } +} + // SnapshotHandler creates the CRConfig JSON and writes it to the snapshot table in the database. func SnapshotHandler(db *sqlx.DB, cfg config.Config) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { diff --git a/traffic_ops/traffic_ops_golang/routes.go b/traffic_ops/traffic_ops_golang/routes.go index 16b8ab988..3453d19d7 100644 --- a/traffic_ops/traffic_ops_golang/routes.go +++ b/traffic_ops/traffic_ops_golang/routes.go @@ -233,7 +233,7 @@ func Routes(d ServerData) ([]Route, []RawRoute, http.Handler, error) { // DEPRECATED - use PUT /api/1.2/snapshot/{cdn} {http.MethodGet, `tools/write_crconfig/{cdn}/?$`, crconfig.SnapshotOldGUIHandler(d.DB, d.Config), crconfig.PrivLevel, Authenticated, nil}, // DEPRECATED - use GET /api/1.2/cdns/{cdn}/snapshot - {http.MethodGet, `CRConfig-Snapshots/{cdn}/CRConfig.json?$`, crconfig.SnapshotGetHandler(d.DB, d.Config), crconfig.PrivLevel, Authenticated, nil}, + {http.MethodGet, `CRConfig-Snapshots/{cdn}/CRConfig.json?$`, crconfig.SnapshotOldGetHandler(d.DB, d.Config), crconfig.PrivLevel, Authenticated, nil}, } return routes, rawRoutes, proxyHandler, nil ---------------------------------------------------------------- This is an automated message from the Apache Git Service. To respond to the message, please log on GitHub and use the URL above to go to the specific comment. For queries about this service, please contact Infrastructure at: us...@infra.apache.org With regards, Apache Git Services