/
tag.go
158 lines (131 loc) · 4.27 KB
/
tag.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
147
148
149
150
151
152
153
154
155
156
157
158
package ecr
import (
"fmt"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/session"
"github.com/aws/aws-sdk-go/service/ecr"
"github.com/nearmap/cvmanager/stats"
"github.com/pkg/errors"
)
type tagger struct {
sess *session.Session
stats stats.Stats
}
// NewTagger provides reference to Tagger and offers capability
// to add/remove/get tags of ECR repos
func NewTagger(sess *session.Session, stats stats.Stats) *tagger {
return &tagger{
sess: sess,
stats: stats,
}
}
// Add adds list of tags to the image identified with version
func (t *tagger) Add(ecrARN string, version string, tags ...string) error {
repoName, accountID, region, err := nameAccountRegionFromARN(ecrARN)
if err != nil {
return errors.Wrap(err, "failed to read ECR repository ARN")
}
ecrClient := ecr.New(t.sess, aws.NewConfig().WithRegion(region))
for _, tag := range tags {
fmt.Printf("Tags are %s \n", tags)
getReq := &ecr.BatchGetImageInput{
ImageIds: []*ecr.ImageIdentifier{
{
ImageTag: aws.String(version),
},
},
RegistryId: aws.String(accountID),
RepositoryName: aws.String(repoName),
}
getRes, err := ecrClient.BatchGetImage(getReq)
if err != nil {
t.stats.IncCount(fmt.Sprintf("ecr.batchget.%s.failure", repoName))
return errors.Wrap(err, fmt.Sprintf("failed to get images of tag %s", tag))
}
for _, img := range getRes.Images {
putReq := &ecr.PutImageInput{
ImageManifest: img.ImageManifest,
ImageTag: aws.String(tag),
RegistryId: aws.String(accountID),
RepositoryName: aws.String(repoName),
}
_, err = ecrClient.PutImage(putReq)
if err != nil {
t.stats.IncCount(fmt.Sprintf("ecr.putimage.%s.failure", repoName))
return errors.Wrap(err, fmt.Sprintf("failed to add tag %s to image manifest %s",
tag, aws.StringValue(img.ImageManifest)))
}
}
}
return nil
}
// Remove removes the list of tags from ECR repository such that no image contains these
// tags
func (t *tagger) Remove(ecrARN string, tags ...string) error {
repoName, accountID, region, err := nameAccountRegionFromARN(ecrARN)
if err != nil {
return errors.Wrap(err, "failed to read ECR repository ARN")
}
ecrClient := ecr.New(t.sess, aws.NewConfig().WithRegion(region))
for _, tag := range tags {
getReq := &ecr.BatchGetImageInput{
ImageIds: []*ecr.ImageIdentifier{
{
ImageTag: aws.String(tag),
},
},
RegistryId: aws.String(accountID),
RepositoryName: aws.String(repoName),
}
getRes, err := ecrClient.BatchGetImage(getReq)
if err != nil {
t.stats.IncCount(fmt.Sprintf("ecr.batchget.%s.failure", repoName))
return errors.Wrap(err, fmt.Sprintf("failed to get images of tag %s", tag))
}
for _, img := range getRes.Images {
delReq := &ecr.BatchDeleteImageInput{
ImageIds: []*ecr.ImageIdentifier{
{
ImageTag: aws.String(tag),
ImageDigest: img.ImageId.ImageDigest,
},
},
RegistryId: aws.String(accountID),
RepositoryName: aws.String(repoName),
}
_, err = ecrClient.BatchDeleteImage(delReq)
if err != nil {
t.stats.IncCount(fmt.Sprintf("ecr.batchdelete.%s.failure", repoName))
return errors.Wrap(err, fmt.Sprintf("failed to perform batch delete image by tag %s and digest %s",
tag, aws.StringValue(img.ImageId.ImageDigest)))
}
}
}
return nil
}
// Get gets the list of tags to the image identified with version
func (t *tagger) Get(ecrARN string, version string) ([]string, error) {
repoName, accountID, region, err := nameAccountRegionFromARN(ecrARN)
if err != nil {
return nil, errors.Wrap(err, "failed to read ECR repository ARN")
}
ecrClient := ecr.New(t.sess, aws.NewConfig().WithRegion(region))
getReq := &ecr.DescribeImagesInput{
ImageIds: []*ecr.ImageIdentifier{
{
ImageTag: aws.String(version),
},
},
RegistryId: aws.String(accountID),
RepositoryName: aws.String(repoName),
}
getRes, err := ecrClient.DescribeImages(getReq)
if err != nil {
t.stats.IncCount(fmt.Sprintf("ecr.descimg.%s.failure", repoName))
return nil, errors.Wrap(err, fmt.Sprintf("failed to get images of tag %s", version))
}
if len(getRes.ImageDetails) > 1 {
return nil, errors.New("More than one image with version tag was found ... bad state!")
}
return aws.StringValueSlice(getRes.ImageDetails[0].ImageTags), nil
}