Extract function to match digests, use for update check instead of pulling new images

This commit is contained in:
Anders Roos 2022-11-27 18:25:44 +01:00
parent cdde01709c
commit 4b494ded86
2 changed files with 58 additions and 19 deletions

View file

@ -63,20 +63,32 @@ func (handle *Handler) HandlePost(w http.ResponseWriter, r *http.Request) {
return return
} }
stale, newestImage, created, err := client.IsContainerStale(container) hasUpdate := false
newVersion := ""
newVersionCreated := ""
matches, err := client.ContainerDigestMatchesWithRegistry(container)
hasUpdate = !matches
if err != nil { if err != nil {
log.Error(err) stale, newestImage, created, err := client.IsContainerStale(container)
w.WriteHeader(http.StatusInternalServerError) hasUpdate = stale
w.Write([]byte(err.Error())) newVersion = newestImage.ShortID()
return newVersionCreated = created
if err != nil {
log.Error(err)
w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte(err.Error()))
return
}
} }
data := checkResponse{ data := checkResponse{
ContainerID: request.ContainerID, ContainerID: request.ContainerID,
HasUpdate: stale, HasUpdate: hasUpdate,
NewVersion: newestImage.ShortID(), NewVersion: newVersion,
NewVersionCreated: created, NewVersionCreated: newVersionCreated,
} }
jsonData, err := json.Marshal(data) jsonData, err := json.Marshal(data)

View file

@ -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 Container) bool WarnOnHeadPullFailed(container Container) bool
ContainerDigestMatchesWithRegistry(container Container) (matches bool, err 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
@ -331,21 +332,13 @@ func (client dockerClient) PullImage(ctx context.Context, container Container) e
log.WithFields(fields).Debugf("Checking if pull is needed") log.WithFields(fields).Debugf("Checking if pull is needed")
if match, err := digest.CompareDigest(container, opts.RegistryAuth); err != nil { matches, err := client.digestMatchesWithRegistry(ctx, container, opts.RegistryAuth)
headLevel := log.DebugLevel if matches == true {
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 {
log.Debug("No pull needed. Skipping image.") log.Debug("No pull needed. Skipping image.")
return nil 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) response, err := client.api.ImagePull(ctx, imageName, opts)
if err != nil { if err != nil {
@ -362,6 +355,40 @@ func (client dockerClient) PullImage(ctx context.Context, container Container) e
return nil 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 { func (client dockerClient) RemoveImageByID(id t.ImageID) error {
log.Infof("Removing image %s", id.ShortID()) log.Infof("Removing image %s", id.ShortID())