Skip to content

Commit

Permalink
Add v2 frontend namer workflow
Browse files Browse the repository at this point in the history
  • Loading branch information
skmatti committed Oct 30, 2019
1 parent 212e82a commit 1e6d996
Show file tree
Hide file tree
Showing 27 changed files with 1,330 additions and 124 deletions.
14 changes: 13 additions & 1 deletion cmd/glbc/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ import (
"time"

flag "github.com/spf13/pflag"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
"k8s.io/ingress-gce/pkg/frontendconfig"
"k8s.io/klog"

Expand Down Expand Up @@ -130,6 +132,16 @@ func main() {
klog.V(0).Infof("Cluster name: %+v", namer.UID())
}

var kubeSystemUID types.UID
if flags.F.EnableV2FrontendNamer {
// Get kube-system UID that will be used for v2 frontend naming scheme.
ksNameSpace, err := kubeClient.CoreV1().Namespaces().Get("kube-system", metav1.GetOptions{})
if err != nil {
klog.Fatalf("kubeClient.CoreV1().Namespaces().Get(%q, _): %v, want nil", "kube-system", err)
}
kubeSystemUID = ksNameSpace.GetUID()
}

cloud := app.NewGCEClient()
defaultBackendServicePort := app.DefaultBackendServicePort(kubeClient)
ctxConfig := ingctx.ControllerContextConfig{
Expand All @@ -141,7 +153,7 @@ func main() {
FrontendConfigEnabled: flags.F.EnableFrontendConfig,
EnableCSM: flags.F.EnableCSM,
}
ctx := ingctx.NewControllerContext(kubeClient, dynamicClient, backendConfigClient, frontendConfigClient, cloud, namer, ctxConfig)
ctx := ingctx.NewControllerContext(kubeClient, dynamicClient, backendConfigClient, frontendConfigClient, cloud, namer, kubeSystemUID, ctxConfig)
go app.RunHTTPServer(ctx.HealthCheck)

if !flags.F.LeaderElection.LeaderElect {
Expand Down
6 changes: 5 additions & 1 deletion pkg/context/context.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import (

apiv1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/types"
"k8s.io/client-go/dynamic"
"k8s.io/client-go/dynamic/dynamicinformer"
informerv1 "k8s.io/client-go/informers/core/v1"
Expand Down Expand Up @@ -51,7 +52,8 @@ type ControllerContext struct {

Cloud *gce.Cloud

ClusterNamer *namer.Namer
ClusterNamer *namer.Namer
KubeSystemUID types.UID

ControllerContextConfig

Expand Down Expand Up @@ -92,12 +94,14 @@ func NewControllerContext(
frontendConfigClient frontendconfigclient.Interface,
cloud *gce.Cloud,
namer *namer.Namer,
kubeSystemUID types.UID,
config ControllerContextConfig) *ControllerContext {

context := &ControllerContext{
KubeClient: kubeClient,
Cloud: cloud,
ClusterNamer: namer,
KubeSystemUID: kubeSystemUID,
ControllerContextConfig: config,
IngressInformer: informerv1beta1.NewIngressInformer(kubeClient, config.Namespace, config.ResyncPeriod, utils.NewNamespaceIndexer()),
ServiceInformer: informerv1.NewServiceInformer(kubeClient, config.Namespace, config.ResyncPeriod, utils.NewNamespaceIndexer()),
Expand Down
92 changes: 78 additions & 14 deletions pkg/controller/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ func NewLoadBalancerController(
hasSynced: ctx.HasSynced,
nodes: NewNodeController(ctx, instancePool),
instancePool: instancePool,
l7Pool: loadbalancers.NewLoadBalancerPool(ctx.Cloud, ctx.ClusterNamer, ctx, namer.NewFrontendNamerFactory(ctx.ClusterNamer)),
l7Pool: loadbalancers.NewLoadBalancerPool(ctx.Cloud, ctx.ClusterNamer, ctx, namer.NewFrontendNamerFactory(ctx.ClusterNamer, ctx.KubeSystemUID)),
backendSyncer: backends.NewBackendSyncer(backendPool, healthChecker, ctx.Cloud),
negLinker: backends.NewNEGLinker(backendPool, negtypes.NewAdapter(ctx.Cloud), ctx.Cloud),
igLinker: backends.NewInstanceGroupLinker(instancePool, backendPool),
Expand Down Expand Up @@ -330,9 +330,10 @@ func (lbc *LoadBalancerController) Stop(deleteAll bool) error {
// TODO(rramkumar): Do we need deleteAll? Can we get rid of its' flag?
if deleteAll {
klog.Infof("Shutting down cluster manager.")
if err := lbc.l7Pool.Shutdown(); err != nil {
if err := lbc.l7Pool.Shutdown(lbc.ctx.Ingresses().List()); err != nil {
return err
}

// The backend pool will also delete instance groups.
return lbc.backendSyncer.Shutdown()
}
Expand Down Expand Up @@ -453,29 +454,46 @@ func (lbc *LoadBalancerController) SyncLoadBalancer(state interface{}) error {
return nil
}

// GCLoadBalancers implements Controller.
func (lbc *LoadBalancerController) GCLoadBalancers(toKeep []*v1beta1.Ingress) error {
// GCV1LoadBalancers implements Controller.
func (lbc *LoadBalancerController) GCV1LoadBalancers(toKeep []*v1beta1.Ingress) error {
// Filter GCE ingresses that use v1 naming scheme.
// Only GCE ingress associated resources are managed by this controller.
GCEIngresses := operator.Ingresses(toKeep).Filter(utils.IsGCEIngress).AsList()
return lbc.l7Pool.GC(common.ToIngressKeys(GCEIngresses))
V1GCEIngresses := operator.Ingresses(toKeep).Filter(func(ing *v1beta1.Ingress) bool {
return utils.IsGCEIngress(ing) && !namer.IsV2NamingScheme(ing)
}).AsList()
return lbc.l7Pool.GC(common.ToIngressKeys(V1GCEIngresses))
}

// MaybeRemoveFinalizers cleans up Finalizers if needed.
func (lbc *LoadBalancerController) MaybeRemoveFinalizers(toCleanup []*v1beta1.Ingress) error {
// EnsureDeleteV1Finalizers ensures that v1 finalizers are removed.
func (lbc *LoadBalancerController) EnsureDeleteV1Finalizers(toCleanup []*v1beta1.Ingress) error {
if !flags.F.FinalizerRemove {
klog.V(4).Infof("Removing finalizers not enabled")
return nil
}
for _, ing := range toCleanup {
if namer.IsV2NamingScheme(ing) {
// Skip if ingress uses v2 naming policy.
continue
}
ingClient := lbc.ctx.KubeClient.NetworkingV1beta1().Ingresses(ing.Namespace)
if err := common.RemoveFinalizer(ing, ingClient); err != nil {
klog.Errorf("Failed to remove Finalizer from Ingress %s/%s: %v", ing.Namespace, ing.Name, err)
if err := common.EnsureDeleteV1Finalizer(ing, ingClient); err != nil {
klog.Errorf("Failed to ensure delete for V1 Finalizer on Ingress %s/%s: %v", ing.Namespace, ing.Name, err)
return err
}
}
return nil
}

// ensureDeleteV2Finalizer ensures that v2 finalizer is removed for given ingress.
func (lbc *LoadBalancerController) ensureDeleteV2Finalizer(ing *v1beta1.Ingress) error {
if !flags.F.FinalizerRemove {
klog.V(4).Infof("Removing finalizers not enabled")
return nil
}
ingClient := lbc.ctx.KubeClient.NetworkingV1beta1().Ingresses(ing.Namespace)
return common.EnsureDeleteV2Finalizer(ing, ingClient)
}

// PostProcess implements Controller.
func (lbc *LoadBalancerController) PostProcess(state interface{}) error {
// We expect state to be a syncState
Expand Down Expand Up @@ -505,17 +523,41 @@ func (lbc *LoadBalancerController) sync(key string) error {
allIngresses := lbc.ctx.Ingresses().List()
// Determine if the ingress needs to be GCed.
if !ingExists || utils.NeedsCleanup(ing) {
// GC will find GCE resources that were used for this ingress and delete them.
// GC workflow for ingress with v2 naming policy.
// 1. GC load balancer for ingress being synced.
// 2. GC load balancers for v1 naming policy.
// 3. GC backends.
// 4. Ensure delete finalizers for v1 naming scheme.
// 5. Ensure delete finalizers for ingress being synced.
if namer.IsV2NamingScheme(ing) {
if err := lbc.l7Pool.V2GC(ing); err != nil {
return fmt.Errorf("error running load balancer garbage collection routine for v2 naming scheme: %v", err)
}
if err := lbc.ingSyncer.GC(allIngresses); err != nil {
return fmt.Errorf("error running garbage collection: %v", err)
}
return lbc.ensureDeleteV2Finalizer(ing)
}
return lbc.ingSyncer.GC(allIngresses)
}

// Get ingress and DeepCopy for assurance that we don't pollute other goroutines with changes.
ing = ing.DeepCopy()
ingClient := lbc.ctx.KubeClient.NetworkingV1beta1().Ingresses(ing.Namespace)
if flags.F.FinalizerAdd {
if err := common.AddFinalizer(ing, ingClient); err != nil {
klog.Errorf("Failed to add Finalizer to Ingress %q: %v", key, err)
if flags.F.FinalizerAdd && !common.HasFinalizer(ing.ObjectMeta) {
// Determine if we need to use v1 frontend naming scheme.
if isV1NamingScheme, err := lbc.needsToUseV1NamingScheme(ing); err != nil {
return err
} else if isV1NamingScheme {
if err := common.EnsureV1Finalizer(ing, ingClient); err != nil {
klog.Errorf("Failed to ensure V1 Finalizer on Ingress %q: %v", key, err)
return err
}
} else {
if err := common.EnsureV2Finalizer(ing, ingClient); err != nil {
klog.Errorf("Failed to ensure V2 Finalizer on Ingress %q: %v", key, err)
return err
}
}
}

Expand Down Expand Up @@ -649,3 +691,25 @@ func (lbc *LoadBalancerController) ToSvcPorts(ings []*v1beta1.Ingress) []utils.S
}
return knownPorts
}

// needsToUseV1NamingScheme returns true if given ingress needs to use legacy(v1) frontend naming scheme.
func (lbc *LoadBalancerController) needsToUseV1NamingScheme(ing *v1beta1.Ingress) (bool, error) {
// Ingress frontend naming scheme is determined based on the following logic,
// V2 frontend namer is disabled : v1 frontend naming scheme
// V2 frontend namer is enabled
// - VIP does not exists : v2 frontend naming scheme
// - VIP exists
// - GCE URL Map exists : v1 frontend naming scheme
// - GCE URL Map does not exists : v2 frontend naming scheme
if !flags.F.EnableV2FrontendNamer {
return true, nil
} else if utils.HasVIP(ing) {
if urlMapExists, err := lbc.l7Pool.HasUrlMap(ing); err != nil {
return false, err
} else if urlMapExists {
return true, nil
}
return false, nil
}
return false, nil
}
Loading

0 comments on commit 1e6d996

Please sign in to comment.