From 7d424ff02ae1eada8bd7cd67b9e4e9db6066f4b7 Mon Sep 17 00:00:00 2001 From: clabbe <clement.labbe@rea-group.com> Date: Thu, 25 Feb 2016 11:16:51 +1100 Subject: [PATCH 01/11] Turn TagsLogic into a class --- lib/tagfish/tags_command.rb | 2 +- lib/tagfish/tags_logic.rb | 19 +++++++++++++------ lib/tagfish/update/updater.rb | 2 +- 3 files changed, 15 insertions(+), 8 deletions(-) diff --git a/lib/tagfish/tags_command.rb b/lib/tagfish/tags_command.rb index e3ccef0..2eda3b8 100644 --- a/lib/tagfish/tags_command.rb +++ b/lib/tagfish/tags_command.rb @@ -12,7 +12,7 @@ def execute docker_uri = DockerURI.parse(repository) docker_api = DockerAPI.new(docker_uri) - tags = TagsLogic.find_tags_by_repository(docker_api, tags_only) + tags = TagsLogic.new(docker_api).find_tags_by_repository(tags_only) begin tags_found = latest? ? tags.latest_tag : tags.tag_names diff --git a/lib/tagfish/tags_logic.rb b/lib/tagfish/tags_logic.rb index d3d93fc..52c0e01 100644 --- a/lib/tagfish/tags_logic.rb +++ b/lib/tagfish/tags_logic.rb @@ -3,23 +3,30 @@ module Tagfish class TagsLogic - def self.find_tags_by_repository(docker_api, tags_only=false) + + attr_reader :docker_api + + def initialize(docker_api) + @docker_api = docker_api + end + + def find_tags_by_repository(tags_only=false) if docker_api.api_version == 'v2' - tags_list = tags_v2(docker_api, tags_only) + tags_list = tags_v2(tags_only) else - tags_list = tags_v1(docker_api) + tags_list = tags_v1 end Tagfish::Tags.new(tags_list) end private - def self.tags_v1(docker_api) + def tags_v1 tags_json = docker_api.tags_v1 tags_v1_api(tags_json) end - def self.tags_v1_api(api_response_data) + def tags_v1_api(api_response_data) case api_response_data when Hash api_response_data @@ -32,7 +39,7 @@ def self.tags_v1_api(api_response_data) end end - def self.tags_v2(docker_api, tags_only) + def tags_v2(tags_only) tags = docker_api.tags_v2["tags"] if tags.nil? abort("No Tags found for this repository") diff --git a/lib/tagfish/update/updater.rb b/lib/tagfish/update/updater.rb index d2b5a7d..976a020 100644 --- a/lib/tagfish/update/updater.rb +++ b/lib/tagfish/update/updater.rb @@ -39,7 +39,7 @@ def updatable?(uri) def update_uri(docker_uri) docker_api = DockerAPI.new(docker_uri) - tags = TagsLogic.find_tags_by_repository(docker_api) + tags = TagsLogic.new(docker_api).find_tags_by_repository newest_tag_name = tags.latest_tag_to_s if newest_tag_name.nil? docker_uri From 22cf04be85e3c59f1282ffebb77fe17e73c21cb2 Mon Sep 17 00:00:00 2001 From: clabbe <clement.labbe@rea-group.com> Date: Thu, 25 Feb 2016 11:42:53 +1100 Subject: [PATCH 02/11] Move TagsLogic into DockerAPI --- lib/tagfish/docker_api.rb | 46 +++++++++++++++++++++++++++ lib/tagfish/tags_command.rb | 4 +-- lib/tagfish/tags_logic.rb | 59 ----------------------------------- lib/tagfish/update/updater.rb | 4 +-- 4 files changed, 50 insertions(+), 63 deletions(-) delete mode 100644 lib/tagfish/tags_logic.rb diff --git a/lib/tagfish/docker_api.rb b/lib/tagfish/docker_api.rb index b116420..b22558b 100644 --- a/lib/tagfish/docker_api.rb +++ b/lib/tagfish/docker_api.rb @@ -2,6 +2,7 @@ require 'json' require 'tagfish/docker_uri' require 'tagfish/api_call' +require 'tagfish/tags' module Tagfish class DockerAPI @@ -49,6 +50,15 @@ def init_auth(api_version) end end + def find_tags_by_repository(tags_only=false) + if api_version == 'v2' + tags_list = tags_v2_logic(tags_only) + else + tags_list = tags_v1_logic + end + Tagfish::Tags.new(tags_list) + end + def tags_v1 APICall.new(tags_v1_uri).get_json(http_auth) end @@ -69,6 +79,42 @@ def search_v1(keyword) APICall.new(search_v1_uri(keyword)).get_json(http_auth) end + private + + def tags_v1_logic + tags_json = tags_v1 + tags_v1_api(tags_json) + end + + def tags_v1_api(api_response_data) + case api_response_data + when Hash + api_response_data + when Array + api_response_data.reduce({}) do |images, tag| + images.merge({tag["name"] => tag["layer"]}) + end + else + raise "unexpected type #{api_response_data.class}" + end + end + + def tags_v2_logic(tags_only) + tags = tags_v2["tags"] + if tags.nil? + abort("No Tags found for this repository") + end + + tags_with_hashes = tags.inject({}) do |dict, tag| + if tags_only + dict[tag] = "dummy_hash" + else + dict[tag] = hash_v2(tag)["fsLayers"][0]["blobSum"] + end + dict + end + end + def base_uri "#{docker_uri.protocol}#{docker_uri.registry}" end diff --git a/lib/tagfish/tags_command.rb b/lib/tagfish/tags_command.rb index 2eda3b8..6f39796 100644 --- a/lib/tagfish/tags_command.rb +++ b/lib/tagfish/tags_command.rb @@ -1,5 +1,5 @@ -require "tagfish/tags_logic" require "tagfish/docker_uri" +require "tagfish/docker_api" module Tagfish class TagsCommand < Clamp::Command @@ -12,7 +12,7 @@ def execute docker_uri = DockerURI.parse(repository) docker_api = DockerAPI.new(docker_uri) - tags = TagsLogic.new(docker_api).find_tags_by_repository(tags_only) + tags = docker_api.find_tags_by_repository(tags_only) begin tags_found = latest? ? tags.latest_tag : tags.tag_names diff --git a/lib/tagfish/tags_logic.rb b/lib/tagfish/tags_logic.rb deleted file mode 100644 index 52c0e01..0000000 --- a/lib/tagfish/tags_logic.rb +++ /dev/null @@ -1,59 +0,0 @@ -require 'json' -require 'tagfish/tags' - -module Tagfish - class TagsLogic - - attr_reader :docker_api - - def initialize(docker_api) - @docker_api = docker_api - end - - def find_tags_by_repository(tags_only=false) - if docker_api.api_version == 'v2' - tags_list = tags_v2(tags_only) - else - tags_list = tags_v1 - end - Tagfish::Tags.new(tags_list) - end - - private - - def tags_v1 - tags_json = docker_api.tags_v1 - tags_v1_api(tags_json) - end - - def tags_v1_api(api_response_data) - case api_response_data - when Hash - api_response_data - when Array - api_response_data.reduce({}) do |images, tag| - images.merge({tag["name"] => tag["layer"]}) - end - else - raise "unexpected type #{api_response_data.class}" - end - end - - def tags_v2(tags_only) - tags = docker_api.tags_v2["tags"] - if tags.nil? - abort("No Tags found for this repository") - end - - tags_with_hashes = tags.inject({}) do |dict, tag| - if tags_only - dict[tag] = "dummy_hash" - else - dict[tag] = docker_api.hash_v2(tag)["fsLayers"][0]["blobSum"] - end - dict - end - end - - end -end diff --git a/lib/tagfish/update/updater.rb b/lib/tagfish/update/updater.rb index 976a020..79d4ab5 100644 --- a/lib/tagfish/update/updater.rb +++ b/lib/tagfish/update/updater.rb @@ -1,6 +1,6 @@ require 'tagfish/tokeniser' require 'tagfish/docker_uri' -require 'tagfish/tags_logic' +require 'tagfish/docker_api' module Tagfish module Update @@ -39,7 +39,7 @@ def updatable?(uri) def update_uri(docker_uri) docker_api = DockerAPI.new(docker_uri) - tags = TagsLogic.new(docker_api).find_tags_by_repository + tags = docker_api.find_tags_by_repository newest_tag_name = tags.latest_tag_to_s if newest_tag_name.nil? docker_uri From ca78a995050124275598e785212f790e45abfab3 Mon Sep 17 00:00:00 2001 From: clabbe <clement.labbe@rea-group.com> Date: Thu, 25 Feb 2016 11:47:05 +1100 Subject: [PATCH 03/11] Rename DockerAPI into DockerRegistryClient --- lib/tagfish/{docker_api.rb => docker_registry_client.rb} | 2 +- lib/tagfish/docker_uri.rb | 1 - lib/tagfish/tags_command.rb | 4 ++-- lib/tagfish/update/updater.rb | 4 ++-- 4 files changed, 5 insertions(+), 6 deletions(-) rename lib/tagfish/{docker_api.rb => docker_registry_client.rb} (99%) diff --git a/lib/tagfish/docker_api.rb b/lib/tagfish/docker_registry_client.rb similarity index 99% rename from lib/tagfish/docker_api.rb rename to lib/tagfish/docker_registry_client.rb index b22558b..355027f 100644 --- a/lib/tagfish/docker_api.rb +++ b/lib/tagfish/docker_registry_client.rb @@ -5,7 +5,7 @@ require 'tagfish/tags' module Tagfish - class DockerAPI + class DockerRegistryClient attr_accessor :docker_uri attr_accessor :api_version diff --git a/lib/tagfish/docker_uri.rb b/lib/tagfish/docker_uri.rb index ca767f5..e1c26ac 100644 --- a/lib/tagfish/docker_uri.rb +++ b/lib/tagfish/docker_uri.rb @@ -1,5 +1,4 @@ require 'tagfish/docker_http_auth' -require 'tagfish/docker_api' module Tagfish class DockerURI diff --git a/lib/tagfish/tags_command.rb b/lib/tagfish/tags_command.rb index 6f39796..210bd8b 100644 --- a/lib/tagfish/tags_command.rb +++ b/lib/tagfish/tags_command.rb @@ -1,5 +1,5 @@ require "tagfish/docker_uri" -require "tagfish/docker_api" +require "tagfish/docker_registry_client" module Tagfish class TagsCommand < Clamp::Command @@ -11,7 +11,7 @@ def execute tags_only = latest? ? false : true docker_uri = DockerURI.parse(repository) - docker_api = DockerAPI.new(docker_uri) + docker_api = DockerRegistryClient.new(docker_uri) tags = docker_api.find_tags_by_repository(tags_only) begin diff --git a/lib/tagfish/update/updater.rb b/lib/tagfish/update/updater.rb index 79d4ab5..7723f20 100644 --- a/lib/tagfish/update/updater.rb +++ b/lib/tagfish/update/updater.rb @@ -1,6 +1,6 @@ require 'tagfish/tokeniser' require 'tagfish/docker_uri' -require 'tagfish/docker_api' +require 'tagfish/docker_registry_client' module Tagfish module Update @@ -38,7 +38,7 @@ def updatable?(uri) end def update_uri(docker_uri) - docker_api = DockerAPI.new(docker_uri) + docker_api = DockerRegistryClient.new(docker_uri) tags = docker_api.find_tags_by_repository newest_tag_name = tags.latest_tag_to_s if newest_tag_name.nil? From 0100afa447ef69851bdd75e186b73ac8e7a667a2 Mon Sep 17 00:00:00 2001 From: clabbe <clement.labbe@rea-group.com> Date: Thu, 25 Feb 2016 12:05:07 +1100 Subject: [PATCH 04/11] MAke DockerRegistryClient a facade in front of what will become v1 and v2 API classes --- lib/tagfish/docker_registry_client.rb | 156 +------------------ lib/tagfish/docker_registry_vboth_client.rb | 159 ++++++++++++++++++++ lib/tagfish/tags_command.rb | 2 +- lib/tagfish/update/updater.rb | 2 +- 4 files changed, 165 insertions(+), 154 deletions(-) create mode 100644 lib/tagfish/docker_registry_vboth_client.rb diff --git a/lib/tagfish/docker_registry_client.rb b/lib/tagfish/docker_registry_client.rb index 355027f..28e1bb2 100644 --- a/lib/tagfish/docker_registry_client.rb +++ b/lib/tagfish/docker_registry_client.rb @@ -1,158 +1,10 @@ -require 'net/http' -require 'json' -require 'tagfish/docker_uri' -require 'tagfish/api_call' -require 'tagfish/tags' +require 'tagfish/docker_registry_vboth_client' module Tagfish - class DockerRegistryClient + module DockerRegistryClient - attr_accessor :docker_uri - attr_accessor :api_version - attr_accessor :http_auth - - def initialize(docker_uri) - @docker_uri = docker_uri - retrieve_api_version_and_auth() - end - - def retrieve_api_version_and_auth - code = try_api('v1') - if code != 200 - code = try_api('v2') - end - if code == 401 - abort("Authentication failed, please `docker login <REGISTRY>` and try again.") - elsif code != 200 - abort("API version not recognized") - end - end - - def try_api(version) - code = APICall.new(ping_uri(version)).response_code - if code == 200 - @api_version = version - elsif code == 401 - code = init_auth(version) - if code == 200 - @api_version = version - end - end - return code - end - - def init_auth(api_version) - @http_auth = DockerHttpAuth.new(docker_uri.registry) - if api_version == 'v2' - code = APICall.new(ping_v2_uri).response_code(http_auth) - elsif api_version == 'v1' - code = APICall.new(ping_v1_uri).response_code(http_auth) - end - end - - def find_tags_by_repository(tags_only=false) - if api_version == 'v2' - tags_list = tags_v2_logic(tags_only) - else - tags_list = tags_v1_logic - end - Tagfish::Tags.new(tags_list) - end - - def tags_v1 - APICall.new(tags_v1_uri).get_json(http_auth) - end - - def tags_v2 - APICall.new(tags_v2_uri).get_json(http_auth) - end - - def hash_v2(tag) - APICall.new(hash_v2_uri(tag)).get_json(http_auth) - end - - def catalog_v2 - APICall.new(catalog_v2_uri).get_json(http_auth) - end - - def search_v1(keyword) - APICall.new(search_v1_uri(keyword)).get_json(http_auth) - end - - private - - def tags_v1_logic - tags_json = tags_v1 - tags_v1_api(tags_json) - end - - def tags_v1_api(api_response_data) - case api_response_data - when Hash - api_response_data - when Array - api_response_data.reduce({}) do |images, tag| - images.merge({tag["name"] => tag["layer"]}) - end - else - raise "unexpected type #{api_response_data.class}" - end - end - - def tags_v2_logic(tags_only) - tags = tags_v2["tags"] - if tags.nil? - abort("No Tags found for this repository") - end - - tags_with_hashes = tags.inject({}) do |dict, tag| - if tags_only - dict[tag] = "dummy_hash" - else - dict[tag] = hash_v2(tag)["fsLayers"][0]["blobSum"] - end - dict - end - end - - def base_uri - "#{docker_uri.protocol}#{docker_uri.registry}" - end - - def ping_uri(version) - if version == 'v1' - ping_v1_uri - elsif version == 'v2' - ping_v2_uri - end - end - - def ping_v2_uri - "#{base_uri}/v2/" - end - - def ping_v1_uri - "#{base_uri}/v1/_ping" - end - - def catalog_v2_uri - "#{base_uri}/v2/_catalog" - end - - def search_v1_uri(keyword) - "#{base_uri}/v1/search?q=#{keyword}" - end - - def tags_v1_uri - "#{base_uri}/v1/repositories/#{docker_uri.repository}/tags" - end - - def tags_v2_uri - "#{base_uri}/v2/#{docker_uri.repository}/tags/list" - end - - def hash_v2_uri(tag) - "#{base_uri}/v2/#{docker_uri.repository}/manifests/#{tag}" + def self.for(*args) + DockerRegistryVbothClient.new(*args) end end diff --git a/lib/tagfish/docker_registry_vboth_client.rb b/lib/tagfish/docker_registry_vboth_client.rb new file mode 100644 index 0000000..fc4fbfd --- /dev/null +++ b/lib/tagfish/docker_registry_vboth_client.rb @@ -0,0 +1,159 @@ +require 'net/http' +require 'json' +require 'tagfish/docker_uri' +require 'tagfish/api_call' +require 'tagfish/tags' + +module Tagfish + class DockerRegistryVbothClient + + attr_accessor :docker_uri + attr_accessor :api_version + attr_accessor :http_auth + + def initialize(docker_uri) + @docker_uri = docker_uri + retrieve_api_version_and_auth() + end + + def retrieve_api_version_and_auth + code = try_api('v1') + if code != 200 + code = try_api('v2') + end + if code == 401 + abort("Authentication failed, please `docker login <REGISTRY>` and try again.") + elsif code != 200 + abort("API version not recognized") + end + end + + def try_api(version) + code = APICall.new(ping_uri(version)).response_code + if code == 200 + @api_version = version + elsif code == 401 + code = init_auth(version) + if code == 200 + @api_version = version + end + end + return code + end + + def init_auth(api_version) + @http_auth = DockerHttpAuth.new(docker_uri.registry) + if api_version == 'v2' + code = APICall.new(ping_v2_uri).response_code(http_auth) + elsif api_version == 'v1' + code = APICall.new(ping_v1_uri).response_code(http_auth) + end + end + + def find_tags_by_repository(tags_only=false) + if api_version == 'v2' + tags_list = tags_v2_logic(tags_only) + else + tags_list = tags_v1_logic + end + Tagfish::Tags.new(tags_list) + end + + def tags_v1 + APICall.new(tags_v1_uri).get_json(http_auth) + end + + def tags_v2 + APICall.new(tags_v2_uri).get_json(http_auth) + end + + def hash_v2(tag) + APICall.new(hash_v2_uri(tag)).get_json(http_auth) + end + + def catalog_v2 + APICall.new(catalog_v2_uri).get_json(http_auth) + end + + def search_v1(keyword) + APICall.new(search_v1_uri(keyword)).get_json(http_auth) + end + + private + + def tags_v1_logic + tags_json = tags_v1 + tags_v1_api(tags_json) + end + + def tags_v1_api(api_response_data) + case api_response_data + when Hash + api_response_data + when Array + api_response_data.reduce({}) do |images, tag| + images.merge({tag["name"] => tag["layer"]}) + end + else + raise "unexpected type #{api_response_data.class}" + end + end + + def tags_v2_logic(tags_only) + tags = tags_v2["tags"] + if tags.nil? + abort("No Tags found for this repository") + end + + tags_with_hashes = tags.inject({}) do |dict, tag| + if tags_only + dict[tag] = "dummy_hash" + else + dict[tag] = hash_v2(tag)["fsLayers"][0]["blobSum"] + end + dict + end + end + + def base_uri + "#{docker_uri.protocol}#{docker_uri.registry}" + end + + def ping_uri(version) + if version == 'v1' + ping_v1_uri + elsif version == 'v2' + ping_v2_uri + end + end + + def ping_v2_uri + "#{base_uri}/v2/" + end + + def ping_v1_uri + "#{base_uri}/v1/_ping" + end + + def catalog_v2_uri + "#{base_uri}/v2/_catalog" + end + + def search_v1_uri(keyword) + "#{base_uri}/v1/search?q=#{keyword}" + end + + def tags_v1_uri + "#{base_uri}/v1/repositories/#{docker_uri.repository}/tags" + end + + def tags_v2_uri + "#{base_uri}/v2/#{docker_uri.repository}/tags/list" + end + + def hash_v2_uri(tag) + "#{base_uri}/v2/#{docker_uri.repository}/manifests/#{tag}" + end + + end +end diff --git a/lib/tagfish/tags_command.rb b/lib/tagfish/tags_command.rb index 210bd8b..44dfb86 100644 --- a/lib/tagfish/tags_command.rb +++ b/lib/tagfish/tags_command.rb @@ -11,7 +11,7 @@ def execute tags_only = latest? ? false : true docker_uri = DockerURI.parse(repository) - docker_api = DockerRegistryClient.new(docker_uri) + docker_api = DockerRegistryClient.for(docker_uri) tags = docker_api.find_tags_by_repository(tags_only) begin diff --git a/lib/tagfish/update/updater.rb b/lib/tagfish/update/updater.rb index 7723f20..d9ad995 100644 --- a/lib/tagfish/update/updater.rb +++ b/lib/tagfish/update/updater.rb @@ -38,7 +38,7 @@ def updatable?(uri) end def update_uri(docker_uri) - docker_api = DockerRegistryClient.new(docker_uri) + docker_api = DockerRegistryClient.for(docker_uri) tags = docker_api.find_tags_by_repository newest_tag_name = tags.latest_tag_to_s if newest_tag_name.nil? From a52425e3d31e40c8ffa42d4150c64b3fcd42618d Mon Sep 17 00:00:00 2001 From: clabbe <clement.labbe@rea-group.com> Date: Thu, 25 Feb 2016 14:40:20 +1100 Subject: [PATCH 05/11] Create DockerRegistryClient sub-classes (empty for now) --- lib/tagfish/docker_registry_client.rb | 17 +++++++- lib/tagfish/docker_registry_v1_client.rb | 11 ++++++ lib/tagfish/docker_registry_v2_client.rb | 11 ++++++ lib/tagfish/docker_registry_vboth_client.rb | 44 +++++---------------- 4 files changed, 46 insertions(+), 37 deletions(-) create mode 100644 lib/tagfish/docker_registry_v1_client.rb create mode 100644 lib/tagfish/docker_registry_v2_client.rb diff --git a/lib/tagfish/docker_registry_client.rb b/lib/tagfish/docker_registry_client.rb index 28e1bb2..7b23f6e 100644 --- a/lib/tagfish/docker_registry_client.rb +++ b/lib/tagfish/docker_registry_client.rb @@ -1,10 +1,23 @@ -require 'tagfish/docker_registry_vboth_client' +require 'tagfish/docker_registry_v1_client' +require 'tagfish/docker_registry_v2_client' module Tagfish module DockerRegistryClient def self.for(*args) - DockerRegistryVbothClient.new(*args) + [DockerRegistryV2Client, DockerRegistryV1Client].each do |client_class| + begin + return client_class.new(*args) + rescue APIVersionError + end + end + raise APIVersionError, "API version unrecognized!" + end + + class AuthenticationError < StandardError + end + + class APIVersionError < StandardError end end diff --git a/lib/tagfish/docker_registry_v1_client.rb b/lib/tagfish/docker_registry_v1_client.rb new file mode 100644 index 0000000..9583e39 --- /dev/null +++ b/lib/tagfish/docker_registry_v1_client.rb @@ -0,0 +1,11 @@ +require 'tagfish/docker_registry_vboth_client' + +module Tagfish + class DockerRegistryV1Client < DockerRegistryVbothClient + + def api_version + 'v1' + end + + end +end diff --git a/lib/tagfish/docker_registry_v2_client.rb b/lib/tagfish/docker_registry_v2_client.rb new file mode 100644 index 0000000..6244ad2 --- /dev/null +++ b/lib/tagfish/docker_registry_v2_client.rb @@ -0,0 +1,11 @@ +require 'tagfish/docker_registry_vboth_client' + +module Tagfish + class DockerRegistryV2Client < DockerRegistryVbothClient + + def api_version + 'v2' + end + + end +end diff --git a/lib/tagfish/docker_registry_vboth_client.rb b/lib/tagfish/docker_registry_vboth_client.rb index fc4fbfd..d16dc88 100644 --- a/lib/tagfish/docker_registry_vboth_client.rb +++ b/lib/tagfish/docker_registry_vboth_client.rb @@ -8,45 +8,19 @@ module Tagfish class DockerRegistryVbothClient attr_accessor :docker_uri - attr_accessor :api_version attr_accessor :http_auth def initialize(docker_uri) @docker_uri = docker_uri - retrieve_api_version_and_auth() - end - - def retrieve_api_version_and_auth - code = try_api('v1') - if code != 200 - code = try_api('v2') + code = APICall.new(ping_uri).response_code + if code == 401 + @http_auth = DockerHttpAuth.new(docker_uri.registry) + code = APICall.new(ping_uri).response_code(http_auth) end if code == 401 - abort("Authentication failed, please `docker login <REGISTRY>` and try again.") + raise DockerRegistryClient::AuthenticationError, "Please `docker login <REGISTRY>` and try again" elsif code != 200 - abort("API version not recognized") - end - end - - def try_api(version) - code = APICall.new(ping_uri(version)).response_code - if code == 200 - @api_version = version - elsif code == 401 - code = init_auth(version) - if code == 200 - @api_version = version - end - end - return code - end - - def init_auth(api_version) - @http_auth = DockerHttpAuth.new(docker_uri.registry) - if api_version == 'v2' - code = APICall.new(ping_v2_uri).response_code(http_auth) - elsif api_version == 'v1' - code = APICall.new(ping_v1_uri).response_code(http_auth) + raise DockerRegistryClient::APIVersionError, "Not recognized" end end @@ -119,10 +93,10 @@ def base_uri "#{docker_uri.protocol}#{docker_uri.registry}" end - def ping_uri(version) - if version == 'v1' + def ping_uri + if api_version == 'v1' ping_v1_uri - elsif version == 'v2' + elsif api_version == 'v2' ping_v2_uri end end From ed952c28b1923f802ae626e20ab1d5a35b48f8a8 Mon Sep 17 00:00:00 2001 From: clabbe <clement.labbe@rea-group.com> Date: Thu, 25 Feb 2016 15:02:54 +1100 Subject: [PATCH 06/11] Make tags_found consistent --- lib/tagfish/tags.rb | 16 +++++++--------- lib/tagfish/tags_command.rb | 26 ++++++++++++-------------- lib/tagfish/update/updater.rb | 2 +- 3 files changed, 20 insertions(+), 24 deletions(-) diff --git a/lib/tagfish/tags.rb b/lib/tagfish/tags.rb index 23ec8ab..3e97a5e 100644 --- a/lib/tagfish/tags.rb +++ b/lib/tagfish/tags.rb @@ -4,23 +4,21 @@ module Tagfish class Tags - def initialize(tags) - @tags = tags + attr_reader :tag_map + + def initialize(tag_map) + @tag_map = tag_map end def tag_names - @tags.keys.sort + tag_map.keys.sort end def latest_tag - tag_names.select do |tag_name| - (@tags[tag_name] == @tags["latest"]) && (tag_name != 'latest') + tag_names.detect do |tag_name| + (tag_map[tag_name] == tag_map["latest"]) && (tag_name != "latest") end end - def latest_tag_to_s - latest_tag.empty? ? nil : latest_tag[0] - end - end end diff --git a/lib/tagfish/tags_command.rb b/lib/tagfish/tags_command.rb index 44dfb86..7383615 100644 --- a/lib/tagfish/tags_command.rb +++ b/lib/tagfish/tags_command.rb @@ -8,23 +8,21 @@ class TagsCommand < Clamp::Command option ["-s", "--short"], :flag, "only return tag, not full image path" def execute - tags_only = latest? ? false : true docker_uri = DockerURI.parse(repository) docker_api = DockerRegistryClient.for(docker_uri) - tags = docker_api.find_tags_by_repository(tags_only) - - begin - tags_found = latest? ? tags.latest_tag : tags.tag_names - rescue Exception => e - puts e.message - return - end - - if tags_found.size == 0 - puts "ERROR: No image explicitly tagged in this Repository, " + - "only `latest` tag available." - return + + if latest? + tags = docker_api.find_tags_by_repository(false) + latest_tag = tags.latest_tag + if latest_tag.nil? + signal_error "No image explicitly tagged in this Repository, " + + "only `latest` tag available." + end + tags_found = [latest_tag] + else + tags = docker_api.find_tags_by_repository(true) + tags_found = tags.tag_names end pretty_tags = tags_found.map do |tag_name| diff --git a/lib/tagfish/update/updater.rb b/lib/tagfish/update/updater.rb index d9ad995..e2252d1 100644 --- a/lib/tagfish/update/updater.rb +++ b/lib/tagfish/update/updater.rb @@ -40,7 +40,7 @@ def updatable?(uri) def update_uri(docker_uri) docker_api = DockerRegistryClient.for(docker_uri) tags = docker_api.find_tags_by_repository - newest_tag_name = tags.latest_tag_to_s + newest_tag_name = tags.latest_tag if newest_tag_name.nil? docker_uri else From 782a8c625fccfcda1be323ff731f6a1e811f781b Mon Sep 17 00:00:00 2001 From: clabbe <clement.labbe@rea-group.com> Date: Thu, 25 Feb 2016 15:31:31 +1100 Subject: [PATCH 07/11] Split v1 and v2 logic --- lib/tagfish/docker_registry_v1_client.rb | 44 +++++++++ lib/tagfish/docker_registry_v2_client.rb | 50 ++++++++++ lib/tagfish/docker_registry_vboth_client.rb | 102 -------------------- 3 files changed, 94 insertions(+), 102 deletions(-) diff --git a/lib/tagfish/docker_registry_v1_client.rb b/lib/tagfish/docker_registry_v1_client.rb index 9583e39..295b2fd 100644 --- a/lib/tagfish/docker_registry_v1_client.rb +++ b/lib/tagfish/docker_registry_v1_client.rb @@ -7,5 +7,49 @@ def api_version 'v1' end + def find_tags_by_repository(tags_only=false) + tags_list = tags_v1_logic + Tagfish::Tags.new(tags_list) + end + + def tags_v1 + APICall.new(tags_v1_uri).get_json(http_auth) + end + + def search_v1(keyword) + APICall.new(search_v1_uri(keyword)).get_json(http_auth) + end + + private + + def tags_v1_logic + tags_json = tags_v1 + tags_v1_api(tags_json) + end + + def tags_v1_api(api_response_data) + case api_response_data + when Hash + api_response_data + when Array + api_response_data.reduce({}) do |images, tag| + images.merge({tag["name"] => tag["layer"]}) + end + else + raise "unexpected type #{api_response_data.class}" + end + end + + def ping_uri + "#{base_uri}/v1/_ping" + end + + def search_v1_uri(keyword) + "#{base_uri}/v1/search?q=#{keyword}" + end + + def tags_v1_uri + "#{base_uri}/v1/repositories/#{docker_uri.repository}/tags" + end end end diff --git a/lib/tagfish/docker_registry_v2_client.rb b/lib/tagfish/docker_registry_v2_client.rb index 6244ad2..09be6bb 100644 --- a/lib/tagfish/docker_registry_v2_client.rb +++ b/lib/tagfish/docker_registry_v2_client.rb @@ -6,6 +6,56 @@ class DockerRegistryV2Client < DockerRegistryVbothClient def api_version 'v2' end + + def find_tags_by_repository(tags_only=false) + tags_list = tags_v2_logic(tags_only) + Tagfish::Tags.new(tags_list) + end + + def tags_v2 + APICall.new(tags_v2_uri).get_json(http_auth) + end + + def hash_v2(tag) + APICall.new(hash_v2_uri(tag)).get_json(http_auth) + end + + def catalog_v2 + APICall.new(catalog_v2_uri).get_json(http_auth) + end + private + + def tags_v2_logic(tags_only) + tags = tags_v2["tags"] + if tags.nil? + abort("No Tags found for this repository") + end + + tags_with_hashes = tags.inject({}) do |dict, tag| + if tags_only + dict[tag] = "dummy_hash" + else + dict[tag] = hash_v2(tag)["fsLayers"][0]["blobSum"] + end + dict + end + end + + def ping_uri + "#{base_uri}/v2/" + end + + def catalog_v2_uri + "#{base_uri}/v2/_catalog" + end + + def tags_v2_uri + "#{base_uri}/v2/#{docker_uri.repository}/tags/list" + end + + def hash_v2_uri(tag) + "#{base_uri}/v2/#{docker_uri.repository}/manifests/#{tag}" + end end end diff --git a/lib/tagfish/docker_registry_vboth_client.rb b/lib/tagfish/docker_registry_vboth_client.rb index d16dc88..9fdcf1d 100644 --- a/lib/tagfish/docker_registry_vboth_client.rb +++ b/lib/tagfish/docker_registry_vboth_client.rb @@ -24,110 +24,8 @@ def initialize(docker_uri) end end - def find_tags_by_repository(tags_only=false) - if api_version == 'v2' - tags_list = tags_v2_logic(tags_only) - else - tags_list = tags_v1_logic - end - Tagfish::Tags.new(tags_list) - end - - def tags_v1 - APICall.new(tags_v1_uri).get_json(http_auth) - end - - def tags_v2 - APICall.new(tags_v2_uri).get_json(http_auth) - end - - def hash_v2(tag) - APICall.new(hash_v2_uri(tag)).get_json(http_auth) - end - - def catalog_v2 - APICall.new(catalog_v2_uri).get_json(http_auth) - end - - def search_v1(keyword) - APICall.new(search_v1_uri(keyword)).get_json(http_auth) - end - - private - - def tags_v1_logic - tags_json = tags_v1 - tags_v1_api(tags_json) - end - - def tags_v1_api(api_response_data) - case api_response_data - when Hash - api_response_data - when Array - api_response_data.reduce({}) do |images, tag| - images.merge({tag["name"] => tag["layer"]}) - end - else - raise "unexpected type #{api_response_data.class}" - end - end - - def tags_v2_logic(tags_only) - tags = tags_v2["tags"] - if tags.nil? - abort("No Tags found for this repository") - end - - tags_with_hashes = tags.inject({}) do |dict, tag| - if tags_only - dict[tag] = "dummy_hash" - else - dict[tag] = hash_v2(tag)["fsLayers"][0]["blobSum"] - end - dict - end - end - def base_uri "#{docker_uri.protocol}#{docker_uri.registry}" end - - def ping_uri - if api_version == 'v1' - ping_v1_uri - elsif api_version == 'v2' - ping_v2_uri - end - end - - def ping_v2_uri - "#{base_uri}/v2/" - end - - def ping_v1_uri - "#{base_uri}/v1/_ping" - end - - def catalog_v2_uri - "#{base_uri}/v2/_catalog" - end - - def search_v1_uri(keyword) - "#{base_uri}/v1/search?q=#{keyword}" - end - - def tags_v1_uri - "#{base_uri}/v1/repositories/#{docker_uri.repository}/tags" - end - - def tags_v2_uri - "#{base_uri}/v2/#{docker_uri.repository}/tags/list" - end - - def hash_v2_uri(tag) - "#{base_uri}/v2/#{docker_uri.repository}/manifests/#{tag}" - end - end end From 6b91c98711ae93fb8024cd4302c8c4c62fbfa146 Mon Sep 17 00:00:00 2001 From: clabbe <clement.labbe@rea-group.com> Date: Thu, 25 Feb 2016 15:42:52 +1100 Subject: [PATCH 08/11] Remove references to specific versions in sub-classes --- lib/tagfish/docker_registry_v1_client.rb | 21 +++++++---------- lib/tagfish/docker_registry_v2_client.rb | 30 ++++++++++++------------ 2 files changed, 23 insertions(+), 28 deletions(-) diff --git a/lib/tagfish/docker_registry_v1_client.rb b/lib/tagfish/docker_registry_v1_client.rb index 295b2fd..fa82c56 100644 --- a/lib/tagfish/docker_registry_v1_client.rb +++ b/lib/tagfish/docker_registry_v1_client.rb @@ -8,26 +8,21 @@ def api_version end def find_tags_by_repository(tags_only=false) - tags_list = tags_v1_logic + tags_list = tags_api(tags) Tagfish::Tags.new(tags_list) end - def tags_v1 - APICall.new(tags_v1_uri).get_json(http_auth) + def tags + APICall.new(tags_uri).get_json(http_auth) end - def search_v1(keyword) - APICall.new(search_v1_uri(keyword)).get_json(http_auth) + def search(keyword) + APICall.new(search_uri(keyword)).get_json(http_auth) end private - def tags_v1_logic - tags_json = tags_v1 - tags_v1_api(tags_json) - end - - def tags_v1_api(api_response_data) + def tags_api(api_response_data) case api_response_data when Hash api_response_data @@ -44,11 +39,11 @@ def ping_uri "#{base_uri}/v1/_ping" end - def search_v1_uri(keyword) + def search_uri(keyword) "#{base_uri}/v1/search?q=#{keyword}" end - def tags_v1_uri + def tags_uri "#{base_uri}/v1/repositories/#{docker_uri.repository}/tags" end end diff --git a/lib/tagfish/docker_registry_v2_client.rb b/lib/tagfish/docker_registry_v2_client.rb index 09be6bb..7a187b1 100644 --- a/lib/tagfish/docker_registry_v2_client.rb +++ b/lib/tagfish/docker_registry_v2_client.rb @@ -8,35 +8,35 @@ def api_version end def find_tags_by_repository(tags_only=false) - tags_list = tags_v2_logic(tags_only) + tags_list = tags_logic(tags_only) Tagfish::Tags.new(tags_list) end - def tags_v2 - APICall.new(tags_v2_uri).get_json(http_auth) + def tags + APICall.new(tags_uri).get_json(http_auth) end - def hash_v2(tag) - APICall.new(hash_v2_uri(tag)).get_json(http_auth) + def hash(tag) + APICall.new(hash_uri(tag)).get_json(http_auth) end - def catalog_v2 - APICall.new(catalog_v2_uri).get_json(http_auth) + def catalog + APICall.new(catalog_uri).get_json(http_auth) end private - def tags_v2_logic(tags_only) - tags = tags_v2["tags"] - if tags.nil? + def tags_logic(tags_only) + tag_names = tags["tags"] + if tag_names.nil? abort("No Tags found for this repository") end - tags_with_hashes = tags.inject({}) do |dict, tag| + tags_with_hashes = tag_names.inject({}) do |dict, tag| if tags_only dict[tag] = "dummy_hash" else - dict[tag] = hash_v2(tag)["fsLayers"][0]["blobSum"] + dict[tag] = hash(tag)["fsLayers"][0]["blobSum"] end dict end @@ -46,15 +46,15 @@ def ping_uri "#{base_uri}/v2/" end - def catalog_v2_uri + def catalog_uri "#{base_uri}/v2/_catalog" end - def tags_v2_uri + def tags_uri "#{base_uri}/v2/#{docker_uri.repository}/tags/list" end - def hash_v2_uri(tag) + def hash_uri(tag) "#{base_uri}/v2/#{docker_uri.repository}/manifests/#{tag}" end end From 9244bbc0e61c6c8bfe2a092cbef1cceb4d554e96 Mon Sep 17 00:00:00 2001 From: clabbe <clement.labbe@rea-group.com> Date: Thu, 25 Feb 2016 16:18:39 +1100 Subject: [PATCH 09/11] Introduce tag_map and tag_names --- lib/tagfish/docker_registry_v1_client.rb | 16 ++++++++-------- lib/tagfish/docker_registry_vboth_client.rb | 9 +++++++++ lib/tagfish/tags_command.rb | 5 ++--- lib/tagfish/update/updater.rb | 2 +- 4 files changed, 20 insertions(+), 12 deletions(-) diff --git a/lib/tagfish/docker_registry_v1_client.rb b/lib/tagfish/docker_registry_v1_client.rb index fa82c56..87e3822 100644 --- a/lib/tagfish/docker_registry_v1_client.rb +++ b/lib/tagfish/docker_registry_v1_client.rb @@ -7,21 +7,21 @@ def api_version 'v1' end + def search(keyword) + APICall.new(search_uri(keyword)).get_json(http_auth) + end + + private + def find_tags_by_repository(tags_only=false) tags_list = tags_api(tags) Tagfish::Tags.new(tags_list) end - + def tags APICall.new(tags_uri).get_json(http_auth) end - - def search(keyword) - APICall.new(search_uri(keyword)).get_json(http_auth) - end - - private - + def tags_api(api_response_data) case api_response_data when Hash diff --git a/lib/tagfish/docker_registry_vboth_client.rb b/lib/tagfish/docker_registry_vboth_client.rb index 9fdcf1d..ac9c688 100644 --- a/lib/tagfish/docker_registry_vboth_client.rb +++ b/lib/tagfish/docker_registry_vboth_client.rb @@ -27,5 +27,14 @@ def initialize(docker_uri) def base_uri "#{docker_uri.protocol}#{docker_uri.registry}" end + + def tag_names + find_tags_by_repository(true).tag_names + end + + def tag_map + find_tags_by_repository(false) + end + end end diff --git a/lib/tagfish/tags_command.rb b/lib/tagfish/tags_command.rb index 7383615..25d387a 100644 --- a/lib/tagfish/tags_command.rb +++ b/lib/tagfish/tags_command.rb @@ -13,7 +13,7 @@ def execute docker_api = DockerRegistryClient.for(docker_uri) if latest? - tags = docker_api.find_tags_by_repository(false) + tags = docker_api.tag_map latest_tag = tags.latest_tag if latest_tag.nil? signal_error "No image explicitly tagged in this Repository, " + @@ -21,8 +21,7 @@ def execute end tags_found = [latest_tag] else - tags = docker_api.find_tags_by_repository(true) - tags_found = tags.tag_names + tags_found = docker_api.tag_names end pretty_tags = tags_found.map do |tag_name| diff --git a/lib/tagfish/update/updater.rb b/lib/tagfish/update/updater.rb index e2252d1..a90fe73 100644 --- a/lib/tagfish/update/updater.rb +++ b/lib/tagfish/update/updater.rb @@ -39,7 +39,7 @@ def updatable?(uri) def update_uri(docker_uri) docker_api = DockerRegistryClient.for(docker_uri) - tags = docker_api.find_tags_by_repository + tags = docker_api.tag_map newest_tag_name = tags.latest_tag if newest_tag_name.nil? docker_uri From 117c9b421b1fecea588ddfa625ea1ad3c7bdb60c Mon Sep 17 00:00:00 2001 From: clabbe <clement.labbe@rea-group.com> Date: Thu, 25 Feb 2016 16:22:44 +1100 Subject: [PATCH 10/11] Privatise --- lib/tagfish/docker_registry_v2_client.rb | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/lib/tagfish/docker_registry_v2_client.rb b/lib/tagfish/docker_registry_v2_client.rb index 7a187b1..1ada972 100644 --- a/lib/tagfish/docker_registry_v2_client.rb +++ b/lib/tagfish/docker_registry_v2_client.rb @@ -7,10 +7,11 @@ def api_version 'v2' end - def find_tags_by_repository(tags_only=false) - tags_list = tags_logic(tags_only) - Tagfish::Tags.new(tags_list) + def catalog + APICall.new(catalog_uri).get_json(http_auth) end + + private def tags APICall.new(tags_uri).get_json(http_auth) @@ -20,11 +21,10 @@ def hash(tag) APICall.new(hash_uri(tag)).get_json(http_auth) end - def catalog - APICall.new(catalog_uri).get_json(http_auth) + def find_tags_by_repository(tags_only=false) + tags_list = tags_logic(tags_only) + Tagfish::Tags.new(tags_list) end - - private def tags_logic(tags_only) tag_names = tags["tags"] From 79c23dc5cc12b1be9d65f89776f4305b40a9d536 Mon Sep 17 00:00:00 2001 From: clabbe <clement.labbe@rea-group.com> Date: Thu, 25 Feb 2016 16:30:43 +1100 Subject: [PATCH 11/11] Push tag_names and tag_map into subclasses --- lib/tagfish/docker_registry_v1_client.rb | 8 ++++++-- lib/tagfish/docker_registry_v2_client.rb | 22 ++++++++++----------- lib/tagfish/docker_registry_vboth_client.rb | 8 -------- 3 files changed, 16 insertions(+), 22 deletions(-) diff --git a/lib/tagfish/docker_registry_v1_client.rb b/lib/tagfish/docker_registry_v1_client.rb index 87e3822..e32a9b0 100644 --- a/lib/tagfish/docker_registry_v1_client.rb +++ b/lib/tagfish/docker_registry_v1_client.rb @@ -11,12 +11,16 @@ def search(keyword) APICall.new(search_uri(keyword)).get_json(http_auth) end - private + def tag_names + tag_map.tag_names + end - def find_tags_by_repository(tags_only=false) + def tag_map tags_list = tags_api(tags) Tagfish::Tags.new(tags_list) end + + private def tags APICall.new(tags_uri).get_json(http_auth) diff --git a/lib/tagfish/docker_registry_v2_client.rb b/lib/tagfish/docker_registry_v2_client.rb index 1ada972..9109665 100644 --- a/lib/tagfish/docker_registry_v2_client.rb +++ b/lib/tagfish/docker_registry_v2_client.rb @@ -10,6 +10,14 @@ def api_version def catalog APICall.new(catalog_uri).get_json(http_auth) end + + def tag_names + tags["tags"] + end + + def tag_map + Tagfish::Tags.new(tags_logic) + end private @@ -21,23 +29,13 @@ def hash(tag) APICall.new(hash_uri(tag)).get_json(http_auth) end - def find_tags_by_repository(tags_only=false) - tags_list = tags_logic(tags_only) - Tagfish::Tags.new(tags_list) - end - - def tags_logic(tags_only) - tag_names = tags["tags"] + def tags_logic if tag_names.nil? abort("No Tags found for this repository") end tags_with_hashes = tag_names.inject({}) do |dict, tag| - if tags_only - dict[tag] = "dummy_hash" - else - dict[tag] = hash(tag)["fsLayers"][0]["blobSum"] - end + dict[tag] = hash(tag)["fsLayers"][0]["blobSum"] dict end end diff --git a/lib/tagfish/docker_registry_vboth_client.rb b/lib/tagfish/docker_registry_vboth_client.rb index ac9c688..627f85f 100644 --- a/lib/tagfish/docker_registry_vboth_client.rb +++ b/lib/tagfish/docker_registry_vboth_client.rb @@ -28,13 +28,5 @@ def base_uri "#{docker_uri.protocol}#{docker_uri.registry}" end - def tag_names - find_tags_by_repository(true).tag_names - end - - def tag_map - find_tags_by_repository(false) - end - end end