Bläddra i källkod

add --wait flag to porter update

Mohammed Nafees 3 år sedan
förälder
incheckning
7e68260a5e
1 ändrade filer med 105 tillägg och 2 borttagningar
  1. 105 2
      cli/cmd/deploy.go

+ 105 - 2
cli/cmd/deploy.go

@@ -5,6 +5,7 @@ import (
 	"fmt"
 	"os"
 	"path/filepath"
+	"sort"
 	"strings"
 	"time"
 
@@ -18,6 +19,7 @@ import (
 	"github.com/porter-dev/porter/cli/cmd/utils"
 	templaterUtils "github.com/porter-dev/porter/internal/templater/utils"
 	"github.com/spf13/cobra"
+	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/client-go/util/homedir"
 )
 
@@ -224,7 +226,7 @@ var updateEnvGroupCmd = &cobra.Command{
 	Aliases: []string{"eg", "envgroup", "env-groups", "envgroups"},
 	Short:   "Updates an environment group's variables, specified by the --name flag.",
 	Run: func(cmd *cobra.Command, args []string) {
-		color.New(color.FgRed).Println("need to specify an operation to continue")
+		color.New(color.FgRed).Fprintln(os.Stderr, "need to specify an operation to continue")
 	},
 }
 
@@ -268,6 +270,7 @@ var version uint
 var varType string
 var normalEnvGroupVars []string
 var secretEnvGroupVars []string
+var waitForSuccessfulDeploy bool
 
 func init() {
 	buildFlagsEnv = []string{}
@@ -372,6 +375,13 @@ func init() {
 
 	updateCmd.PersistentFlags().MarkDeprecated("force-push", "--force-push is now deprecated")
 
+	updateCmd.PersistentFlags().BoolVar(
+		&waitForSuccessfulDeploy,
+		"wait",
+		false,
+		"set this to wait and be notified when a deployment is successful, otherwise time out",
+	)
+
 	updateCmd.AddCommand(updateGetEnvCmd)
 
 	updateGetEnvCmd.PersistentFlags().StringVar(
@@ -480,6 +490,14 @@ func updateFull(_ *types.GetAuthenticatedUserResponse, client *api.Client, args
 		return err
 	}
 
+	if waitForSuccessfulDeploy {
+		err := checkDeploymentStatus(client)
+
+		if err != nil {
+			return err
+		}
+	}
+
 	return nil
 }
 
@@ -588,7 +606,21 @@ func updateUpgrade(_ *types.GetAuthenticatedUserResponse, client *api.Client, ar
 		return err
 	}
 
-	return updateUpgradeWithAgent(updateAgent)
+	err = updateUpgradeWithAgent(updateAgent)
+
+	if err != nil {
+		return err
+	}
+
+	if waitForSuccessfulDeploy {
+		err := checkDeploymentStatus(client)
+
+		if err != nil {
+			return err
+		}
+	}
+
+	return nil
 }
 
 func updateSetEnvGroup(_ *types.GetAuthenticatedUserResponse, client *api.Client, args []string) error {
@@ -1029,3 +1061,74 @@ func updateUpgradeWithAgent(updateAgent *deploy.DeployAgent) error {
 
 	return nil
 }
+
+func checkDeploymentStatus(client *api.Client) error {
+	color.New(color.FgBlue).Println("waiting for deployment to be ready, this may take a few minutes and will time out if it takes longer than 30 minutes")
+
+	sharedConf := &PorterRunSharedConfig{
+		Client: client,
+	}
+
+	err := sharedConf.setSharedConfig()
+
+	if err != nil {
+		return fmt.Errorf("could not retrieve kubernetes credentials: %w", err)
+	}
+
+	timeWait := time.Now().Add(30 * time.Minute)
+	prevRefresh := time.Now()
+	success := false
+
+	for time.Now().Before(timeWait) {
+		// refresh the client every 10 minutes
+		if time.Now().After(prevRefresh.Add(10 * time.Minute)) {
+			err = sharedConf.setSharedConfig()
+
+			if err != nil {
+				return fmt.Errorf("could not retrieve kube credentials: %s", err.Error())
+			}
+
+			prevRefresh = time.Now()
+		}
+
+		depls, err := sharedConf.Clientset.AppsV1().Deployments(namespace).List(
+			context.Background(),
+			metav1.ListOptions{
+				LabelSelector: fmt.Sprintf("app.kubernetes.io/instance=%s", app),
+			},
+		)
+
+		if err != nil {
+			return fmt.Errorf("could not get deployments for app %s: %w", app, err)
+		}
+
+		if len(depls.Items) == 0 {
+			return fmt.Errorf("could not find any deployments for app %s", app)
+		}
+
+		sort.Slice(depls.Items, func(i, j int) bool {
+			return depls.Items[i].CreationTimestamp.After(depls.Items[j].CreationTimestamp.Time)
+		})
+
+		depl := depls.Items[0]
+
+		// determine if the deployment has an appropriate number of ready replicas
+		minUnavailable := *(depl.Spec.Replicas) - getMaxUnavailable(depl)
+
+		if minUnavailable <= depl.Status.ReadyReplicas {
+			success = true
+		}
+
+		if success {
+			break
+		}
+	}
+
+	if success {
+		color.New(color.FgGreen).Printf("%s has been successfully deployed on the cluster\n", app)
+	} else {
+		return fmt.Errorf("timed out waiting for deployment to be ready, please check the Porter dashboard for more information")
+	}
+
+	return nil
+}