Skip to content

Commit 3d842e6

Browse files
author
Roman Minebaev
committed
Added authorization in registry
1 parent fffe3b3 commit 3d842e6

File tree

11 files changed

+225
-133
lines changed

11 files changed

+225
-133
lines changed

.gitignore

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
bin/
22
.idea/
3-
.vscode/
43
.DS_Store
5-
infile
6-
*.out
4+
file
5+
*.out

.vscode/launch.json

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
{
2+
// Use IntelliSense to learn about possible attributes.
3+
// Hover to view descriptions of existing attributes.
4+
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
5+
"version": "0.2.0",
6+
"configurations": [
7+
{
8+
"name": "Connect to server",
9+
"type": "go",
10+
"request": "attach",
11+
"mode": "remote",
12+
"remotePath": "${workspaceFolder}",
13+
"port": 2345,
14+
"host": "127.0.0.1"
15+
},
16+
{
17+
"name": "Launch Package",
18+
"type": "go",
19+
"request": "launch",
20+
"mode": "auto",
21+
//"program": "${fileDirname}",
22+
"program": "main.go",
23+
"args": [
24+
"--file=images.list",
25+
"--newregistry=localhost:5000",
26+
]
27+
}
28+
]
29+
}

.vscode/tasks.json

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
{
2+
// See https://go.microsoft.com/fwlink/?LinkId=733558
3+
// for the documentation about the tasks.json format
4+
"version": "2.0.0",
5+
"tasks": [
6+
{
7+
"label": "shell",
8+
"type": "shell",
9+
"command": "cd ${workspaceFolder} && ${env:HOME}/go/bin/dlv debug --headless --listen=:2345 --log --api-version=2 -- --file=images-thirdparty.list --newregistry=localhost:5000 --skiplogin=false",
10+
"problemMatcher": [],
11+
"group": {
12+
"kind": "build",
13+
"isDefault": true
14+
}
15+
}
16+
]
17+
}

go.mod

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
module docker-retagger
2+
3+
go 1.17

images.list.template

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
private.azurecr.io/test:R212-7843
2+
docker.io/bitnami/minideb:buster
3+
docker.io/bitnami/redis-exporter:1.21.0-debian-10-r1
4+
docker.io/bitnami/redis:6.2.2
5+
docker.io/bitnami/postgresql:12.2.0
6+
docker.io/bitnami/postgres-exporter:0.7.0-debian-9-r12
7+
docker.io/bitnami/minideb:stretch
8+
docker.io/bitnami/fluentd:1.12.0-debian-10-r0
9+
fluent/fluent-bit:1.3.7
10+
consul:1.8.2
11+
curlimages/curl:latest
12+
hashicorp/consul:1.9.7
13+
k8s.gcr.io/defaultbackend-amd64:1.5
14+
k8s.gcr.io/ingress-nginx/controller:v1.0.4
15+
ghcr.io/kedacore/keda:2.2.0
16+
ghcr.io/kedacore/keda-metrics-apiserver:2.2.0
17+
docker.io/busybox

main.go

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
package main
2+
3+
import (
4+
"bufio"
5+
"flag"
6+
"log"
7+
"net/url"
8+
"os"
9+
"strings"
10+
"sync"
11+
12+
"docker-retagger/pkg/docker"
13+
"docker-retagger/pkg/images"
14+
)
15+
16+
var origin, newRegistry, file string
17+
var skiplogin bool
18+
19+
func init() {
20+
flag.StringVar(&origin, "image", "", "the original image to pull")
21+
flag.StringVar(&newRegistry, "newregistry", "", "the registry to set the image to")
22+
flag.StringVar(&file, "file", "", "use an input file rather than one-off flags")
23+
flag.BoolVar(&skiplogin, "skiplogin", false, "if you want continue without login in original registry")
24+
flag.Parse()
25+
26+
if err := docker.CheckDocker(); err != nil {
27+
log.Fatalf("docker does not appear to be installed, %+v", err)
28+
}
29+
}
30+
31+
func belongsToList(list []string, lookup string) bool {
32+
for _, val := range list {
33+
if val == lookup {
34+
return true
35+
}
36+
}
37+
return false
38+
}
39+
40+
func main() {
41+
var img *images.Image
42+
var originalRegistry string
43+
var allRegistries []string
44+
d := make(map[*images.Image]string)
45+
46+
if file != "" {
47+
if newRegistry == "" {
48+
log.Fatal("--newregistry flag must not be \"\"")
49+
}
50+
f, err := os.Open(file)
51+
if err != nil {
52+
log.Fatal(err)
53+
}
54+
defer f.Close()
55+
56+
scanner := bufio.NewScanner(f)
57+
for scanner.Scan() {
58+
split := strings.Split(scanner.Text(), "\n")
59+
img, err = images.ParseImage(split[0])
60+
if err != nil {
61+
log.Fatal(err)
62+
}
63+
d[img] = split[0]
64+
}
65+
if err := scanner.Err(); err != nil {
66+
log.Fatal(err)
67+
}
68+
} else {
69+
switch {
70+
case origin == "":
71+
log.Fatal("--image flag must not be \"\"")
72+
case newRegistry == "":
73+
log.Fatal("--newregistry flag must not be \"\"")
74+
default:
75+
var err error
76+
img, err = images.ParseImage(origin)
77+
if err != nil {
78+
log.Fatal(err)
79+
}
80+
d[img] = newRegistry
81+
}
82+
}
83+
84+
if err := docker.DockerAuth(newRegistry); err != nil {
85+
log.Fatalf("Failed to authorization in %s", newRegistry)
86+
}
87+
88+
wg := &sync.WaitGroup{}
89+
for k, v := range d {
90+
wg.Add(1)
91+
originalImage, err := k.Marshal()
92+
if err != nil {
93+
log.Fatal(err)
94+
}
95+
96+
_, err = url.Parse(v)
97+
if err != nil {
98+
log.Fatalf("%s is not a valid origin url", v)
99+
}
100+
originalRegistry = k.Registry
101+
k.Registry = newRegistry
102+
k.User = ""
103+
newImage, err := k.Marshal()
104+
if err != nil {
105+
log.Fatal(err)
106+
}
107+
if !skiplogin && !belongsToList(allRegistries, originalRegistry) {
108+
allRegistries = append(allRegistries, originalRegistry)
109+
if err := docker.DockerAuth(originalRegistry); err != nil {
110+
log.Fatalf("Failed to authorization in %s", originalRegistry)
111+
}
112+
}
113+
114+
go docker.UpdateImage(wg, originalImage, newImage)
115+
}
116+
wg.Wait()
117+
}

makefile

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ test:
1313

1414
.PHONY:build
1515
build:
16-
@CGO_ENABLED=0 go build -o bin/retagger retagger.go
16+
@CGO_ENABLED=0 go build -o bin/retagger main.go
1717

1818
install:./bin/retagger
1919
@mv ./bin/retagger /usr/local/bin/retagger
@@ -27,15 +27,15 @@ build_artifacts: build_linux build_windows build_darwin
2727

2828
.PHONY: build_linux
2929
build_linux:
30-
@CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -a -o bin/retagger retagger.go
30+
@CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -a -o bin/retagger main.go
3131
@cd bin;tar -czf retagger_linux_amd64.tar.gz retagger;rm -f retagger
3232

3333
.PHONY: build_windows
3434
build_windows:
35-
@CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build -a -o bin/retagger retagger.go
35+
@CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build -a -o bin/retagger main.go
3636
@cd bin;tar -czf retagger_windows_amd64.tar.gz retagger;rm -f retagger
3737

3838
.PHONY: build_darwin
3939
build_darwin:
40-
@CGO_ENABLED=0 GOOS=darwin GOARCH=amd64 go build -a -o bin/retagger retagger.go
41-
@cd bin;tar -czf retagger_darwin_amd64.tar.gz retagger;rm -f retagger
40+
@CGO_ENABLED=0 GOOS=darwin GOARCH=amd64 go build -a -o bin/retagger main.go
41+
@cd bin;tar -czf retagger_darwin_amd64.tar.gz retagger;rm -f retagger

pkg/docker/docker.go

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package docker
22

33
import (
44
"fmt"
5+
"os"
56
"os/exec"
67
"sync"
78
)
@@ -11,6 +12,16 @@ func CheckDocker() error {
1112
return err
1213
}
1314

15+
func DockerAuth(registry string) error {
16+
fmt.Printf("Authorization in %s registry\n", registry)
17+
cmd := exec.Command("docker", "login", registry)
18+
cmd.Stdout = os.Stdout
19+
cmd.Stderr = os.Stderr
20+
cmd.Stdin = os.Stdin
21+
err := cmd.Run()
22+
return err
23+
}
24+
1425
func UpdateImage(wg *sync.WaitGroup, o, n string) {
1526
if err := exec.Command("docker", "pull", o).Run(); err != nil {
1627
fmt.Printf("error running docker pull on %s, %+v\n", o, err)
@@ -20,7 +31,8 @@ func UpdateImage(wg *sync.WaitGroup, o, n string) {
2031
}
2132
if err := exec.Command("docker", "push", n).Run(); err != nil {
2233
fmt.Printf("error running docker push on %s, %+v\n", o, err)
34+
} else {
35+
fmt.Printf("Image: %s has successfully pushed.\n", n)
2336
}
24-
fmt.Printf("Image: %s has successfully pushed.\n", n)
2537
wg.Done()
2638
}

pkg/images/image.go

Lines changed: 15 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -3,54 +3,51 @@ package images
33
import (
44
"fmt"
55
"regexp"
6-
"strings"
76
)
87

98
type Image struct {
109
Registry string
1110
User string
1211
Name string
1312
Tag string
14-
Hash string
1513
}
1614

1715
func (I *Image) Marshal() (string, error) {
1816
if I.User != "" {
1917
if I.Tag != "" {
2018
return fmt.Sprintf("%s/%s/%s:%s", I.Registry, I.User, I.Name, I.Tag), nil
21-
} else if I.Hash != "" {
22-
return fmt.Sprintf("%s/%s/%s@%s", I.Registry, I.User, I.Name, I.Hash), nil
2319
} else {
24-
return "", fmt.Errorf("no Tag or Hash value found")
20+
return "", fmt.Errorf("no Tag value found")
2521
}
2622
} else {
2723
if I.Tag != "" {
2824
return fmt.Sprintf("%s/%s:%s", I.Registry, I.Name, I.Tag), nil
29-
} else if I.Hash != "" {
30-
return fmt.Sprintf("%s/%s@%s", I.Registry, I.Name, I.Hash), nil
3125
} else {
32-
return "", fmt.Errorf("no Tag or Hash value found")
26+
return "", fmt.Errorf("no Tag value found")
3327
}
3428
}
3529
}
3630

3731
func ParseImage(image string) (*Image, error) {
3832
img := &Image{}
39-
r := regexp.MustCompile("^(((?P<Registry>[a-zA-Z0-9-_]+?(\\.[a-zA-Z0-9]+?)+?\\.[a-zA-Z]{2,})/)?((?P<Name>[a-zA-Z0-9-_]+?)|(?P<UserName>[a-zA-Z0-9-_]+?)/(?P<ImageName>[a-zA-Z-_]+?))((:(?P<Tag>[a-zA-Z0-9-_\\.]+?))|(@(?P<Hash>sha256:[a-z0-9]{64}))))$")
33+
r := regexp.MustCompile(`(?P<Registry>[a-z0-9\-.]+\.[a-z0-9\-]+:?[0-9]*)?/?((?P<Name>[a-zA-Z0-9-_]+?)|(?P<UserName>[a-zA-Z0-9-_]+?)/(?P<ImageName>[a-zA-Z-_]+?))(:(?P<Tag>[a-zA-Z0-9-_\\.]+?)|)$`)
4034
if r.MatchString(image) {
4135
matches := r.FindStringSubmatch(image)
42-
img.Registry = strings.TrimSuffix(matches[2], "/")
43-
if matches[4] != "" {
44-
img.Name = strings.TrimPrefix(matches[5], "/")
36+
if matches[1] != "" {
37+
img.Registry = matches[1]
4538
} else {
46-
img.User = strings.TrimPrefix(matches[6], "/")
47-
img.Name = strings.TrimPrefix(matches[7], "/")
39+
img.Registry = "docker.io"
4840
}
49-
if matches[9] != "" {
50-
img.Tag = strings.TrimPrefix(matches[10], ":")
41+
if matches[3] != "" {
42+
img.Name = matches[3]
43+
} else {
44+
img.User = matches[4]
45+
img.Name = matches[5]
5146
}
52-
if matches[11] != "" {
53-
img.Hash = matches[12]
47+
if matches[7] != "" {
48+
img.Tag = matches[7]
49+
} else {
50+
img.Tag = "latest"
5451
}
5552
return img, nil
5653
} else {

readme.md

Lines changed: 7 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -4,21 +4,12 @@ This tool allows you to pull, re-tag, and push the re-tagged docker images on ei
44

55
## Usage
66

7-
```bash
8-
Usage of retagger:
9-
-image string
10-
the original image to pull
11-
-infile string
12-
use an input file rather than one-off flags
13-
-new-origin string
14-
the origin to set the image to
15-
```
16-
17-
| flag | type | required | help | example |
18-
|--------------|--------|--------------------------------------------------------|---------------------------------------------------------------------------------------|--------------------------|
19-
| --image | string | only if --infile is not used | The original image to pull | `golang:latest` |
20-
| --new-origin | string | only if --infile is not used | The new repository you are pushing to | `my.awesome.docker.repo` |
21-
| --infile | string | no, but takes preference over --image and --new-origin | A file with the original image and the new origin seperated by a space (one per line) | `infile.txt` |
7+
| flag | type | required | help | example |
8+
|---------------|--------|---------------------------------------|---------------------------------------------------------|--------------------------|
9+
| --image | string | only if --file is not used | The original image to pull | `golang:latest` |
10+
| --newregistry | string | only if --file is used | The new repository you are pushing to | `my.awesome.docker.repo` |
11+
| --file | string | no, but takes preference over --image | A file with the original images (one per line) | `images.list.template` |
12+
| --skiplogin | bool | no | if you want continue without login in original registry | `true / false` |
2213

2314
## Installation
2415

@@ -45,4 +36,4 @@ You will need to grab the zip file from the releases and put the binary wherever
4536

4637
### Disclaimer
4738

48-
I am well aware this is a poorly constructed CLI :smile:, but it worked in a pinch. I'll try to fix it later.
39+
I am well aware this is a poorly constructed CLI :smile:, but it worked in a pinch. I'll try to fix it later.

0 commit comments

Comments
 (0)