This is an automated email from the ASF dual-hosted git repository.

zrhoffman pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/trafficcontrol.git


The following commit(s) were added to refs/heads/master by this push:
     new 46a2792  Fix federations API when using same resolvers for multiple 
DSes (#6109)
46a2792 is described below

commit 46a279204af553c51cee69bd03a6fbba2589208b
Author: Rawlin Peters <[email protected]>
AuthorDate: Mon Aug 16 18:01:41 2021 -0600

    Fix federations API when using same resolvers for multiple DSes (#6109)
    
    Instead of allowing the query to return no row on conflict, ensure it
    always returns a row so that we can associate the resolver ID to the
    federation.
    
    Closes: #6104
---
 CHANGELOG.md                                       |   1 +
 traffic_ops/testing/api/v4/federations_test.go     | 109 +++++++++++++++++++++
 .../traffic_ops_golang/federations/federations.go  |  14 ++-
 3 files changed, 116 insertions(+), 8 deletions(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index b4539b7..bbc8cac 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -70,6 +70,7 @@ The format is based on [Keep a 
Changelog](http://keepachangelog.com/en/1.0.0/).
 - [#5609](https://github.com/apache/trafficcontrol/issues/5609) - Fixed GET 
/servercheck filter for an extra query param.
 - [#5954](https://github.com/apache/trafficcontrol/issues/5954) - Traffic Ops 
HTTP response write errors are ignored
 - [#6048](https://github.com/apache/trafficcontrol/issues/6048) - TM sometimes 
sets cachegroups to unavailable even though all caches are online
+- [#6104](https://github.com/apache/trafficcontrol/issues/6104) - PUT 
/api/x/federations only respects first item in request payload
 - [#5288](https://github.com/apache/trafficcontrol/issues/5288) - Fixed the 
ability to create and update a server with MTU value >= 1280.
 - [#5284](https://github.com/apache/trafficcontrol/issues/5284) - Fixed error 
message when creating a server with non-existent profile
 - Fixed a NullPointerException in TR when a client passes a null SNI hostname 
in a TLS request
diff --git a/traffic_ops/testing/api/v4/federations_test.go 
b/traffic_ops/testing/api/v4/federations_test.go
index 071bb3d..c1958c6 100644
--- a/traffic_ops/testing/api/v4/federations_test.go
+++ b/traffic_ops/testing/api/v4/federations_test.go
@@ -19,6 +19,8 @@ import (
        "errors"
        "fmt"
        "net/http"
+       "reflect"
+       "sort"
        "testing"
        "time"
 
@@ -33,6 +35,7 @@ func TestFederations(t *testing.T) {
                GetTestFederations(t)
                GetTestFederationsIMS(t)
                AddFederationResolversForCurrentUserTest(t)
+               ReplaceFederationResolversForCurrentUserTest(t)
                RemoveFederationResolversForCurrentUserTest(t)
        })
 }
@@ -268,3 +271,109 @@ func AddFederationResolversForCurrentUserTest(t 
*testing.T) {
                }
        }
 }
+
+func ReplaceFederationResolversForCurrentUserTest(t *testing.T) {
+       fedID, ds, ds1, err := createFederationToDeliveryServiceAssociation()
+       if err != nil {
+               t.Fatal(err.Error())
+       }
+
+       // need to assign myself the federation to set its mappings
+       me, _, err := TOSession.GetUserCurrent(client.RequestOptions{})
+       if err != nil {
+               t.Fatalf("Couldn't figure out who I am: %v - alerts: %+v", err, 
me.Alerts)
+       }
+       if me.Response.ID == nil {
+               t.Fatal("Current user has no ID, cannot continue.")
+       }
+
+       fedUsers, _, err := TOSession.GetFederationUsers(fedID, 
client.RequestOptions{})
+       if err != nil {
+               t.Fatalf("unexpected error getting federation users: %v", err)
+       }
+       foundFedUser := false
+       for _, fedUser := range fedUsers.Response {
+               if *fedUser.ID == *me.Response.ID {
+                       foundFedUser = true
+                       break
+               }
+       }
+       if !foundFedUser {
+               alerts, _, err := TOSession.CreateFederationUsers(fedID, 
[]int{*me.Response.ID}, false, client.RequestOptions{})
+               if err != nil {
+                       t.Fatalf("Failed to assign Federation to current user: 
%v - alerts: %+v", err, alerts.Alerts)
+               }
+       }
+       expectedResolve4 := []string{"192.0.2.0/25", "192.0.2.128/25"}
+       expectedResolve6 := []string{"2001:db8::/33", "2001:db8:8000::/33"}
+       sort.Strings(expectedResolve4)
+       sort.Strings(expectedResolve6)
+
+       mappings := tc.DeliveryServiceFederationResolverMappingRequest{
+               tc.DeliveryServiceFederationResolverMapping{
+                       DeliveryService: *ds.XMLID,
+                       Mappings: tc.ResolverMapping{
+                               Resolve4: expectedResolve4,
+                               Resolve6: expectedResolve6,
+                       },
+               },
+               // for the purpose of this test, it's important that at least 
two different mappings have the same resolvers
+               tc.DeliveryServiceFederationResolverMapping{
+                       DeliveryService: *ds1.XMLID,
+                       Mappings: tc.ResolverMapping{
+                               Resolve4: expectedResolve4,
+                               Resolve6: expectedResolve6,
+                       },
+               },
+       }
+
+       alerts, _, err := 
TOSession.ReplaceFederationResolverMappingsForCurrentUser(mappings, 
client.RequestOptions{})
+       if err != nil {
+               t.Fatalf("Unexpected error replacing Federation Resolver 
mappings for the current user: %v - alerts: %+v", err, alerts.Alerts)
+       }
+       for _, a := range alerts.Alerts {
+               if a.Level == tc.ErrorLevel.String() {
+                       t.Errorf("Unexpected error-level alert from replacing 
Federation Resolver mappings for the current user: %s", a.Text)
+               }
+       }
+
+       feds, _, err := TOSession.Federations(client.RequestOptions{})
+       if err != nil {
+               t.Fatalf("unexpected error getting federations: %v", err)
+       }
+       for _, fed := range feds.Response {
+               if fed.DeliveryService.String() == *ds.XMLID || 
fed.DeliveryService.String() == *ds1.XMLID {
+                       if len(fed.Mappings) != 1 {
+                               t.Fatalf("expected 1 mapping, got %d", 
len(fed.Mappings))
+                       }
+                       sort.Strings(fed.Mappings[0].Resolve4)
+                       sort.Strings(fed.Mappings[0].Resolve6)
+                       if !reflect.DeepEqual(expectedResolve4, 
fed.Mappings[0].Resolve4) {
+                               t.Errorf("checking federation resolver 
mappings, expected: %+v, actual: %+v", expectedResolve4, 
fed.Mappings[0].Resolve4)
+                       }
+                       if !reflect.DeepEqual(expectedResolve6, 
fed.Mappings[0].Resolve6) {
+                               t.Errorf("checking federation resolver 
mappings, expected: %+v, actual: %+v", expectedResolve6, 
fed.Mappings[0].Resolve6)
+                       }
+               }
+       }
+
+       mappings = tc.DeliveryServiceFederationResolverMappingRequest{
+               tc.DeliveryServiceFederationResolverMapping{
+                       DeliveryService: "aoeuhtns",
+                       Mappings: tc.ResolverMapping{
+                               Resolve4: []string{},
+                               Resolve6: []string{"dead::beef", 
"f1d0::f00d/82"},
+                       },
+               },
+       }
+
+       alerts, _, err = 
TOSession.ReplaceFederationResolverMappingsForCurrentUser(mappings, 
client.RequestOptions{})
+       if err == nil {
+               t.Fatal("Expected error replacing Federation Resolver mappings 
for the current user, but didn't get one")
+       }
+       for _, a := range alerts.Alerts {
+               if a.Level == tc.SuccessLevel.String() {
+                       t.Errorf("Unexpected success from replacing Federation 
Resolver mappings for the current user: %s", a.Text)
+               }
+       }
+}
diff --git a/traffic_ops/traffic_ops_golang/federations/federations.go 
b/traffic_ops/traffic_ops_golang/federations/federations.go
index 8bef373..7d462c4 100644
--- a/traffic_ops/traffic_ops_golang/federations/federations.go
+++ b/traffic_ops/traffic_ops_golang/federations/federations.go
@@ -49,7 +49,7 @@ VALUES ($1, (
        FROM type
        WHERE type.name = $2
 ))
-ON CONFLICT DO NOTHING
+ON CONFLICT (ip_address) DO UPDATE SET ip_address = 
federation_resolver.ip_address
 RETURNING federation_resolver.ip_address, federation_resolver.id
 `
 
@@ -324,7 +324,7 @@ WHERE
        return feds, nil, http.StatusOK, &maxTime
 }
 
-// AddFederationResorverMappingsForCurrentUser is the handler for a POST 
request to /federations.
+// AddFederationResolverMappingsForCurrentUser is the handler for a POST 
request to /federations.
 // Confusingly, it does not create a federation, but is instead used to 
manipulate the resolvers
 // used by one or more particular Delivery Services for one or more particular 
Federations.
 func AddFederationResolverMappingsForCurrentUser(w http.ResponseWriter, r 
*http.Request) {
@@ -426,14 +426,12 @@ func addFederationResolver(res []string, t 
tc.FederationResolverType, fedID uint
        for _, r := range res {
                var ip string
                var id uint
-               if err := tx.QueryRow(insertResolverQuery, r, t).Scan(&ip, 
&id); err != nil && err != sql.ErrNoRows {
+               if err := tx.QueryRow(insertResolverQuery, r, t).Scan(&ip, 
&id); err != nil {
                        return nil, err
                }
-               if ip != "" && id > 0 {
-                       inserted = append(inserted, ip)
-                       if _, err := 
tx.Exec(associateFederationWithResolverQuery, fedID, id); err != nil {
-                               return nil, err
-                       }
+               inserted = append(inserted, ip)
+               if _, err := tx.Exec(associateFederationWithResolverQuery, 
fedID, id); err != nil {
+                       return nil, err
                }
 
        }

Reply via email to