Class: DockerRegistry2::Registry
- Inherits:
-
Object
- Object
- DockerRegistry2::Registry
- Defined in:
- lib/plankton/monkey_patches.rb
Overview
Monkey patch the DockerRegistry2::Registry issues away.
Things that are broken by default:
-
pull
Things that are not ideal:
-
Tons of round trips while auth probing (again, and again, and again..)
-
Tons of round trips to always get a “fresh” JWT token
-
Performance
See: docs.docker.com/registry/spec/api See: github.com/gitlabhq/gitlabhq/tree/v10.0.0/lib/container_registry
Instance Method Summary collapse
-
#authenticate_bearer(header) ⇒ Object
Speed up processing, by memorizing the JWT token for the given header.
-
#blob(repo, digest, file) ⇒ Object
Download a blob to a opened IO handle.
-
#do_basic_req(type, url, stream = nil) ⇒ Object
Save the auth type as basic, when the very first (ping) request was successful.
-
#do_bearer_req(type, url, header, stream = nil) ⇒ Object
Save the auth type as bearer, when the very first (ping) request was successful.
-
#doreq(type, url, stream = nil) ⇒ Object
# Speed up the system by memorize the probed auth type.
-
#initialize(uri, options = {}) ⇒ Registry
constructor
A new instance of Registry.
-
#manifest(repo:, tag:) ⇒ Object
Do it the same way as the original, but return a OpenStruct because its easy to work with.
- #orig_authenticate_bearer ⇒ Object
- #orig_do_basic_req ⇒ Object
- #orig_do_bearer_req ⇒ Object
- #orig_doreq ⇒ Object
-
#orig_initialize ⇒ Object
All these methods are useful, but needs some improvements from outer space.
- #orig_rmtag ⇒ Object
-
#pull(repo:, tag:, dir:) ⇒ Object
Pull all layers of a given tag.
-
#rmtag(repo:, tag: nil, digest: nil) ⇒ Object
Sometimes it is handy do delete a tag by its name, sometimes it is handy to delete a tag by its digest.
-
#tag(repo:, tag:) ⇒ Object
Fetch details about a tag.
-
#tags(repo:, details: false, limit: 20) ⇒ Object
Fetch all tags of a repository, with the possibility to fetch all their details as well.
Constructor Details
#initialize(uri, options = {}) ⇒ Registry
Returns a new instance of Registry.
27 28 29 30 |
# File 'lib/plankton/monkey_patches.rb', line 27 def initialize(uri, = {}) @verbose = .key?(:verbose) ? [:verbose] : false orig_initialize(uri, ) end |
Instance Method Details
#authenticate_bearer(header) ⇒ Object
Speed up processing, by memorizing the JWT token for the given header.
34 35 36 37 |
# File 'lib/plankton/monkey_patches.rb', line 34 def authenticate_bearer(header) @token ||= {} @token[header] ||= orig_authenticate_bearer(header) end |
#blob(repo, digest, file) ⇒ Object
Download a blob to a opened IO handle.
77 78 79 |
# File 'lib/plankton/monkey_patches.rb', line 77 def blob(repo, digest, file) doreq('get', "/v2/#{repo}/blobs/#{digest}", file) end |
#do_basic_req(type, url, stream = nil) ⇒ Object
Save the auth type as basic, when the very first (ping) request was successful.
41 42 43 44 45 |
# File 'lib/plankton/monkey_patches.rb', line 41 def do_basic_req(type, url, stream = nil) res = orig_do_basic_req(type, url, stream) @auth ||= :basic res end |
#do_bearer_req(type, url, header, stream = nil) ⇒ Object
Save the auth type as bearer, when the very first (ping) request was successful.
49 50 51 52 53 54 |
# File 'lib/plankton/monkey_patches.rb', line 49 def do_bearer_req(type, url, header, stream = nil) res = orig_do_bearer_req(type, url, header, stream) @auth ||= :bearer @header = header res end |
#doreq(type, url, stream = nil) ⇒ Object
# Speed up the system by memorize the probed auth type.
57 58 59 60 61 62 63 64 |
# File 'lib/plankton/monkey_patches.rb', line 57 def doreq(type, url, stream = nil) puts "[#{type.upcase}] #{@base_uri}#{url}" if @verbose return orig_do_basic_req(type, url, stream) if @auth == :basic return orig_do_bearer_req(type, url, @header, stream) if @auth == :bearer orig_doreq(type, url, stream) rescue DockerRegistry2::RegistryAuthenticationException orig_doreq(type, url, stream) end |
#manifest(repo:, tag:) ⇒ Object
Do it the same way as the original, but return a OpenStruct because its easy to work with.
68 69 70 71 72 73 74 |
# File 'lib/plankton/monkey_patches.rb', line 68 def manifest(repo:, tag:) res = doget("/v2/#{repo}/manifests/#{tag}") digest = res.headers[:docker_content_digest] res = RecursiveOpenStruct.new(JSON.parse(res), recurse_over_arrays: true) res.digest = digest res end |
#orig_authenticate_bearer ⇒ Object
18 |
# File 'lib/plankton/monkey_patches.rb', line 18 alias_method :orig_authenticate_bearer, :authenticate_bearer |
#orig_do_basic_req ⇒ Object
19 |
# File 'lib/plankton/monkey_patches.rb', line 19 alias_method :orig_do_basic_req, :do_basic_req |
#orig_do_bearer_req ⇒ Object
20 |
# File 'lib/plankton/monkey_patches.rb', line 20 alias_method :orig_do_bearer_req, :do_bearer_req |
#orig_doreq ⇒ Object
21 |
# File 'lib/plankton/monkey_patches.rb', line 21 alias_method :orig_doreq, :doreq |
#orig_initialize ⇒ Object
All these methods are useful, but needs some improvements from outer space.
16 |
# File 'lib/plankton/monkey_patches.rb', line 16 alias_method :orig_initialize, :initialize |
#orig_rmtag ⇒ Object
17 |
# File 'lib/plankton/monkey_patches.rb', line 17 alias_method :orig_rmtag, :rmtag |
#pull(repo:, tag:, dir:) ⇒ Object
Pull all layers of a given tag.
82 83 84 85 86 87 88 89 90 91 92 |
# File 'lib/plankton/monkey_patches.rb', line 82 def pull(repo:, tag:, dir:) # make sure the directory exists FileUtils::mkdir_p(dir) # pull each of the layers manifest(repo: repo, tag: tag).layers.each do |layer| # make sure the layer does not exist first unless File.file? "#{dir}/#{layer.digest}" blob(repo, layer.digest, File.new("#{dir}/#{layer.digest}", 'w+')) end end end |
#rmtag(repo:, tag: nil, digest: nil) ⇒ Object
Sometimes it is handy do delete a tag by its name, sometimes it is handy to delete a tag by its digest. The digest variant is faster due no lookup have to be done.
128 129 130 131 132 |
# File 'lib/plankton/monkey_patches.rb', line 128 def rmtag(repo:, tag: nil, digest: nil) raise 'No tag or digest was given' if tag.nil? && digest.nil? return orig_rmtag(repo, tag) unless tag.nil? dodelete("/v2/#{repo}/manifests/#{digest}").code end |
#tag(repo:, tag:) ⇒ Object
Fetch details about a tag.
95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 |
# File 'lib/plankton/monkey_patches.rb', line 95 def tag(repo:, tag:) # Create new string IO handle config_input = StringIO.new # Download the manifest for the tag manifest = manifest(repo: repo, tag: tag) # Download the config blob for the tag blob(repo, manifest.config.digest, config_input) # Parse the JSON input config = RecursiveOpenStruct.new(JSON.parse(config_input.string)) created = DateTime.parse(config.created) layer_size = manifest.layers.reduce(0) { |sum, l| sum + l.size } # Pass back all the detailed information OpenStruct.new(tag: tag, digest: manifest.digest, created_at: created, layer_size: layer_size, config: config, manifest: manifest) end |
#tags(repo:, details: false, limit: 20) ⇒ Object
Fetch all tags of a repository, with the possibility to fetch all their details as well.
117 118 119 120 121 122 123 |
# File 'lib/plankton/monkey_patches.rb', line 117 def (repo:, details: false, limit: 20) unless details res = JSON.parse(doget("/v2/#{repo}/tags/list?n=#{limit}")) return RecursiveOpenStruct.new(res). || [] end (repo: repo).map { |tag| tag(repo: repo, tag: tag) } end |