Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix for backend service update #1709

Merged
merged 1 commit into from
May 17, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion pkg/backends/ig_linker.go
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,5 @@ func getInstanceGroupsToAdd(be *composite.BackendService, igLinks []string) ([]s
klog.V(2).Infof("Backend service %q has instance groups %+v, want %+v",
be.Name, existingIGs.List(), wantIGs.List())
}

return missingIGs.List(), nil
}
86 changes: 86 additions & 0 deletions pkg/backends/ig_linker_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,10 @@ package backends

import (
"context"
"fmt"
"net/http"
"reflect"
"sort"
"testing"

"github.com/GoogleCloudPlatform/k8s-cloud-provider/pkg/cloud"
Expand Down Expand Up @@ -165,3 +168,86 @@ func TestBackendsForIG(t *testing.T) {
})
}
}

func TestGetIGLinksToAdd(t *testing.T) {
url := "https://googleapis.com/v1/compute/projects/my-project/global/backendServices/%s"
link := "projects/my-project/global/backendServices/%s"
for _, tc := range []struct {
name string
igLinks []string
currentIGLinks []string
want []string
}{
{
name: "empty",
igLinks: []string{},
currentIGLinks: []string{},
want: []string{},
},
{
name: "No IGs to add",
igLinks: []string{fmt.Sprintf(url, "same-backend")},
currentIGLinks: []string{fmt.Sprintf(url, "same-backend")},
want: []string{},
},
{
name: "same IGs in wrong order",
igLinks: []string{fmt.Sprintf(url, "same-backend2"), fmt.Sprintf(url, "same-backend")},
currentIGLinks: []string{fmt.Sprintf(url, "same-backend"), fmt.Sprintf(url, "same-backend2")},
want: []string{},
},
{
name: "one IG to add",
igLinks: []string{fmt.Sprintf(url, "same-backend"), fmt.Sprintf(url, "same-backend2"), fmt.Sprintf(url, "same-backend3")},
currentIGLinks: []string{fmt.Sprintf(url, "same-backend"), fmt.Sprintf(url, "same-backend2")},
want: []string{fmt.Sprintf(link, "same-backend3")},
},
{
name: "IGs in wrong order",
igLinks: []string{fmt.Sprintf(url, "same-backend2"), fmt.Sprintf(url, "same-backend")},
currentIGLinks: []string{fmt.Sprintf(url, "same-backend3"), fmt.Sprintf(url, "same-backend2")},
want: []string{fmt.Sprintf(link, "same-backend")},
},
{
name: "different IGs",
igLinks: []string{fmt.Sprintf(url, "same-backend"), fmt.Sprintf(url, "same-backend2")},
currentIGLinks: []string{fmt.Sprintf(url, "same-backend3"), fmt.Sprintf(url, "same-backend4")},
want: []string{fmt.Sprintf(link, "same-backend"), fmt.Sprintf(link, "same-backend2")},
},
{
name: "empty current",
igLinks: []string{fmt.Sprintf(url, "same-backend"), fmt.Sprintf(url, "same-backend2")},
currentIGLinks: []string{},
want: []string{fmt.Sprintf(link, "same-backend"), fmt.Sprintf(link, "same-backend2")},
},
{
name: "empty IGs and non-empty current",
igLinks: []string{},
currentIGLinks: []string{fmt.Sprintf(url, "same-backend"), fmt.Sprintf(url, "same-backend2")},
want: []string{},
},
} {
t.Run(tc.name, func(t *testing.T) {
be := composite.BackendService{}
var newBackends []*composite.Backend
for _, igLink := range tc.currentIGLinks {
b := &composite.Backend{
Group: igLink,
}
newBackends = append(newBackends, b)
}
be.Backends = newBackends
toAdd, err := getInstanceGroupsToAdd(&be, tc.igLinks)
if err != nil {
t.Fatalf("getInstanceGroupsToAdd(_,_): err:%v ", err)
}
sort.Slice(toAdd, func(i, j int) bool {
return toAdd[i] <= toAdd[j]
})
if !reflect.DeepEqual(toAdd, tc.want) {
t.Fatalf("getInstanceGroupsToAdd(_,_) error. Got:%v, Want:%v", toAdd, tc.want)
}
})
}

}
34 changes: 16 additions & 18 deletions pkg/backends/regional_ig_linker.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,10 @@ import (

cloudprovider "github.com/GoogleCloudPlatform/k8s-cloud-provider/pkg/cloud"
"github.com/GoogleCloudPlatform/k8s-cloud-provider/pkg/cloud/meta"
"k8s.io/apimachinery/pkg/util/sets"
"k8s.io/ingress-gce/pkg/composite"
"k8s.io/ingress-gce/pkg/instances"
"k8s.io/ingress-gce/pkg/utils"
"k8s.io/klog"
)

// RegionalInstanceGroupLinker handles linking backends to InstanceGroups.
Expand All @@ -39,40 +39,38 @@ func NewRegionalInstanceGroupLinker(instancePool instances.NodePool, backendPool

// Link performs linking instance groups to regional backend service
func (linker *RegionalInstanceGroupLinker) Link(sp utils.ServicePort, projectID string, zones []string) error {
var igLinks []string
klog.V(2).Infof("Link(%v, %q, %v)", sp, projectID, zones)

var igLinks []string
for _, zone := range zones {
key := meta.ZonalKey(sp.IGName(), zone)
igSelfLink := cloudprovider.SelfLink(meta.VersionGA, projectID, "instanceGroups", key)
igLinks = append(igLinks, igSelfLink)
}
kl52752 marked this conversation as resolved.
Show resolved Hide resolved

addIGs := sets.String{}
for _, igLink := range igLinks {
path, err := utils.RelativeResourceName(igLink)
if err != nil {
return fmt.Errorf("failed to parse instance group %s: %w", igLink, err)
}
addIGs.Insert(path)
bs, err := linker.backendPool.Get(sp.BackendName(), meta.VersionGA, meta.Regional)
if err != nil {
return err
}
addIGs, err := getInstanceGroupsToAdd(bs, igLinks)
if err != nil {
return err
}
if len(addIGs) == 0 {
klog.V(3).Infof("No backends to add for %s, skipping update.", sp.BackendName())
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we have this at V(2) so it appears in the normal log? Is it too noisy?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can do this as a follow up

return nil
kl52752 marked this conversation as resolved.
Show resolved Hide resolved
}
// TODO(kl52752) Check for existing links and add only new one

var newBackends []*composite.Backend
for _, igLink := range addIGs.List() {
for _, igLink := range addIGs {
kl52752 marked this conversation as resolved.
Show resolved Hide resolved
b := &composite.Backend{
Group: igLink,
}
newBackends = append(newBackends, b)
}
be, err := linker.backendPool.Get(sp.BackendName(), meta.VersionGA, meta.Regional)
if err != nil {
return err
}
be.Backends = newBackends

if err := linker.backendPool.Update(be); err != nil {
bs.Backends = newBackends
klog.V(3).Infof("Update Backend %s, with %d backends.", sp.BackendName(), len(addIGs))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same comment here V(2)

if err := linker.backendPool.Update(bs); err != nil {
kl52752 marked this conversation as resolved.
Show resolved Hide resolved
return fmt.Errorf("updating backend service %s for IG failed, err:%w", sp.BackendName(), err)
}
return nil
Expand Down
36 changes: 36 additions & 0 deletions pkg/backends/regional_ig_linker_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,42 @@ func TestRegionalLink(t *testing.T) {
}
}

func TestRegionalUpdateLink(t *testing.T) {
t.Parallel()
fakeGCE := gce.NewFakeGCECloud(linkerTestClusterValues())
clusterID, _ := fakeGCE.ClusterID.GetID()
l4Namer := namer.NewL4Namer("uid1", namer.NewNamer(clusterID, ""))
sp := utils.ServicePort{NodePort: 8080, BackendNamer: l4Namer}
fakeBackendPool := NewPool(fakeGCE, l4Namer)
linker := newTestRegionalIgLinker(fakeGCE, fakeBackendPool, l4Namer)
if _, err := linker.instancePool.EnsureInstanceGroupsAndPorts(l4Namer.InstanceGroup(), []int64{sp.NodePort}); err != nil {
t.Fatalf("Unexpected error when ensuring IG for ServicePort %+v: %v", sp, err)
}
createBackendService(t, sp, fakeBackendPool)

if err := linker.Link(sp, fakeGCE.ProjectID(), []string{uscentralzone}); err != nil {
t.Fatalf("Unexpected error in Link(_). Error: %v", err)
}
// Add error hook to check that Link function will not call Backend Service Update when no IG was added
(fakeGCE.Compute().(*cloud.MockGCE)).MockRegionBackendServices.UpdateHook = test.UpdateRegionBackendServiceWithErrorHookUpdate

if err := linker.Link(sp, fakeGCE.ProjectID(), []string{uscentralzone}); err != nil {
t.Fatalf("Unexpected error in Link(_). Error: %v", err)
}
be, err := fakeGCE.GetRegionBackendService(sp.BackendName(), fakeGCE.Region())
if err != nil {
t.Fatalf("Get Regional Backend Service failed %v", err)
}
if len(be.Backends) == 0 {
t.Fatalf("Expected Backends to be created")
}
ig, _ := linker.instancePool.Get(sp.IGName(), uscentralzone)
expectedLink, _ := utils.RelativeResourceName(ig.SelfLink)
if be.Backends[0].Group != expectedLink {
t.Fatalf("Expected Backend Group: %s received: %s", expectedLink, be.Backends[0].Group)
}
}

func createBackendService(t *testing.T, sp utils.ServicePort, backendPool *Backends) {
t.Helper()
namespacedName := types.NamespacedName{Name: "service.Name", Namespace: "service.Namespace"}
Expand Down
4 changes: 4 additions & 0 deletions pkg/test/gcehooks.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,10 @@ func DeleteBackendServicesErrorHook(ctx context.Context, key *meta.Key, m *cloud
return true, fmt.Errorf("DeleteBackendServicesErrorHook")
}

func UpdateRegionBackendServiceWithErrorHookUpdate(context.Context, *meta.Key, *compute.BackendService, *cloud.MockRegionBackendServices) error {
return fmt.Errorf("Undefined error")
}

func DeleteHealthCheckErrorHook(ctx context.Context, key *meta.Key, m *cloud.MockRegionHealthChecks) (bool, error) {
return true, fmt.Errorf("DeleteHealthCheckErrorHook")
}
Expand Down