require 'picsolve_docker_builder/base' require 'excon' require 'json' require 'base64' require 'picsolve_docker_builder/helpers/repository' 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 self.creds(image = nil) if image.nil? registry = 'https://docker.picsolve.net' else registry = "https://#{image.split('/')[0]}" end new(registry).creds end 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) base_url = "/v1/repositories/#{image.user}/#{image.repo}" endpoint = "#{base_url}/tags" r = connection.get(path: endpoint) JSON.parse(r.body) end def list_tags_v2(image) base_url = "/v2/#{image.user}/#{image.repo}" endpoint = "#{base_url}/tags/list" r = connection.get(path: endpoint) o = {} JSON.parse(r.body)['tags'].each do |tag| endpoint = "#{base_url}/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) image = Repository.new 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, 'Authorization' => "Basic #{login_basic}" } end def connection @connection ||= Excon.new( @registry, headers: headers ) end def dockercfg_path File.expand_path '~/.dockercfg' end def dockercfg JSON.parse( File.open( dockercfg_path ).read ) end def creds auth = Base64.decode64(login_basic).split(':') { 'username' => auth[0], 'password' => auth[1] } end def login_basic dockercfg[http_host]['auth'] rescue StandardError nil end end end end