Session report collection and report templates (#981)

* wip: notification stats

* make report notifications optional

* linting/documentation fixes

* linting/documentation fixes

* merge types.Container and container.Interface

* smaller naming/format fixes

* use typed image/container IDs

* simplify notifier and update tests

* add missed doc comments

* lint fixes

* remove unused constructors

* rename old/new current/latest
This commit is contained in:
nils måsén 2021-06-27 09:05:01 +02:00 committed by GitHub
parent d0ecc23d72
commit e3dd8d688a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
32 changed files with 853 additions and 598 deletions

View file

@ -26,13 +26,13 @@ const defaultStopSignal = "SIGTERM"
// Docker API.
type Client interface {
ListContainers(t.Filter) ([]Container, error)
GetContainer(containerID string) (Container, error)
GetContainer(containerID t.ContainerID) (Container, error)
StopContainer(Container, time.Duration) error
StartContainer(Container) (string, error)
StartContainer(Container) (t.ContainerID, error)
RenameContainer(Container, string) error
IsContainerStale(Container) (bool, error)
ExecuteCommand(containerID string, command string, timeout int) (SkipUpdate bool, err error)
RemoveImageByID(string) error
IsContainerStale(Container) (stale bool, latestImage t.ImageID, err error)
ExecuteCommand(containerID t.ContainerID, command string, timeout int) (SkipUpdate bool, err error)
RemoveImageByID(t.ImageID) error
WarnOnHeadPullFailed(container Container) bool
}
@ -108,7 +108,7 @@ func (client dockerClient) ListContainers(fn t.Filter) ([]Container, error) {
for _, runningContainer := range containers {
c, err := client.GetContainer(runningContainer.ID)
c, err := client.GetContainer(t.ContainerID(runningContainer.ID))
if err != nil {
return nil, err
}
@ -137,10 +137,10 @@ func (client dockerClient) createListFilter() filters.Args {
return filterArgs
}
func (client dockerClient) GetContainer(containerID string) (Container, error) {
func (client dockerClient) GetContainer(containerID t.ContainerID) (Container, error) {
bg := context.Background()
containerInfo, err := client.api.ContainerInspect(bg, containerID)
containerInfo, err := client.api.ContainerInspect(bg, string(containerID))
if err != nil {
return Container{}, err
}
@ -161,11 +161,12 @@ func (client dockerClient) StopContainer(c Container, timeout time.Duration) err
signal = defaultStopSignal
}
shortID := ShortID(c.ID())
idStr := string(c.ID())
shortID := c.ID().ShortID()
if c.IsRunning() {
log.Infof("Stopping %s (%s) with %s", c.Name(), shortID, signal)
if err := client.api.ContainerKill(bg, c.ID(), signal); err != nil {
if err := client.api.ContainerKill(bg, idStr, signal); err != nil {
return err
}
}
@ -178,7 +179,7 @@ func (client dockerClient) StopContainer(c Container, timeout time.Duration) err
} else {
log.Debugf("Removing container %s", shortID)
if err := client.api.ContainerRemove(bg, c.ID(), types.ContainerRemoveOptions{Force: true, RemoveVolumes: client.removeVolumes}); err != nil {
if err := client.api.ContainerRemove(bg, idStr, types.ContainerRemoveOptions{Force: true, RemoveVolumes: client.removeVolumes}); err != nil {
return err
}
}
@ -191,7 +192,7 @@ func (client dockerClient) StopContainer(c Container, timeout time.Duration) err
return nil
}
func (client dockerClient) StartContainer(c Container) (string, error) {
func (client dockerClient) StartContainer(c Container) (t.ContainerID, error) {
bg := context.Background()
config := c.runtimeConfig()
hostConfig := c.hostConfig()
@ -234,18 +235,19 @@ func (client dockerClient) StartContainer(c Container) (string, error) {
}
createdContainerID := t.ContainerID(createdContainer.ID)
if !c.IsRunning() && !client.reviveStopped {
return createdContainer.ID, nil
return createdContainerID, nil
}
return createdContainer.ID, client.doStartContainer(bg, c, createdContainer)
return createdContainerID, client.doStartContainer(bg, c, createdContainer)
}
func (client dockerClient) doStartContainer(bg context.Context, c Container, creation container.ContainerCreateCreatedBody) error {
name := c.Name()
log.Debugf("Starting container %s (%s)", name, ShortID(creation.ID))
log.Debugf("Starting container %s (%s)", name, t.ContainerID(creation.ID).ShortID())
err := client.api.ContainerStart(bg, creation.ID, types.ContainerStartOptions{})
if err != nil {
return err
@ -255,38 +257,39 @@ func (client dockerClient) doStartContainer(bg context.Context, c Container, cre
func (client dockerClient) RenameContainer(c Container, newName string) error {
bg := context.Background()
log.Debugf("Renaming container %s (%s) to %s", c.Name(), ShortID(c.ID()), newName)
return client.api.ContainerRename(bg, c.ID(), newName)
log.Debugf("Renaming container %s (%s) to %s", c.Name(), c.ID().ShortID(), newName)
return client.api.ContainerRename(bg, string(c.ID()), newName)
}
func (client dockerClient) IsContainerStale(container Container) (bool, error) {
func (client dockerClient) IsContainerStale(container Container) (stale bool, latestImage t.ImageID, err error) {
ctx := context.Background()
if !client.pullImages {
log.Debugf("Skipping image pull.")
} else if err := client.PullImage(ctx, container); err != nil {
return false, err
return false, container.SafeImageID(), err
}
return client.HasNewImage(ctx, container)
}
func (client dockerClient) HasNewImage(ctx context.Context, container Container) (bool, error) {
oldImageID := container.containerInfo.ContainerJSONBase.Image
func (client dockerClient) HasNewImage(ctx context.Context, container Container) (hasNew bool, latestImage t.ImageID, err error) {
currentImageID := t.ImageID(container.containerInfo.ContainerJSONBase.Image)
imageName := container.ImageName()
newImageInfo, _, err := client.api.ImageInspectWithRaw(ctx, imageName)
if err != nil {
return false, err
return false, currentImageID, err
}
if newImageInfo.ID == oldImageID {
newImageID := t.ImageID(newImageInfo.ID)
if newImageID == currentImageID {
log.Debugf("No new images found for %s", container.Name())
return false, nil
return false, currentImageID, nil
}
log.Infof("Found new %s image (%s)", imageName, ShortID(newImageInfo.ID))
return true, nil
log.Infof("Found new %s image (%s)", imageName, newImageID.ShortID())
return true, newImageID, nil
}
// PullImage pulls the latest image for the supplied container, optionally skipping if it's digest can be confirmed
@ -343,12 +346,12 @@ func (client dockerClient) PullImage(ctx context.Context, container Container) e
return nil
}
func (client dockerClient) RemoveImageByID(id string) error {
log.Infof("Removing image %s", ShortID(id))
func (client dockerClient) RemoveImageByID(id t.ImageID) error {
log.Infof("Removing image %s", id.ShortID())
_, err := client.api.ImageRemove(
context.Background(),
id,
string(id),
types.ImageRemoveOptions{
Force: true,
})
@ -356,7 +359,7 @@ func (client dockerClient) RemoveImageByID(id string) error {
return err
}
func (client dockerClient) ExecuteCommand(containerID string, command string, timeout int) (SkipUpdate bool, err error) {
func (client dockerClient) ExecuteCommand(containerID t.ContainerID, command string, timeout int) (SkipUpdate bool, err error) {
bg := context.Background()
// Create the exec
@ -366,7 +369,7 @@ func (client dockerClient) ExecuteCommand(containerID string, command string, ti
Cmd: []string{"sh", "-c", command},
}
exec, err := client.api.ContainerExecCreate(bg, containerID, execConfig)
exec, err := client.api.ContainerExecCreate(bg, string(containerID), execConfig)
if err != nil {
return false, err
}
@ -462,7 +465,7 @@ func (client dockerClient) waitForStopOrTimeout(c Container, waitTime time.Durat
case <-timeout:
return nil
default:
if ci, err := client.api.ContainerInspect(bg, c.ID()); err != nil {
if ci, err := client.api.ContainerInspect(bg, string(c.ID())); err != nil {
return err
} else if !ci.State.Running {
return nil