From b6cf0ac410d7c61d667b6043ef04f3e6426ac081 Mon Sep 17 00:00:00 2001 From: Krzysztof Taraszka Date: Mon, 12 Feb 2024 14:29:34 +0100 Subject: [PATCH 01/14] add latest tag to every latest image dokku push --- plugins/registry/functions.go | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/plugins/registry/functions.go b/plugins/registry/functions.go index d5cd64c1d..9da8c1d1b 100644 --- a/plugins/registry/functions.go +++ b/plugins/registry/functions.go @@ -88,6 +88,7 @@ func pushToRegistry(appName string, tag int, imageID string, imageRepo string) e imageTag, _ := common.GetRunningImageTag(appName, "") fullImage := fmt.Sprintf("%s%s:%d", registryServer, imageRepo, tag) + latestImage := fmt.Sprintf("%s%s:latest", registryServer, imageRepo) common.LogVerboseQuiet(fmt.Sprintf("Tagging %s:%d in registry format", imageRepo, tag)) if !dockerTag(imageID, fullImage) { @@ -100,9 +101,11 @@ func pushToRegistry(appName string, tag int, imageID string, imageRepo string) e return errors.New("Unable to tag image") } - // For the future, we should also add the ability to create the remote repository - // This is only really important for registries that do not support creation on push - // Examples include AWS and Quay.io + // Tagging the image as latest + common.LogVerboseQuiet(fmt.Sprintf("Tagging %s as latest in registry format", imageRepo)) + if !dockerTag(imageID, latestImage) { + return errors.New("Unable to tag image as latest") + } common.LogVerboseQuiet(fmt.Sprintf("Pushing %s", fullImage)) if !dockerPush(fullImage) { @@ -110,6 +113,12 @@ func pushToRegistry(appName string, tag int, imageID string, imageRepo string) e return errors.New("Unable to push image") } + // Pushing the latest tag + common.LogVerboseQuiet(fmt.Sprintf("Pushing %s", latestImage)) + if !dockerPush(latestImage) { + return errors.New("Unable to push image with latest tag") + } + // Only clean up when the scheduler is not docker-local // other schedulers do not retire local images if common.GetAppScheduler(appName) != "docker-local" { From c8897f42e47a37f429bb0ad8fa21b6448c2aa1ce Mon Sep 17 00:00:00 2001 From: Krzysztof Taraszka Date: Wed, 14 Feb 2024 18:27:42 +0100 Subject: [PATCH 02/14] jq is missing in current bento Ubuntu image --- Vagrantfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Vagrantfile b/Vagrantfile index 3cd1c44d7..eb55a3787 100644 --- a/Vagrantfile +++ b/Vagrantfile @@ -53,7 +53,7 @@ Vagrant::configure("2") do |config| vb.customize ["modifyvm", :id, "--cableconnected1", "on"] end - vm.vm.provision :shell, :inline => "export DEBIAN_FRONTEND=noninteractive && apt-get update -qq >/dev/null && apt-get -qq -y --no-install-recommends install git build-essential >/dev/null && cd /root/dokku && #{make_cmd}" + vm.vm.provision :shell, :inline => "export DEBIAN_FRONTEND=noninteractive && apt-get update -qq >/dev/null && apt-get -qq -y --no-install-recommends install git build-essential jq >/dev/null && cd /root/dokku && #{make_cmd}" vm.vm.provision :shell do |s| s.inline = <<-EOT echo '"\e[5~": history-search-backward' > /root/.inputrc From dff13a8f1b33e88e6e015db739b8ceccac77d338 Mon Sep 17 00:00:00 2001 From: Krzysztof Taraszka Date: Wed, 14 Feb 2024 18:29:49 +0100 Subject: [PATCH 03/14] push based on push-extra-tags list of tags --- plugins/registry/functions.go | 34 +++++++++++++++++++++++----------- plugins/registry/registry.go | 2 ++ plugins/registry/report.go | 5 +++++ 3 files changed, 30 insertions(+), 11 deletions(-) diff --git a/plugins/registry/functions.go b/plugins/registry/functions.go index 9da8c1d1b..c88639edf 100644 --- a/plugins/registry/functions.go +++ b/plugins/registry/functions.go @@ -81,6 +81,15 @@ func incrementTagVersion(appName string) (int, error) { return version, nil } +func getRegistryPushExtraTagsForApp(appName string) string { + value := common.PropertyGet("registry", appName, "push-extra-tags") + common.LogVerboseQuiet(fmt.Sprintf("VALUE IS: %s", value)) + if value == "" { + value = common.PropertyGet("registry", "--global", "push-extra-tags") + } + return value +} + func pushToRegistry(appName string, tag int, imageID string, imageRepo string) error { common.LogVerboseQuiet("Retrieving image info for app") @@ -88,7 +97,6 @@ func pushToRegistry(appName string, tag int, imageID string, imageRepo string) e imageTag, _ := common.GetRunningImageTag(appName, "") fullImage := fmt.Sprintf("%s%s:%d", registryServer, imageRepo, tag) - latestImage := fmt.Sprintf("%s%s:latest", registryServer, imageRepo) common.LogVerboseQuiet(fmt.Sprintf("Tagging %s:%d in registry format", imageRepo, tag)) if !dockerTag(imageID, fullImage) { @@ -101,10 +109,20 @@ func pushToRegistry(appName string, tag int, imageID string, imageRepo string) e return errors.New("Unable to tag image") } - // Tagging the image as latest - common.LogVerboseQuiet(fmt.Sprintf("Tagging %s as latest in registry format", imageRepo)) - if !dockerTag(imageID, latestImage) { - return errors.New("Unable to tag image as latest") + extraTags := getRegistryPushExtraTagsForApp(appName) + if extraTags != "" { + extraTagsArray := strings.Split(extraTags, ",") + for _, extraTag := range extraTagsArray { + extraTagImage := fmt.Sprintf("%s%s:%s", registryServer, imageRepo, extraTag) + common.LogVerboseQuiet(fmt.Sprintf("Tagging %s as %s in registry format", imageRepo, extraTag)) + if !dockerTag(imageID, extraTagImage) { + return errors.New(fmt.Sprintf("Unable to tag image as %s", extraTag)) + } + common.LogVerboseQuiet(fmt.Sprintf("Pushing %s", extraTagImage)) + if !dockerPush(extraTagImage) { + return errors.New(fmt.Sprintf("Unable to push image with %s tag", tag)) + } + } } common.LogVerboseQuiet(fmt.Sprintf("Pushing %s", fullImage)) @@ -113,12 +131,6 @@ func pushToRegistry(appName string, tag int, imageID string, imageRepo string) e return errors.New("Unable to push image") } - // Pushing the latest tag - common.LogVerboseQuiet(fmt.Sprintf("Pushing %s", latestImage)) - if !dockerPush(latestImage) { - return errors.New("Unable to push image with latest tag") - } - // Only clean up when the scheduler is not docker-local // other schedulers do not retire local images if common.GetAppScheduler(appName) != "docker-local" { diff --git a/plugins/registry/registry.go b/plugins/registry/registry.go index abea76773..420960bd3 100644 --- a/plugins/registry/registry.go +++ b/plugins/registry/registry.go @@ -6,6 +6,7 @@ var ( "image-repo": "", "push-on-release": "false", "server": "", + "push-extra-tags": "", } // GlobalProperties is a map of all valid global registry properties @@ -13,5 +14,6 @@ var ( "image-repo-template": true, "push-on-release": true, "server": true, + "push-extra-tags": true, } ) diff --git a/plugins/registry/report.go b/plugins/registry/report.go index 710719f32..9d1fe3251 100644 --- a/plugins/registry/report.go +++ b/plugins/registry/report.go @@ -23,6 +23,7 @@ func ReportSingleApp(appName string, format string, infoFlag string) error { "--registry-global-image-repo-template": reportGlobalImageRepoTemplate, "--registry-server": reportServer, "--registry-tag-version": reportTagVersion, + "--registry-push-extra-tags": reportPushExtraTags, } flagKeys := []string{} @@ -96,3 +97,7 @@ func reportTagVersion(appName string) string { tagVersion := common.PropertyGet("registry", appName, "tag-version") return strings.TrimSpace(tagVersion) } + +func reportPushExtraTags(appName string) string { + return common.PropertyGet("registry", appName, "push-extra-tags") +} From 881d16ea90d3b42b87bad19fcb991a662c9d7556 Mon Sep 17 00:00:00 2001 From: Krzysztof Taraszka Date: Sun, 25 Feb 2024 15:23:27 +0100 Subject: [PATCH 04/14] Untag extra image tag --- plugins/registry/functions.go | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/plugins/registry/functions.go b/plugins/registry/functions.go index c88639edf..c63e54362 100644 --- a/plugins/registry/functions.go +++ b/plugins/registry/functions.go @@ -120,7 +120,11 @@ func pushToRegistry(appName string, tag int, imageID string, imageRepo string) e } common.LogVerboseQuiet(fmt.Sprintf("Pushing %s", extraTagImage)) if !dockerPush(extraTagImage) { - return errors.New(fmt.Sprintf("Unable to push image with %s tag", tag)) + return errors.New(fmt.Sprintf("Unable to push image with %s tag", extraTag)) + } + common.LogVerboseQuiet(fmt.Sprintf("Untagging extra tag %s", extraTag)) + if !dockerRemoveTag(extraTagImage) { + return errors.New(fmt.Sprintf("Unable to untag extra tag %s", extraTag)) } } } @@ -156,6 +160,17 @@ func dockerTag(imageID string, imageTag string) bool { return true } +func dockerRemoveTag(image string) bool { + cmd := sh.Command(common.DockerBin(), "image", "remove", image) + cmd.Stdout = nil + cmd.Stderr = nil + if err := cmd.Run(); err != nil { + return false + } + + return true +} + func dockerPush(imageTag string) bool { cmd := sh.Command(common.DockerBin(), "image", "push", imageTag) cmd.Stdout = os.Stdout From 2ad1572080b54c83859322ecc2a43f864ded19b2 Mon Sep 17 00:00:00 2001 From: Krzysztof Taraszka Date: Sun, 25 Feb 2024 16:26:24 +0100 Subject: [PATCH 05/14] whops, remove my DEBUG print --- plugins/registry/functions.go | 1 - 1 file changed, 1 deletion(-) diff --git a/plugins/registry/functions.go b/plugins/registry/functions.go index c63e54362..708b71894 100644 --- a/plugins/registry/functions.go +++ b/plugins/registry/functions.go @@ -83,7 +83,6 @@ func incrementTagVersion(appName string) (int, error) { func getRegistryPushExtraTagsForApp(appName string) string { value := common.PropertyGet("registry", appName, "push-extra-tags") - common.LogVerboseQuiet(fmt.Sprintf("VALUE IS: %s", value)) if value == "" { value = common.PropertyGet("registry", "--global", "push-extra-tags") } From 23a27d9fb7feb74688437d64e748e87e98ec3e0c Mon Sep 17 00:00:00 2001 From: Krzysztof Taraszka Date: Sun, 25 Feb 2024 16:48:33 +0100 Subject: [PATCH 06/14] add documentation for push-extra-tags option --- docs/advanced-usage/registry-management.md | 31 ++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/docs/advanced-usage/registry-management.md b/docs/advanced-usage/registry-management.md index 808b1390e..9f67802ec 100644 --- a/docs/advanced-usage/registry-management.md +++ b/docs/advanced-usage/registry-management.md @@ -135,3 +135,34 @@ dokku registry:set node-js-app push-on-release # globally dokku registry:set --global push-on-release ``` + +### Push extra tags + +To push the image on release with extra tags, set the `push-extra-tags` to a comma-separated list of tags via the `registry:set` command. The default value for this property is `false`. Setting the property will result in the image being tagged with extra tags every release. + +```shell +# multiple-tags +dokku registry:set node-js-app push-extra-tags foo,bar +``` +The `push-extra-tags` can be set to a single tag too. + +```shell +# single tag +dokku registry:set node-js-app push-extra-tags foo +``` + +This property can be set for a single app or globally via the `--global` flag. When set globally, the app-specific value will always overide the global value. The default global value for this property is `false`. + +```shell +dokku registry:set --global push-extra-tags foo,bar +``` + +Setting the property value to an empty string will reset the value to the system default. Resetting the value can be done per app or globally. + +```shell +# per-app +dokku registry:set node-js-app push-extra-tags + +# globally +dokku registry:set --global push-extra-tags +``` From 07417af8193aed74511d19939a694e0d532b8853 Mon Sep 17 00:00:00 2001 From: Krzysztof Taraszka Date: Sun, 25 Feb 2024 17:20:42 +0100 Subject: [PATCH 07/14] this will go to a separate PR --- Vagrantfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Vagrantfile b/Vagrantfile index eb55a3787..3cd1c44d7 100644 --- a/Vagrantfile +++ b/Vagrantfile @@ -53,7 +53,7 @@ Vagrant::configure("2") do |config| vb.customize ["modifyvm", :id, "--cableconnected1", "on"] end - vm.vm.provision :shell, :inline => "export DEBIAN_FRONTEND=noninteractive && apt-get update -qq >/dev/null && apt-get -qq -y --no-install-recommends install git build-essential jq >/dev/null && cd /root/dokku && #{make_cmd}" + vm.vm.provision :shell, :inline => "export DEBIAN_FRONTEND=noninteractive && apt-get update -qq >/dev/null && apt-get -qq -y --no-install-recommends install git build-essential >/dev/null && cd /root/dokku && #{make_cmd}" vm.vm.provision :shell do |s| s.inline = <<-EOT echo '"\e[5~": history-search-backward' > /root/.inputrc From 5af90b76a3ae582bb7265af27655527a6ca32a35 Mon Sep 17 00:00:00 2001 From: Krzysztof Taraszka Date: Sun, 25 Feb 2024 17:38:27 +0100 Subject: [PATCH 08/14] s/false/empty/g --- docs/advanced-usage/registry-management.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/advanced-usage/registry-management.md b/docs/advanced-usage/registry-management.md index 9f67802ec..8e2eef8f6 100644 --- a/docs/advanced-usage/registry-management.md +++ b/docs/advanced-usage/registry-management.md @@ -138,7 +138,7 @@ dokku registry:set --global push-on-release ### Push extra tags -To push the image on release with extra tags, set the `push-extra-tags` to a comma-separated list of tags via the `registry:set` command. The default value for this property is `false`. Setting the property will result in the image being tagged with extra tags every release. +To push the image on release with extra tags, set the `push-extra-tags` to a comma-separated list of tags via the `registry:set` command. The default value for this property is empty. Setting the property will result in the image being tagged with extra tags every release. ```shell # multiple-tags From 54f74cccd0c48992a335a82e962ecb6dd5feaee0 Mon Sep 17 00:00:00 2001 From: Krzysztof Taraszka Date: Sun, 25 Feb 2024 18:46:45 +0100 Subject: [PATCH 09/14] anonymous func to run defer in a block --- plugins/registry/functions.go | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/plugins/registry/functions.go b/plugins/registry/functions.go index 708b71894..95cab0bb0 100644 --- a/plugins/registry/functions.go +++ b/plugins/registry/functions.go @@ -117,14 +117,18 @@ func pushToRegistry(appName string, tag int, imageID string, imageRepo string) e if !dockerTag(imageID, extraTagImage) { return errors.New(fmt.Sprintf("Unable to tag image as %s", extraTag)) } + func() { + defer func() { + common.LogVerboseQuiet(fmt.Sprintf("Untagging extra tag %s", extraTag)) + if !dockerRemoveTag(extraTagImage) { + common.LogWarn(fmt.Sprintf("Unable to untag extra tag %s", extraTag)) + } + }() + }() common.LogVerboseQuiet(fmt.Sprintf("Pushing %s", extraTagImage)) if !dockerPush(extraTagImage) { return errors.New(fmt.Sprintf("Unable to push image with %s tag", extraTag)) } - common.LogVerboseQuiet(fmt.Sprintf("Untagging extra tag %s", extraTag)) - if !dockerRemoveTag(extraTagImage) { - return errors.New(fmt.Sprintf("Unable to untag extra tag %s", extraTag)) - } } } From 00925b6c09281fe477eaeb723c69f8c093d93994 Mon Sep 17 00:00:00 2001 From: Krzysztof Taraszka Date: Sun, 25 Feb 2024 20:10:04 +0100 Subject: [PATCH 10/14] use common.RemoveImages --- plugins/registry/functions.go | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/plugins/registry/functions.go b/plugins/registry/functions.go index 95cab0bb0..253b8651b 100644 --- a/plugins/registry/functions.go +++ b/plugins/registry/functions.go @@ -111,8 +111,10 @@ func pushToRegistry(appName string, tag int, imageID string, imageRepo string) e extraTags := getRegistryPushExtraTagsForApp(appName) if extraTags != "" { extraTagsArray := strings.Split(extraTags, ",") + imagesToRemove := []string{} for _, extraTag := range extraTagsArray { extraTagImage := fmt.Sprintf("%s%s:%s", registryServer, imageRepo, extraTag) + imagesToRemove = append(imagesToRemove, extraTagImage) common.LogVerboseQuiet(fmt.Sprintf("Tagging %s as %s in registry format", imageRepo, extraTag)) if !dockerTag(imageID, extraTagImage) { return errors.New(fmt.Sprintf("Unable to tag image as %s", extraTag)) @@ -120,7 +122,7 @@ func pushToRegistry(appName string, tag int, imageID string, imageRepo string) e func() { defer func() { common.LogVerboseQuiet(fmt.Sprintf("Untagging extra tag %s", extraTag)) - if !dockerRemoveTag(extraTagImage) { + if !common.RemoveImages(imagesToRemove) { common.LogWarn(fmt.Sprintf("Unable to untag extra tag %s", extraTag)) } }() @@ -163,17 +165,6 @@ func dockerTag(imageID string, imageTag string) bool { return true } -func dockerRemoveTag(image string) bool { - cmd := sh.Command(common.DockerBin(), "image", "remove", image) - cmd.Stdout = nil - cmd.Stderr = nil - if err := cmd.Run(); err != nil { - return false - } - - return true -} - func dockerPush(imageTag string) bool { cmd := sh.Command(common.DockerBin(), "image", "push", imageTag) cmd.Stdout = os.Stdout From 58fd25ebf47f7c5b083cb00bb4fc8e81e25b191b Mon Sep 17 00:00:00 2001 From: Krzysztof Taraszka Date: Sun, 25 Feb 2024 20:34:34 +0100 Subject: [PATCH 11/14] fun() wrapper is not necessary; removed imagesToRemove array --- plugins/registry/functions.go | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/plugins/registry/functions.go b/plugins/registry/functions.go index 253b8651b..95f704637 100644 --- a/plugins/registry/functions.go +++ b/plugins/registry/functions.go @@ -111,7 +111,6 @@ func pushToRegistry(appName string, tag int, imageID string, imageRepo string) e extraTags := getRegistryPushExtraTagsForApp(appName) if extraTags != "" { extraTagsArray := strings.Split(extraTags, ",") - imagesToRemove := []string{} for _, extraTag := range extraTagsArray { extraTagImage := fmt.Sprintf("%s%s:%s", registryServer, imageRepo, extraTag) imagesToRemove = append(imagesToRemove, extraTagImage) @@ -119,13 +118,11 @@ func pushToRegistry(appName string, tag int, imageID string, imageRepo string) e if !dockerTag(imageID, extraTagImage) { return errors.New(fmt.Sprintf("Unable to tag image as %s", extraTag)) } - func() { - defer func() { - common.LogVerboseQuiet(fmt.Sprintf("Untagging extra tag %s", extraTag)) - if !common.RemoveImages(imagesToRemove) { - common.LogWarn(fmt.Sprintf("Unable to untag extra tag %s", extraTag)) - } - }() + defer func() { + common.LogVerboseQuiet(fmt.Sprintf("Untagging extra tag %s", extraTag)) + if err := common.RemoveImages(extraTagImage); err != nil { + common.LogWarn(fmt.Sprintf("Unable to untag extra tag %s", extraTag, err.Error())) + } }() common.LogVerboseQuiet(fmt.Sprintf("Pushing %s", extraTagImage)) if !dockerPush(extraTagImage) { From dfa7409486cc87844f0ac6aed346a537c70fde4e Mon Sep 17 00:00:00 2001 From: Krzysztof Taraszka Date: Sun, 25 Feb 2024 20:44:56 +0100 Subject: [PATCH 12/14] ah, right, this is not used here --- plugins/registry/functions.go | 1 - 1 file changed, 1 deletion(-) diff --git a/plugins/registry/functions.go b/plugins/registry/functions.go index 5c6e7f3cb..d53485f98 100644 --- a/plugins/registry/functions.go +++ b/plugins/registry/functions.go @@ -111,7 +111,6 @@ func pushToRegistry(appName string, tag int, imageID string, imageRepo string) e extraTagsArray := strings.Split(extraTags, ",") for _, extraTag := range extraTagsArray { extraTagImage := fmt.Sprintf("%s%s:%s", registryServer, imageRepo, extraTag) - imagesToRemove = append(imagesToRemove, extraTagImage) common.LogVerboseQuiet(fmt.Sprintf("Tagging %s as %s in registry format", imageRepo, extraTag)) if !dockerTag(imageID, extraTagImage) { return errors.New(fmt.Sprintf("Unable to tag image as %s", extraTag)) From 52b095d7accfa7862bd5d4bc7df9833857ec501e Mon Sep 17 00:00:00 2001 From: Krzysztof Taraszka Date: Sun, 25 Feb 2024 22:36:21 +0100 Subject: [PATCH 13/14] fix CI --- plugins/registry/functions.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/registry/functions.go b/plugins/registry/functions.go index d53485f98..7c2882c62 100644 --- a/plugins/registry/functions.go +++ b/plugins/registry/functions.go @@ -117,7 +117,7 @@ func pushToRegistry(appName string, tag int, imageID string, imageRepo string) e } defer func() { common.LogVerboseQuiet(fmt.Sprintf("Untagging extra tag %s", extraTag)) - if err := common.RemoveImages(extraTagImage); err != nil { + if err := common.RemoveImages([]string{extraTagImage}); err != nil { common.LogWarn(fmt.Sprintf("Unable to untag extra tag %s", extraTag, err.Error())) } }() From c4c961bef11abe992f18b001642e6ea1ec77d5a5 Mon Sep 17 00:00:00 2001 From: Krzysztof Taraszka Date: Sun, 10 Mar 2024 16:46:59 +0100 Subject: [PATCH 14/14] add bats test for push-extra-tags --- tests/unit/registry.bats | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/tests/unit/registry.bats b/tests/unit/registry.bats index 403e68f9d..321c7bf31 100644 --- a/tests/unit/registry.bats +++ b/tests/unit/registry.bats @@ -294,3 +294,30 @@ teardown() { echo "status: $status" assert_success } + +@test "(registry) registry:set push-extra-tags" { + if [[ -z "$DOCKERHUB_USERNAME" ]] || [[ -z "$DOCKERHUB_TOKEN" ]]; then + skip "skipping due to missing docker.io credentials DOCKERHUB_USERNAME:DOCKERHUB_TOKEN" + fi + + run /bin/bash -c "dokku registry:set $TEST_APP push-on-release true" + echo "output: $output" + echo "status: $status" + assert_success + + run /bin/bash -c "dokku registry:set $TEST_APP image-repo dokku/test-app" + echo "output: $output" + echo "status: $status" + assert_success + + run /bin/bash -c "dokku registry:set $TEST_APP push-extra-tags foo" + echo "output: $output" + echo "status: $status" + assert_success + + run deploy_app + echo "output: $output" + echo "status: $status" + assert_success + assert_output_contains "dokku/test-app:foo" +}