mirror of
https://github.com/containrrr/watchtower.git
synced 2025-12-16 07:00:13 +01:00
add support for opencontainers meta labels
This commit is contained in:
parent
9f60766692
commit
77a46ab3bd
8 changed files with 125 additions and 5 deletions
|
|
@ -5,6 +5,8 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
dockerTypes "github.com/docker/docker/api/types"
|
||||||
|
|
||||||
t "github.com/containrrr/watchtower/pkg/types"
|
t "github.com/containrrr/watchtower/pkg/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -66,6 +68,11 @@ func (client MockClient) RemoveImageByID(_ t.ImageID) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetImage is a mock method
|
||||||
|
func (client MockClient) GetImage(_ t.ImageID) (dockerTypes.ImageInspect, error) {
|
||||||
|
return dockerTypes.ImageInspect{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
// GetContainer is a mock method
|
// GetContainer is a mock method
|
||||||
func (client MockClient) GetContainer(_ t.ContainerID) (t.Container, error) {
|
func (client MockClient) GetContainer(_ t.ContainerID) (t.Container, error) {
|
||||||
return client.TestData.Containers[0], nil
|
return client.TestData.Containers[0], nil
|
||||||
|
|
|
||||||
|
|
@ -33,7 +33,7 @@ func Update(client container.Client, params types.UpdateParams) (types.Report, e
|
||||||
staleCheckFailed := 0
|
staleCheckFailed := 0
|
||||||
|
|
||||||
for i, targetContainer := range containers {
|
for i, targetContainer := range containers {
|
||||||
stale, newestImage, err := client.IsContainerStale(targetContainer)
|
stale, newestImageID, err := client.IsContainerStale(targetContainer)
|
||||||
shouldUpdate := stale && !params.NoRestart && !params.MonitorOnly && !targetContainer.IsMonitorOnly()
|
shouldUpdate := stale && !params.NoRestart && !params.MonitorOnly && !targetContainer.IsMonitorOnly()
|
||||||
if err == nil && shouldUpdate {
|
if err == nil && shouldUpdate {
|
||||||
// Check to make sure we have all the necessary information for recreating the container
|
// Check to make sure we have all the necessary information for recreating the container
|
||||||
|
|
@ -55,12 +55,15 @@ func Update(client container.Client, params types.UpdateParams) (types.Report, e
|
||||||
staleCheckFailed++
|
staleCheckFailed++
|
||||||
progress.AddSkipped(targetContainer, err)
|
progress.AddSkipped(targetContainer, err)
|
||||||
} else {
|
} else {
|
||||||
progress.AddScanned(targetContainer, newestImage)
|
progress.AddScanned(targetContainer, newestImageID)
|
||||||
}
|
}
|
||||||
containers[i].SetStale(stale)
|
containers[i].SetStale(stale)
|
||||||
|
|
||||||
if stale {
|
if stale {
|
||||||
staleCount++
|
staleCount++
|
||||||
|
if latestImage, err := client.GetImage(newestImageID); err == nil {
|
||||||
|
progress.UpdateLatestImage(targetContainer.ID(), latestImage)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -34,6 +34,7 @@ type Client interface {
|
||||||
ExecuteCommand(containerID t.ContainerID, command string, timeout int) (SkipUpdate bool, err error)
|
ExecuteCommand(containerID t.ContainerID, command string, timeout int) (SkipUpdate bool, err error)
|
||||||
RemoveImageByID(t.ImageID) error
|
RemoveImageByID(t.ImageID) error
|
||||||
WarnOnHeadPullFailed(container t.Container) bool
|
WarnOnHeadPullFailed(container t.Container) bool
|
||||||
|
GetImage(imageID t.ImageID) (types.ImageInspect, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewClient returns a new Client instance which can be used to interact with
|
// NewClient returns a new Client instance which can be used to interact with
|
||||||
|
|
@ -397,6 +398,14 @@ func (client dockerClient) PullImage(ctx context.Context, container t.Container)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (client dockerClient) GetImage(id t.ImageID) (types.ImageInspect, error) {
|
||||||
|
imageInfo, _, err := client.api.ImageInspectWithRaw(context.Background(), string(id))
|
||||||
|
if err != nil {
|
||||||
|
return types.ImageInspect{}, err
|
||||||
|
}
|
||||||
|
return imageInfo, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (client dockerClient) RemoveImageByID(id t.ImageID) error {
|
func (client dockerClient) RemoveImageByID(id t.ImageID) error {
|
||||||
log.Infof("Removing image %s", id.ShortID())
|
log.Infof("Removing image %s", id.ShortID())
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,8 @@ type ContainerStatus struct {
|
||||||
imageName string
|
imageName string
|
||||||
error
|
error
|
||||||
state State
|
state State
|
||||||
|
beforeMeta imageMeta
|
||||||
|
afterMeta imageMeta
|
||||||
}
|
}
|
||||||
|
|
||||||
// ID returns the container ID
|
// ID returns the container ID
|
||||||
|
|
@ -80,3 +82,13 @@ func (u *ContainerStatus) State() string {
|
||||||
return "Unknown"
|
return "Unknown"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Before returns the metadata for the image considered latest before the session
|
||||||
|
func (u *ContainerStatus) Before() wt.ImageMeta {
|
||||||
|
return u.beforeMeta
|
||||||
|
}
|
||||||
|
|
||||||
|
// After returns the metadata for the image considered latest after the session
|
||||||
|
func (u *ContainerStatus) After() wt.ImageMeta {
|
||||||
|
return u.afterMeta
|
||||||
|
}
|
||||||
|
|
|
||||||
55
pkg/session/image_meta.go
Normal file
55
pkg/session/image_meta.go
Normal file
|
|
@ -0,0 +1,55 @@
|
||||||
|
package session
|
||||||
|
|
||||||
|
import "strings"
|
||||||
|
|
||||||
|
type imageMeta map[string]string
|
||||||
|
|
||||||
|
func imageMetaFromLabels(labels map[string]string) imageMeta {
|
||||||
|
im := make(imageMeta)
|
||||||
|
for key, value := range labels {
|
||||||
|
if suffix, found := strings.CutPrefix(key, "org.opencontainers.image."); found {
|
||||||
|
im[suffix] = value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return im
|
||||||
|
}
|
||||||
|
|
||||||
|
func (im imageMeta) Authors() string {
|
||||||
|
return im["authors"]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (im imageMeta) Created() string {
|
||||||
|
return im["created"]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (im imageMeta) Description() string {
|
||||||
|
return im["description"]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (im imageMeta) Documentation() string {
|
||||||
|
return im["documentation"]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (im imageMeta) Licenses() string {
|
||||||
|
return im["licenses"]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (im imageMeta) Revision() string {
|
||||||
|
return im["revision"]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (im imageMeta) Source() string {
|
||||||
|
return im["source"]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (im imageMeta) Title() string {
|
||||||
|
return im["title"]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (im imageMeta) Url() string {
|
||||||
|
return im["url"]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (im imageMeta) Version() string {
|
||||||
|
return im["version"]
|
||||||
|
}
|
||||||
|
|
@ -2,6 +2,7 @@ package session
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/containrrr/watchtower/pkg/types"
|
"github.com/containrrr/watchtower/pkg/types"
|
||||||
|
dockerTypes "github.com/docker/docker/api/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Progress contains the current session container status
|
// Progress contains the current session container status
|
||||||
|
|
@ -9,6 +10,14 @@ type Progress map[types.ContainerID]*ContainerStatus
|
||||||
|
|
||||||
// UpdateFromContainer sets various status fields from their corresponding container equivalents
|
// UpdateFromContainer sets various status fields from their corresponding container equivalents
|
||||||
func UpdateFromContainer(cont types.Container, newImage types.ImageID, state State) *ContainerStatus {
|
func UpdateFromContainer(cont types.Container, newImage types.ImageID, state State) *ContainerStatus {
|
||||||
|
|
||||||
|
var beforeMeta imageMeta
|
||||||
|
if imageInfo := cont.ImageInfo(); imageInfo != nil && imageInfo.Config != nil {
|
||||||
|
beforeMeta = imageMetaFromLabels(imageInfo.Config.Labels)
|
||||||
|
} else {
|
||||||
|
beforeMeta = make(imageMeta)
|
||||||
|
}
|
||||||
|
|
||||||
return &ContainerStatus{
|
return &ContainerStatus{
|
||||||
containerID: cont.ID(),
|
containerID: cont.ID(),
|
||||||
containerName: cont.Name(),
|
containerName: cont.Name(),
|
||||||
|
|
@ -16,6 +25,8 @@ func UpdateFromContainer(cont types.Container, newImage types.ImageID, state Sta
|
||||||
oldImage: cont.SafeImageID(),
|
oldImage: cont.SafeImageID(),
|
||||||
newImage: newImage,
|
newImage: newImage,
|
||||||
state: state,
|
state: state,
|
||||||
|
beforeMeta: beforeMeta,
|
||||||
|
afterMeta: beforeMeta,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -27,8 +38,9 @@ func (m Progress) AddSkipped(cont types.Container, err error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddScanned adds a container to the Progress with the state set as scanned
|
// AddScanned adds a container to the Progress with the state set as scanned
|
||||||
func (m Progress) AddScanned(cont types.Container, newImage types.ImageID) {
|
func (m Progress) AddScanned(cont types.Container, newImageID types.ImageID) {
|
||||||
m.Add(UpdateFromContainer(cont, newImage, ScannedState))
|
m.Add(UpdateFromContainer(cont, newImageID, ScannedState))
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdateFailed updates the containers passed, setting their state as failed with the supplied error
|
// UpdateFailed updates the containers passed, setting their state as failed with the supplied error
|
||||||
|
|
@ -54,3 +66,9 @@ func (m Progress) MarkForUpdate(containerID types.ContainerID) {
|
||||||
func (m Progress) Report() types.Report {
|
func (m Progress) Report() types.Report {
|
||||||
return NewReport(m)
|
return NewReport(m)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m Progress) UpdateLatestImage(containerID types.ContainerID, image dockerTypes.ImageInspect) {
|
||||||
|
if image.Config != nil {
|
||||||
|
m[containerID].afterMeta = imageMetaFromLabels(image.Config.Labels)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
14
pkg/types/image_meta.go
Normal file
14
pkg/types/image_meta.go
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
package types
|
||||||
|
|
||||||
|
type ImageMeta interface {
|
||||||
|
Authors() string
|
||||||
|
Created() string
|
||||||
|
Description() string
|
||||||
|
Documentation() string
|
||||||
|
Licenses() string
|
||||||
|
Revision() string
|
||||||
|
Source() string
|
||||||
|
Title() string
|
||||||
|
Url() string
|
||||||
|
Version() string
|
||||||
|
}
|
||||||
|
|
@ -20,4 +20,6 @@ type ContainerReport interface {
|
||||||
ImageName() string
|
ImageName() string
|
||||||
Error() string
|
Error() string
|
||||||
State() string
|
State() string
|
||||||
|
Before() ImageMeta
|
||||||
|
After() ImageMeta
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue