Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,6 @@ github-release
vendor

# sometimes an example launchpad.yaml is used
**/launchpad.yaml
**/launchpad.yaml
.gemini/
gha-creds-*.json
32 changes: 32 additions & 0 deletions pkg/docker/image.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package docker

import (
"errors"
"fmt"
"regexp"
"strings"
Expand Down Expand Up @@ -146,3 +147,34 @@ func AllToRepository(images []*Image, repo string) (list []*Image) {
}
return list
}

var errInvalidVersion = errors.New("invalid image version")

// ImageRepoAndTag returns the Repo and tag from a container image.
//
// e.g. `dtr.efzp.com:9026/mirantis/ucp-agent:3.8.10` => `dtr.efzp.com:9026/mirantis/ucp-agent`, `3.8.10`
func ImageRepoAndTag(image string) (string, string, error) {
lastColon := strings.LastIndexByte(image, ':')
lastSlash := strings.LastIndexByte(image, '/')

// If there is no colon, tag is implicitly "latest"
if lastColon == -1 {
return image, "latest", nil
}

// If the last colon is part of the registry host (before the first slash),
// and there are no more colons, then the tag is also implicitly "latest".
// e.g. "localhost:5000/my-image"
if lastColon < lastSlash {
return image, "latest", nil
}

repo := image[:lastColon]
tag := image[lastColon+1:]

if tag == "" {
return "", "", fmt.Errorf("%w: empty tag in version output: %s", errInvalidVersion, image)
}

return repo, tag, nil
}
32 changes: 32 additions & 0 deletions pkg/docker/image_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,3 +69,35 @@ registry.ci.mirantis.com/mirantiseng/ucp-auth-store:3.8.7`
require.Equal(t, "registry.ci.mirantis.com/mirantiseng/ucp-alertmanager:3.8.7", images[1].String())
require.Equal(t, "registry.ci.mirantis.com/mirantiseng/ucp-auth-store:3.8.7", images[2].String())
}

func TestImageVersions(t *testing.T) {
cases := []struct {
input string
expected string
tag string
}{
{"mirantis/ucp-proxy:3.8.8", "mirantis/ucp-proxy", "3.8.8"},
{"dtr.efzp.com:9026/mirantis/ucp-agent:3.8.10", "dtr.efzp.com:9026/mirantis/ucp-agent", "3.8.10"},
{"ucp-proxy:3.8.8", "ucp-proxy", "3.8.8"},
{"docker.io/library/alpine:latest", "docker.io/library/alpine", "latest"},
{"localhost:5000/my-image:1.0.0", "localhost:5000/my-image", "1.0.0"},
{"registry.mirantis.com/mirantiseng/ucp:3.9.0-rc2", "registry.mirantis.com/mirantiseng/ucp", "3.9.0-rc2"},
{"registry.ci.mirantis.com/mirantiseng/ecp", "registry.ci.mirantis.com/mirantiseng/ecp", "latest"},
{"localhost:5000/my-image", "localhost:5000/my-image", "latest"},
{"my-complex-repo:5000/org/image:v1", "my-complex-repo:5000/org/image", "v1"},
}

for _, tc := range cases {
repo, tag, err := docker.ImageRepoAndTag(tc.input)
require.Nil(t, err, "ImageRepoAndTag gave unexpected error from valid version string: %s", tc.input)
require.Equal(t, tc.expected, repo, "ImageRepoAndTag gave wrong repo value for: %s", tc.input)
require.Equal(t, tc.tag, tag, "ImageRepoAndTag gave wrong tag value for: %s", tc.input)
}
}

func TestImageVersionsWithColon(t *testing.T) {
repo, tag, err := docker.ImageRepoAndTag("dtr.efzp.com:9026/mirantis/ucp-agent:3.8.10")
require.Nil(t, err, "SwarmMKEVersion gave unexpected error from valid version string")
require.Equal(t, "dtr.efzp.com:9026/mirantis/ucp-agent", repo, "SwarmMKEVersion gave wrong repo value")
require.Equal(t, "3.8.10", tag, "SwarmMKEVersion gave wrong repo value")
}
15 changes: 6 additions & 9 deletions pkg/mke/mke.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (
"time"

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

var errInvalidVersion = errors.New("invalid version")

// CollectFacts gathers the current status of installed mke setup.
func CollectFacts(swarmLeader *mkeconfig.Host, mkeMeta *mkeconfig.MKEMetadata) error {
output, err := swarmLeader.ExecOutput(swarmLeader.Configurer.DockerCommandf(`inspect --format '{{.Config.Image}}' ucp-proxy`))
Expand All @@ -51,15 +50,13 @@ func CollectFacts(swarmLeader *mkeconfig.Host, mkeMeta *mkeconfig.MKEMetadata) e
return nil
}

vparts := strings.Split(output, ":")
if len(vparts) != 2 {
return fmt.Errorf("%w: malformed version output: %s", errInvalidVersion, output)
repo, tag, verr := docker.ImageRepoAndTag(output)
if verr != nil {
return fmt.Errorf("%w: malformed version output: %s", verr, output)
}
repo := vparts[0][:strings.LastIndexByte(vparts[0], '/')]

mkeMeta.Installed = true
mkeMeta.InstalledVersion = vparts[1]
mkeMeta.InstalledBootstrapImage = fmt.Sprintf("%s:/ucp:%s", repo, vparts[1])
mkeMeta.InstalledVersion = tag
mkeMeta.InstalledBootstrapImage = fmt.Sprintf("%s:/ucp:%s", repo, tag)

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