mirror of
https://github.com/crazy-max/diun.git
synced 2025-04-17 16:32:35 +00:00
Handle digest based image reference (#335)
Co-authored-by: CrazyMax <crazy-max@users.noreply.github.com>
This commit is contained in:
parent
b7d9265df4
commit
9b4e62474b
5 changed files with 160 additions and 37 deletions
|
@ -6,12 +6,10 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/crazy-max/diun/v4/internal/model"
|
"github.com/crazy-max/diun/v4/internal/model"
|
||||||
"github.com/rs/zerolog/log"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// ValidateContainerImage returns a standard image through Docker labels
|
// ValidateImage returns a standard image through Docker labels
|
||||||
func ValidateContainerImage(image string, labels map[string]string, watchByDef bool) (img model.Image, err error) {
|
func ValidateImage(image string, labels map[string]string, watchByDef bool) (img model.Image, err error) {
|
||||||
log.Debug().Msgf("Validating %s", image)
|
|
||||||
if i := strings.Index(image, "@sha256:"); i > 0 {
|
if i := strings.Index(image, "@sha256:"); i > 0 {
|
||||||
image = image[:i]
|
image = image[:i]
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,28 +36,73 @@ func (c *Client) listContainerImage() []model.Image {
|
||||||
|
|
||||||
var list []model.Image
|
var list []model.Image
|
||||||
for _, ctn := range ctns {
|
for _, ctn := range ctns {
|
||||||
imageRaw, err := cli.RawImage(ctn.Image)
|
imageName := ctn.Image
|
||||||
|
imageRaw, err := cli.ImageInspectWithRaw(imageName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.logger.Error().Err(err).Msgf("Cannot inspect image from container %s", ctn.ID)
|
c.logger.Error().Err(err).
|
||||||
continue
|
Str("ctn_id", ctn.ID).
|
||||||
}
|
Str("ctn_image", imageName).
|
||||||
if local := cli.IsLocalImage(imageRaw); local {
|
Msg("Cannot inspect image")
|
||||||
c.logger.Debug().Msgf("Skip locally built image from container %s", ctn.ID)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if dangling := cli.IsDanglingImage(imageRaw); dangling {
|
|
||||||
c.logger.Debug().Msgf("Skip dangling image from container %s", ctn.ID)
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
image, err := provider.ValidateContainerImage(ctn.Image, ctn.Labels, *c.config.WatchByDefault)
|
if local := cli.IsLocalImage(imageRaw); local {
|
||||||
if err != nil {
|
c.logger.Debug().
|
||||||
c.logger.Error().Err(err).Msgf("Cannot get image from container %s", ctn.ID)
|
Str("ctn_id", ctn.ID).
|
||||||
continue
|
Str("ctn_image", imageName).
|
||||||
} else if reflect.DeepEqual(image, model.Image{}) {
|
Msg("Skip locally built image")
|
||||||
c.logger.Debug().Msgf("Watch disabled for container %s", ctn.ID)
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if dangling := cli.IsDanglingImage(imageRaw); dangling {
|
||||||
|
c.logger.Debug().
|
||||||
|
Str("ctn_id", ctn.ID).
|
||||||
|
Str("ctn_image", imageName).
|
||||||
|
Msg("Skip dangling image")
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if cli.IsDigest(imageName) {
|
||||||
|
if len(imageRaw.RepoDigests) > 0 {
|
||||||
|
c.logger.Debug().
|
||||||
|
Str("ctn_id", ctn.ID).
|
||||||
|
Str("ctn_image", imageName).
|
||||||
|
Strs("img_repodigests", imageRaw.RepoDigests).
|
||||||
|
Msg("Using first image repo digest available as image name")
|
||||||
|
imageName = imageRaw.RepoDigests[0]
|
||||||
|
} else {
|
||||||
|
c.logger.Debug().
|
||||||
|
Str("ctn_id", ctn.ID).
|
||||||
|
Str("ctn_image", imageName).
|
||||||
|
Strs("img_repodigests", imageRaw.RepoDigests).
|
||||||
|
Msg("Skip unknown image digest ref")
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
c.logger.Debug().
|
||||||
|
Str("ctn_id", ctn.ID).
|
||||||
|
Str("ctn_image", imageName).
|
||||||
|
Interface("ctn_labels", ctn.Labels).
|
||||||
|
Msg("Validate image")
|
||||||
|
image, err := provider.ValidateImage(imageName, ctn.Labels, *c.config.WatchByDefault)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
c.logger.Error().Err(err).
|
||||||
|
Str("ctn_id", ctn.ID).
|
||||||
|
Str("ctn_image", imageName).
|
||||||
|
Interface("ctn_labels", ctn.Labels).
|
||||||
|
Msg("Invalid image")
|
||||||
|
continue
|
||||||
|
} else if reflect.DeepEqual(image, model.Image{}) {
|
||||||
|
c.logger.Debug().
|
||||||
|
Str("ctn_id", ctn.ID).
|
||||||
|
Str("ctn_image", imageName).
|
||||||
|
Interface("ctn_labels", ctn.Labels).
|
||||||
|
Msg("Watch disabled")
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
list = append(list, image)
|
list = append(list, image)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -32,14 +32,32 @@ func (c *Client) listPodImage() []model.Image {
|
||||||
var list []model.Image
|
var list []model.Image
|
||||||
for _, pod := range pods {
|
for _, pod := range pods {
|
||||||
for _, ctn := range pod.Spec.Containers {
|
for _, ctn := range pod.Spec.Containers {
|
||||||
image, err := provider.ValidateContainerImage(ctn.Image, pod.Annotations, *c.config.WatchByDefault)
|
c.logger.Debug().
|
||||||
|
Str("pod_name", pod.Name).
|
||||||
|
Interface("pod_annot", pod.Annotations).
|
||||||
|
Str("ctn_name", ctn.Name).
|
||||||
|
Str("ctn_image", ctn.Image).
|
||||||
|
Msg("Validate image")
|
||||||
|
|
||||||
|
image, err := provider.ValidateImage(ctn.Image, pod.Annotations, *c.config.WatchByDefault)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.logger.Error().Err(err).Msgf("Cannot get image from container %s (pod %s)", ctn.Name, pod.Name)
|
c.logger.Error().Err(err).
|
||||||
|
Str("pod_name", pod.Name).
|
||||||
|
Interface("pod_annot", pod.Annotations).
|
||||||
|
Str("ctn_name", ctn.Name).
|
||||||
|
Str("ctn_image", ctn.Image).
|
||||||
|
Msg("Invalid image")
|
||||||
continue
|
continue
|
||||||
} else if reflect.DeepEqual(image, model.Image{}) {
|
} else if reflect.DeepEqual(image, model.Image{}) {
|
||||||
c.logger.Debug().Msgf("Watch disabled for container %s (pod %s)", ctn.Name, pod.Name)
|
c.logger.Debug().
|
||||||
|
Str("pod_name", pod.Name).
|
||||||
|
Interface("pod_annot", pod.Annotations).
|
||||||
|
Str("ctn_name", ctn.Name).
|
||||||
|
Str("ctn_image", ctn.Image).
|
||||||
|
Msg("Watch disabled")
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
list = append(list, image)
|
list = append(list, image)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,25 +29,73 @@ func (c *Client) listServiceImage() []model.Image {
|
||||||
|
|
||||||
var list []model.Image
|
var list []model.Image
|
||||||
for _, svc := range svcs {
|
for _, svc := range svcs {
|
||||||
if imageRaw, err := cli.RawImage(svc.Spec.TaskTemplate.ContainerSpec.Image); err == nil {
|
imageName := svc.Spec.TaskTemplate.ContainerSpec.Image
|
||||||
if local := cli.IsLocalImage(imageRaw); local {
|
imageRaw, err := cli.ImageInspectWithRaw(svc.Spec.TaskTemplate.ContainerSpec.Image)
|
||||||
c.logger.Debug().Msgf("Skip locally built image for service %s", svc.Spec.Name)
|
if err != nil {
|
||||||
continue
|
c.logger.Error().Err(err).
|
||||||
}
|
Str("svc_name", svc.Spec.Name).
|
||||||
if dangling := cli.IsDanglingImage(imageRaw); dangling {
|
Str("ctn_image", imageName).
|
||||||
c.logger.Debug().Msgf("Skip dangling image for service %s", svc.Spec.Name)
|
Msg("Cannot inspect image")
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if local := cli.IsLocalImage(imageRaw); local {
|
||||||
|
c.logger.Debug().
|
||||||
|
Str("svc_name", svc.Spec.Name).
|
||||||
|
Str("ctn_image", imageName).
|
||||||
|
Msg("Skip locally built image")
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if dangling := cli.IsDanglingImage(imageRaw); dangling {
|
||||||
|
c.logger.Debug().
|
||||||
|
Str("svc_name", svc.Spec.Name).
|
||||||
|
Str("ctn_image", imageName).
|
||||||
|
Msg("Skip dangling image")
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if cli.IsDigest(imageName) {
|
||||||
|
if len(imageRaw.RepoDigests) > 0 {
|
||||||
|
c.logger.Debug().
|
||||||
|
Str("svc_name", svc.Spec.Name).
|
||||||
|
Str("ctn_image", imageName).
|
||||||
|
Strs("img_repodigests", imageRaw.RepoDigests).
|
||||||
|
Msg("Using first image repo digest available as image name")
|
||||||
|
imageName = imageRaw.RepoDigests[0]
|
||||||
|
} else {
|
||||||
|
c.logger.Debug().
|
||||||
|
Str("svc_name", svc.Spec.Name).
|
||||||
|
Str("ctn_image", imageName).
|
||||||
|
Strs("img_repodigests", imageRaw.RepoDigests).
|
||||||
|
Msg("Skip unknown image digest ref")
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
image, err := provider.ValidateContainerImage(svc.Spec.TaskTemplate.ContainerSpec.Image, svc.Spec.Labels, *c.config.WatchByDefault)
|
c.logger.Debug().
|
||||||
|
Str("svc_name", svc.Spec.Name).
|
||||||
|
Interface("svc_labels", svc.Spec.Labels).
|
||||||
|
Str("ctn_image", imageName).
|
||||||
|
Msg("Validate image")
|
||||||
|
|
||||||
|
image, err := provider.ValidateImage(imageName, svc.Spec.Labels, *c.config.WatchByDefault)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.logger.Error().Err(err).Msgf("Cannot get image from service %s", svc.Spec.Name)
|
c.logger.Error().Err(err).
|
||||||
|
Str("svc_name", svc.Spec.Name).
|
||||||
|
Interface("svc_labels", svc.Spec.Labels).
|
||||||
|
Str("ctn_image", svc.Spec.TaskTemplate.ContainerSpec.Image).
|
||||||
|
Msg("Invalid image")
|
||||||
continue
|
continue
|
||||||
} else if reflect.DeepEqual(image, model.Image{}) {
|
} else if reflect.DeepEqual(image, model.Image{}) {
|
||||||
c.logger.Debug().Msgf("Watch disabled for service %s", svc.Spec.Name)
|
c.logger.Debug().
|
||||||
|
Str("svc_name", svc.Spec.Name).
|
||||||
|
Interface("svc_labels", svc.Spec.Labels).
|
||||||
|
Str("ctn_image", svc.Spec.TaskTemplate.ContainerSpec.Image).
|
||||||
|
Msg("Watch disabled")
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
list = append(list, image)
|
list = append(list, image)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,24 @@
|
||||||
package docker
|
package docker
|
||||||
|
|
||||||
import "github.com/docker/docker/api/types"
|
import (
|
||||||
|
"regexp"
|
||||||
|
|
||||||
// RawImage returns the image information and its raw representation
|
"github.com/docker/docker/api/types"
|
||||||
func (c *Client) RawImage(image string) (types.ImageInspect, error) {
|
)
|
||||||
imageRaw, _, err := c.API.ImageInspectWithRaw(c.ctx, image)
|
|
||||||
|
// ContainerInspect returns the container information.
|
||||||
|
func (c *Client) ContainerInspect(containerID string) (types.ContainerJSON, error) {
|
||||||
|
return c.API.ContainerInspect(c.ctx, containerID)
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsDigest determines image it looks like a digest based image reference.
|
||||||
|
func (c *Client) IsDigest(imageID string) bool {
|
||||||
|
return regexp.MustCompile(`^(@|sha256:|@sha256:)([0-9a-f]{64})$`).MatchString(imageID)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ImageInspectWithRaw returns the image information and its raw representation.
|
||||||
|
func (c *Client) ImageInspectWithRaw(imageID string) (types.ImageInspect, error) {
|
||||||
|
imageRaw, _, err := c.API.ImageInspectWithRaw(c.ctx, imageID)
|
||||||
return imageRaw, err
|
return imageRaw, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue