From 5b8bd2808b6f7741f90641b7f435b2b747c79624 Mon Sep 17 00:00:00 2001 From: Sven Walter Date: Wed, 16 Aug 2017 20:30:55 +0200 Subject: [PATCH] add removeOldJob interceptor --- pkg/api/app.go | 10 ++ pkg/api/apply.go | 8 +- pkg/api/test-fixtures/deployments-golden.yaml | 14 +++ pkg/interceptors/interfaces.go | 7 +- pkg/interceptors/multi.go | 22 ++++- pkg/interceptors/rmoldjob/interceptor.go | 93 +++++++++++++++++++ .../rmoldjob/interceptors_test.go | 13 +++ pkg/interceptors/waiter/interceptor.go | 2 +- pkg/interceptors/waiter/interceptors_test.go | 4 +- pkg/settings/interceptors.go | 1 + .../test-fixtures/services-clean-golden.yaml | 18 ++++ .../services-context-golden.yaml | 18 ++++ .../test-fixtures/services-plain-golden.yaml | 4 + 13 files changed, 207 insertions(+), 7 deletions(-) create mode 100644 pkg/interceptors/rmoldjob/interceptor.go create mode 100644 pkg/interceptors/rmoldjob/interceptors_test.go diff --git a/pkg/api/app.go b/pkg/api/app.go index 784523d..3a080dd 100644 --- a/pkg/api/app.go +++ b/pkg/api/app.go @@ -5,6 +5,7 @@ import ( "github.com/rebuy-de/kubernetes-deployment/pkg/gh" "github.com/rebuy-de/kubernetes-deployment/pkg/interceptors" "github.com/rebuy-de/kubernetes-deployment/pkg/interceptors/prestopsleep" + "github.com/rebuy-de/kubernetes-deployment/pkg/interceptors/rmoldjob" "github.com/rebuy-de/kubernetes-deployment/pkg/interceptors/rmresspec" "github.com/rebuy-de/kubernetes-deployment/pkg/interceptors/statuschecker" "github.com/rebuy-de/kubernetes-deployment/pkg/interceptors/waiter" @@ -91,6 +92,15 @@ func New(p *Parameters) (*App, error) { )) } + if interceptors.RemoveOldJob.Enabled == settings.Enabled { + log.WithFields(log.Fields{ + "Interceptor": "removeOldJob", + }).Debug("enabling removeOldJob interceptor") + app.Interceptors.Add(rmoldjob.New( + app.Clients.Kubernetes, + )) + } + return app, nil } diff --git a/pkg/api/apply.go b/pkg/api/apply.go index 8279a2c..99bb58c 100644 --- a/pkg/api/apply.go +++ b/pkg/api/apply.go @@ -27,11 +27,17 @@ func (app *App) Apply(project, branchName string) error { } for _, obj := range objects { + obj, err = app.Interceptors.PreManifestApply(obj) + if err != nil { + return errors.WithStack(err) + } + upstreamObj, err := app.Clients.Kubectl.Apply(obj) if err != nil { return errors.Wrap(err, "unable to apply manifest") } - err = app.Interceptors.PreManifestApply(upstreamObj) + + err = app.Interceptors.PostManifestApply(upstreamObj) if err != nil { return errors.WithStack(err) } diff --git a/pkg/api/test-fixtures/deployments-golden.yaml b/pkg/api/test-fixtures/deployments-golden.yaml index 6a876e9..6f6309f 100644 --- a/pkg/api/test-fixtures/deployments-golden.yaml +++ b/pkg/api/test-fixtures/deployments-golden.yaml @@ -12,6 +12,8 @@ defaults: seconds: 3 removeResourceSpecs: enabled: null + removeOldJob: + enabled: null waiter: enabled: null ghStatusChecker: @@ -38,6 +40,8 @@ services: seconds: 3 removeResourceSpecs: enabled: null + removeOldJob: + enabled: null waiter: enabled: null ghStatusChecker: @@ -63,6 +67,8 @@ services: seconds: 3 removeResourceSpecs: enabled: null + removeOldJob: + enabled: null waiter: enabled: null ghStatusChecker: @@ -88,6 +94,8 @@ services: seconds: 3 removeResourceSpecs: enabled: null + removeOldJob: + enabled: null waiter: enabled: null ghStatusChecker: @@ -113,6 +121,8 @@ services: seconds: 3 removeResourceSpecs: enabled: null + removeOldJob: + enabled: null waiter: enabled: null ghStatusChecker: @@ -138,6 +148,8 @@ contexts: seconds: 3 removeResourceSpecs: enabled: null + removeOldJob: + enabled: null waiter: enabled: null ghStatusChecker: @@ -162,6 +174,8 @@ contexts: seconds: 3 removeResourceSpecs: enabled: null + removeOldJob: + enabled: null waiter: enabled: null ghStatusChecker: diff --git a/pkg/interceptors/interfaces.go b/pkg/interceptors/interfaces.go index 63614a9..15b2d10 100644 --- a/pkg/interceptors/interfaces.go +++ b/pkg/interceptors/interfaces.go @@ -9,6 +9,7 @@ type Interface interface { PostFetcher PreApplier PreManifestApplier + PostManifestApplier PostApplier PostManifestRenderer Closer @@ -23,7 +24,11 @@ type PreApplier interface { } type PreManifestApplier interface { - PreManifestApply(runtime.Object) error + PreManifestApply(runtime.Object) (runtime.Object, error) +} + +type PostManifestApplier interface { + PostManifestApply(runtime.Object) error } type PostApplier interface { diff --git a/pkg/interceptors/multi.go b/pkg/interceptors/multi.go index b30086d..4ce7088 100644 --- a/pkg/interceptors/multi.go +++ b/pkg/interceptors/multi.go @@ -53,14 +53,32 @@ func (m *Multi) PreApply(objs []runtime.Object) error { return nil } -func (m *Multi) PreManifestApply(obj runtime.Object) error { +func (m *Multi) PreManifestApply(obj runtime.Object) (runtime.Object, error) { + var err error + for _, i := range m.Interceptors { c, ok := i.(PreManifestApplier) if !ok { continue } - err := c.PreManifestApply(obj) + obj, err = c.PreManifestApply(obj) + if err != nil { + return obj, errors.WithStack(err) + } + } + + return obj, nil +} + +func (m *Multi) PostManifestApply(obj runtime.Object) error { + for _, i := range m.Interceptors { + c, ok := i.(PostManifestApplier) + if !ok { + continue + } + + err := c.PostManifestApply(obj) if err != nil { return errors.WithStack(err) } diff --git a/pkg/interceptors/rmoldjob/interceptor.go b/pkg/interceptors/rmoldjob/interceptor.go new file mode 100644 index 0000000..d3d9544 --- /dev/null +++ b/pkg/interceptors/rmoldjob/interceptor.go @@ -0,0 +1,93 @@ +package rmoldjob + +import ( + "fmt" + "reflect" + + "github.com/pkg/errors" + log "github.com/sirupsen/logrus" + k8serr "k8s.io/apimachinery/pkg/api/errors" + v1meta "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/client-go/kubernetes" + v1batch "k8s.io/client-go/pkg/apis/batch/v1" +) + +const Annotation = "rebuy.com/delete-on-deploy" + +type Interceptor struct { + client kubernetes.Interface +} + +func New(client kubernetes.Interface) *Interceptor { + return &Interceptor{ + client: client, + } +} + +func (i *Interceptor) PreManifestApply(obj runtime.Object) (runtime.Object, error) { + job, ok := obj.(*v1batch.Job) + if !ok { + log.WithFields(log.Fields{ + "type": reflect.TypeOf(obj), + }).Debug("type doesn't support deletion of old jobs") + return obj, nil + } + + name := job.ObjectMeta.Name + namespace := job.ObjectMeta.Namespace + + if namespace == "" { + namespace = "default" + } + + has, err := i.hasJob(namespace, name) + if !has || err != nil { + return obj, errors.WithStack(err) + } + + if !v1meta.HasAnnotation(job.ObjectMeta, Annotation) || + job.ObjectMeta.Annotations[Annotation] != "true" { + log.WithFields(log.Fields{ + "Namespace": namespace, + "Name": name, + }).Debug("skip deletion of job, because the annotation is missing") + return obj, nil + } + + log.WithFields(log.Fields{ + "Namespace": namespace, + "Name": name, + }).Infof("deleting pending job: %s", name) + + return obj, i.client. + Batch(). + Jobs(namespace). + Delete(name, nil) +} + +func (i *Interceptor) hasJob(namespace, name string) (bool, error) { + _, err := i.client. + Batch(). + Jobs(namespace). + Get(name, v1meta.GetOptions{}) + + if err == nil { + return true, nil + } + + status, ok := err.(*k8serr.StatusError) + if !ok { + return false, err + } + + log.WithFields(log.Fields{ + "Error": fmt.Sprintf("%#v", status.ErrStatus), + }).Debug("got error status") + + if status.ErrStatus.Reason == v1meta.StatusReasonNotFound { + return false, nil + } + + return false, err +} diff --git a/pkg/interceptors/rmoldjob/interceptors_test.go b/pkg/interceptors/rmoldjob/interceptors_test.go new file mode 100644 index 0000000..bed1cfd --- /dev/null +++ b/pkg/interceptors/rmoldjob/interceptors_test.go @@ -0,0 +1,13 @@ +package rmoldjob + +import ( + "testing" + + "github.com/rebuy-de/kubernetes-deployment/pkg/interceptors" +) + +func TestTypePreManifestApplier(t *testing.T) { + var inter interceptors.PreManifestApplier + inter = &Interceptor{} + _ = inter +} diff --git a/pkg/interceptors/waiter/interceptor.go b/pkg/interceptors/waiter/interceptor.go index ca07581..f27fdfb 100644 --- a/pkg/interceptors/waiter/interceptor.go +++ b/pkg/interceptors/waiter/interceptor.go @@ -51,7 +51,7 @@ func (dwi *DeploymentWaitInterceptor) Close() error { return nil } -func (dwi *DeploymentWaitInterceptor) PreManifestApply(obj runtime.Object) error { +func (dwi *DeploymentWaitInterceptor) PostManifestApply(obj runtime.Object) error { deployment, ok := obj.(*v1beta1.Deployment) if !ok { return nil diff --git a/pkg/interceptors/waiter/interceptors_test.go b/pkg/interceptors/waiter/interceptors_test.go index 9d86492..df208ee 100644 --- a/pkg/interceptors/waiter/interceptors_test.go +++ b/pkg/interceptors/waiter/interceptors_test.go @@ -12,8 +12,8 @@ func TestTypePostApplier(t *testing.T) { _ = inter } -func TestTypePreManifestApplier(t *testing.T) { - var inter interceptors.PreManifestApplier +func TestTypePostManifestApplier(t *testing.T) { + var inter interceptors.PostManifestApplier inter = &DeploymentWaitInterceptor{} _ = inter } diff --git a/pkg/settings/interceptors.go b/pkg/settings/interceptors.go index 6cea76f..76648ad 100644 --- a/pkg/settings/interceptors.go +++ b/pkg/settings/interceptors.go @@ -8,6 +8,7 @@ import ( type Interceptors struct { PreStopSleep PreStopSleepInterceptor `yaml:"preStopSleep"` RemoveResourceSpecs Interceptor `yaml:"removeResourceSpecs"` + RemoveOldJob Interceptor `yaml:"removeOldJob"` Waiter Interceptor `yaml:"waiter"` GHStatusChecker GHStatusCheckerInterceptor `yaml:"ghStatusChecker"` } diff --git a/pkg/settings/test-fixtures/services-clean-golden.yaml b/pkg/settings/test-fixtures/services-clean-golden.yaml index 56a3279..dce403e 100644 --- a/pkg/settings/test-fixtures/services-clean-golden.yaml +++ b/pkg/settings/test-fixtures/services-clean-golden.yaml @@ -13,6 +13,8 @@ defaults: seconds: 3 removeResourceSpecs: enabled: null + removeOldJob: + enabled: null waiter: enabled: true ghStatusChecker: @@ -41,6 +43,8 @@ services: seconds: 3 removeResourceSpecs: enabled: null + removeOldJob: + enabled: null waiter: enabled: true ghStatusChecker: @@ -68,6 +72,8 @@ services: seconds: 3 removeResourceSpecs: enabled: null + removeOldJob: + enabled: null waiter: enabled: true ghStatusChecker: @@ -95,6 +101,8 @@ services: seconds: 3 removeResourceSpecs: enabled: null + removeOldJob: + enabled: null waiter: enabled: true ghStatusChecker: @@ -122,6 +130,8 @@ services: seconds: 3 removeResourceSpecs: enabled: null + removeOldJob: + enabled: null waiter: enabled: true ghStatusChecker: @@ -149,6 +159,8 @@ services: seconds: 3 removeResourceSpecs: enabled: null + removeOldJob: + enabled: null waiter: enabled: true ghStatusChecker: @@ -176,6 +188,8 @@ services: seconds: 3 removeResourceSpecs: enabled: null + removeOldJob: + enabled: null waiter: enabled: true ghStatusChecker: @@ -203,6 +217,8 @@ contexts: seconds: 3 removeResourceSpecs: enabled: null + removeOldJob: + enabled: null waiter: enabled: true ghStatusChecker: @@ -229,6 +245,8 @@ contexts: seconds: 3 removeResourceSpecs: enabled: true + removeOldJob: + enabled: null waiter: enabled: true ghStatusChecker: diff --git a/pkg/settings/test-fixtures/services-context-golden.yaml b/pkg/settings/test-fixtures/services-context-golden.yaml index c3abc3a..f66bd9c 100644 --- a/pkg/settings/test-fixtures/services-context-golden.yaml +++ b/pkg/settings/test-fixtures/services-context-golden.yaml @@ -13,6 +13,8 @@ defaults: seconds: 3 removeResourceSpecs: enabled: null + removeOldJob: + enabled: null waiter: enabled: true ghStatusChecker: @@ -41,6 +43,8 @@ services: seconds: 3 removeResourceSpecs: enabled: true + removeOldJob: + enabled: null waiter: enabled: true ghStatusChecker: @@ -68,6 +72,8 @@ services: seconds: 3 removeResourceSpecs: enabled: true + removeOldJob: + enabled: null waiter: enabled: true ghStatusChecker: @@ -95,6 +101,8 @@ services: seconds: 3 removeResourceSpecs: enabled: true + removeOldJob: + enabled: null waiter: enabled: true ghStatusChecker: @@ -122,6 +130,8 @@ services: seconds: 3 removeResourceSpecs: enabled: true + removeOldJob: + enabled: null waiter: enabled: true ghStatusChecker: @@ -149,6 +159,8 @@ services: seconds: 3 removeResourceSpecs: enabled: true + removeOldJob: + enabled: null waiter: enabled: true ghStatusChecker: @@ -176,6 +188,8 @@ services: seconds: 3 removeResourceSpecs: enabled: true + removeOldJob: + enabled: null waiter: enabled: true ghStatusChecker: @@ -203,6 +217,8 @@ contexts: seconds: 3 removeResourceSpecs: enabled: null + removeOldJob: + enabled: null waiter: enabled: true ghStatusChecker: @@ -229,6 +245,8 @@ contexts: seconds: 3 removeResourceSpecs: enabled: true + removeOldJob: + enabled: null waiter: enabled: true ghStatusChecker: diff --git a/pkg/settings/test-fixtures/services-plain-golden.yaml b/pkg/settings/test-fixtures/services-plain-golden.yaml index cc30699..66cfc25 100644 --- a/pkg/settings/test-fixtures/services-plain-golden.yaml +++ b/pkg/settings/test-fixtures/services-plain-golden.yaml @@ -12,6 +12,8 @@ defaults: seconds: 3 removeResourceSpecs: enabled: null + removeOldJob: + enabled: null waiter: enabled: true ghStatusChecker: @@ -49,6 +51,8 @@ contexts: seconds: 0 removeResourceSpecs: enabled: true + removeOldJob: + enabled: null waiter: enabled: null ghStatusChecker: