mirror of
https://github.com/containrrr/watchtower.git
synced 2026-02-26 17:04:08 +01:00
Merge 4b494ded86 into c16ac967c5
This commit is contained in:
commit
beba45c17b
40 changed files with 3951 additions and 33 deletions
|
|
@ -30,18 +30,19 @@ type Client interface {
|
|||
StopContainer(Container, time.Duration) error
|
||||
StartContainer(Container) (t.ContainerID, error)
|
||||
RenameContainer(Container, string) error
|
||||
IsContainerStale(Container) (stale bool, latestImage t.ImageID, err error)
|
||||
IsContainerStale(Container) (stale bool, latestImage t.ImageID, created string, err error)
|
||||
ExecuteCommand(containerID t.ContainerID, command string, timeout int) (SkipUpdate bool, err error)
|
||||
RemoveImageByID(t.ImageID) error
|
||||
WarnOnHeadPullFailed(container Container) bool
|
||||
ContainerDigestMatchesWithRegistry(container Container) (matches bool, err error)
|
||||
}
|
||||
|
||||
// NewClient returns a new Client instance which can be used to interact with
|
||||
// the Docker API.
|
||||
// The client reads its configuration from the following environment variables:
|
||||
// * DOCKER_HOST the docker-engine host to send api requests to
|
||||
// * DOCKER_TLS_VERIFY whether to verify tls certificates
|
||||
// * DOCKER_API_VERSION the minimum docker api version to work with
|
||||
// - DOCKER_HOST the docker-engine host to send api requests to
|
||||
// - DOCKER_TLS_VERIFY whether to verify tls certificates
|
||||
// - DOCKER_API_VERSION the minimum docker api version to work with
|
||||
func NewClient(opts ClientOptions) Client {
|
||||
cli, err := sdkClient.NewClientWithOpts(sdkClient.FromEnv)
|
||||
|
||||
|
|
@ -277,35 +278,35 @@ func (client dockerClient) RenameContainer(c Container, newName string) error {
|
|||
return client.api.ContainerRename(bg, string(c.ID()), newName)
|
||||
}
|
||||
|
||||
func (client dockerClient) IsContainerStale(container Container) (stale bool, latestImage t.ImageID, err error) {
|
||||
func (client dockerClient) IsContainerStale(container Container) (stale bool, latestImage t.ImageID, created string, err error) {
|
||||
ctx := context.Background()
|
||||
|
||||
if !client.PullImages {
|
||||
log.Debugf("Skipping image pull.")
|
||||
} else if err := client.PullImage(ctx, container); err != nil {
|
||||
return false, container.SafeImageID(), err
|
||||
return false, container.SafeImageID(), "", err
|
||||
}
|
||||
|
||||
return client.HasNewImage(ctx, container)
|
||||
}
|
||||
|
||||
func (client dockerClient) HasNewImage(ctx context.Context, container Container) (hasNew bool, latestImage t.ImageID, err error) {
|
||||
func (client dockerClient) HasNewImage(ctx context.Context, container Container) (hasNew bool, latestImage t.ImageID, created string, err error) {
|
||||
currentImageID := t.ImageID(container.containerInfo.ContainerJSONBase.Image)
|
||||
imageName := container.ImageName()
|
||||
|
||||
newImageInfo, _, err := client.api.ImageInspectWithRaw(ctx, imageName)
|
||||
if err != nil {
|
||||
return false, currentImageID, err
|
||||
return false, currentImageID, "", err
|
||||
}
|
||||
|
||||
newImageID := t.ImageID(newImageInfo.ID)
|
||||
if newImageID == currentImageID {
|
||||
log.Debugf("No new images found for %s", container.Name())
|
||||
return false, currentImageID, nil
|
||||
return false, currentImageID, "", nil
|
||||
}
|
||||
|
||||
log.Infof("Found new %s image (%s)", imageName, newImageID.ShortID())
|
||||
return true, newImageID, nil
|
||||
return true, newImageID, newImageInfo.Created, nil
|
||||
}
|
||||
|
||||
// PullImage pulls the latest image for the supplied container, optionally skipping if it's digest can be confirmed
|
||||
|
|
@ -335,21 +336,13 @@ func (client dockerClient) PullImage(ctx context.Context, container Container) e
|
|||
|
||||
log.WithFields(fields).Debugf("Checking if pull is needed")
|
||||
|
||||
if match, err := digest.CompareDigest(container, opts.RegistryAuth); err != nil {
|
||||
headLevel := log.DebugLevel
|
||||
if client.WarnOnHeadPullFailed(container) {
|
||||
headLevel = log.WarnLevel
|
||||
}
|
||||
log.WithFields(fields).Logf(headLevel, "Could not do a head request for %q, falling back to regular pull.", imageName)
|
||||
log.WithFields(fields).Log(headLevel, "Reason: ", err)
|
||||
} else if match {
|
||||
matches, err := client.digestMatchesWithRegistry(ctx, container, opts.RegistryAuth)
|
||||
if matches == true {
|
||||
log.Debug("No pull needed. Skipping image.")
|
||||
return nil
|
||||
} else {
|
||||
log.Debug("Digests did not match, doing a pull.")
|
||||
}
|
||||
|
||||
log.WithFields(fields).Debugf("Pulling image")
|
||||
log.WithFields(fields).Debugf("Digests did not match, pulling image")
|
||||
|
||||
response, err := client.api.ImagePull(ctx, imageName, opts)
|
||||
if err != nil {
|
||||
|
|
@ -366,6 +359,40 @@ func (client dockerClient) PullImage(ctx context.Context, container Container) e
|
|||
return nil
|
||||
}
|
||||
|
||||
func (client dockerClient) ContainerDigestMatchesWithRegistry(container Container) (matches bool, err error) {
|
||||
ctx := context.Background()
|
||||
imageName := container.ImageName()
|
||||
opts, err := registry.GetPullOptions(imageName)
|
||||
if err != nil {
|
||||
log.Debugf("Error loading authentication credentials %s", err)
|
||||
return false, err
|
||||
}
|
||||
|
||||
return client.digestMatchesWithRegistry(ctx, container, opts.RegistryAuth)
|
||||
}
|
||||
|
||||
func (client dockerClient) digestMatchesWithRegistry(ctx context.Context, container Container, registryAuth string) (matches bool, err error) {
|
||||
containerName := container.Name()
|
||||
imageName := container.ImageName()
|
||||
fields := log.Fields{
|
||||
"image": imageName,
|
||||
"container": containerName,
|
||||
}
|
||||
|
||||
match, err := digest.CompareDigest(container, registryAuth)
|
||||
if err != nil {
|
||||
headLevel := log.DebugLevel
|
||||
if client.WarnOnHeadPullFailed(container) {
|
||||
headLevel = log.WarnLevel
|
||||
}
|
||||
log.WithFields(fields).Logf(headLevel, "Could not do a head request for %q, falling back to regular pull.", imageName)
|
||||
log.WithFields(fields).Log(headLevel, "Reason: ", err)
|
||||
return false, err
|
||||
}
|
||||
|
||||
return match, nil
|
||||
}
|
||||
|
||||
func (client dockerClient) RemoveImageByID(id t.ImageID) error {
|
||||
log.Infof("Removing image %s", id.ShortID())
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue