From c0205fb7309b870f9e3313735699beffd1e74eae Mon Sep 17 00:00:00 2001 From: Vadim Gedz Date: Sun, 26 May 2024 00:21:30 +0300 Subject: [PATCH] chore(client): add support for additional configuration --- pkg/client/client.go | 17 ++++++++++++++--- pkg/client/client_test.go | 24 ++++++++++++++++++++++++ pkg/client/config.go | 30 ++++++++++++++++-------------- pkg/client/utility.go | 4 ++-- pkg/client/utility_test.go | 8 ++++---- 5 files changed, 60 insertions(+), 23 deletions(-) diff --git a/pkg/client/client.go b/pkg/client/client.go index b0e481e..315597c 100644 --- a/pkg/client/client.go +++ b/pkg/client/client.go @@ -21,7 +21,7 @@ import ( ) var ( - clientConfig *ClientConfig + clientConfig *Config ) type Watcher struct { @@ -124,6 +124,8 @@ func (watcher *Watcher) getWatcherConfig() (*config.ServerConfig, error) { } func (watcher *Watcher) waitForDeployment(id, appName, version string) error { + retryCount := 0 + for { taskInfo, err := watcher.getTaskStatus(id) if err != nil { @@ -134,8 +136,13 @@ func (watcher *Watcher) waitForDeployment(id, appName, version string) error { case models.StatusFailedMessage: return fmt.Errorf("The deployment has failed, please check logs.\n%s", taskInfo.StatusReason) case models.StatusInProgressMessage: - log.Println("Application deployment is in progress...") - time.Sleep(15 * time.Second) + if !isDeploymentOverTime(retryCount, clientConfig.RetryInterval, clientConfig.ExpectedDeploymentTime) { + log.Println("Application deployment is in progress...") + } else { + log.Println("Application deployment is taking longer than expected, it might be worth checking ArgoCD UI...") + } + retryCount++ + time.Sleep(clientConfig.RetryInterval) case models.StatusAppNotFoundMessage: return fmt.Errorf("Application %s does not exist.\n%s", appName, taskInfo.StatusReason) case models.StatusArgoCDUnavailableMessage: @@ -163,6 +170,10 @@ func handleFatalError(err error, message string) { log.Fatalf("%s Got the following error: %s", message, err) } +func isDeploymentOverTime(retryCount int, retryInterval time.Duration, expectedDeploymentTime time.Duration) bool { + return time.Duration(retryCount)*retryInterval > expectedDeploymentTime +} + func Run() { var err error diff --git a/pkg/client/client_test.go b/pkg/client/client_test.go index 2700807..4da4de4 100644 --- a/pkg/client/client_test.go +++ b/pkg/client/client_test.go @@ -280,3 +280,27 @@ func TestWaitForDeployment(t *testing.T) { }) } } + +func TestIsDeploymentOverTime(t *testing.T) { + var tests = []struct { + retryCount int + retryInterval time.Duration + expectedDuration time.Duration + expected bool + }{ + {10, 5 * time.Second, 1 * time.Minute, false}, + {13, 5 * time.Second, 1 * time.Minute, true}, + {7, 10 * time.Second, 1 * time.Minute, true}, + {7, 15 * time.Second, 1 * time.Minute, true}, + {0, 2 * time.Second, 1 * time.Minute, false}, + } + + for _, tt := range tests { + t.Run("", func(t *testing.T) { + result := isDeploymentOverTime(tt.retryCount, tt.retryInterval, tt.expectedDuration) + if result != tt.expected { + t.Errorf("for %d retries with %s interval, expected %t but got %t", tt.retryCount, tt.retryInterval, tt.expected, result) + } + }) + } +} diff --git a/pkg/client/config.go b/pkg/client/config.go index cf05f39..11e4e64 100644 --- a/pkg/client/config.go +++ b/pkg/client/config.go @@ -6,22 +6,24 @@ import ( envConfig "github.com/caarlos0/env/v10" ) -type ClientConfig struct { - Url string `env:"ARGO_WATCHER_URL,required"` - Images []string `env:"IMAGES,required"` - Tag string `env:"IMAGE_TAG,required"` - App string `env:"ARGO_APP,required"` - Author string `env:"COMMIT_AUTHOR,required"` - Project string `env:"PROJECT_NAME,required"` - Token string `env:"ARGO_WATCHER_DEPLOY_TOKEN"` - JsonWebToken string `env:"BEARER_TOKEN"` - Timeout time.Duration `env:"TIMEOUT" envDefault:"60s"` - TaskTimeout int `env:"TASK_TIMEOUT"` - Debug bool `env:"DEBUG"` +type Config struct { + Url string `env:"ARGO_WATCHER_URL,required"` + Images []string `env:"IMAGES,required"` + Tag string `env:"IMAGE_TAG,required"` + App string `env:"ARGO_APP,required"` + Author string `env:"COMMIT_AUTHOR,required"` + Project string `env:"PROJECT_NAME,required"` + Token string `env:"ARGO_WATCHER_DEPLOY_TOKEN"` + JsonWebToken string `env:"BEARER_TOKEN"` + Timeout time.Duration `env:"TIMEOUT" envDefault:"60s"` + TaskTimeout int `env:"TASK_TIMEOUT"` + RetryInterval time.Duration `env:"RETRY_INTERVAL" envDefault:"15s"` + ExpectedDeploymentTime time.Duration `env:"EXPECTED_DEPLOY_TIME" envDefault:"15m"` + Debug bool `env:"DEBUG"` } -func NewClientConfig() (*ClientConfig, error) { - var config ClientConfig +func NewClientConfig() (*Config, error) { + var config Config if err := envConfig.Parse(&config); err != nil { return nil, err diff --git a/pkg/client/utility.go b/pkg/client/utility.go index b5dbb04..afc4a5f 100644 --- a/pkg/client/utility.go +++ b/pkg/client/utility.go @@ -49,7 +49,7 @@ func getImagesList(list []string, tag string) []models.Image { return images } -func createTask(config *ClientConfig) models.Task { +func createTask(config *Config) models.Task { images := getImagesList(config.Images, config.Tag) return models.Task{ App: config.App, @@ -86,7 +86,7 @@ func generateAppUrl(watcher *Watcher, task models.Task) (string, error) { return fmt.Sprintf("%s://%s/applications/%s", cfg.ArgoUrl.Scheme, cfg.ArgoUrl.Host, task.App), nil } -func setupWatcher(config *ClientConfig) *Watcher { +func setupWatcher(config *Config) *Watcher { return NewWatcher( strings.TrimSuffix(config.Url, "/"), config.Debug, diff --git a/pkg/client/utility_test.go b/pkg/client/utility_test.go index 76e52d5..077c72a 100644 --- a/pkg/client/utility_test.go +++ b/pkg/client/utility_test.go @@ -96,7 +96,7 @@ func TestGetImagesList(t *testing.T) { func TestCreateTask(t *testing.T) { t.Run("TimeoutProvided", func(t *testing.T) { - config := &ClientConfig{ + config := &Config{ App: "test-app", Author: "test-author", Project: "test-project", @@ -128,7 +128,7 @@ func TestCreateTask(t *testing.T) { }) t.Run("TimeoutNotProvided", func(t *testing.T) { - config := &ClientConfig{ + config := &Config{ App: "test-app", Author: "test-author", Project: "test-project", @@ -161,7 +161,7 @@ func TestCreateTask(t *testing.T) { func TestPrintClientConfiguration(t *testing.T) { // Initialize clientConfig - clientConfig = &ClientConfig{ + clientConfig = &Config{ Url: "http://localhost:8080", Images: []string{"image1", "image2"}, Tag: "test-tag", @@ -334,7 +334,7 @@ func TestGenerateAppUrl(t *testing.T) { func TestSetupWatcher(t *testing.T) { // Define the input - config := &ClientConfig{ + config := &Config{ Url: "http://localhost:8080", Debug: true, }