refactor: don't reinvent the wheel
This commit is contained in:
@ -2,19 +2,19 @@ package deploy
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"regexp"
|
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
appPkg "coopcloud.tech/abra/pkg/app"
|
appPkg "coopcloud.tech/abra/pkg/app"
|
||||||
"coopcloud.tech/abra/pkg/client"
|
"coopcloud.tech/abra/pkg/client"
|
||||||
"coopcloud.tech/abra/pkg/envfile"
|
"coopcloud.tech/abra/pkg/envfile"
|
||||||
|
"coopcloud.tech/abra/pkg/formatter"
|
||||||
"coopcloud.tech/abra/pkg/log"
|
"coopcloud.tech/abra/pkg/log"
|
||||||
"coopcloud.tech/abra/pkg/recipe"
|
"coopcloud.tech/abra/pkg/recipe"
|
||||||
"coopcloud.tech/abra/pkg/secret"
|
"coopcloud.tech/abra/pkg/secret"
|
||||||
|
|
||||||
|
"github.com/distribution/reference"
|
||||||
composetypes "github.com/docker/cli/cli/compose/types"
|
composetypes "github.com/docker/cli/cli/compose/types"
|
||||||
"github.com/docker/docker/api/types/swarm"
|
"github.com/docker/docker/api/types/swarm"
|
||||||
dockerClient "github.com/docker/docker/client"
|
dockerClient "github.com/docker/docker/client"
|
||||||
@ -82,19 +82,6 @@ func GetConfigsForStack(cl *dockerClient.Client, app appPkg.App) (map[string]str
|
|||||||
return configs, nil
|
return configs, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetImageNameAndTag(imageName string) (string, string, error) {
|
|
||||||
imageParts := regexp.MustCompile("^([^:]*):([^@]*)@?").FindSubmatch([]byte(imageName))
|
|
||||||
|
|
||||||
if len(imageParts) == 0 {
|
|
||||||
return "", "", errors.New("can't determine image version for image '%s'")
|
|
||||||
}
|
|
||||||
|
|
||||||
imageBaseName := string(imageParts[1])
|
|
||||||
imageTag := string(imageParts[2])
|
|
||||||
|
|
||||||
return imageBaseName, imageTag, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetImagesForStack retrieves all Docker images for services in a given stack.
|
// GetImagesForStack retrieves all Docker images for services in a given stack.
|
||||||
func GetImagesForStack(cl *dockerClient.Client, app appPkg.App) (map[string]string, error) {
|
func GetImagesForStack(cl *dockerClient.Client, app appPkg.App) (map[string]string, error) {
|
||||||
filters, err := app.Filters(false, false)
|
filters, err := app.Filters(false, false)
|
||||||
@ -116,12 +103,15 @@ func GetImagesForStack(cl *dockerClient.Client, app appPkg.App) (map[string]stri
|
|||||||
if service.Spec.TaskTemplate.ContainerSpec != nil {
|
if service.Spec.TaskTemplate.ContainerSpec != nil {
|
||||||
imageName := service.Spec.TaskTemplate.ContainerSpec.Image
|
imageName := service.Spec.TaskTemplate.ContainerSpec.Image
|
||||||
|
|
||||||
imageBaseName, imageTag, err := GetImageNameAndTag(imageName)
|
imageParsed, err := reference.ParseNormalizedNamed(imageName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Warn(err)
|
log.Warn(err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
imageBaseName := reference.Path(imageParsed)
|
||||||
|
imageTag := imageParsed.(reference.NamedTagged).Tag()
|
||||||
|
|
||||||
existingImageVersion, ok := images[imageBaseName]
|
existingImageVersion, ok := images[imageBaseName]
|
||||||
if !ok {
|
if !ok {
|
||||||
// First time seeing this, add to map
|
// First time seeing this, add to map
|
||||||
@ -210,7 +200,10 @@ func GatherImagesForDeploy(cl *dockerClient.Client, app appPkg.App, compose *com
|
|||||||
newImages := make(map[string]string)
|
newImages := make(map[string]string)
|
||||||
|
|
||||||
for _, service := range compose.Services {
|
for _, service := range compose.Services {
|
||||||
imageBaseName, imageTag, err := GetImageNameAndTag(service.Image)
|
imageParsed, err := reference.ParseNormalizedNamed(service.Image)
|
||||||
|
imageBaseName := reference.Path(imageParsed)
|
||||||
|
imageTag := imageParsed.(reference.NamedTagged).Tag()
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Warn(err)
|
log.Warn(err)
|
||||||
continue
|
continue
|
||||||
@ -233,13 +226,13 @@ func GatherImagesForDeploy(cl *dockerClient.Client, app appPkg.App, compose *com
|
|||||||
if currentVersion, exists := currentImages[newImageName]; exists {
|
if currentVersion, exists := currentImages[newImageName]; exists {
|
||||||
if currentVersion == newImageVersion {
|
if currentVersion == newImageVersion {
|
||||||
if showUnchanged {
|
if showUnchanged {
|
||||||
imageInfo = append(imageInfo, fmt.Sprintf("%s: %s (unchanged)", newImageName, newImageVersion))
|
imageInfo = append(imageInfo, fmt.Sprintf("%s: %s (unchanged)", formatter.StripTagMeta(newImageName), newImageVersion))
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
imageInfo = append(imageInfo, fmt.Sprintf("%s: %s → %s", newImageName, currentVersion, newImageVersion))
|
imageInfo = append(imageInfo, fmt.Sprintf("%s: %s → %s", formatter.StripTagMeta(newImageName), currentVersion, newImageVersion))
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
imageInfo = append(imageInfo, fmt.Sprintf("%s: %s (new)", newImageName, newImageVersion))
|
imageInfo = append(imageInfo, fmt.Sprintf("%s: %s (new)", formatter.StripTagMeta(newImageName), newImageVersion))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,87 +0,0 @@
|
|||||||
package deploy
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestGetImageNameAndTag(t *testing.T) {
|
|
||||||
tests := []struct {
|
|
||||||
name string
|
|
||||||
imageName string
|
|
||||||
expectedName string
|
|
||||||
expectedTag string
|
|
||||||
expectError bool
|
|
||||||
description string
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
name: "standard image with tag",
|
|
||||||
imageName: "nginx:1.23",
|
|
||||||
expectedName: "nginx",
|
|
||||||
expectedTag: "1.23",
|
|
||||||
expectError: false,
|
|
||||||
description: "should parse standard image name with tag",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "image with digest",
|
|
||||||
imageName: "nginx:1.23@sha256:abc123",
|
|
||||||
expectedName: "nginx",
|
|
||||||
expectedTag: "1.23",
|
|
||||||
expectError: false,
|
|
||||||
description: "should parse image with digest, ignoring digest part",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "image with latest tag",
|
|
||||||
imageName: "redis:latest",
|
|
||||||
expectedName: "redis",
|
|
||||||
expectedTag: "latest",
|
|
||||||
expectError: false,
|
|
||||||
description: "should parse image with latest tag",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "image with numeric tag",
|
|
||||||
imageName: "postgres:14",
|
|
||||||
expectedName: "postgres",
|
|
||||||
expectedTag: "14",
|
|
||||||
expectError: false,
|
|
||||||
description: "should parse image with numeric tag",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "image with complex name",
|
|
||||||
imageName: "registry.example.com/myapp/api:v1.2.3",
|
|
||||||
expectedName: "registry.example.com/myapp/api",
|
|
||||||
expectedTag: "v1.2.3",
|
|
||||||
expectError: false,
|
|
||||||
description: "should parse image with registry prefix and complex name",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "image without tag",
|
|
||||||
imageName: "nginx",
|
|
||||||
expectError: true,
|
|
||||||
description: "should error when no tag present",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "empty image name",
|
|
||||||
imageName: "",
|
|
||||||
expectError: true,
|
|
||||||
description: "should error on empty image name",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, tt := range tests {
|
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
|
||||||
name, tag, err := GetImageNameAndTag(tt.imageName)
|
|
||||||
|
|
||||||
if tt.expectError {
|
|
||||||
assert.Error(t, err)
|
|
||||||
assert.Empty(t, name)
|
|
||||||
assert.Empty(t, tag)
|
|
||||||
} else {
|
|
||||||
assert.NoError(t, err)
|
|
||||||
assert.Equal(t, tt.expectedName, name)
|
|
||||||
assert.Equal(t, tt.expectedTag, tag)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
Reference in New Issue
Block a user