Skip to content

Commit

Permalink
Introduction of sha_as_tag=True config in astro cli which will be use…
Browse files Browse the repository at this point in the history
…d during Astro deploy (#1752)

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
  • Loading branch information
1 parent b3db2fd commit c13b5f8
Show file tree
Hide file tree
Showing 7 changed files with 91 additions and 3 deletions.
1 change: 1 addition & 0 deletions airflow/container.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ type ImageHandler interface {
Pytest(pytestFile, airflowHome, envFile, testHomeDirectory string, pytestArgs []string, htmlReport bool, config types.ImageBuildConfig) (string, error)
ConflictTest(workingDirectory, testHomeDirectory string, buildConfig types.ImageBuildConfig) (string, error)
CreatePipFreeze(altImageName, pipFreezeFile string) error
GetImageSha() (string, error)
}

type DockerComposeAPI interface {
Expand Down
23 changes: 23 additions & 0 deletions airflow/docker_image.go
Original file line number Diff line number Diff line change
Expand Up @@ -410,6 +410,29 @@ func (d *DockerImage) Push(remoteImage, username, token string) error {
return nil
}

func (d *DockerImage) GetImageSha() (string, error) {
containerRuntime, err := runtimes.GetContainerRuntimeBinary()
if err != nil {
return "", err
}
// Get the digest of the pushed image
remoteDigest := ""
out := &bytes.Buffer{}
err = cmdExec(containerRuntime, out, nil, "inspect", "--format={{index .RepoDigests 0}}", d.imageName)
if err != nil {
return remoteDigest, fmt.Errorf("failed to get digest for image %s: %w", d.imageName, err)
}
// Parse and clean the output
digestOutput := strings.TrimSpace(out.String())
if digestOutput != "" {
parts := strings.Split(digestOutput, "@")
if len(parts) == 2 {
remoteDigest = parts[1] // Extract the digest part (after '@')
}
}
return remoteDigest, nil
}

func (d *DockerImage) pushWithClient(authConfig *cliTypes.AuthConfig, remoteImage string) error {
ctx := context.Background()

Expand Down
24 changes: 24 additions & 0 deletions airflow/mocks/ImageHandler.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ var (
DisableAstroRun: newCfg("disable_astro_run", "false"),
DisableEnvObjects: newCfg("disable_env_objects", "false"),
AutoSelect: newCfg("auto_select", "false"),
ShaAsTag: newCfg("sha_as_tag", "false"),
}

// viperHome is the viper object in the users home directory
Expand Down
1 change: 1 addition & 0 deletions config/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ type cfgs struct {
DisableAstroRun cfg
DisableEnvObjects cfg
AutoSelect cfg
ShaAsTag cfg
}

// Creates a new cfg struct
Expand Down
12 changes: 9 additions & 3 deletions software/deploy/deploy.go
Original file line number Diff line number Diff line change
Expand Up @@ -181,11 +181,11 @@ func buildPushDockerImage(houstonClient houston.ClientInterface, c *config.Conte
Output: true,
Labels: deployLabels,
}

err = imageHandler.Build("", "", buildConfig)
if err != nil {
return err
}

var registry, remoteImage, token string
if byoRegistryEnabled {
registry = byoRegistryDomain
Expand All @@ -195,13 +195,19 @@ func buildPushDockerImage(houstonClient houston.ClientInterface, c *config.Conte
remoteImage = fmt.Sprintf("%s/%s", registry, airflow.ImageName(name, nextTag))
token = c.Token
}

err = imageHandler.Push(remoteImage, "", token)
if err != nil {
return err
}

if byoRegistryEnabled {
useShaAsTag := config.CFG.ShaAsTag.GetBool()
if useShaAsTag {
sha, err := imageHandler.GetImageSha()
if (sha == "") || (err != nil) {
return fmt.Errorf("failed to get image sha: %w", err)
}
remoteImage = fmt.Sprintf("%s@%s", registry, sha)
}
runtimeVersion, _ := imageHandler.GetLabel("", runtimeImageLabel)
airflowVersion, _ := imageHandler.GetLabel("", airflowImageLabel)
req := houston.UpdateDeploymentImageRequest{ReleaseName: name, Image: remoteImage, AirflowVersion: airflowVersion, RuntimeVersion: runtimeVersion}
Expand Down
32 changes: 32 additions & 0 deletions software/deploy/deploy_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,38 @@ func (s *Suite) TestBuildPushDockerImageSuccessWithBYORegistry() {
assert.Contains(s.T(), capturedBuildConfig.Labels, expectedLabel)
mockImageHandler.AssertExpectations(s.T())
houstonMock.AssertExpectations(s.T())

// Case when SHA is used as tag
houstonMock.On("UpdateDeploymentImage", houston.UpdateDeploymentImageRequest{ReleaseName: "test", Image: "test.registry.io@image_sha", AirflowVersion: "1.10.12", RuntimeVersion: ""}).Return(nil, nil)
imageHandlerInit = func(image string) airflow.ImageHandler {
// Mock the Build function, capturing the buildConfig
mockImageHandler.On("Build", mock.Anything, mock.Anything, mock.MatchedBy(func(buildConfig types.ImageBuildConfig) bool {
// Capture buildConfig for later assertions
capturedBuildConfig = buildConfig
// Check if the deploy label contains the correct description
for _, label := range buildConfig.Labels {
if label == deployRevisionDescriptionLabel+"="+description {
return true
}
}
return false
})).Return(nil).Once()

mockImageHandler.On("Push", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil)
mockImageHandler.On("GetLabel", "", runtimeImageLabel).Return("", nil).Once()
mockImageHandler.On("GetLabel", "", airflowImageLabel).Return("1.10.12", nil).Once()
mockImageHandler.On("GetImageSha", mock.Anything, mock.Anything).Return("image_sha", nil).Once()

return mockImageHandler
}
config.CFG.ShaAsTag.SetHomeString("true")
defer config.CFG.ShaAsTag.SetHomeString("false")
err = buildPushDockerImage(houstonMock, &config.Context{}, mockDeployment, "test", "./testfiles/", "test", "test", "test.registry.io", false, true, description)
s.NoError(err)
expectedLabel = deployRevisionDescriptionLabel + "=" + description
assert.Contains(s.T(), capturedBuildConfig.Labels, expectedLabel)
mockImageHandler.AssertExpectations(s.T())
houstonMock.AssertExpectations(s.T())
}

func (s *Suite) TestBuildPushDockerImageFailure() {
Expand Down

0 comments on commit c13b5f8

Please sign in to comment.