Files
flagger/pkg/router/gloo.go
T
Tanner Altares 92937a8f48 kubectl annotation support
rebase and squash

fix fmt issues

revert Dockerfile

revert go.mod and go.sum

introduction of finalizer

introduction of finalizer

remove test for finalizer add istio tests

fix fmt issues

revert go.mod and go.sum

revert Dockerfile and main.go

fmt deployment controller

introduction of finalizer

rebase and squash

fix fmt issues

revert Dockerfile

revert go.mod and go.sum

introduction of finalizer

introduction of finalizer

remove test for finalizer add istio tests

fix fmt issues

revert go.mod and go.sum

revert Dockerfile and main.go

fmt deployment controller

add unit tests for finalizing

introduction of finalizer

rebase and squash

fix fmt issues

revert Dockerfile

revert go.mod and go.sum

introduction of finalizer

introduction of finalizer

remove test for finalizer add istio tests

fix fmt issues

revert go.mod and go.sum

revert Dockerfile and main.go

fmt deployment controller

run fmt to clean up formatting

review changes

add kubectl annotation

add kubectl annotation support

introduction of finalizer

introduction of finalizer

rebase and squash

fix fmt issues

revert Dockerfile

revert go.mod and go.sum

introduction of finalizer

introduction of finalizer

remove test for finalizer add istio tests

fix fmt issues

revert go.mod and go.sum

revert Dockerfile and main.go

fmt deployment controller

introduction of finalizer

rebase and squash

fix fmt issues

revert Dockerfile

revert go.mod and go.sum

introduction of finalizer

introduction of finalizer

remove test for finalizer add istio tests

fix fmt issues

revert go.mod and go.sum

revert Dockerfile and main.go

fmt deployment controller

add unit tests for finalizing

introduction of finalizer

rebase and squash

fix fmt issues

revert Dockerfile

revert go.mod and go.sum

introduction of finalizer

introduction of finalizer

remove test for finalizer add istio tests

fix fmt issues

revert go.mod and go.sum

revert Dockerfile and main.go

fmt deployment controller

run fmt to clean up formatting

review changes

introduction of finalizer

introduction of finalizer

rebase and squash

fix fmt issues

revert Dockerfile

revert go.mod and go.sum

introduction of finalizer

introduction of finalizer

remove test for finalizer add istio tests

fix fmt issues

revert go.mod and go.sum

revert Dockerfile and main.go

fmt deployment controller

introduction of finalizer

rebase and squash

fix fmt issues

revert Dockerfile

revert go.mod and go.sum

introduction of finalizer

introduction of finalizer

remove test for finalizer add istio tests

fix fmt issues

revert go.mod and go.sum

revert Dockerfile and main.go

fmt deployment controller

add unit tests for finalizing

introduction of finalizer

rebase and squash

fix fmt issues

revert Dockerfile

revert go.mod and go.sum

introduction of finalizer

introduction of finalizer

remove test for finalizer add istio tests

fix fmt issues

revert go.mod and go.sum

revert Dockerfile and main.go

fmt deployment controller

run fmt to clean up formatting

review changes
2020-03-20 15:13:51 -05:00

192 lines
5.8 KiB
Go

package router
import (
"fmt"
"github.com/google/go-cmp/cmp"
"github.com/google/go-cmp/cmp/cmpopts"
gloov1 "github.com/weaveworks/flagger/pkg/apis/gloo/v1"
"go.uber.org/zap"
"k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/client-go/kubernetes"
flaggerv1 "github.com/weaveworks/flagger/pkg/apis/flagger/v1beta1"
clientset "github.com/weaveworks/flagger/pkg/client/clientset/versioned"
)
// GlooRouter is managing Istio virtual services
type GlooRouter struct {
kubeClient kubernetes.Interface
glooClient clientset.Interface
flaggerClient clientset.Interface
logger *zap.SugaredLogger
upstreamDiscoveryNs string
}
// Reconcile creates or updates the Istio virtual service
func (gr *GlooRouter) Reconcile(canary *flaggerv1.Canary) error {
apexName, _, _ := canary.GetServiceNames()
canaryName := fmt.Sprintf("%s-%s-canary-%v", canary.Namespace, apexName, canary.Spec.Service.Port)
primaryName := fmt.Sprintf("%s-%s-primary-%v", canary.Namespace, apexName, canary.Spec.Service.Port)
newSpec := gloov1.UpstreamGroupSpec{
Destinations: []gloov1.WeightedDestination{
{
Destination: gloov1.Destination{
Upstream: gloov1.ResourceRef{
Name: primaryName,
Namespace: gr.upstreamDiscoveryNs,
},
},
Weight: 100,
},
{
Destination: gloov1.Destination{
Upstream: gloov1.ResourceRef{
Name: canaryName,
Namespace: gr.upstreamDiscoveryNs,
},
},
Weight: 0,
},
},
}
upstreamGroup, err := gr.glooClient.GlooV1().UpstreamGroups(canary.Namespace).Get(apexName, metav1.GetOptions{})
if errors.IsNotFound(err) {
upstreamGroup = &gloov1.UpstreamGroup{
ObjectMeta: metav1.ObjectMeta{
Name: apexName,
Namespace: canary.Namespace,
OwnerReferences: []metav1.OwnerReference{
*metav1.NewControllerRef(canary, schema.GroupVersionKind{
Group: flaggerv1.SchemeGroupVersion.Group,
Version: flaggerv1.SchemeGroupVersion.Version,
Kind: flaggerv1.CanaryKind,
}),
},
},
Spec: newSpec,
}
_, err = gr.glooClient.GlooV1().UpstreamGroups(canary.Namespace).Create(upstreamGroup)
if err != nil {
return fmt.Errorf("UpstreamGroup %s.%s create error: %w", apexName, canary.Namespace, err)
}
gr.logger.With("canary", fmt.Sprintf("%s.%s", canary.Name, canary.Namespace)).
Infof("UpstreamGroup %s.%s created", upstreamGroup.GetName(), canary.Namespace)
return nil
} else if err != nil {
return fmt.Errorf("UpstreamGroup %s.%s get query error: %w", apexName, canary.Namespace, err)
}
// update upstreamGroup but keep the original destination weights
if upstreamGroup != nil {
if diff := cmp.Diff(
newSpec,
upstreamGroup.Spec,
cmpopts.IgnoreFields(gloov1.WeightedDestination{}, "Weight"),
); diff != "" {
clone := upstreamGroup.DeepCopy()
clone.Spec = newSpec
_, err = gr.glooClient.GlooV1().UpstreamGroups(canary.Namespace).Update(clone)
if err != nil {
return fmt.Errorf("UpstreamGroup %s.%s update error: %w", apexName, canary.Namespace, err)
}
gr.logger.With("canary", fmt.Sprintf("%s.%s", canary.Name, canary.Namespace)).
Infof("UpstreamGroup %s.%s updated", upstreamGroup.GetName(), canary.Namespace)
}
}
return nil
}
// GetRoutes returns the destinations weight for primary and canary
func (gr *GlooRouter) GetRoutes(canary *flaggerv1.Canary) (
primaryWeight int,
canaryWeight int,
mirrored bool,
err error,
) {
apexName := canary.Spec.TargetRef.Name
primaryName := fmt.Sprintf("%s-%s-primary-%v", canary.Namespace, canary.Spec.TargetRef.Name, canary.Spec.Service.Port)
upstreamGroup, err := gr.glooClient.GlooV1().UpstreamGroups(canary.Namespace).Get(apexName, metav1.GetOptions{})
if err != nil {
err = fmt.Errorf("UpstreamGroup %s.%s get query error: %w", apexName, canary.Namespace, err)
return
}
if len(upstreamGroup.Spec.Destinations) < 2 {
err = fmt.Errorf("UpstreamGroup %s.%s destinations not found", apexName, canary.Namespace)
return
}
for _, dst := range upstreamGroup.Spec.Destinations {
if dst.Destination.Upstream.Name == primaryName {
primaryWeight = int(dst.Weight)
canaryWeight = 100 - primaryWeight
return
}
}
return
}
// SetRoutes updates the destinations weight for primary and canary
func (gr *GlooRouter) SetRoutes(
canary *flaggerv1.Canary,
primaryWeight int,
canaryWeight int,
_ bool,
) error {
apexName, _, _ := canary.GetServiceNames()
canaryName := fmt.Sprintf("%s-%s-canary-%v", canary.Namespace, apexName, canary.Spec.Service.Port)
primaryName := fmt.Sprintf("%s-%s-primary-%v", canary.Namespace, apexName, canary.Spec.Service.Port)
if primaryWeight == 0 && canaryWeight == 0 {
return fmt.Errorf("RoutingRule %s.%s update failed: no valid weights", apexName, canary.Namespace)
}
upstreamGroup, err := gr.glooClient.GlooV1().UpstreamGroups(canary.Namespace).Get(apexName, metav1.GetOptions{})
if err != nil {
return fmt.Errorf("UpstreamGroup %s.%s query error: %w", apexName, canary.Namespace, err)
}
upstreamGroup.Spec = gloov1.UpstreamGroupSpec{
Destinations: []gloov1.WeightedDestination{
{
Destination: gloov1.Destination{
Upstream: gloov1.ResourceRef{
Name: primaryName,
Namespace: gr.upstreamDiscoveryNs,
},
},
Weight: uint32(primaryWeight),
},
{
Destination: gloov1.Destination{
Upstream: gloov1.ResourceRef{
Name: canaryName,
Namespace: gr.upstreamDiscoveryNs,
},
},
Weight: uint32(canaryWeight),
},
},
}
_, err = gr.glooClient.GlooV1().UpstreamGroups(canary.Namespace).Update(upstreamGroup)
if err != nil {
return fmt.Errorf("UpstreamGroup %s.%s update error: %w", apexName, canary.Namespace, err)
}
return nil
}
func (gr *GlooRouter) Finalize(canary *flaggerv1.Canary) error {
return nil
}