Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
* Bumped version to 1.5.6

* Container/Compose stale status
  • Loading branch information
salilponde committed Dec 30, 2023
1 parent fc3c003 commit cff76a2
Show file tree
Hide file tree
Showing 16 changed files with 498 additions and 17 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ on:
branches: ["main"]

env:
VERSION: "1.5.5"
VERSION: "1.5.6"

jobs:
docker:
Expand Down
15 changes: 15 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -19,35 +19,50 @@ require (
)

require (
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect
github.com/Microsoft/go-winio v0.6.1 // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/daaku/go.zipexe v1.0.2 // indirect
github.com/distribution/reference v0.5.0 // indirect
github.com/docker/distribution v2.8.3+incompatible // indirect
github.com/docker/go-connections v0.4.0 // indirect
github.com/docker/go-metrics v0.0.1 // indirect
github.com/docker/go-units v0.5.0 // indirect
github.com/docker/libtrust v0.0.0-20160708172513-aabc10ec26b7 // indirect
github.com/dustin/go-humanize v1.0.1 // indirect
github.com/gabriel-vasile/mimetype v1.4.2 // indirect
github.com/glebarez/go-sqlite v1.21.2 // indirect
github.com/go-playground/locales v0.14.1 // indirect
github.com/go-playground/universal-translator v0.18.1 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang-jwt/jwt v3.2.2+incompatible // indirect
github.com/golang/protobuf v1.3.2 // indirect
github.com/google/go-querystring v1.1.0 // indirect
github.com/gorilla/mux v1.8.1 // indirect
github.com/heroku/docker-registry-client v0.0.0-20211012143308-9463674c8930 // indirect
github.com/jellydator/ttlcache/v3 v3.1.1 // indirect
github.com/jinzhu/inflection v1.0.0 // indirect
github.com/jinzhu/now v1.1.5 // indirect
github.com/leodido/go-urn v1.2.4 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect
github.com/moby/term v0.5.0 // indirect
github.com/morikuni/aec v1.0.0 // indirect
github.com/opencontainers/go-digest v1.0.0 // indirect
github.com/opencontainers/image-spec v1.0.2 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/prometheus/client_golang v1.1.0 // indirect
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90 // indirect
github.com/prometheus/common v0.6.0 // indirect
github.com/prometheus/procfs v0.0.3 // indirect
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
github.com/sirupsen/logrus v1.9.0 // indirect
github.com/valyala/bytebufferpool v1.0.0 // indirect
github.com/valyala/fasttemplate v1.2.2 // indirect
golang.org/x/mod v0.8.0 // indirect
golang.org/x/net v0.17.0 // indirect
golang.org/x/sync v0.1.0 // indirect
golang.org/x/sys v0.15.0 // indirect
golang.org/x/text v0.14.0 // indirect
golang.org/x/time v0.3.0 // indirect
Expand Down
199 changes: 199 additions & 0 deletions go.sum

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions pkg/agent/agent.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"time"

"github.com/productiveops/dokemon/pkg/common"
"github.com/productiveops/dokemon/pkg/dockerapi"
"github.com/productiveops/dokemon/pkg/messages"

"github.com/gorilla/websocket"
Expand All @@ -25,6 +26,7 @@ var (
func Main() {
parseArgs()
setLogLevel(logLevel)
go dockerapi.ContainerScheduleRefreshStaleStatus()
listen()
}

Expand Down
2 changes: 1 addition & 1 deletion pkg/common/common.go
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
package common

const Version = "1.5.5"
const Version = "1.5.6"
59 changes: 57 additions & 2 deletions pkg/dockerapi/compose.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,39 @@ import (
"github.com/rs/zerolog/log"
)

func composeGetStaleStatus(projectName string) string {
l, err := ComposeContainerList(&DockerComposeContainerList{ProjectName: projectName})
if err != nil {
log.Error().Err(err).Msg("Error while calling ComposeContainerList")
return StaleStatusError
}

anyError := false
anyProcessing := false

for _, item := range l.Items {
if item.Stale == StaleStatusYes {
return StaleStatusYes
}
if item.Stale == StaleStatusError {
anyError = true
}
if item.Stale == StaleStatusProcessing {
anyProcessing = true
}
}

if anyError {
return StaleStatusError
}

if anyProcessing {
return StaleStatusProcessing
}

return StaleStatusNo
}

func ComposeList(req *DockerComposeList) (*DockerComposeListResponse, error) {
cmd := exec.Command("docker-compose", "ls", "-a", "--format=json")
var outb bytes.Buffer
Expand All @@ -38,7 +71,12 @@ func ComposeList(req *DockerComposeList) (*DockerComposeListResponse, error) {

items := make([]ComposeItem, len(itemsInternal))
for i, itemInternal := range itemsInternal {
items[i] = ComposeItem(itemInternal)
items[i] = ComposeItem{
Name: itemInternal.Name,
Status: itemInternal.Status,
ConfigFiles: itemInternal.ConfigFiles,
Stale: composeGetStaleStatus(itemInternal.Name),
}
}

return &DockerComposeListResponse{Items: items}, nil
Expand Down Expand Up @@ -81,7 +119,20 @@ func ComposeContainerList(req *DockerComposeContainerList) (*DockerComposeContai
if err != nil {
return nil, err
}
items = append(items, ComposeContainer(item))
stale, ok := containerStaleStatus[item.Id]
if !ok {
stale = StaleStatusProcessing
}
items = append(items, ComposeContainer{
Id: item.Id,
Name: item.Name,
Image: item.Image,
Service: item.Service,
Status: item.Status,
State: item.State,
Ports: item.Ports,
Stale: stale,
})
}

sort.Slice(items, func(i, j int) bool {
Expand Down Expand Up @@ -262,6 +313,10 @@ func performComposeAction(action string, projectName string, definition string,
log.Error().Err(err).Msg(fmt.Sprintf("Error executing compose %s", action))
}

if action == "up" {
go ContainerRefreshStaleStatus()
}

return nil
}

Expand Down
6 changes: 6 additions & 0 deletions pkg/dockerapi/container.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,13 +33,19 @@ func ContainerList(req *DockerContainerList) (*DockerContainerListResponse, erro
}

image := strings.Split(c.Image, "@")[0]
stale, ok := containerStaleStatus[c.ID]
if !ok {
stale = StaleStatusProcessing
}

containers[i] = Container{
Id: c.ID,
Name: c.Names[0][1:],
Image: image,
Status: c.Status,
State: c.State,
Ports: ports,
Stale: stale,
}
}

Expand Down
121 changes: 121 additions & 0 deletions pkg/dockerapi/container_stale_check.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
package dockerapi

import (
"context"
"fmt"
"strings"
"time"

"github.com/docker/docker/api/types"
"github.com/docker/docker/client"
"github.com/heroku/docker-registry-client/registry"
"github.com/rs/zerolog/log"
)

var containerStaleStatus map[string]string
const (
StaleStatusProcessing = "processing"
StaleStatusYes = "yes"
StaleStatusNo = "no"
StaleStatusError = "error"
)

func isContainerImageStale(imageAndTag string, imageId string, cli *client.Client) (bool, error) {
parts := strings.Split(imageAndTag, ":")
image := parts[0]
tag := "latest"
if len(parts) == 2 {
tag = parts[1]
}

registryName := "docker.io"
imageWithoutRegistryName := image
registryNameIncluded := strings.Count(image, "/") == 2
if registryNameIncluded {
registryName, imageWithoutRegistryName, _ = strings.Cut(image, "/")
}

latestDigest := ""
registryUrl := fmt.Sprintf("https://%s/", registryName)
if registryName == "docker.io" {
registryUrl = "https://registry-1.docker.io/"
}

reg, err := registry.New(registryUrl, "", "") // TODO: Credentials for private repos
if err != nil {
return false, err
}
if !strings.Contains(imageWithoutRegistryName, "/") {
imageWithoutRegistryName = fmt.Sprintf("library/%s", imageWithoutRegistryName)
}

digest, err := reg.ManifestDigest(imageWithoutRegistryName, tag)
if err != nil {
return false, err
}

latestDigest = digest.String()
imageInspect, _, err := cli.ImageInspectWithRaw(context.Background(), imageId)
if err != nil {
return false, err
}

currentDigest := imageInspect.RepoDigests[0]
if strings.Contains(currentDigest, "@") {
currentDigest = strings.Split(currentDigest, "@")[1]
}

isStale := currentDigest != latestDigest
return isStale, nil
}

func ContainerScheduleRefreshStaleStatus() {
for {
log.Info().Msg("Refreshing container stale status")
ContainerRefreshStaleStatus()
time.Sleep(1 * time.Hour)
}
}

func ContainerRefreshStaleStatus() error {
if containerStaleStatus == nil {
containerStaleStatus = make(map[string]string)
}

cli, err := client.NewClientWithOpts(client.FromEnv, client.WithAPIVersionNegotiation())
if err != nil {
return err
}

dcontainers, err := cli.ContainerList(context.Background(), types.ContainerListOptions{All: true})
if err != nil {
return err
}

for _, c := range dcontainers {
_, ok := containerStaleStatus[c.ID]
if !ok {
containerStaleStatus[c.ID] = StaleStatusProcessing
}
}

for _, c := range dcontainers {
image := strings.Split(c.Image, "@")[0]
stale := StaleStatusProcessing
isStale, err := isContainerImageStale(image, c.ImageID, cli)
if err != nil {
stale = StaleStatusError
log.Error().Err(err).Str("containerId", c.ID).Str("image", image).Msg("Error while checking if container is stale")
} else {
if isStale {
stale = StaleStatusYes
} else {
stale = StaleStatusNo
}
}
containerStaleStatus[c.ID] = stale
containerStaleStatus[c.ID[:12]] = stale // docker compose -p PROJECT ps --format json returns 12 chars of ID. So need this.
}

return nil
}
18 changes: 12 additions & 6 deletions pkg/dockerapi/models.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,14 @@ type Port struct {
Type string `json:"type"`
}


type Container struct {
Id string `json:"id"`
Name string `json:"name"`
Id string `json:"id"`
Name string `json:"name"`
Image string `json:"image"`
Status string `json:"status"`
State string `json:"state"`
Ports []Port `json:"ports"`
Status string `json:"status"`
State string `json:"state"`
Ports []Port `json:"ports"`
Stale string `json:"stale"` // yes, no, error, processing
}

type DockerContainerList struct {
Expand Down Expand Up @@ -165,6 +165,7 @@ type ComposeItem struct {
Name string `json:"name"`
Status string `json:"status"`
ConfigFiles string `json:"configFiles"`
Stale string `json:"stale"`
}

type DockerComposeListResponse struct {
Expand All @@ -176,19 +177,24 @@ type DockerComposeContainerList struct {
}

type ComposeContainerInternal struct {
Id string `json:"ID"`
Name string `json:"Name"`
Image string `json:"Image"`
Service string `json:"Service"`
Status string `json:"Status"`
State string `json:"State"`
Ports string `json:"Ports"`
}

type ComposeContainer struct {
Id string `json:"id"`
Name string `json:"name"`
Image string `json:"image"`
Service string `json:"service"`
Status string `json:"status"`
State string `json:"state"`
Ports string `json:"ports"`
Stale string `json:"stale"`
}

type DockerComposeContainerListResponse struct {
Expand Down
Loading

0 comments on commit cff76a2

Please sign in to comment.