Files
flagger/pkg/controller/finalizer.go
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

210 lines
6.1 KiB
Go

package controller
import (
"fmt"
ex "github.com/pkg/errors"
flaggerv1 "github.com/weaveworks/flagger/pkg/apis/flagger/v1beta1"
"github.com/weaveworks/flagger/pkg/canary"
"k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/util/retry"
)
const finalizer = "finalizer.flagger.app"
func (c *Controller) finalize(old interface{}) error {
var r *flaggerv1.Canary
var ok bool
//Ensure interface is a canary
if r, ok = old.(*flaggerv1.Canary); !ok {
c.logger.Warnf("Received unexpected object: %v", old)
return nil
}
//Retrieve a controller
canaryController := c.canaryFactory.Controller(r.Spec.TargetRef.Kind)
//Set the status to terminating if not already in that state
if r.Status.Phase != flaggerv1.CanaryPhaseTerminating {
if err := canaryController.SetStatusPhase(r, flaggerv1.CanaryPhaseTerminating); err != nil {
c.logger.Infof("Failed to update status to finalizing %s", err)
return err
}
//record event
c.recordEventInfof(r, "Terminating canary %s.%s", r.Name, r.Namespace)
}
err := c.revertTargetRef(canaryController, r)
if err != nil {
if errors.IsNotFound(err) {
//No reason to wait not found
c.logger.Warnf("%s.%s failed due to %s not found", r.Name, r.Namespace, r.Spec.TargetRef.Kind)
return nil
}
c.logger.Errorf("%s.%s failed due to %s", r.Name, r.Namespace, err)
return err
} else {
//Ensure that targetRef has met a ready state
c.logger.Infof("Checking is canary is ready %s.%s", r.Name, r.Namespace)
ready, err := canaryController.IsCanaryReady(r)
if err != nil && ready {
return fmt.Errorf("%s.%s has not reached ready state during finalizing", r.Name, r.Namespace)
}
}
c.logger.Infof("%s.%s moving forward with router finalizing", r.Name, r.Namespace)
labelSelector, ports, err := canaryController.GetMetadata(r)
if err != nil {
c.logger.Errorf("%s.%s failed to get metadata for router finalizing", r.Name, r.Namespace)
return err
}
//Revert the router
if err := c.revertRouter(r, labelSelector, ports); err != nil {
if errors.IsNotFound(err) {
return nil
}
return err
}
c.logger.Infof("%s.%s moving forward with mesh finalizing", r.Name, r.Namespace)
//TODO if I can't revert the mesh continue on?
//Revert the Mesh
if err := c.revertMesh(r); err != nil {
if errors.IsNotFound(err) {
return nil
}
return err
}
c.logger.Infof("Finalization complete for %s.%s", r.Name, r.Namespace)
return nil
}
func (c *Controller) revertTargetRef(ctrl canary.Controller, r *flaggerv1.Canary) error {
if err := ctrl.Finalize(r); err != nil {
return err
}
c.logger.Infof("%s.%s kind %s reverted", r.Name, r.Namespace, r.Spec.TargetRef.Kind)
return nil
}
//revertRouter
func (c *Controller) revertRouter(r *flaggerv1.Canary, labelSelector string, ports map[string]int32) error {
router := c.routerFactory.KubernetesRouter(r.Spec.TargetRef.Kind, labelSelector, map[string]string{}, ports)
if err := router.Finalize(r); err != nil {
c.logger.Errorf("%s.%s router failed with error %s", r.Name, r.Namespace, err)
return err
}
c.logger.Infof("Service %s.%s reverted", r.Name, r.Namespace)
return nil
}
//revertMesh reverts defined mesh provider based upon the implementation's respective Finalize method.
//If the Finalize method encounters and error that is returned, else revert is considered successful.
func (c *Controller) revertMesh(r *flaggerv1.Canary) error {
provider := c.meshProvider
if r.Spec.Provider != "" {
provider = r.Spec.Provider
}
//Establish provider
meshRouter := c.routerFactory.MeshRouter(provider)
//Finalize mesh
err := meshRouter.Finalize(r)
if err != nil {
c.logger.Errorf("%s.%s mesh failed with error %s", r.Name, r.Namespace, err)
return err
}
c.logger.Infof("%s.%s mesh provider %s reverted", r.Name, r.Namespace, provider)
return nil
}
//hasFinalizer evaluates the finalizers of a given canary for for existence of a provide finalizer string.
//It returns a boolean, true if the finalizer is found false otherwise.
func hasFinalizer(canary *flaggerv1.Canary, finalizerString string) bool {
currentFinalizers := canary.ObjectMeta.Finalizers
for _, f := range currentFinalizers {
if f == finalizerString {
return true
}
}
return false
}
//addFinalizer adds a provided finalizer to the specified canary resource.
//If failures occur the error will be returned otherwise the action is deemed successful
//and error will be nil.
func (c *Controller) addFinalizer(canary *flaggerv1.Canary, finalizerString string) error {
firstTry := true
err := retry.RetryOnConflict(retry.DefaultBackoff, func() (err error) {
var selErr error
if !firstTry {
canary, selErr = c.flaggerClient.FlaggerV1beta1().Canaries(canary.Namespace).Get(canary.GetName(), metav1.GetOptions{})
if selErr != nil {
return selErr
}
}
copy := canary.DeepCopy()
copy.ObjectMeta.Finalizers = append(copy.ObjectMeta.Finalizers, finalizerString)
_, err = c.flaggerClient.FlaggerV1beta1().Canaries(canary.Namespace).Update(copy)
firstTry = false
return
})
if err != nil {
return ex.Wrap(err, "Remove finalizer failed")
}
return nil
}
//removeFinalizer removes a provided finalizer to the specified canary resource.
//If failures occur the error will be returned otherwise the action is deemed successful
//and error will be nil.
func (c *Controller) removeFinalizer(canary *flaggerv1.Canary, finalizerString string) error {
firstTry := true
err := retry.RetryOnConflict(retry.DefaultBackoff, func() (err error) {
var selErr error
if !firstTry {
canary, selErr = c.flaggerClient.FlaggerV1beta1().Canaries(canary.Namespace).Get(canary.GetName(), metav1.GetOptions{})
if selErr != nil {
return selErr
}
}
copy := canary.DeepCopy()
newSlice := make([]string, 0)
for _, item := range copy.ObjectMeta.Finalizers {
if item == finalizerString {
continue
}
newSlice = append(newSlice, item)
}
if len(newSlice) == 0 {
newSlice = nil
}
copy.ObjectMeta.Finalizers = newSlice
_, err = c.flaggerClient.FlaggerV1beta1().Canaries(canary.Namespace).Update(copy)
firstTry = false
return
})
if err != nil {
return ex.Wrap(err, "Remove finalizer failed")
}
return nil
}