-
Notifications
You must be signed in to change notification settings - Fork 1
/
ecr.go
146 lines (128 loc) · 3.8 KB
/
ecr.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
package registry
import (
"context"
"encoding/base64"
"encoding/json"
"fmt"
"regexp"
"strings"
"github.com/apex/log"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/session"
awsecr "github.com/aws/aws-sdk-go/service/ecr"
"github.com/aws/aws-sdk-go/service/ecr/ecriface"
"github.com/aws/aws-sdk-go/service/sts"
"github.com/aws/aws-sdk-go/service/sts/stsiface"
"github.com/docker/docker/api/types"
"github.com/buildtool/build-tools/pkg/docker"
)
type ECR struct {
dockerRegistry `yaml:"-"`
Url string `yaml:"url" env:"ECR_URL"`
Region string `yaml:"region,omitempty" env:"ECR_REGION"`
username string
password string
ecrSvc ecriface.ECRAPI
stsSvc stsiface.STSAPI
registryId *string
}
var _ Registry = &ECR{}
func (r *ECR) Name() string {
return "ECR"
}
func (r *ECR) Configured() bool {
if len(r.Url) > 0 {
sess, err := session.NewSession(&aws.Config{Region: r.region()})
if err != nil {
return false
}
r.ecrSvc = awsecr.New(sess)
r.stsSvc = sts.New(sess)
registryId, err := r.registry()
if err != nil {
return false
}
r.registryId = registryId
return true
}
return false
}
func (r *ECR) region() *string {
if r.Region == "" {
regex := regexp.MustCompile(`.*\.dkr\.ecr.(.*)\.amazonaws\.com`)
if submatch := regex.FindStringSubmatch(r.Url); len(submatch) == 2 {
r.Region = submatch[1]
}
}
return &r.Region
}
func (r *ECR) registry() (*string, error) {
regex := regexp.MustCompile(`(.*)\.dkr\.ecr..*\.amazonaws\.com`)
if submatch := regex.FindStringSubmatch(r.Url); len(submatch) == 2 {
return &submatch[1], nil
}
return nil, fmt.Errorf("failed to extract registryid from string %s", r.Url)
}
func (r *ECR) Login(client docker.Client) error {
input := &awsecr.GetAuthorizationTokenInput{}
result, err := r.ecrSvc.GetAuthorizationToken(input)
if err != nil {
return err
}
decoded, err := base64.StdEncoding.DecodeString(*result.AuthorizationData[0].AuthorizationToken)
if err != nil {
return err
}
parts := strings.Split(string(decoded), ":")
r.username = parts[0]
r.password = parts[1]
if ok, err := client.RegistryLogin(context.Background(), types.AuthConfig{Username: r.username, Password: r.password, ServerAddress: r.Url}); err == nil {
log.Debugf("%s\n", ok.Status)
return nil
} else {
return err
}
}
func (r *ECR) GetAuthConfig() types.AuthConfig {
return types.AuthConfig{Username: r.username, Password: r.password}
}
func (r *ECR) GetAuthInfo() string {
authBytes, _ := json.Marshal(r.GetAuthConfig())
return base64.URLEncoding.EncodeToString(authBytes)
}
func (r ECR) RegistryUrl() string {
return r.Url
}
func (r ECR) Create(repository string) error {
identity, err := r.stsSvc.GetCallerIdentity(&sts.GetCallerIdentityInput{})
if err != nil {
return err
}
if *identity.Account != *r.registryId {
return fmt.Errorf("account mismatch, logged in at '%s' got '%s' from repository url %s", *identity.Account, *r.registryId, r.Url)
}
if _, err := r.ecrSvc.DescribeRepositories(&awsecr.DescribeRepositoriesInput{
RegistryId: r.registryId,
RepositoryNames: []*string{&repository},
}); err != nil {
switch err.(type) {
case *awsecr.RepositoryNotFoundException:
break
default:
return err
}
input := &awsecr.CreateRepositoryInput{
RepositoryName: aws.String(repository),
}
if _, err := r.ecrSvc.CreateRepository(input); err != nil {
return err
} else {
policyText := `{"rules":[{"rulePriority":10,"description":"Only keep 20 images","selection":{"tagStatus":"untagged","countType":"imageCountMoreThan","countNumber":20},"action":{"type":"expire"}}]}`
if _, err := r.ecrSvc.PutLifecyclePolicy(&awsecr.PutLifecyclePolicyInput{LifecyclePolicyText: &policyText, RepositoryName: &repository}); err != nil {
return err
}
return nil
}
}
return nil
}