require 'picsolve_docker_builder/base' require 'excon' require 'json' require 'base64' module PicsolveDockerBuilder module Helpers # This represents a remote registry, that is queried for # for informations about images class Registry include PicsolveDockerBuilder::Base attr_reader :config def initialize(registry) @registry = registry end def api_version_unsupported fail 'No supported version found at registry' end def api_version return @api_version unless @api_version.nil? if connection.get(path: '/v2/').status == 200 @api_version = :v2 elsif connection.get(path: '/v1/_ping').status == 200 @api_version = :v1 else api_version_unsupported end log.info "Detected api version #{@api_version} on registry #{@registry}" @api_version end def list_tags_v1(image) endpoint = "/v1/repositories/#{image}/tags" r = connection.get(path: endpoint) JSON.parse(r.body) end def list_tags_v2(image) endpoint = "/v2/#{image}/tags/list" r = connection.get(path: endpoint) o = {} JSON.parse(r.body)['tags'].each do |tag| endpoint = "/v2/#{image}/manifests/#{tag}" r = connection.get(path: endpoint) digest = Digest::SHA2.new(256) JSON.parse(r.body)['fsLayers'].each do |fs_hash| digest.update(fs_hash['blobSum']) end o[tag] = digest.to_s end o end def unique_tag(image, tag) tags = list_tags(image) fail "tag '#{tag}' not found" unless tags.include? tag tags.each do |my_tag, hash| # next if not right name next unless my_tag.match(/^jenkins-/) # next hash not matching next if hash != tags[tag] # return tag name now return my_tag end fail "no unique tag found for tag=#{tag}" end def list_tags(image) if api_version == :v1 list_tags_v1(image) elsif api_version == :v2 list_tags_v2(image) else api_version_unsupported end end def http_host URI(@registry).host end def headers { 'Host' => http_host } end def connection @connection ||= Excon.new( @registry, headers: headers ) end def self.dockercfg_path File.expand_path '~/.dockercfg' end def self.dockercfg JSON.parse( File.open( dockercfg_path ).read ) end def self.creds(*args) auth = Base64.decode64( get_login_basic( *args ) ).split(':') { 'username' => auth[0], 'password' => auth[1] } end def self.get_login_basic(registry = 'docker.picsolve.net') dockercfg[registry]['auth'] rescue StandardError nil end def self.repo_tag_unique(image_name) repo_tag = image_name.split(%r{/})[1..-1].join('/') repo_tag_split = repo_tag.split(/:/) repo = repo_tag_split[0] tag = repo_tag_split[1] || 'latest' headers = {} login_basic = get_login_basic headers['Authorization'] = "Basic #{login_basic}" \ unless login_basic.nil? connection = Excon.new( 'https://docker.picsolve.net', headers: headers, persistent: true ) response = connection.get(path: "/v1/repositories/#{repo}/tags") tags = JSON.parse(response.body) hash = tags[tag] tags.each do |t, h| next if h != hash next if t == tag next unless t.match(/jenkins-[0-9]+/) return { tag_unique: "#{image_name.split(':').first}:#{t}", hash: hash } end fail "Can not find a uniqe tag for #{image_name}" end end end end