diff --git a/packages/kn-plugin-workflow/go.mod b/packages/kn-plugin-workflow/go.mod index bc294a6fadd..6e22d50b284 100644 --- a/packages/kn-plugin-workflow/go.mod +++ b/packages/kn-plugin-workflow/go.mod @@ -12,6 +12,7 @@ require ( github.com/apache/incubator-kie-tools/packages/sonataflow-operator/api v0.0.0 github.com/apache/incubator-kie-tools/packages/sonataflow-operator/workflowproj v0.0.0 github.com/beevik/etree v1.2.0 + github.com/docker/distribution v2.8.2+incompatible github.com/docker/docker v24.0.9+incompatible github.com/docker/go-connections v0.4.0 github.com/jstemmer/go-junit-report/v2 v2.0.0 @@ -31,7 +32,6 @@ require ( github.com/cespare/xxhash/v2 v2.2.0 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/dgraph-io/ristretto v0.1.1 // indirect - github.com/docker/distribution v2.8.2+incompatible // indirect github.com/docker/go-units v0.5.0 // indirect github.com/dprotaso/go-yit v0.0.0-20220510233725-9ba8df137936 // indirect github.com/dustin/go-humanize v1.0.1 // indirect diff --git a/packages/kn-plugin-workflow/pkg/common/containers.go b/packages/kn-plugin-workflow/pkg/common/containers.go index af06f6a68a9..50d27052afc 100644 --- a/packages/kn-plugin-workflow/pkg/common/containers.go +++ b/packages/kn-plugin-workflow/pkg/common/containers.go @@ -24,6 +24,7 @@ import ( "encoding/json" "errors" "fmt" + "github.com/docker/distribution/reference" "io" "os" "os/exec" @@ -35,7 +36,6 @@ import ( "github.com/apache/incubator-kie-tools/packages/kn-plugin-workflow/pkg/metadata" "github.com/docker/docker/api/types" "github.com/docker/docker/api/types/container" - "github.com/docker/docker/api/types/filters" "github.com/docker/docker/client" "github.com/docker/docker/pkg/stdcopy" "github.com/docker/go-connections/nat" @@ -51,6 +51,10 @@ type DockerLogMessage struct { ID string `json:"id,omitempty"` } +type DockerClient interface { + ImageList(ctx context.Context, options types.ImageListOptions) ([]types.ImageSummary, error) +} + func getDockerClient() (*client.Client, error) { cli, err := client.NewClientWithOpts(client.FromEnv, client.WithAPIVersionNegotiation()) if err != nil { @@ -203,16 +207,13 @@ func pullDockerImage(cli *client.Client, ctx context.Context) (io.ReadCloser, er // For that we should check only the image name and tag, removing the registry, // as `docker image ls --filter reference=` will return empty if the image_full_url is not the first tag // of an image. - imageNameWithoutRegistry := strings.Split(metadata.DevModeImage, "/") - imageFilters := filters.NewArgs() - imageFilters.Add("reference", fmt.Sprintf("*/%s", imageNameWithoutRegistry[len(imageNameWithoutRegistry)-1])) - images, err := cli.ImageList(ctx, types.ImageListOptions{Filters: imageFilters}) + exists, err := CheckImageExists(cli, ctx, metadata.DevModeImage) if err != nil { return nil, fmt.Errorf("error listing images: %s", err) } // If the image is not found locally, pull it from the remote registry - if len(images) == 0 { + if !exists { reader, err := cli.ImagePull(ctx, metadata.DevModeImage, types.ImagePullOptions{}) if err != nil { return nil, fmt.Errorf("\nError pulling image: %s. Error is: %s", metadata.DevModeImage, err) @@ -223,6 +224,29 @@ func pullDockerImage(cli *client.Client, ctx context.Context) (io.ReadCloser, er return nil, nil } +func CheckImageExists(cli DockerClient, ctx context.Context, imageName string) (bool, error) { + named, err := reference.ParseNormalizedNamed(imageName) + + if tagged, ok := named.(reference.Tagged); ok { + imageName = fmt.Sprintf("%s:%s", reference.Path(named), tagged.Tag()) + } else { + imageName = fmt.Sprintf("%s:%s", reference.Path(named), "latest") + } + images, err := cli.ImageList(ctx, types.ImageListOptions{All: true}) + if err != nil { + return false, fmt.Errorf("error listing images: %s", err) + } + + for _, image := range images { + for _, tag := range image.RepoTags { + if strings.HasSuffix(tag, imageName) { + return true, nil + } + } + } + return false, nil +} + func processDockerImagePullLogs(reader io.ReadCloser) error { for { err := waitToImageBeReady(reader)