diff --git a/CHANGELOG.md b/CHANGELOG.md index 6a3bcd6b8b..d8805b0b5b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased +- Add support for multiple credentials per-registry + - Image resource will match on the longest case match by default + - Credentials to use can be explicitly set by `:repo_credential_override` + ## 11.9.2 - *2025-02-02* ## 11.9.1 - *2025-02-01* diff --git a/libraries/base.rb b/libraries/base.rb deleted file mode 100644 index bd329a5a33..0000000000 --- a/libraries/base.rb +++ /dev/null @@ -1,10 +0,0 @@ -module Docker - module Cookbook - module Helpers - # https://github.com/docker/docker/blob/4fcb9ac40ce33c4d6e08d5669af6be5e076e2574/registry/auth.go#L231 - def parse_registry_host(val) - val.sub(%r{https?://}, '').split('/').first - end - end - end -end diff --git a/resources/image.rb b/resources/image.rb index e1005b6e3e..3c0ef55909 100644 --- a/resources/image.rb +++ b/resources/image.rb @@ -10,6 +10,7 @@ property :nocache, [true, false], default: false property :noprune, [true, false], default: false property :repo, String, name_property: true +property :repo_credential_override, String property :rm, [true, false], default: true property :source, String property :tag, String, default: 'latest' @@ -140,7 +141,7 @@ def import_image def pull_image with_retries do - creds = credentails + creds = credentials original_image = Docker::Image.get(image_identifier, {}, connection) if Docker::Image.exist?(image_identifier, {}, connection) new_image = Docker::Image.create({ 'fromImage' => image_identifier }, creds, connection) @@ -150,7 +151,7 @@ def pull_image def push_image with_retries do - creds = credentails + creds = credentials i = Docker::Image.get(image_identifier, {}, connection) i.push(creds, repo_tag: image_identifier) end @@ -175,8 +176,25 @@ def load_image end end - def credentails + def credentials + return new_resource.repo_credential_override unless new_resource.repo_credential_override.nil? || new_resource.repo_credential_override.empty? + registry_host = parse_registry_host(new_resource.repo) - node.run_state['docker_auth'] && node.run_state['docker_auth'][registry_host] || {} + # Return unless we have credentials stored and we have a custom repo path + return registry_host unless registry_host.include?('/') && node.run_state.key?('docker_auth') + + # Longest-path registry credentials match + registry_host = nil + registry_split = new_resource.repo.split('/') + join_count = registry_split.count + + until registry_host || (join_count < 0) + join_count -= 1 + registry_host = registry_split[0..join_count].join('/') if node.run_state['docker_auth'].key?(registry_split[0..join_count].join('/')) + end + + return {} unless registry_host + + node.run_state.dig('docker_auth', registry_host) || {} end end diff --git a/resources/partial/_base.rb b/resources/partial/_base.rb index 138752f736..d9b6686185 100644 --- a/resources/partial/_base.rb +++ b/resources/partial/_base.rb @@ -129,10 +129,10 @@ def parse_registry_host(val) # domain.ext/image (=> 3rd party registry) # domain.ext/.../image (=> 3rd party registry) # - first_part = val.sub(%r{https?://}, '').split('/').first + registry = val.sub(%r{https?://}, '') # looks like a host name of a custom docker registry - return first_part if first_part.include?('.') + return registry if registry.include?('.') # default host 'index.docker.io'