ソースを参照

do not re-build an image if one already exists

Mohammed Nafees 4 年 前
コミット
6357473b19
3 ファイル変更99 行追加53 行削除
  1. 51 40
      cli/cmd/deploy/create.go
  2. 19 6
      cli/cmd/deploy/deploy.go
  3. 29 7
      cli/cmd/docker/agent.go

+ 51 - 40
cli/cmd/deploy/create.go

@@ -272,59 +272,70 @@ func (c *CreateAgent) CreateFromDocker(
 		return "", err
 	}
 
-	env, err := GetEnvFromConfig(mergedValues)
+	err = agent.CheckIfImageExists(fmt.Sprintf("%s:%s", imageURL, imageTag))
 
 	if err != nil {
-		env = map[string]string{}
-	}
-
-	// add additional env based on options
-	for key, val := range opts.SharedOpts.AdditionalEnv {
-		env[key] = val
-	}
+		if !strings.Contains(err.Error(), "image not found") {
+			// some other error we need to report
+			return "", err
+		}
 
-	buildAgent := &BuildAgent{
-		SharedOpts:  opts.SharedOpts,
-		client:      c.Client,
-		imageRepo:   imageURL,
-		env:         env,
-		imageExists: false,
-	}
+		// image does not exist so we create one
 
-	if opts.Method == DeployBuildTypeDocker {
-		basePath, err := filepath.Abs(".")
+		env, err := GetEnvFromConfig(mergedValues)
 
 		if err != nil {
-			return "", err
+			env = map[string]string{}
 		}
 
-		err = buildAgent.BuildDocker(agent, basePath, opts.LocalPath, opts.LocalDockerfile, imageTag, "")
-	} else {
-		err = buildAgent.BuildPack(agent, opts.LocalPath, imageTag, "", extraBuildConfig)
-	}
+		// add additional env based on options
+		for key, val := range opts.SharedOpts.AdditionalEnv {
+			env[key] = val
+		}
 
-	if err != nil {
-		return "", err
-	}
+		buildAgent := &BuildAgent{
+			SharedOpts:  opts.SharedOpts,
+			client:      c.Client,
+			imageRepo:   imageURL,
+			env:         env,
+			imageExists: false,
+		}
 
-	// create repository
-	err = c.Client.CreateRepository(
-		context.Background(),
-		opts.ProjectID,
-		regID,
-		&types.CreateRegistryRepositoryRequest{
-			ImageRepoURI: imageURL,
-		},
-	)
+		if opts.Method == DeployBuildTypeDocker {
+			basePath, err := filepath.Abs(".")
 
-	if err != nil {
-		return "", err
-	}
+			if err != nil {
+				return "", err
+			}
 
-	err = agent.PushImage(fmt.Sprintf("%s:%s", imageURL, imageTag))
+			err = buildAgent.BuildDocker(agent, basePath, opts.LocalPath, opts.LocalDockerfile, imageTag, "")
+		} else {
+			err = buildAgent.BuildPack(agent, opts.LocalPath, imageTag, "", extraBuildConfig)
+		}
 
-	if err != nil {
-		return "", err
+		if err != nil {
+			return "", err
+		}
+
+		// create repository
+		err = c.Client.CreateRepository(
+			context.Background(),
+			opts.ProjectID,
+			regID,
+			&types.CreateRegistryRepositoryRequest{
+				ImageRepoURI: imageURL,
+			},
+		)
+
+		if err != nil {
+			return "", err
+		}
+
+		err = agent.PushImage(fmt.Sprintf("%s:%s", imageURL, imageTag))
+
+		if err != nil {
+			return "", err
+		}
 	}
 
 	subdomain, err := c.CreateSubdomainIfRequired(mergedValues)

+ 19 - 6
cli/cmd/deploy/deploy.go

@@ -217,10 +217,28 @@ func (d *DeployAgent) WriteBuildEnv(fileDest string) error {
 // Build uses the deploy agent options to build a new container image from either
 // buildpack or docker.
 func (d *DeployAgent) Build(overrideBuildConfig *types.BuildConfig) error {
+	err := d.agent.CheckIfImageExists(fmt.Sprintf("%s:%s", d.imageRepo, d.tag))
+
+	if err == nil {
+		d.imageExists = true
+	} else {
+		if !strings.Contains(err.Error(), "image not found") {
+			// some other error we need to report
+			return err
+		}
+
+		d.imageExists = false
+	}
+
+	// we do not want to re-build an image
+	// FIXME: what if overrideBuildConfig == nil but the image stays the same?
+	if overrideBuildConfig == nil && d.imageExists {
+		return nil
+	}
+
 	// if build is not local, fetch remote source
 	var basePath string
 	buildCtx := d.opts.LocalPath
-	var err error
 
 	if !d.opts.Local {
 		repoSplit := strings.Split(d.release.GitActionConfig.GitRepo, "/")
@@ -275,11 +293,6 @@ func (d *DeployAgent) Build(overrideBuildConfig *types.BuildConfig) error {
 	// if image is not found, don't return an error
 	if err != nil && err != docker.PullImageErrNotFound {
 		return err
-	} else if err != nil && err == docker.PullImageErrNotFound {
-		fmt.Println("could not find image, moving to build step")
-		d.imageExists = false
-	} else if err == nil {
-		d.imageExists = true
 	}
 
 	buildAgent := &BuildAgent{

+ 29 - 7
cli/cmd/docker/agent.go

@@ -158,6 +158,19 @@ var PullImageErrNotFound = fmt.Errorf("Requested image not found")
 
 var PullImageErrUnauthorized = fmt.Errorf("Could not pull image: unauthorized")
 
+// CheckIfImageExists checks if the image exists in the registry
+func (a *Agent) CheckIfImageExists(image string) error {
+	encodedRegistryAuth, err := a.getEncodedRegistryAuth(image)
+
+	if err != nil {
+		return err
+	}
+
+	_, err = a.client.DistributionInspect(context.Background(), image, encodedRegistryAuth)
+
+	return err
+}
+
 // PullImage pulls an image specified by the image string
 func (a *Agent) PullImage(image string) error {
 	opts, err := a.getPullOptions(image)
@@ -219,17 +232,30 @@ func (a *Agent) getPullOptions(image string) (types.ImagePullOptions, error) {
 		return types.ImagePullOptions{}, nil
 	}
 
+	authConfigEncoded, err := a.getEncodedRegistryAuth(image)
+
+	if err != nil {
+		return types.ImagePullOptions{}, err
+	}
+
+	return types.ImagePullOptions{
+		RegistryAuth: authConfigEncoded,
+		Platform:     "linux/amd64",
+	}, nil
+}
+
+func (a *Agent) getEncodedRegistryAuth(image string) (string, error) {
 	// get using server url
 	serverURL, err := GetServerURLFromTag(image)
 
 	if err != nil {
-		return types.ImagePullOptions{}, err
+		return "", err
 	}
 
 	user, secret, err := a.authGetter.GetCredentials(serverURL)
 
 	if err != nil {
-		return types.ImagePullOptions{}, err
+		return "", err
 	}
 
 	var authConfig = types.AuthConfig{
@@ -239,12 +265,8 @@ func (a *Agent) getPullOptions(image string) (types.ImagePullOptions, error) {
 	}
 
 	authConfigBytes, _ := json.Marshal(authConfig)
-	authConfigEncoded := base64.URLEncoding.EncodeToString(authConfigBytes)
 
-	return types.ImagePullOptions{
-		RegistryAuth: authConfigEncoded,
-		Platform:     "linux/amd64",
-	}, nil
+	return base64.URLEncoding.EncodeToString(authConfigBytes), nil
 }
 
 func (a *Agent) getPushOptions(image string) (types.ImagePushOptions, error) {