From 9065397bab1e52fdc31b2315017fe695f34b4044 Mon Sep 17 00:00:00 2001 From: mmengspv <60773476+mmengspv@users.noreply.github.com> Date: Fri, 21 Oct 2022 10:53:01 +0700 Subject: [PATCH] =?UTF-8?q?=F0=9F=8D=B1=20[minor]=20Add=20NoDowntimeGuaran?= =?UTF-8?q?tee=20flag=20(#140)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: add customMessage field to s2h workflow * fix: reporter send with criteria and add test case * fix: change customMessage to extraMessage * example: add extraMessage to example config.yaml * fix: clean-up slackExtraMessage * chore: extraMessage example config descption * fix: refactor and change description * chore: clean-up unused parse string * chore: edit example extraMessage description * fix: slack reporter_test unused parse string * feat: add switch before demote flag * fix: change to NoDowntimeGuarantee, add logging and logic to send the report * fix: send the report only active namespace has been promoted * chore: edit a warning description * fix: add condition to check noDowntime cannot be nil * chore: edit description of the examples --- api/v1/activepromotion_types.go | 4 +++ api/v1/config_types.go | 3 +++ api/v1/zz_generated.deepcopy.go | 5 ++++ ....samsahai.io_activepromotionhistories.yaml | 5 ++++ .../env.samsahai.io_activepromotions.yaml | 5 ++++ config/crds/env.samsahai.io_configs.yaml | 10 +++++++ docs/docs.go | 10 ++++++- docs/swagger.json | 8 ++++++ docs/swagger.yaml | 10 +++++++ .../crds/active-promotion-example.yaml | 3 ++- examples/configs/crds/config-example.yaml | 1 + examples/starter/crds/active-promotion.yaml | 7 +++++ examples/starter/crds/config.yaml | 6 +++++ .../activepromotion/collect_result.go | 7 +++++ .../samsahai/activepromotion/controller.go | 21 +++++++++++---- internal/samsahai/activepromotion/demote.go | 26 +++++++++++++++++++ .../samsahai/activepromotion/postactive.go | 2 +- internal/samsahai/activepromotion/promote.go | 14 ++++++++-- ....samsahai.io_activepromotionhistories.yaml | 5 ++++ .../env.samsahai.io_activepromotions.yaml | 5 ++++ test/data/crds/env.samsahai.io_configs.yaml | 10 +++++++ 21 files changed, 157 insertions(+), 10 deletions(-) diff --git a/api/v1/activepromotion_types.go b/api/v1/activepromotion_types.go index 5b197226..c1a7a310 100644 --- a/api/v1/activepromotion_types.go +++ b/api/v1/activepromotion_types.go @@ -130,6 +130,10 @@ type ActivePromotionSpec struct { // PromotedBy represents a person who promoted the ActivePromotion // +optional PromotedBy string `json:"promotedBy,omitempty"` + + // NoDowntimeGuarantee represents a flag for switching to the new namespace before demoting the active namespace and guarantees the process will not have a downtime + // +optional + NoDowntimeGuarantee *bool `json:"noDowntimeGuarantee,omitempty"` } func (s *ActivePromotionSpec) SetTearDownDuration(d metav1.Duration) { diff --git a/api/v1/config_types.go b/api/v1/config_types.go index 0945ca4d..1eea2431 100644 --- a/api/v1/config_types.go +++ b/api/v1/config_types.go @@ -319,6 +319,9 @@ type ConfigActivePromotion struct { // +optional OutdatedNotification *OutdatedNotification `json:"outdatedNotification,omitempty"` + // NoDowntimeGuarantee defines a flag for switching to the new namespace before demoting the active namespace and guarantees the process will not have a downtime + NoDowntimeGuarantee bool `json:"noDowntimeGuarantee,omitempty"` + // Deployment represents configuration about deploy // +optional Deployment *ConfigDeploy `json:"deployment,omitempty"` diff --git a/api/v1/zz_generated.deepcopy.go b/api/v1/zz_generated.deepcopy.go index 8cab74ea..c647ef9b 100644 --- a/api/v1/zz_generated.deepcopy.go +++ b/api/v1/zz_generated.deepcopy.go @@ -229,6 +229,11 @@ func (in *ActivePromotionSpec) DeepCopyInto(out *ActivePromotionSpec) { *out = new(metav1.Duration) **out = **in } + if in.NoDowntimeGuarantee != nil { + in, out := &in.NoDowntimeGuarantee, &out.NoDowntimeGuarantee + *out = new(bool) + **out = **in + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ActivePromotionSpec. diff --git a/config/crds/env.samsahai.io_activepromotionhistories.yaml b/config/crds/env.samsahai.io_activepromotionhistories.yaml index 76b43180..3047811c 100644 --- a/config/crds/env.samsahai.io_activepromotionhistories.yaml +++ b/config/crds/env.samsahai.io_activepromotionhistories.yaml @@ -59,6 +59,11 @@ spec: description: ActivePromotionSpec defines the desired state of ActivePromotion properties: + noDowntimeGuarantee: + description: NoDowntimeGuarantee represents a flag for switching + to the new namespace before demoting the active namespace + and guarantees the process will not have a downtime + type: boolean noOfRetry: description: NoOfRetry represents how many times this active promotion process has been run diff --git a/config/crds/env.samsahai.io_activepromotions.yaml b/config/crds/env.samsahai.io_activepromotions.yaml index 38e2d03a..087ad875 100644 --- a/config/crds/env.samsahai.io_activepromotions.yaml +++ b/config/crds/env.samsahai.io_activepromotions.yaml @@ -36,6 +36,11 @@ spec: spec: description: ActivePromotionSpec defines the desired state of ActivePromotion properties: + noDowntimeGuarantee: + description: NoDowntimeGuarantee represents a flag for switching to + the new namespace before demoting the active namespace and guarantees + the process will not have a downtime + type: boolean noOfRetry: description: NoOfRetry represents how many times this active promotion process has been run diff --git a/config/crds/env.samsahai.io_configs.yaml b/config/crds/env.samsahai.io_configs.yaml index 3405d37b..dcda79fd 100644 --- a/config/crds/env.samsahai.io_configs.yaml +++ b/config/crds/env.samsahai.io_configs.yaml @@ -117,6 +117,11 @@ spec: description: MaxRetry defines max retry counts of active promotion process in case failure type: integer + noDowntimeGuarantee: + description: NoDowntimeGuarantee defines a flag for switching + to the new namespace before demoting the active namespace and + guarantees the process will not have a downtime + type: boolean outdatedNotification: description: OutdatedNotification defines a configuration of outdated notification @@ -1034,6 +1039,11 @@ spec: description: MaxRetry defines max retry counts of active promotion process in case failure type: integer + noDowntimeGuarantee: + description: NoDowntimeGuarantee defines a flag for switching + to the new namespace before demoting the active namespace + and guarantees the process will not have a downtime + type: boolean outdatedNotification: description: OutdatedNotification defines a configuration of outdated notification diff --git a/docs/docs.go b/docs/docs.go index a14ce055..d445592a 100644 --- a/docs/docs.go +++ b/docs/docs.go @@ -1,6 +1,6 @@ // GENERATED BY THE COMMAND ABOVE; DO NOT EDIT // This file was generated by swaggo/swag at -// 2022-08-05 12:18:44.527278 +0700 +07 m=+0.172559437 +// 2022-10-19 11:09:44.83837 +0700 +07 m=+0.333853050 package docs @@ -954,6 +954,10 @@ var doc = `{ "v1.ActivePromotionSpec": { "type": "object", "properties": { + "noDowntimeGuarantee": { + "description": "NoDowntimeGuarantee represents a flag for switching to the new namespace before demoting the active namespace and guarantees the process will not have a downtime\n+optional", + "type": "boolean" + }, "noOfRetry": { "description": "NoOfRetry represents how many times this active promotion process has been run\n+optional", "type": "integer" @@ -1167,6 +1171,10 @@ var doc = `{ "description": "MaxRetry defines max retry counts of active promotion process in case failure\n+optional", "type": "integer" }, + "noDowntimeGuarantee": { + "description": "NoDowntimeGuarantee defines a flag for switching to the new namespace before demoting the active namespace and guarantees the process will not have a downtime", + "type": "boolean" + }, "outdatedNotification": { "description": "OutdatedNotification defines a configuration of outdated notification\n+optional", "type": "object", diff --git a/docs/swagger.json b/docs/swagger.json index dd0db591..b8884be8 100644 --- a/docs/swagger.json +++ b/docs/swagger.json @@ -933,6 +933,10 @@ "v1.ActivePromotionSpec": { "type": "object", "properties": { + "noDowntimeGuarantee": { + "description": "NoDowntimeGuarantee represents a flag for switching to the new namespace before demoting the active namespace and guarantees the process will not have a downtime\n+optional", + "type": "boolean" + }, "noOfRetry": { "description": "NoOfRetry represents how many times this active promotion process has been run\n+optional", "type": "integer" @@ -1146,6 +1150,10 @@ "description": "MaxRetry defines max retry counts of active promotion process in case failure\n+optional", "type": "integer" }, + "noDowntimeGuarantee": { + "description": "NoDowntimeGuarantee defines a flag for switching to the new namespace before demoting the active namespace and guarantees the process will not have a downtime", + "type": "boolean" + }, "outdatedNotification": { "description": "OutdatedNotification defines a configuration of outdated notification\n+optional", "type": "object", diff --git a/docs/swagger.yaml b/docs/swagger.yaml index daa55152..0f4644d9 100644 --- a/docs/swagger.yaml +++ b/docs/swagger.yaml @@ -50,6 +50,11 @@ definitions: type: object v1.ActivePromotionSpec: properties: + noDowntimeGuarantee: + description: |- + NoDowntimeGuarantee represents a flag for switching to the new namespace before demoting the active namespace and guarantees the process will not have a downtime + +optional + type: boolean noOfRetry: description: |- NoOfRetry represents how many times this active promotion process has been run @@ -258,6 +263,11 @@ definitions: MaxRetry defines max retry counts of active promotion process in case failure +optional type: integer + noDowntimeGuarantee: + description: NoDowntimeGuarantee defines a flag for switching to the new namespace + before demoting the active namespace and guarantees the process will not + have a downtime + type: boolean outdatedNotification: $ref: '#/definitions/v1.OutdatedNotification' description: |- diff --git a/examples/configs/crds/active-promotion-example.yaml b/examples/configs/crds/active-promotion-example.yaml index 63127abd..db8fe3ae 100644 --- a/examples/configs/crds/active-promotion-example.yaml +++ b/examples/configs/crds/active-promotion-example.yaml @@ -4,4 +4,5 @@ metadata: name: example spec: tearDownDuration: 5m - skipTestRunner: false \ No newline at end of file + skipTestRunner: false + noDowntimeGuarantee: false \ No newline at end of file diff --git a/examples/configs/crds/config-example.yaml b/examples/configs/crds/config-example.yaml index 3ae625c6..89636cac 100644 --- a/examples/configs/crds/config-example.yaml +++ b/examples/configs/crds/config-example.yaml @@ -61,6 +61,7 @@ spec: tearDownDuration: 10s demotionTimeout: 3m rollbackTimeout: 5m + noDowntimeGuarantee: false deployment: timeout: 5m engine: helm3 diff --git a/examples/starter/crds/active-promotion.yaml b/examples/starter/crds/active-promotion.yaml index 29236619..cd71da3d 100644 --- a/examples/starter/crds/active-promotion.yaml +++ b/examples/starter/crds/active-promotion.yaml @@ -20,6 +20,13 @@ spec: # use 'false' for using the default setting from Config.yaml skipTestRunner: false + #! WARNING: noDowntimeGuarantee does not support the service that has a fixed nodePort + # [optional] boolean flag for running an active promotion with no downtime + # when promoting active environment + # use 'true' for running an active promotion with no downtime + # use 'false' for using the default setting from Config.yaml + noDowntimeGuarantee: false + # [optional] name of user who applying active promotion # default value is empty promotedBy: \ No newline at end of file diff --git a/examples/starter/crds/config.yaml b/examples/starter/crds/config.yaml index c2b8e213..5af8d450 100644 --- a/examples/starter/crds/config.yaml +++ b/examples/starter/crds/config.yaml @@ -153,6 +153,12 @@ spec: # default value is 7 maxHistories: 20 + #! WARNING: noDowntimeGuarantee does not support the service that has a fixed nodePort + # [optional] specify the noDowntimeGuarantee for running an active promotion with no downtime + # use true for applying noDowntimeGuarantee and it will run promoting an active environment before demote the previous environment + # use false for applying noDowntimeGuarantee and it will run demoting an previous environment before promote an active environment + noDowntimeGuarantee: false + # deployment flow of active environment configuration deployment: # how long the active environment should be ready? diff --git a/internal/samsahai/activepromotion/collect_result.go b/internal/samsahai/activepromotion/collect_result.go index f97e0b7c..4825cd9f 100644 --- a/internal/samsahai/activepromotion/collect_result.go +++ b/internal/samsahai/activepromotion/collect_result.go @@ -47,9 +47,16 @@ func (c *controller) collectResult(ctx context.Context, atpComp *s2hv1.ActivePro return nil } + if atpComp.Spec.NoDowntimeGuarantee != nil && *atpComp.Spec.NoDowntimeGuarantee { + atpComp.SetState(s2hv1.ActivePromotionActiveEnvironment, "Promoting an active environment") + logger.Info("Collected a result, and start promoting an active environment") + return nil + } + atpComp.Status.SetCondition(s2hv1.ActivePromotionCondActiveDemotionStarted, corev1.ConditionTrue, "Active demotion has been started") atpComp.SetState(s2hv1.ActivePromotionDemoting, "Demoting an active environment") + logger.Info("Collected a result, and start demoting an active environment") return nil } diff --git a/internal/samsahai/activepromotion/controller.go b/internal/samsahai/activepromotion/controller.go index 497ccb72..d083142c 100644 --- a/internal/samsahai/activepromotion/controller.go +++ b/internal/samsahai/activepromotion/controller.go @@ -83,15 +83,15 @@ func New( } func (c *controller) setup(ctx context.Context, atpComp *s2hv1.ActivePromotion) error { + config, err := c.s2hCtrl.GetConfigController().Get(atpComp.Name) + if err != nil { + return err + } + // set teardown duration from configuration if it's unset if atpComp.Spec.TearDownDuration == nil { duration := c.configs.ActivePromotion.TearDownDuration - config, err := c.s2hCtrl.GetConfigController().Get(atpComp.Name) - if err != nil { - return err - } - if config.Status.Used.ActivePromotion != nil && config.Status.Used.ActivePromotion.TearDownDuration.Duration != 0 { duration = config.Status.Used.ActivePromotion.TearDownDuration } @@ -99,6 +99,17 @@ func (c *controller) setup(ctx context.Context, atpComp *s2hv1.ActivePromotion) atpComp.Spec.SetTearDownDuration(duration) } + // set NoDowntimeGuarantee from active-promotion.yaml if the value in the configuration file is not set + if atpComp.Spec.NoDowntimeGuarantee == nil { + atpComp.Spec.NoDowntimeGuarantee = &config.Spec.ActivePromotion.NoDowntimeGuarantee + } + + if *atpComp.Spec.NoDowntimeGuarantee { + logger.Info("The active promotion will run promote before demote") + } else { + logger.Info("The active promotion will run demote before promote") + } + c.appendStateLabel(atpComp, stateWaiting) atpComp.SetState(s2hv1.ActivePromotionWaiting, "Waiting in queue") logger.Info("activepromotion is waiting in queue", "team", atpComp.Name) diff --git a/internal/samsahai/activepromotion/demote.go b/internal/samsahai/activepromotion/demote.go index ef9a7a0e..25a27d50 100644 --- a/internal/samsahai/activepromotion/demote.go +++ b/internal/samsahai/activepromotion/demote.go @@ -39,7 +39,16 @@ func (c *controller) demoteActiveEnvironment(ctx context.Context, atpComp *s2hv1 "team", teamName, "namespace", prevNs) atpComp.Status.SetCondition(s2hv1.ActivePromotionCondActiveDemoted, corev1.ConditionFalse, "Failed to demote active environment, active environment has been deleted") + + if atpComp.Spec.NoDowntimeGuarantee != nil && *atpComp.Spec.NoDowntimeGuarantee { + atpComp.SetState(s2hv1.ActivePromotionDestroyingPreviousActive, + "Failed to demote active environment") + logger.Info("Demote failed, and start destroying an active environment") + return nil + } + atpComp.SetState(s2hv1.ActivePromotionActiveEnvironment, "Failed to demote active environment") + logger.Info("Demote failed, and start promoting an active environment") return nil } @@ -48,7 +57,16 @@ func (c *controller) demoteActiveEnvironment(ctx context.Context, atpComp *s2hv1 atpComp.Status.SetDemotionStatus(s2hv1.ActivePromotionDemotionSuccess) atpComp.Status.SetCondition(s2hv1.ActivePromotionCondActiveDemoted, corev1.ConditionTrue, "Demoted an active environment successfully") + + if atpComp.Spec.NoDowntimeGuarantee != nil && *atpComp.Spec.NoDowntimeGuarantee { + atpComp.SetState(s2hv1.ActivePromotionDestroyingPreviousActive, + "Destroying the previous active environment") + logger.Info("Demote successfully, and start destroying the previous active environment") + return nil + } + atpComp.SetState(s2hv1.ActivePromotionActiveEnvironment, "Promoting an active environment") + logger.Info("Demote successfully, and start promoting an active environment") return nil } @@ -101,7 +119,15 @@ func (c *controller) checkDemotionTimeout(ctx context.Context, atpComp *s2hv1.Ac "team", teamName, "namespace", prevNs) atpComp.Status.SetCondition(s2hv1.ActivePromotionCondActiveDemoted, corev1.ConditionFalse, "Demoted an active environment timeout, active environment has been deleted") + + if atpComp.Spec.NoDowntimeGuarantee != nil && *atpComp.Spec.NoDowntimeGuarantee { + atpComp.SetState(s2hv1.ActivePromotionDestroyingPreviousActive, "Demoted active environment timeout") + logger.Info("Demote timeout, and start destroying an active environment") + return s2herrors.ErrActiveDemotionTimeout + } + atpComp.SetState(s2hv1.ActivePromotionActiveEnvironment, "Demoted active environment timeout") + logger.Info("Demote timeout, and start destroying an active environment") if err := c.updateActivePromotion(ctx, atpComp); err != nil { return err diff --git a/internal/samsahai/activepromotion/postactive.go b/internal/samsahai/activepromotion/postactive.go index 1e699b82..7bf1d809 100644 --- a/internal/samsahai/activepromotion/postactive.go +++ b/internal/samsahai/activepromotion/postactive.go @@ -27,7 +27,7 @@ func (c *controller) runPostActive(ctx context.Context, atpComp *s2hv1.ActivePro return err } - logger.Debug("activepromotionhistory has been created", + logger.Debug("active promotion history has been created", "team", atpComp.Name, "status", atpComp.Status.Result, "name", histName) logger.Debug("active promotion report has been sent", "team", atpComp.Name, "status", atpComp.Status.Result) diff --git a/internal/samsahai/activepromotion/promote.go b/internal/samsahai/activepromotion/promote.go index 24ce9260..cab87c60 100644 --- a/internal/samsahai/activepromotion/promote.go +++ b/internal/samsahai/activepromotion/promote.go @@ -52,9 +52,19 @@ func (c *controller) promoteActiveEnvironment(ctx context.Context, atpComp *s2hv "Result has been collected, promoted successfully") atpComp.Status.SetCondition(s2hv1.ActivePromotionCondActivePromoted, corev1.ConditionTrue, "Active environment has been promoted") - atpComp.SetState(s2hv1.ActivePromotionDestroyingPreviousActive, - "Destroying the previous active environment") + if atpComp.Spec.NoDowntimeGuarantee != nil && *atpComp.Spec.NoDowntimeGuarantee { + atpComp.Status.SetCondition(s2hv1.ActivePromotionCondActiveDemotionStarted, corev1.ConditionTrue, + "Active demotion has been started") + atpComp.SetState(s2hv1.ActivePromotionDemoting, "Demoting an active environment") + logger.Info("Active environment has been promoted, and start demoting an active environment") + } else { + atpComp.SetState(s2hv1.ActivePromotionDestroyingPreviousActive, + "Destroying the previous active environment") + logger.Info("Active environment has been promoted, and start destroying the previous active environment") + } + + // Send the reports when active namespace has been promoted if err := c.runPostActive(ctx, atpComp); err != nil { return err } diff --git a/test/data/crds/env.samsahai.io_activepromotionhistories.yaml b/test/data/crds/env.samsahai.io_activepromotionhistories.yaml index 568c90db..c8d12036 100644 --- a/test/data/crds/env.samsahai.io_activepromotionhistories.yaml +++ b/test/data/crds/env.samsahai.io_activepromotionhistories.yaml @@ -56,6 +56,11 @@ spec: spec: description: ActivePromotionSpec defines the desired state of ActivePromotion properties: + noDowntimeGuarantee: + description: NoDowntimeGuarantee represents a flag for switching + to the new namespace before demoting the active namespace + and guarantees the process will not have a downtime + type: boolean noOfRetry: description: NoOfRetry represents how many times this active promotion process has been run diff --git a/test/data/crds/env.samsahai.io_activepromotions.yaml b/test/data/crds/env.samsahai.io_activepromotions.yaml index 8b6fb806..8adf486b 100644 --- a/test/data/crds/env.samsahai.io_activepromotions.yaml +++ b/test/data/crds/env.samsahai.io_activepromotions.yaml @@ -34,6 +34,11 @@ spec: spec: description: ActivePromotionSpec defines the desired state of ActivePromotion properties: + noDowntimeGuarantee: + description: NoDowntimeGuarantee represents a flag for switching to + the new namespace before demoting the active namespace and guarantees + the process will not have a downtime + type: boolean noOfRetry: description: NoOfRetry represents how many times this active promotion process has been run diff --git a/test/data/crds/env.samsahai.io_configs.yaml b/test/data/crds/env.samsahai.io_configs.yaml index 3ff05ae1..868d4667 100644 --- a/test/data/crds/env.samsahai.io_configs.yaml +++ b/test/data/crds/env.samsahai.io_configs.yaml @@ -114,6 +114,11 @@ spec: description: MaxRetry defines max retry counts of active promotion process in case failure type: integer + noDowntimeGuarantee: + description: NoDowntimeGuarantee defines a flag for switching to + the new namespace before demoting the active namespace and guarantees + the process will not have a downtime + type: boolean outdatedNotification: description: OutdatedNotification defines a configuration of outdated notification @@ -1022,6 +1027,11 @@ spec: description: MaxRetry defines max retry counts of active promotion process in case failure type: integer + noDowntimeGuarantee: + description: NoDowntimeGuarantee defines a flag for switching + to the new namespace before demoting the active namespace + and guarantees the process will not have a downtime + type: boolean outdatedNotification: description: OutdatedNotification defines a configuration of outdated notification