Skip to content

Commit bd4b6bc

Browse files
PRODENG-3325-mke-repo-with-colon-port (#607)
* PRODENG-3325-mke-repo-with-colon-port - fix failure with MKE repo with a `:port` in it, which breaks detection - made new docker image repo tag detector function, and added tests for this failure - mke Collect facts uses this new detector function Signed-off-by: James Nesbitt <jnesbitt@mirantis.com> * Added test cases for ImageRepoAndTag including implicit latest tag * PRODENG-3225 more image tag detection use cases - add tagless iamges to the image tag detection and refactor the tag detection to handled them Signed-off-by: James Nesbitt <james.r.nesbitt@gmail.com> --------- Signed-off-by: James Nesbitt <jnesbitt@mirantis.com> Signed-off-by: James Nesbitt <james.r.nesbitt@gmail.com>
1 parent 38186d3 commit bd4b6bc

File tree

4 files changed

+73
-10
lines changed

4 files changed

+73
-10
lines changed

.gitignore

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,4 +16,6 @@ github-release
1616
vendor
1717

1818
# sometimes an example launchpad.yaml is used
19-
**/launchpad.yaml
19+
**/launchpad.yaml
20+
.gemini/
21+
gha-creds-*.json

pkg/docker/image.go

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package docker
22

33
import (
4+
"errors"
45
"fmt"
56
"regexp"
67
"strings"
@@ -146,3 +147,34 @@ func AllToRepository(images []*Image, repo string) (list []*Image) {
146147
}
147148
return list
148149
}
150+
151+
var errInvalidVersion = errors.New("invalid image version")
152+
153+
// ImageRepoAndTag returns the Repo and tag from a container image.
154+
//
155+
// e.g. `dtr.efzp.com:9026/mirantis/ucp-agent:3.8.10` => `dtr.efzp.com:9026/mirantis/ucp-agent`, `3.8.10`
156+
func ImageRepoAndTag(image string) (string, string, error) {
157+
lastColon := strings.LastIndexByte(image, ':')
158+
lastSlash := strings.LastIndexByte(image, '/')
159+
160+
// If there is no colon, tag is implicitly "latest"
161+
if lastColon == -1 {
162+
return image, "latest", nil
163+
}
164+
165+
// If the last colon is part of the registry host (before the first slash),
166+
// and there are no more colons, then the tag is also implicitly "latest".
167+
// e.g. "localhost:5000/my-image"
168+
if lastColon < lastSlash {
169+
return image, "latest", nil
170+
}
171+
172+
repo := image[:lastColon]
173+
tag := image[lastColon+1:]
174+
175+
if tag == "" {
176+
return "", "", fmt.Errorf("%w: empty tag in version output: %s", errInvalidVersion, image)
177+
}
178+
179+
return repo, tag, nil
180+
}

pkg/docker/image_test.go

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,3 +69,35 @@ registry.ci.mirantis.com/mirantiseng/ucp-auth-store:3.8.7`
6969
require.Equal(t, "registry.ci.mirantis.com/mirantiseng/ucp-alertmanager:3.8.7", images[1].String())
7070
require.Equal(t, "registry.ci.mirantis.com/mirantiseng/ucp-auth-store:3.8.7", images[2].String())
7171
}
72+
73+
func TestImageVersions(t *testing.T) {
74+
cases := []struct {
75+
input string
76+
expected string
77+
tag string
78+
}{
79+
{"mirantis/ucp-proxy:3.8.8", "mirantis/ucp-proxy", "3.8.8"},
80+
{"dtr.efzp.com:9026/mirantis/ucp-agent:3.8.10", "dtr.efzp.com:9026/mirantis/ucp-agent", "3.8.10"},
81+
{"ucp-proxy:3.8.8", "ucp-proxy", "3.8.8"},
82+
{"docker.io/library/alpine:latest", "docker.io/library/alpine", "latest"},
83+
{"localhost:5000/my-image:1.0.0", "localhost:5000/my-image", "1.0.0"},
84+
{"registry.mirantis.com/mirantiseng/ucp:3.9.0-rc2", "registry.mirantis.com/mirantiseng/ucp", "3.9.0-rc2"},
85+
{"registry.ci.mirantis.com/mirantiseng/ecp", "registry.ci.mirantis.com/mirantiseng/ecp", "latest"},
86+
{"localhost:5000/my-image", "localhost:5000/my-image", "latest"},
87+
{"my-complex-repo:5000/org/image:v1", "my-complex-repo:5000/org/image", "v1"},
88+
}
89+
90+
for _, tc := range cases {
91+
repo, tag, err := docker.ImageRepoAndTag(tc.input)
92+
require.Nil(t, err, "ImageRepoAndTag gave unexpected error from valid version string: %s", tc.input)
93+
require.Equal(t, tc.expected, repo, "ImageRepoAndTag gave wrong repo value for: %s", tc.input)
94+
require.Equal(t, tc.tag, tag, "ImageRepoAndTag gave wrong tag value for: %s", tc.input)
95+
}
96+
}
97+
98+
func TestImageVersionsWithColon(t *testing.T) {
99+
repo, tag, err := docker.ImageRepoAndTag("dtr.efzp.com:9026/mirantis/ucp-agent:3.8.10")
100+
require.Nil(t, err, "SwarmMKEVersion gave unexpected error from valid version string")
101+
require.Equal(t, "dtr.efzp.com:9026/mirantis/ucp-agent", repo, "SwarmMKEVersion gave wrong repo value")
102+
require.Equal(t, "3.8.10", tag, "SwarmMKEVersion gave wrong repo value")
103+
}

pkg/mke/mke.go

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import (
2020
"time"
2121

2222
"github.com/Mirantis/launchpad/pkg/constant"
23+
"github.com/Mirantis/launchpad/pkg/docker"
2324
commonconfig "github.com/Mirantis/launchpad/pkg/product/common/config"
2425
mkeconfig "github.com/Mirantis/launchpad/pkg/product/mke/config"
2526
"github.com/hashicorp/go-version"
@@ -40,8 +41,6 @@ type Credentials struct {
4041
Password string `json:"password,omitempty"` // #nosec G117 -- MKE API credentials
4142
}
4243

43-
var errInvalidVersion = errors.New("invalid version")
44-
4544
// CollectFacts gathers the current status of installed mke setup.
4645
func CollectFacts(swarmLeader *mkeconfig.Host, mkeMeta *mkeconfig.MKEMetadata) error {
4746
output, err := swarmLeader.ExecOutput(swarmLeader.Configurer.DockerCommandf(`inspect --format '{{.Config.Image}}' ucp-proxy`))
@@ -51,15 +50,13 @@ func CollectFacts(swarmLeader *mkeconfig.Host, mkeMeta *mkeconfig.MKEMetadata) e
5150
return nil
5251
}
5352

54-
vparts := strings.Split(output, ":")
55-
if len(vparts) != 2 {
56-
return fmt.Errorf("%w: malformed version output: %s", errInvalidVersion, output)
53+
repo, tag, verr := docker.ImageRepoAndTag(output)
54+
if verr != nil {
55+
return fmt.Errorf("%w: malformed version output: %s", verr, output)
5756
}
58-
repo := vparts[0][:strings.LastIndexByte(vparts[0], '/')]
59-
6057
mkeMeta.Installed = true
61-
mkeMeta.InstalledVersion = vparts[1]
62-
mkeMeta.InstalledBootstrapImage = fmt.Sprintf("%s:/ucp:%s", repo, vparts[1])
58+
mkeMeta.InstalledVersion = tag
59+
mkeMeta.InstalledBootstrapImage = fmt.Sprintf("%s:/ucp:%s", repo, tag)
6360

6461
// Find out calico data plane by inspecting the calico container's env variables
6562
cmd := swarmLeader.Configurer.DockerCommandf(`ps --filter label=name="Calico node" --format {{.ID}}`)

0 commit comments

Comments
 (0)