From 696310eb980565ddc3478fdc0456c797dc1ea47f Mon Sep 17 00:00:00 2001 From: Edouard Bonlieu Date: Tue, 22 Feb 2022 14:29:42 +0100 Subject: [PATCH 1/2] Add wait flag for Services --- pkg/koyeb/services.go | 4 ++++ pkg/koyeb/services_create.go | 13 ++++++++++++- pkg/koyeb/services_redeploy.go | 24 +++++++++++++++++++++++- pkg/koyeb/services_update.go | 15 +++++++++++++-- pkg/koyeb/utils.go | 29 +++++++++++++++++++++++++++++ 5 files changed, 81 insertions(+), 4 deletions(-) diff --git a/pkg/koyeb/services.go b/pkg/koyeb/services.go index 796906ea..0de765b6 100644 --- a/pkg/koyeb/services.go +++ b/pkg/koyeb/services.go @@ -42,6 +42,7 @@ func NewServiceCmd() *cobra.Command { } addServiceDefinitionFlags(createServiceCmd.Flags()) createServiceCmd.Flags().StringP("app", "a", "", "App") + createServiceCmd.Flags().BoolP("wait", "w", false, "Wait for the service deployment to be completed") createServiceCmd.MarkFlagRequired("app") serviceCmd.AddCommand(createServiceCmd) @@ -106,6 +107,7 @@ func NewServiceCmd() *cobra.Command { }, } addServiceDefinitionFlags(updateServiceCmd.Flags()) + updateServiceCmd.Flags().BoolP("wait", "w", false, "Wait for the service deployment to be completed") serviceCmd.AddCommand(updateServiceCmd) redeployServiceCmd := &cobra.Command{ @@ -114,6 +116,7 @@ func NewServiceCmd() *cobra.Command { Args: cobra.ExactArgs(1), RunE: h.ReDeploy, } + redeployServiceCmd.Flags().BoolP("wait", "w", false, "Wait for the service deployment to be completed") serviceCmd.AddCommand(redeployServiceCmd) deleteServiceCmd := &cobra.Command{ @@ -178,6 +181,7 @@ func addServiceDefinitionFlags(flags *pflag.FlagSet) { flags.String("instance-type", "nano", "Instance type") flags.Int64("min-scale", 1, "Min scale") flags.Int64("max-scale", 1, "Max scale") + } func parseServiceDefinitionFlags(flags *pflag.FlagSet, definition *koyeb.ServiceDefinition, useDefault bool) error { diff --git a/pkg/koyeb/services_create.go b/pkg/koyeb/services_create.go index 13bca44e..de5bd57b 100644 --- a/pkg/koyeb/services_create.go +++ b/pkg/koyeb/services_create.go @@ -22,9 +22,20 @@ func (h *ServiceHandler) Create(cmd *cobra.Command, args []string, createService log.Infof("Service deployment in progress. Access deployment logs running: koyeb service logs %s.", res.Service.GetId()[:8]) + wait := GetBoolFlags(cmd, "wait") + if wait { + watchDeployment(h, res.Service.GetLatestDeploymentId()) + } + full := GetBoolFlags(cmd, "full") output := GetStringFlags(cmd, "output") - getServiceReply := NewGetServiceReply(h.mapper, &koyeb.GetServiceReply{Service: res.Service}, full) + + gRes, gResp, err := h.client.ServicesApi.GetService(h.ctx, res.Service.GetId()).Execute() + if err != nil { + fatalApiError(err, gResp) + } + + getServiceReply := NewGetServiceReply(h.mapper, &koyeb.GetServiceReply{Service: gRes.Service}, full) return renderer.NewDescribeRenderer(getServiceReply).Render(output) } diff --git a/pkg/koyeb/services_redeploy.go b/pkg/koyeb/services_redeploy.go index 78e3ddf7..0c182f33 100644 --- a/pkg/koyeb/services_redeploy.go +++ b/pkg/koyeb/services_redeploy.go @@ -2,6 +2,7 @@ package koyeb import ( "github.com/koyeb/koyeb-api-client-go/api/v1/koyeb" + "github.com/koyeb/koyeb-cli/pkg/koyeb/renderer" log "github.com/sirupsen/logrus" "github.com/spf13/cobra" ) @@ -13,5 +14,26 @@ func (h *ServiceHandler) ReDeploy(cmd *cobra.Command, args []string) error { fatalApiError(err, resp) } log.Infof("Service %s redeployed.", args[0]) - return nil + + gRes, gResp, err := h.client.ServicesApi.GetService(h.ctx, h.ResolveServiceArgs(args[0])).Execute() + if err != nil { + fatalApiError(err, gResp) + } + + wait := GetBoolFlags(cmd, "wait") + if wait { + watchDeployment(h, gRes.Service.GetLatestDeploymentId()) + } + + full := GetBoolFlags(cmd, "full") + output := GetStringFlags(cmd, "output") + + gRes, gResp, err = h.client.ServicesApi.GetService(h.ctx, h.ResolveServiceArgs(args[0])).Execute() + if err != nil { + fatalApiError(err, gResp) + } + + getServiceReply := NewGetServiceReply(h.mapper, &koyeb.GetServiceReply{Service: gRes.Service}, full) + + return renderer.NewDescribeRenderer(getServiceReply).Render(output) } diff --git a/pkg/koyeb/services_update.go b/pkg/koyeb/services_update.go index 4ce9aee3..a78a4195 100644 --- a/pkg/koyeb/services_update.go +++ b/pkg/koyeb/services_update.go @@ -14,9 +14,20 @@ func (h *ServiceHandler) Update(cmd *cobra.Command, args []string, updateService } log.Infof("Service deployment in progress. Access deployment logs running: koyeb service logs %s.", res.Service.GetId()[:8]) + wait := GetBoolFlags(cmd, "wait") + if wait { + watchDeployment(h, res.Service.GetLatestDeploymentId()) + } + full := GetBoolFlags(cmd, "full") output := GetStringFlags(cmd, "output") - getServiceReply := NewGetServiceReply(h.mapper, &koyeb.GetServiceReply{Service: res.Service}, full) - return renderer.NewDescribeItemRenderer(getServiceReply).Render(output) + gRes, gResp, err := h.client.ServicesApi.GetService(h.ctx, res.Service.GetId()).Execute() + if err != nil { + fatalApiError(err, gResp) + } + + getServiceReply := NewGetServiceReply(h.mapper, &koyeb.GetServiceReply{Service: gRes.Service}, full) + + return renderer.NewDescribeRenderer(getServiceReply).Render(output) } diff --git a/pkg/koyeb/utils.go b/pkg/koyeb/utils.go index 0dc9c9ef..d3540c78 100644 --- a/pkg/koyeb/utils.go +++ b/pkg/koyeb/utils.go @@ -5,8 +5,11 @@ import ( "errors" "io/ioutil" "strings" + "time" "github.com/ghodss/yaml" + "github.com/koyeb/koyeb-api-client-go/api/v1/koyeb" + log "github.com/sirupsen/logrus" ) func isYaml(file string) bool { @@ -69,3 +72,29 @@ func loadYaml(file string) (string, error) { } return "", errors.New("Unknown format") } + +func watchDeployment(h *ServiceHandler, deploymentId string) { + numAttemptsOnUnhealthy := 12 + retryCount := 0 + retryInterval := 5 + + for { + res, resp, err := h.client.DeploymentsApi.GetDeployment(h.ctx, deploymentId).Execute() + if err != nil { + fatalApiError(err, resp) + } + currentStatus := res.Deployment.GetStatus() + + log.Infof("Service deployment in progress. Deployment status is %s. Next update in %d seconds.", currentStatus, retryInterval) + + if currentStatus == koyeb.DEPLOYMENTSTATUS_ERROR || currentStatus == koyeb.DEPLOYMENTSTATUS_HEALTHY || retryCount >= numAttemptsOnUnhealthy { + break + } else if currentStatus == koyeb.DEPLOYMENTSTATUS_UNHEALTHY { + retryCount += 1 + retryInterval = 10 + time.Sleep(time.Duration(retryInterval) * time.Second) + } else { + time.Sleep(time.Duration(retryInterval) * time.Second) + } + } +} From 0be3b36e80e92a2c1a3dbd85155db168e9f9292a Mon Sep 17 00:00:00 2001 From: Edouard Bonlieu Date: Wed, 23 Feb 2022 10:16:51 +0100 Subject: [PATCH 2/2] Add log in case of deployment error / unhealthy --- pkg/koyeb/utils.go | 31 ++++++++++++++++++------------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/pkg/koyeb/utils.go b/pkg/koyeb/utils.go index d3540c78..89e07e13 100644 --- a/pkg/koyeb/utils.go +++ b/pkg/koyeb/utils.go @@ -74,27 +74,32 @@ func loadYaml(file string) (string, error) { } func watchDeployment(h *ServiceHandler, deploymentId string) { - numAttemptsOnUnhealthy := 12 - retryCount := 0 - retryInterval := 5 + now := time.Now() + prevStatus := koyeb.DEPLOYMENTSTATUS_PENDING + retryInterval := 5 * time.Second + timeoutAt := time.Minute * 10 - for { + for time.Since(now) < timeoutAt { res, resp, err := h.client.DeploymentsApi.GetDeployment(h.ctx, deploymentId).Execute() if err != nil { fatalApiError(err, resp) } currentStatus := res.Deployment.GetStatus() - log.Infof("Service deployment in progress. Deployment status is %s. Next update in %d seconds.", currentStatus, retryInterval) + log.Infof("Service deployment in progress. Deployment status is %q. Next update in %s.", currentStatus, retryInterval) - if currentStatus == koyeb.DEPLOYMENTSTATUS_ERROR || currentStatus == koyeb.DEPLOYMENTSTATUS_HEALTHY || retryCount >= numAttemptsOnUnhealthy { - break - } else if currentStatus == koyeb.DEPLOYMENTSTATUS_UNHEALTHY { - retryCount += 1 - retryInterval = 10 - time.Sleep(time.Duration(retryInterval) * time.Second) - } else { - time.Sleep(time.Duration(retryInterval) * time.Second) + if currentStatus == koyeb.DEPLOYMENTSTATUS_ERROR || currentStatus == koyeb.DEPLOYMENTSTATUS_HEALTHY { + if currentStatus == koyeb.DEPLOYMENTSTATUS_ERROR { + log.Infof("Service deployment failed. Please check the logs.") + } + return + } else if currentStatus == koyeb.DEPLOYMENTSTATUS_UNHEALTHY && prevStatus != koyeb.DEPLOYMENTSTATUS_UNHEALTHY { + timeoutAt = time.Minute * 5 + now = time.Now() } + time.Sleep(retryInterval) + prevStatus = currentStatus } + + log.Infof("Service deployment didn't pass health checks. Last status was %q", prevStatus) }