From 6bfb8d4a22d2c7e35b4bb04e29edaed4c9837523 Mon Sep 17 00:00:00 2001 From: virtualzone <13085858+virtualzone@users.noreply.github.com> Date: Sat, 23 Apr 2022 14:08:22 +0200 Subject: [PATCH] Refactorings --- src/compose-service.go | 16 ++++--- src/docker-image.go | 5 ++ src/main.go | 9 ++-- src/update-event.go | 55 ++++++++++++++++++++++ src/updater.go | 103 +++++++++++++++++++++-------------------- src/version.go | 2 +- test/c2.yaml | 2 + test/run-test.sh | 33 +++++++------ 8 files changed, 148 insertions(+), 77 deletions(-) create mode 100644 src/update-event.go diff --git a/src/compose-service.go b/src/compose-service.go index a2bc1f4..ac83d2d 100644 --- a/src/compose-service.go +++ b/src/compose-service.go @@ -31,15 +31,19 @@ func (s *ComposeService) Build() bool { return true } -/* +func (s *ComposeService) RequiresBuild() bool { + return len(s.BuildInfo) > 0 +} + +func (s *ComposeService) IsWatched() bool { + return s.Instance != nil +} + +// ATTENTION: docker compose restart does not use an updated image in Docker Compose V2 yet. func (s *ComposeService) Restart() bool { - log.Println("docker", "compose", "-f", s.ComposeFile.YamlFilePath, "up", "-d", "--no-deps", s.Name) - out, err := exec.Command("docker", "compose", "-f", s.ComposeFile.YamlFilePath, "up", "-d", "--no-deps", s.Name).CombinedOutput() + err := exec.Command("docker", "compose", "-f", s.ComposeFile.YamlFilePath, "up", "-d", "--no-deps", s.Name).Run() if err != nil { - log.Println(err) return false } - log.Println("-----> " + string(out)) return true } -*/ diff --git a/src/docker-image.go b/src/docker-image.go index 0a51961..14b498f 100644 --- a/src/docker-image.go +++ b/src/docker-image.go @@ -32,3 +32,8 @@ func (i *DockerImage) ReadImageHash() error { i.Hash = strings.TrimSpace(string(out)) return nil } + +func (i *DockerImage) ExistsNewerImageHash() bool { + newImage := CreateDockerImageInstance(i.ID) + return i.Hash != newImage.Hash +} diff --git a/src/main.go b/src/main.go index e9f3203..b7416e0 100644 --- a/src/main.go +++ b/src/main.go @@ -29,13 +29,9 @@ func printHeader() { } func mainLoop() { + updater := &Updater{} for { - PerformComposeUpdates() - if GlobalSettings.Cleanup { - log.Println("Removing unused images...") - CleanUp() - } - log.Println("Done.") + updater.PerformComposeUpdates() if GlobalSettings.Once { return } @@ -54,6 +50,7 @@ func main() { if GlobalSettings.PrintSettings { GlobalSettings.Print() } + CreateEventBus() initLogger(GlobalSettings.UpdateLog) mainLoop() } diff --git a/src/update-event.go b/src/update-event.go new file mode 100644 index 0000000..ff7c859 --- /dev/null +++ b/src/update-event.go @@ -0,0 +1,55 @@ +package main + +import "log" + +type UpdateEvent struct{} + +var EventBus *UpdateEvent = nil + +func CreateEventBus() { + EventBus = &UpdateEvent{} +} + +func (e *UpdateEvent) OnPerformUpdatesStart() { + log.Println("Gathering details about running containers...") +} + +func (e *UpdateEvent) OnPerformUpdatesComplete() { + log.Println("Done.") +} + +func (e *UpdateEvent) OnProcessComposeFileStart(composeFile *ComposeFile) { + log.Printf("Checking for updates of services in %s...\n", composeFile.YamlFilePath) +} + +func (e *UpdateEvent) OnSkipRestartComposeFileDryMode(composeFile *ComposeFile) { + log.Printf("Dry-Mode enabled, not restarting services in %s\n", composeFile.YamlFilePath) +} + +func (e *UpdateEvent) OnSkipRestartComposeFileNoUpdates(composeFile *ComposeFile) { + log.Printf("No need to restart services in %s\n", composeFile.YamlFilePath) +} + +func (e *UpdateEvent) OnRestartComposeFile(composeFile *ComposeFile) { + log.Printf("Restarting services in %s...\n", composeFile.YamlFilePath) +} + +func (e *UpdateEvent) OnRestartComposeFileComplete(composeFile *ComposeFile) { + log.Printf("Restarted services in %s\n", composeFile.YamlFilePath) +} + +func (e *UpdateEvent) OnProcessServiceStart(service *ComposeService) { + log.Printf("Processing service %s (requires build: %t, watched: %t)...\n", service.Name, service.RequiresBuild(), service.IsWatched()) +} + +func (e *UpdateEvent) OnServiceNewImageBuilt(service *ComposeService) { + log.Printf("Built new image for service %s\n", service.Name) +} + +func (e *UpdateEvent) OnServiceNewImagePulled(service *ComposeService) { + log.Printf("Pulled new image %s for service %s\n", service.ImageName, service.Name) +} + +func (e *UpdateEvent) OnImagePruneStart() { + log.Println("Removing unused images...") +} diff --git a/src/updater.go b/src/updater.go index 78a2439..0cd2d31 100644 --- a/src/updater.go +++ b/src/updater.go @@ -5,58 +5,22 @@ import ( "os/exec" ) -func PerformComposeUpdates() { - log.Println("Gathering details about running containers...") - composeFiles := createComposeFileContainerMapping() +type Updater struct{} + +func (u *Updater) PerformComposeUpdates() { + EventBus.OnPerformUpdatesStart() + composeFiles := u.createComposeFileContainerMapping() for _, composeFile := range composeFiles { - compositionRestart := false - log.Printf("Checking for updates of services in %s...\n", composeFile.YamlFilePath) - for _, service := range composeFile.Services { - if service.Instance == nil { - continue - } - requiresBuild := len(service.BuildInfo) > 0 - log.Printf("Processing service %s (requires build: %t)...\n", service.Name, requiresBuild) - if !requiresBuild { - service.Pull() - } else if GlobalSettings.Build { - service.Build() - } - newImage := CreateDockerImageInstance(service.Instance.Image.ID) - if service.Instance.Image.Hash != newImage.Hash { - if requiresBuild { - log.Printf("Built new image for service %s\n", service.Name) - } else { - log.Printf("Pulled new image %s for service %s\n", service.ImageName, service.Name) - } - /* - Not working with Docker Compose V2 yet - if !GlobalSettings.CompleteStop { - log.Printf("Restarting service %s in %s...\n", service.Name, composeFile.YamlFilePath) - service.Restart() - } else { - compositionRestart = true - } - */ - compositionRestart = true - } - } - if compositionRestart { - if GlobalSettings.Dry { - log.Printf("Dry-Mode enabled, not restarting services in %s\n", composeFile.YamlFilePath) - } else { - log.Printf("Restarting services in %s...\n", composeFile.YamlFilePath) - composeFile.Down() - composeFile.Up() - log.Printf("Restarted services in %s\n", composeFile.YamlFilePath) - } - } else { - log.Printf("No need to restart services in %s\n", composeFile.YamlFilePath) - } + u.processComposeFile(composeFile) } + if GlobalSettings.Cleanup { + u.CleanUp() + } + EventBus.OnPerformUpdatesComplete() } -func CleanUp() bool { +func (u *Updater) CleanUp() bool { + EventBus.OnImagePruneStart() err := exec.Command("docker", "image", "prune", "-a", "-f").Run() if err != nil { return false @@ -64,7 +28,48 @@ func CleanUp() bool { return true } -func createComposeFileContainerMapping() []*ComposeFile { +func (u *Updater) processComposeFile(composeFile *ComposeFile) { + EventBus.OnProcessComposeFileStart(composeFile) + compositionRestart := false + for _, service := range composeFile.Services { + compositionRestart = u.processService(service) || compositionRestart + } + if compositionRestart { + if GlobalSettings.Dry { + EventBus.OnSkipRestartComposeFileDryMode(composeFile) + } else { + EventBus.OnRestartComposeFile(composeFile) + composeFile.Down() + composeFile.Up() + EventBus.OnRestartComposeFileComplete(composeFile) + } + } else { + EventBus.OnSkipRestartComposeFileNoUpdates(composeFile) + } +} + +func (u *Updater) processService(service *ComposeService) bool { + EventBus.OnProcessServiceStart(service) + if !service.IsWatched() { + return false + } + if !service.RequiresBuild() { + service.Pull() + } else if GlobalSettings.Build { + service.Build() + } + if service.Instance.Image.ExistsNewerImageHash() { + if service.RequiresBuild() { + EventBus.OnServiceNewImageBuilt(service) + } else { + EventBus.OnServiceNewImagePulled(service) + } + return true + } + return false +} + +func (u *Updater) createComposeFileContainerMapping() []*ComposeFile { containers := GetWatchedRunningContainers() cache := make(map[string]*ComposeFile) for _, container := range containers { diff --git a/src/version.go b/src/version.go index 63748b2..e8ff6dd 100644 --- a/src/version.go +++ b/src/version.go @@ -1,4 +1,4 @@ package main // BuildVersion is the version -const BuildVersion = "2.0.1" +const BuildVersion = "2.0.2" diff --git a/test/c2.yaml b/test/c2.yaml index ac4d62b..adb2e4a 100644 --- a/test/c2.yaml +++ b/test/c2.yaml @@ -10,3 +10,5 @@ services: labels: - "docker-compose-watcher.watch=1" - "docker-compose-watcher.dir=${PWD}/c2" + test23: + image: nginx:alpine diff --git a/test/run-test.sh b/test/run-test.sh index 50e8b20..a937146 100755 --- a/test/run-test.sh +++ b/test/run-test.sh @@ -56,11 +56,12 @@ function testShouldFindNoUpdates() { runComposeUpdateAndLog checkLogContains "${TESTNAME} / check c1 found" "Checking for updates of services in ${WORKDIR}/c1/compose1.yaml" 1 checkLogContains "${TESTNAME} / check c2 found" "Checking for updates of services in ${WORKDIR}/c2/docker-compose.yml" 1 - checkLogContains "${TESTNAME} / check service test11 found" "Processing service test11" 1 - checkLogContains "${TESTNAME} / check service test12 found" "Processing service test12" 1 - checkLogContains "${TESTNAME} / check service test13 found" "Processing service test13" 1 - checkLogContains "${TESTNAME} / check service test21 found" "Processing service test21" 1 - checkLogContains "${TESTNAME} / check service test22 found" "Processing service test22" 1 + checkLogContains "${TESTNAME} / check service test11 found" "Processing service test11 (requires build: false, watched: true)" 1 + checkLogContains "${TESTNAME} / check service test12 found" "Processing service test12 (requires build: true, watched: true)" 1 + checkLogContains "${TESTNAME} / check service test13 found" "Processing service test13 (requires build: true, watched: true)" 1 + checkLogContains "${TESTNAME} / check service test21 found" "Processing service test21 (requires build: false, watched: true)" 1 + checkLogContains "${TESTNAME} / check service test22 found" "Processing service test22 (requires build: false, watched: true)" 1 + checkLogContains "${TESTNAME} / check service test23 found" "Processing service test23 (requires build: false, watched: false)" 1 checkLogContains "${TESTNAME} / check no pulls" "Pulled new image" 0 checkLogContains "${TESTNAME} / check no builds" "Built new image" 0 checkLogContains "${TESTNAME} / check no service restarts in c1" "Restarting services in ${WORKDIR}/c1/compose1.yaml" 0 @@ -73,11 +74,12 @@ function testShouldFindUpdateC1() { runComposeUpdateAndLog checkLogContains "${TESTNAME} / check c1 found" "Checking for updates of services in ${WORKDIR}/c1/compose1.yaml" 1 checkLogContains "${TESTNAME} / check c2 found" "Checking for updates of services in ${WORKDIR}/c2/docker-compose.yml" 1 - checkLogContains "${TESTNAME} / check service test11 found" "Processing service test11" 1 - checkLogContains "${TESTNAME} / check service test12 found" "Processing service test12" 1 - checkLogContains "${TESTNAME} / check service test13 found" "Processing service test13" 1 - checkLogContains "${TESTNAME} / check service test21 found" "Processing service test21" 1 - checkLogContains "${TESTNAME} / check service test22 found" "Processing service test22" 1 + checkLogContains "${TESTNAME} / check service test11 found" "Processing service test11 (requires build: false, watched: true)" 1 + checkLogContains "${TESTNAME} / check service test12 found" "Processing service test12 (requires build: true, watched: true)" 1 + checkLogContains "${TESTNAME} / check service test13 found" "Processing service test13 (requires build: true, watched: true)" 1 + checkLogContains "${TESTNAME} / check service test21 found" "Processing service test21 (requires build: false, watched: true)" 1 + checkLogContains "${TESTNAME} / check service test22 found" "Processing service test22 (requires build: false, watched: true)" 1 + checkLogContains "${TESTNAME} / check service test23 found" "Processing service test23 (requires build: false, watched: false)" 1 checkLogContains "${TESTNAME} / check one pull" "Pulled new image" 1 checkLogContains "${TESTNAME} / check no builds" "Built new image" 0 checkLogContains "${TESTNAME} / check no service restarts in c1" "Restarting services in ${WORKDIR}/c1/compose1.yaml" 1 @@ -90,11 +92,12 @@ function testShouldFindUpdateC2() { runComposeUpdateAndLog checkLogContains "${TESTNAME} / check c1 found" "Checking for updates of services in ${WORKDIR}/c1/compose1.yaml" 1 checkLogContains "${TESTNAME} / check c2 found" "Checking for updates of services in ${WORKDIR}/c2/docker-compose.yml" 1 - checkLogContains "${TESTNAME} / check service test11 found" "Processing service test11" 1 - checkLogContains "${TESTNAME} / check service test12 found" "Processing service test12" 1 - checkLogContains "${TESTNAME} / check service test13 found" "Processing service test13" 1 - checkLogContains "${TESTNAME} / check service test21 found" "Processing service test21" 1 - checkLogContains "${TESTNAME} / check service test22 found" "Processing service test22" 1 + checkLogContains "${TESTNAME} / check service test11 found" "Processing service test11 (requires build: false, watched: true)" 1 + checkLogContains "${TESTNAME} / check service test12 found" "Processing service test12 (requires build: true, watched: true)" 1 + checkLogContains "${TESTNAME} / check service test13 found" "Processing service test13 (requires build: true, watched: true)" 1 + checkLogContains "${TESTNAME} / check service test21 found" "Processing service test21 (requires build: false, watched: true)" 1 + checkLogContains "${TESTNAME} / check service test22 found" "Processing service test22 (requires build: false, watched: true)" 1 + checkLogContains "${TESTNAME} / check service test23 found" "Processing service test23 (requires build: false, watched: false)" 1 checkLogContains "${TESTNAME} / check one pull" "Pulled new image" 1 checkLogContains "${TESTNAME} / check no builds" "Built new image" 0 checkLogContains "${TESTNAME} / check no service restarts in c1" "Restarting services in ${WORKDIR}/c1/compose1.yaml" 0