summaryrefslogtreecommitdiff
path: root/lib/container_registry
diff options
context:
space:
mode:
authorKamil Trzcinski <ayufan@ayufan.eu>2016-05-09 22:14:46 +0300
committerKamil Trzcinski <ayufan@ayufan.eu>2016-05-09 22:14:46 +0300
commit08396be619eee2e71c2f5f7aa27eea6f5ddf10ff (patch)
tree57377cb67bcc8e9eb9d221e24f167485f3e1ed11 /lib/container_registry
parent565a5e36fc456831fd08e0627a936855d87eb932 (diff)
downloadgitlab-ce-08396be619eee2e71c2f5f7aa27eea6f5ddf10ff.tar.gz
Rename ImageRegistry to ContainerRegistry
Diffstat (limited to 'lib/container_registry')
-rw-r--r--lib/container_registry/blob.rb51
-rw-r--r--lib/container_registry/client.rb64
-rw-r--r--lib/container_registry/config.rb15
-rw-r--r--lib/container_registry/registry.rb14
-rw-r--r--lib/container_registry/repository.rb55
-rw-r--r--lib/container_registry/tag.rb75
6 files changed, 274 insertions, 0 deletions
diff --git a/lib/container_registry/blob.rb b/lib/container_registry/blob.rb
new file mode 100644
index 00000000000..e0d9923f217
--- /dev/null
+++ b/lib/container_registry/blob.rb
@@ -0,0 +1,51 @@
+module ContainerRegistry
+ class Blob
+ attr_reader :repository, :config
+
+ def initialize(repository, config)
+ @repository = repository
+ @config = config || {}
+ end
+
+ def valid?
+ digest.present?
+ end
+
+ def digest
+ config['digest']
+ end
+
+ def type
+ config['mediaType']
+ end
+
+ def size
+ config['size']
+ end
+
+ def revision
+ digest.split(':')[1]
+ end
+
+ def short_revision
+ revision[0..8]
+ end
+
+ def client
+ @client ||= repository.client
+ end
+
+ def delete
+ client.delete_blob(repository.name, digest)
+ end
+
+ def data
+ return @data if defined?(@data)
+ @data ||= client.blob(repository.name, digest, type)
+ end
+
+ def mount_to(to_repository)
+ client.repository_mount_blob(to_repository.name, digest, repository.name)
+ end
+ end
+end
diff --git a/lib/container_registry/client.rb b/lib/container_registry/client.rb
new file mode 100644
index 00000000000..b823428344b
--- /dev/null
+++ b/lib/container_registry/client.rb
@@ -0,0 +1,64 @@
+require 'faraday'
+require 'faraday_middleware'
+
+module ContainerRegistry
+ class Client
+ attr_accessor :uri
+
+ MANIFEST_VERSION = 'application/vnd.docker.distribution.manifest.v2+json'
+
+ def initialize(base_uri, options = {})
+ @base_uri = base_uri
+ @faraday = Faraday.new(@base_uri) do |builder|
+ builder.request :json
+ builder.headers['Accept'] = MANIFEST_VERSION
+
+ builder.response :json, :content_type => /\bjson$/
+ builder.response :json, :content_type => 'application/vnd.docker.distribution.manifest.v1+prettyjws'
+
+ if options[:user] && options[:password]
+ builder.request(:basic_auth, options[:user].to_s, options[:password].to_s)
+ elsif options[:token]
+ builder.request(:authorization, :bearer, options[:token].to_s)
+ end
+
+ builder.adapter :net_http
+ end
+ end
+
+ def repository_tags(name)
+ @faraday.get("/v2/#{name}/tags/list").body
+ end
+
+ def repository_manifest(name, reference)
+ @faraday.get("/v2/#{name}/manifests/#{reference}").body
+ end
+
+ def put_repository_manifest(name, reference, manifest)
+ @faraday.put("/v2/#{name}/manifests/#{reference}", manifest, { "Content-Type" => MANIFEST_VERSION }).success?
+ end
+
+ def repository_mount_blob(name, digest, from)
+ @faraday.post("/v2/#{name}/blobs/uploads/?mount=#{digest}&from=#{from}").status == 201
+ end
+
+ def repository_tag_digest(name, reference)
+ response = @faraday.head("/v2/#{name}/manifests/#{reference}")
+ response.headers['docker-content-digest'] if response.success?
+ end
+
+ def delete_repository_tag(name, reference)
+ @faraday.delete("/v2/#{name}/manifests/#{reference}").success?
+ end
+
+ def blob(name, digest, type = nil)
+ headers = {}
+ headers['Accept'] = type if type
+ @faraday.get("/v2/#{name}/blobs/#{digest}", nil, headers).body
+ end
+
+ def delete_blob(name, digest)
+ @faraday.delete("/v2/#{name}/blobs/#{digest}").success?
+ end
+ end
+end
diff --git a/lib/container_registry/config.rb b/lib/container_registry/config.rb
new file mode 100644
index 00000000000..626b36cbaa9
--- /dev/null
+++ b/lib/container_registry/config.rb
@@ -0,0 +1,15 @@
+module ContainerRegistry
+ class Config
+ attr_reader :tag, :blob, :data
+
+ def initialize(tag, blob)
+ @tag, @blob = tag, blob
+ @data = JSON.parse(blob.data)
+ end
+
+ def [](key)
+ return unless data
+ data[key]
+ end
+ end
+end
diff --git a/lib/container_registry/registry.rb b/lib/container_registry/registry.rb
new file mode 100644
index 00000000000..f866862db22
--- /dev/null
+++ b/lib/container_registry/registry.rb
@@ -0,0 +1,14 @@
+module ContainerRegistry
+ class Registry
+ attr_reader :uri, :client
+
+ def initialize(uri, options = {})
+ @uri = URI.parse(uri)
+ @client = ContainerRegistry::Client.new(uri, options)
+ end
+
+ def [](name)
+ ContainerRegistry::Repository.new(self, name)
+ end
+ end
+end
diff --git a/lib/container_registry/repository.rb b/lib/container_registry/repository.rb
new file mode 100644
index 00000000000..c930878d265
--- /dev/null
+++ b/lib/container_registry/repository.rb
@@ -0,0 +1,55 @@
+module ContainerRegistry
+ class Repository
+ attr_reader :registry, :name
+
+ def initialize(registry, name)
+ @registry, @name = registry, name
+ end
+
+ def client
+ @client ||= registry.client
+ end
+
+ def [](tag)
+ ContainerRegistry::Tag.new(self, tag)
+ end
+
+ def manifest
+ return @manifest if defined?(@manifest)
+ @manifest = client.repository_tags(name)
+ end
+
+ def valid?
+ manifest.present?
+ end
+
+ def tags
+ return @tags if defined?(@tags)
+ return [] unless manifest && manifest['tags']
+ @tags = manifest['tags'].map do |tag|
+ ContainerRegistry::Tag.new(self, tag)
+ end
+ @tags ||= []
+ end
+
+ def delete_tags
+ return unless tags
+ tags.each(:delete)
+ end
+
+ def mount_blob(blob)
+ return unless blob
+ client.repository_mount_blob(name, blob.digest, blob.repository.name)
+ end
+
+ def mount_manifest(tag, manifest)
+ client.put_repository_manifest(name, tag, manifest)
+ end
+
+ def copy_to(other_repository)
+ tags.all? do |tag|
+ tag.copy_to(other_repository)
+ end
+ end
+ end
+end
diff --git a/lib/container_registry/tag.rb b/lib/container_registry/tag.rb
new file mode 100644
index 00000000000..324778bdf2a
--- /dev/null
+++ b/lib/container_registry/tag.rb
@@ -0,0 +1,75 @@
+module ContainerRegistry
+ class Tag
+ attr_reader :repository, :name
+
+ def initialize(repository, name)
+ @repository, @name = repository, name
+ end
+
+ def valid?
+ manifest.present?
+ end
+
+ def manifest
+ return @manifest if defined?(@manifest)
+ @manifest = client.repository_manifest(repository.name, name)
+ end
+
+ def [](key)
+ return unless manifest
+ manifest[key]
+ end
+
+ def digest
+ return @digest if defined?(@digest)
+ @digest = client.repository_tag_digest(repository.name, name)
+ end
+
+ def config_blob
+ return @config_blob if defined?(@config_blob)
+ return unless manifest && manifest['config']
+ @config_blob = ContainerRegistry::Blob.new(repository, manifest['config'])
+ end
+
+ def config
+ return unless config_blob
+ @config ||= ContainerRegistry::Config.new(self, config_blob)
+ end
+
+ def created_at
+ return unless config
+ @created_at ||= DateTime.rfc3339(config['created'])
+ end
+
+ def layers
+ return @layers if defined?(@layers)
+ return unless manifest
+ @layers = manifest['layers'].map do |layer|
+ ContainerRegistry::Blob.new(repository, layer)
+ end
+ end
+
+ def total_size
+ return unless layers
+ layers.map(&:size).sum
+ end
+
+ def delete
+ return unless digest
+ client.delete_repository_tag(repository.name, digest)
+ end
+
+ def copy_to(repository)
+ return unless manifest
+ layers.each do |blob|
+ repository.mount_blob(blob)
+ end
+ repository.mount_blob(config_blob)
+ repository.mount_manifest(name, manifest.to_json)
+ end
+
+ def client
+ @client ||= repository.client
+ end
+ end
+end