Skip to content

Commit 168e807

Browse files
committed
Auto-create ECR registries before docker push
1 parent 64d1c62 commit 168e807

File tree

5 files changed

+130
-4
lines changed

5 files changed

+130
-4
lines changed

go.mod

+5-4
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ module github.com/gitpod-io/leeway
33
go 1.21
44

55
require (
6-
github.com/aws/aws-sdk-go-v2 v1.21.2
6+
github.com/aws/aws-sdk-go-v2 v1.30.4
77
github.com/aws/aws-sdk-go-v2/config v1.18.45
88
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.11.90
99
github.com/aws/aws-sdk-go-v2/service/s3 v1.40.2
@@ -37,17 +37,18 @@ require (
3737
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.14 // indirect
3838
github.com/aws/aws-sdk-go-v2/credentials v1.13.43 // indirect
3939
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.13 // indirect
40-
github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.43 // indirect
41-
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.37 // indirect
40+
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.16 // indirect
41+
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.16 // indirect
4242
github.com/aws/aws-sdk-go-v2/internal/ini v1.3.45 // indirect
4343
github.com/aws/aws-sdk-go-v2/internal/v4a v1.1.6 // indirect
44+
github.com/aws/aws-sdk-go-v2/service/ecr v1.32.2 // indirect
4445
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.9.15 // indirect
4546
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.38 // indirect
4647
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.37 // indirect
4748
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.15.6 // indirect
4849
github.com/aws/aws-sdk-go-v2/service/sso v1.15.2 // indirect
4950
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.17.3 // indirect
50-
github.com/aws/smithy-go v1.15.0 // indirect
51+
github.com/aws/smithy-go v1.20.4 // indirect
5152
github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869 // indirect
5253
github.com/coreos/go-systemd/v22 v22.3.2 // indirect
5354
github.com/cyphar/filepath-securejoin v0.2.3 // indirect

go.sum

+10
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
github.com/aws/aws-sdk-go-v2 v1.21.2 h1:+LXZ0sgo8quN9UOKXXzAWRT3FWd4NxeXWOZom9pE7GA=
22
github.com/aws/aws-sdk-go-v2 v1.21.2/go.mod h1:ErQhvNuEMhJjweavOYhxVkn2RUx7kQXVATHrjKtxIpM=
3+
github.com/aws/aws-sdk-go-v2 v1.30.4 h1:frhcagrVNrzmT95RJImMHgabt99vkXGslubDaDagTk8=
4+
github.com/aws/aws-sdk-go-v2 v1.30.4/go.mod h1:CT+ZPWXbYrci8chcARI3OmI/qgd+f6WtuLOoaIA8PR0=
35
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.14 h1:Sc82v7tDQ/vdU1WtuSyzZ1I7y/68j//HJ6uozND1IDs=
46
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.14/go.mod h1:9NCTOURS8OpxvoAVHq79LK81/zC78hfRWFn+aL0SPcY=
57
github.com/aws/aws-sdk-go-v2/config v1.18.45 h1:Aka9bI7n8ysuwPeFdm77nfbyHCAKQ3z9ghB3S/38zes=
@@ -12,12 +14,18 @@ github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.11.90 h1:mtJRt80k1oGw7QQPluAx
1214
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.11.90/go.mod h1:lYwZTkeMQWPvNU+u7oYArdNhQ8EKiSGU76jVv0w2GH4=
1315
github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.43 h1:nFBQlGtkbPzp/NjZLuFxRqmT91rLJkgvsEQs68h962Y=
1416
github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.43/go.mod h1:auo+PiyLl0n1l8A0e8RIeR8tOzYPfZZH/JNlrJ8igTQ=
17+
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.16 h1:TNyt/+X43KJ9IJJMjKfa3bNTiZbUP7DeCxfbTROESwY=
18+
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.16/go.mod h1:2DwJF39FlNAUiX5pAc0UNeiz16lK2t7IaFcm0LFHEgc=
1519
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.37 h1:JRVhO25+r3ar2mKGP7E0LDl8K9/G36gjlqca5iQbaqc=
1620
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.37/go.mod h1:Qe+2KtKml+FEsQF/DHmDV+xjtche/hwoF75EG4UlHW8=
21+
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.16 h1:jYfy8UPmd+6kJW5YhY0L1/KftReOGxI/4NtVSTh9O/I=
22+
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.16/go.mod h1:7ZfEPZxkW42Afq4uQB8H2E2e6ebh6mXTueEpYzjCzcs=
1723
github.com/aws/aws-sdk-go-v2/internal/ini v1.3.45 h1:hze8YsjSh8Wl1rYa1CJpRmXP21BvOBuc76YhW0HsuQ4=
1824
github.com/aws/aws-sdk-go-v2/internal/ini v1.3.45/go.mod h1:lD5M20o09/LCuQ2mE62Mb/iSdSlCNuj6H5ci7tW7OsE=
1925
github.com/aws/aws-sdk-go-v2/internal/v4a v1.1.6 h1:wmGLw2i8ZTlHLw7a9ULGfQbuccw8uIiNr6sol5bFzc8=
2026
github.com/aws/aws-sdk-go-v2/internal/v4a v1.1.6/go.mod h1:Q0Hq2X/NuL7z8b1Dww8rmOFl+jzusKEcyvkKspwdpyc=
27+
github.com/aws/aws-sdk-go-v2/service/ecr v1.32.2 h1:2RjzMZp/8PXJUMqiKkDSp7RVj6inF5DpVel35THjV+I=
28+
github.com/aws/aws-sdk-go-v2/service/ecr v1.32.2/go.mod h1:kdk+WJbHcGVbIlRQfSrKyuKkbWDdD8I9NScyS5vZ8eQ=
2129
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.9.15 h1:7R8uRYyXzdD71KWVCL78lJZltah6VVznXBazvKjfH58=
2230
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.9.15/go.mod h1:26SQUPcTNgV1Tapwdt4a1rOsYRsnBsJHLMPoxK2b0d8=
2331
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.38 h1:skaFGzv+3kA+v2BPKhuekeb1Hbb105+44r8ASC+q5SE=
@@ -36,6 +44,8 @@ github.com/aws/aws-sdk-go-v2/service/sts v1.23.2 h1:0BkLfgeDjfZnZ+MhB3ONb01u9pwF
3644
github.com/aws/aws-sdk-go-v2/service/sts v1.23.2/go.mod h1:Eows6e1uQEsc4ZaHANmsPRzAKcVDrcmjjWiih2+HUUQ=
3745
github.com/aws/smithy-go v1.15.0 h1:PS/durmlzvAFpQHDs4wi4sNNP9ExsqZh6IlfdHXgKK8=
3846
github.com/aws/smithy-go v1.15.0/go.mod h1:Tg+OJXh4MB2R/uN61Ko2f6hTZwB/ZYGOtib8J3gBHzA=
47+
github.com/aws/smithy-go v1.20.4 h1:2HK1zBdPgRbjFOHlfeQZfpC4r72MOb9bZkiFwggKO+4=
48+
github.com/aws/smithy-go v1.20.4/go.mod h1:irrKGvNn1InZwb2d7fkIRNucdfwR8R+Ts3wxYa/cJHg=
3949
github.com/blang/semver v3.5.1+incompatible h1:cQNTCjp13qL8KC3Nbxr/y2Bqb63oX6wdnnjpJbkM4JQ=
4050
github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM=
4151
github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ=

pkg/leeway/build.go

+5
Original file line numberDiff line numberDiff line change
@@ -1426,6 +1426,11 @@ func (p *Package) buildDocker(buildctx *buildContext, wd, result string) (res *p
14261426
buildcmd = append(buildcmd, ".")
14271427
commands[PackageBuildPhaseBuild] = append(commands[PackageBuildPhaseBuild], buildcmd)
14281428

1429+
err = cfg.EnsureRegistryExists()
1430+
if err != nil {
1431+
log.Warnf("failed to create the registries: %v", err)
1432+
}
1433+
14291434
if len(cfg.Image) == 0 {
14301435
// we don't push the image, let's export it
14311436
ef := strings.TrimSuffix(result, ".gz")

pkg/leeway/images.go

+80
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
package leeway
2+
3+
import (
4+
"context"
5+
"errors"
6+
"fmt"
7+
8+
"os/exec"
9+
10+
"github.com/aws/aws-sdk-go-v2/aws"
11+
"github.com/aws/aws-sdk-go-v2/config"
12+
"github.com/aws/aws-sdk-go-v2/service/ecr"
13+
"github.com/aws/aws-sdk-go-v2/service/ecr/types"
14+
)
15+
16+
type ImageAdapter interface {
17+
Create(imageName string) error
18+
Sign(imageName, profileARN string) error
19+
}
20+
21+
// ECRAdapter implements the ImageAdapter interface for AWS ECR
22+
type ECRAdapter struct {
23+
ecrClient *ecr.Client
24+
}
25+
26+
// NewECRAdapter initializes an ECRAdapter with an AWS ECR client
27+
func NewECRAdapter() (*ECRAdapter, error) {
28+
cfg, err := config.LoadDefaultConfig(context.TODO())
29+
if err != nil {
30+
return nil, fmt.Errorf("unable to load SDK config, %v", err)
31+
}
32+
33+
client := ecr.NewFromConfig(cfg)
34+
return &ECRAdapter{
35+
ecrClient: client,
36+
}, nil
37+
}
38+
39+
// Create checks if the ECR image exists and creates it if it doesn't
40+
func (e *ECRAdapter) Create(imageName string) error {
41+
_, err := e.ecrClient.DescribeImages(context.TODO(), &ecr.DescribeImagesInput{
42+
RepositoryName: aws.String(imageName),
43+
})
44+
if err == nil {
45+
fmt.Printf("Image %s already exists\n", imageName)
46+
return nil
47+
}
48+
49+
if !isRepositoryNotFoundErr(err) {
50+
return fmt.Errorf("failed to check if ECR image %s exists: %w", imageName, err)
51+
}
52+
53+
_, err = e.ecrClient.CreateRepository(context.TODO(), &ecr.CreateRepositoryInput{
54+
RepositoryName: aws.String(imageName),
55+
})
56+
if err != nil {
57+
return fmt.Errorf("failed to create ECR image: %w", err)
58+
}
59+
60+
fmt.Printf("Image %s created successfully\n", imageName)
61+
return nil
62+
}
63+
64+
// Sign uses the notation tool to sign the ECR image
65+
func (e *ECRAdapter) Sign(imageName, profileARN string) error {
66+
cmd := exec.Command("notation", "sign", "--profile", profileARN, imageName)
67+
output, err := cmd.CombinedOutput()
68+
if err != nil {
69+
return fmt.Errorf("failed to sign the image: %v, output: %s", err, string(output))
70+
}
71+
72+
fmt.Printf("Image %s signed successfully\n", imageName)
73+
return nil
74+
}
75+
76+
// isImageNotFoundErr checks if the error is an ImageNotFoundException
77+
func isRepositoryNotFoundErr(err error) bool {
78+
var notFoundErr *types.RepositoryNotFoundException
79+
return errors.As(err, &notFoundErr)
80+
}

pkg/leeway/package.go

+30
Original file line numberDiff line numberDiff line change
@@ -551,6 +551,36 @@ func (cfg DockerPkgConfig) AdditionalSources(workspaceOrigin string) []string {
551551
return []string{cfg.Dockerfile}
552552
}
553553

554+
// CreateAndSign processes the Docker image: creates and signs it using the appropriate adapter
555+
func (cfg *DockerPkgConfig) EnsureRegistryExists() error {
556+
for _, image := range cfg.Image {
557+
var adapter ImageAdapter
558+
var err error
559+
560+
if isECRImage(image) {
561+
adapter, err = NewECRAdapter()
562+
if err != nil {
563+
return fmt.Errorf("failed to create ECR adapter: %w", err)
564+
}
565+
} else {
566+
log.Debugf("no supported adapter for image registry for image: %s", image)
567+
return nil
568+
}
569+
570+
if err := adapter.Create(image); err != nil {
571+
return fmt.Errorf("failed to create image %s: %w", image, err)
572+
}
573+
}
574+
575+
return nil
576+
}
577+
578+
// isECRImage checks if the image is hosted on AWS ECR
579+
func isECRImage(image string) bool {
580+
// AWS ECR images typically start with account-id.dkr.ecr.region.amazonaws.com
581+
return strings.Contains(image, ".dkr.ecr.")
582+
}
583+
554584
// GenericPkgConfig configures a generic package
555585
type GenericPkgConfig struct {
556586
Commands [][]string `yaml:"commands"`

0 commit comments

Comments
 (0)