Przeglądaj źródła

add wait for job option to update config

Alexander Belanger 4 lat temu
rodzic
commit
b983fdaaa4
4 zmienionych plików z 166 dodań i 113 usunięć
  1. 7 1
      cli/cmd/apply.go
  2. 130 0
      cli/cmd/deploy/wait/job.go
  3. 7 112
      cli/cmd/job.go
  4. 22 0
      cli/cmd/preview/update_config_driver.go

+ 7 - 1
cli/cmd/apply.go

@@ -18,6 +18,7 @@ import (
 	"github.com/porter-dev/porter/api/types"
 	"github.com/porter-dev/porter/cli/cmd/config"
 	"github.com/porter-dev/porter/cli/cmd/deploy"
+	"github.com/porter-dev/porter/cli/cmd/deploy/wait"
 	"github.com/porter-dev/porter/cli/cmd/preview"
 	"github.com/porter-dev/porter/internal/templater/utils"
 	"github.com/porter-dev/switchboard/pkg/drivers"
@@ -400,7 +401,12 @@ func (d *Driver) applyApplication(resource *models.Resource, client *api.Client,
 		cliConf.Project = d.target.Project
 		cliConf.Cluster = d.target.Cluster
 
-		err = waitForJob(nil, client, []string{})
+		err = wait.WaitForJob(client, &wait.WaitOpts{
+			ProjectID: cliConf.Project,
+			ClusterID: cliConf.Cluster,
+			Namespace: namespace,
+			Name:      name,
+		})
 
 		if err != nil {
 			return nil, err

+ 130 - 0
cli/cmd/deploy/wait/job.go

@@ -0,0 +1,130 @@
+package wait
+
+import (
+	"context"
+	"fmt"
+	"strconv"
+	"time"
+
+	"github.com/fatih/color"
+	api "github.com/porter-dev/porter/api/client"
+	v1 "k8s.io/api/batch/v1"
+)
+
+type WaitOpts struct {
+	ProjectID, ClusterID uint
+	Namespace, Name      string
+}
+
+// WaitForJob waits for a job with a given name/namespace to complete its run
+func WaitForJob(client *api.Client, opts *WaitOpts) error {
+	// get the job release
+	jobRelease, err := client.GetRelease(context.Background(), opts.ProjectID, opts.ClusterID, opts.Namespace, opts.Name)
+
+	if err != nil {
+		return err
+	}
+
+	// make sure the job chart has a manual job running
+	pausedVal, ok := jobRelease.Release.Config["paused"]
+	pausedErr := fmt.Errorf("this job template is not currently running a manual job")
+
+	if !ok {
+		return pausedErr
+	}
+
+	if pausedValBool, ok := pausedVal.(bool); ok && pausedValBool {
+		return pausedErr
+	}
+
+	// attempt to parse out the timeout value for the job, given by `sidecar.timeout`
+	// if it does not exist, we set the default to 30 minutes
+	timeoutVal := getJobTimeoutValue(jobRelease.Release.Config)
+
+	color.New(color.FgYellow).Printf("Waiting for timeout seconds %.1f\n", timeoutVal.Seconds())
+
+	// if no job exists with the given revision, wait for the timeout value
+	timeWait := time.Now().Add(timeoutVal)
+
+	for time.Now().Before(timeWait) {
+		// get the jobs for that job chart
+		jobs, err := client.GetJobs(context.Background(), opts.ProjectID, opts.ClusterID, opts.Namespace, opts.Name)
+
+		if err != nil {
+			return err
+		}
+
+		job := getJobMatchingRevision(uint(jobRelease.Release.Version), jobs)
+
+		if job == nil {
+			time.Sleep(10 * time.Second)
+			continue
+		}
+
+		// once job is running, wait for status to be completed, or failed
+		// if failed, exit with non-zero exit code
+		if job.Status.Failed > 0 {
+			return fmt.Errorf("job failed")
+		}
+
+		if job.Status.Succeeded > 0 {
+			return nil
+		}
+
+		// otherwise, return no error
+		time.Sleep(10 * time.Second)
+	}
+
+	return fmt.Errorf("timed out waiting for job")
+}
+
+func getJobMatchingRevision(revision uint, jobs []v1.Job) *v1.Job {
+	for _, job := range jobs {
+		revisionLabel, revisionLabelExists := job.Labels["helm.sh/revision"]
+
+		if !revisionLabelExists {
+			continue
+		}
+
+		jobRevision, err := strconv.ParseUint(revisionLabel, 10, 64)
+
+		if err != nil {
+			continue
+		}
+
+		if uint(jobRevision) == revision {
+			return &job
+		}
+	}
+
+	return nil
+}
+
+func getJobTimeoutValue(values map[string]interface{}) time.Duration {
+	defaultTimeout := time.Minute * 60
+	sidecarInter, ok := values["sidecar"]
+
+	if !ok {
+		return defaultTimeout
+	}
+
+	sidecarVal, ok := sidecarInter.(map[string]interface{})
+
+	if !ok {
+		return defaultTimeout
+	}
+
+	timeoutInter, ok := sidecarVal["timeout"]
+
+	if !ok {
+		return defaultTimeout
+	}
+
+	timeoutVal, ok := timeoutInter.(float64)
+
+	if !ok {
+		return defaultTimeout
+	}
+
+	return time.Second * time.Duration(timeoutVal)
+}

+ 7 - 112
cli/cmd/job.go

@@ -4,14 +4,12 @@ import (
 	"context"
 	"fmt"
 	"os"
-	"strconv"
-	"time"
 
 	"github.com/fatih/color"
 	api "github.com/porter-dev/porter/api/client"
 	"github.com/porter-dev/porter/api/types"
+	"github.com/porter-dev/porter/cli/cmd/deploy/wait"
 	"github.com/spf13/cobra"
-	v1 "k8s.io/api/batch/v1"
 )
 
 var jobCmd = &cobra.Command{
@@ -147,113 +145,10 @@ func batchImageUpdate(_ *types.GetAuthenticatedUserResponse, client *api.Client,
 
 // waits for a job with a given name/namespace
 func waitForJob(_ *types.GetAuthenticatedUserResponse, client *api.Client, args []string) error {
-	// get the job release
-	jobRelease, err := client.GetRelease(context.Background(), cliConf.Project, cliConf.Cluster, namespace, name)
-
-	if err != nil {
-		return err
-	}
-
-	// make sure the job chart has a manual job running
-	pausedVal, ok := jobRelease.Release.Config["paused"]
-	pausedErr := fmt.Errorf("this job template is not currently running a manual job")
-
-	if !ok {
-		return pausedErr
-	}
-
-	if pausedValBool, ok := pausedVal.(bool); ok && pausedValBool {
-		return pausedErr
-	}
-
-	// attempt to parse out the timeout value for the job, given by `sidecar.timeout`
-	// if it does not exist, we set the default to 30 minutes
-	timeoutVal := GetJobTimeoutValue(jobRelease.Release.Config)
-
-	color.New(color.FgYellow).Printf("Waiting for timeout seconds %.1f\n", timeoutVal.Seconds())
-
-	// if no job exists with the given revision, wait for the timeout value
-	timeWait := time.Now().Add(timeoutVal)
-
-	for time.Now().Before(timeWait) {
-		// get the jobs for that job chart
-		jobs, err := client.GetJobs(context.Background(), cliConf.Project, cliConf.Cluster, namespace, name)
-
-		if err != nil {
-			return err
-		}
-
-		job := getJobMatchingRevision(uint(jobRelease.Release.Version), jobs)
-
-		if job == nil {
-			time.Sleep(10 * time.Second)
-			continue
-		}
-
-		// once job is running, wait for status to be completed, or failed
-		// if failed, exit with non-zero exit code
-		if job.Status.Failed > 0 {
-			return fmt.Errorf("job failed")
-		}
-
-		if job.Status.Succeeded > 0 {
-			return nil
-		}
-
-		// otherwise, return no error
-		time.Sleep(10 * time.Second)
-	}
-
-	return fmt.Errorf("timed out waiting for job")
-}
-
-func getJobMatchingRevision(revision uint, jobs []v1.Job) *v1.Job {
-	for _, job := range jobs {
-		revisionLabel, revisionLabelExists := job.Labels["helm.sh/revision"]
-
-		if !revisionLabelExists {
-			continue
-		}
-
-		jobRevision, err := strconv.ParseUint(revisionLabel, 10, 64)
-
-		if err != nil {
-			continue
-		}
-
-		if uint(jobRevision) == revision {
-			return &job
-		}
-	}
-
-	return nil
-}
-
-func GetJobTimeoutValue(values map[string]interface{}) time.Duration {
-	defaultTimeout := time.Minute * 60
-	sidecarInter, ok := values["sidecar"]
-
-	if !ok {
-		return defaultTimeout
-	}
-
-	sidecarVal, ok := sidecarInter.(map[string]interface{})
-
-	if !ok {
-		return defaultTimeout
-	}
-
-	timeoutInter, ok := sidecarVal["timeout"]
-
-	if !ok {
-		return defaultTimeout
-	}
-
-	timeoutVal, ok := timeoutInter.(float64)
-
-	if !ok {
-		return defaultTimeout
-	}
-
-	return time.Second * time.Duration(timeoutVal)
+	return wait.WaitForJob(client, &wait.WaitOpts{
+		ProjectID: cliConf.Project,
+		ClusterID: cliConf.Cluster,
+		Namespace: namespace,
+		Name:      name,
+	})
 }

+ 22 - 0
cli/cmd/preview/update_config_driver.go

@@ -12,12 +12,19 @@ import (
 	"github.com/porter-dev/porter/api/types"
 	"github.com/porter-dev/porter/cli/cmd/config"
 	"github.com/porter-dev/porter/cli/cmd/deploy"
+	"github.com/porter-dev/porter/cli/cmd/deploy/wait"
 	"github.com/porter-dev/porter/internal/templater/utils"
 	"github.com/porter-dev/switchboard/pkg/drivers"
 	"github.com/porter-dev/switchboard/pkg/models"
 )
 
 type UpdateConfigDriverConfig struct {
+	WaitForJob bool
+
+	// If set to true, this does not run an update, it only creates the initial application and job,
+	// skipping subsequent updates
+	OnlyCreate bool
+
 	UpdateConfig struct {
 		Image string
 	} `mapstructure:"update_config"`
@@ -143,6 +150,21 @@ func (d *UpdateConfigDriver) Apply(resource *models.Resource) (*models.Resource,
 		}
 	}
 
+	if d.source.Name == "job" && updateConfigDriverConfig.WaitForJob && (shouldCreate || !updateConfigDriverConfig.OnlyCreate) {
+		color.New(color.FgYellow).Printf("Waiting for job '%s' to finish\n", resource.Name)
+
+		err = wait.WaitForJob(client, &wait.WaitOpts{
+			ProjectID: d.target.Project,
+			ClusterID: d.target.Cluster,
+			Namespace: d.target.Namespace,
+			Name:      d.target.AppName,
+		})
+
+		if err != nil {
+			return nil, err
+		}
+	}
+
 	err = d.assignOutput(resource, client)
 
 	if err != nil {