Project

General

Profile

Download (2.66 KB) Statistics
| Branch: | Tag: | Revision:

foreman_docker / app / models / service / registry_api.rb @ f6a9acbd

1
module Service
2
  class RegistryApi
3
    DOCKER_HUB = 'https://registry.hub.docker.com/'.freeze
4
    DEFAULTS = {
5
      url: 'http://localhost:5000'.freeze,
6
      connection: { omit_default_port: true }
7
    }
8

    
9
    attr_accessor :config, :url
10
    delegate :logger, :to => Rails
11

    
12
    def initialize(params = {})
13
      self.config = DEFAULTS.merge(params)
14
      self.url = config[:url]
15
      @user = config[:user] unless config[:user].blank?
16
      @password = config[:password] unless config[:password].blank?
17

    
18
      Docker.logger = logger if Rails.env.development? || Rails.env.test?
19
    end
20

    
21
    def connection
22
      @connection ||= ::Docker::Connection.new(url, credentials)
23
    end
24

    
25
    def get(path, params = nil)
26
      response = connection.get('/'.freeze, params,
27
                                DEFAULTS[:connection].merge({ path: "#{path}" }))
28
      response = parse_json(response)
29
      response
30
    end
31

    
32
    # Since the Registry API v2 does not support a search the v1 endpoint is used
33
    # Newer registries will fail, the v2 catalog endpoint is used
34
    def search(query)
35
      get('/v1/search'.freeze, { q: query })
36
    rescue => e
37
      logger.warn "API v1 - Search failed #{e.backtrace}"
38
      { 'results' => catalog(query) }
39
    end
40

    
41
    # Some Registries might have this endpoint not implemented/enabled
42
    def catalog(query)
43
      get('/v2/_catalog'.freeze)['repositories'].select do |image|
44
        image =~ /^#{query}/
45
      end.map { |image_name| { 'name' => image_name } }
46
    end
47

    
48
    def tags(image_name, query = nil)
49
      result = get_tags(image_name)
50
      result = result.keys.map { |t| {'name' => t.to_s } } if result.is_a? Hash
51
      result = filter_tags(result, query) if query
52
      result
53
    end
54

    
55
    def ok?
56
      get('/v1/'.freeze).match("Docker Registry API")
57
    rescue => e
58
      logger.warn "API v1 - Ping failed #{e.backtrace}"
59
      get('/v2/'.freeze).is_a? Hash
60
    end
61

    
62
    def self.docker_hub
63
      @@docker_hub ||= new(url: DOCKER_HUB)
64
    end
65

    
66
    private
67

    
68
    def parse_json(string)
69
      JSON.parse(string)
70
    rescue => e
71
      logger.warn "JSON parsing failed: #{e.backtrace}"
72
      string
73
    end
74

    
75
    def get_tags(image_name)
76
      get("/v1/repositories/#{image_name}/tags")
77
    rescue => e
78
      logger.warn "API v1 - Repository images request failed #{e.backtrace}"
79
      tags_v2(image_name)
80
    end
81

    
82
    def tags_v2(image_name)
83
      get("/v2/#{image_name}/tags/list")['tags'].map { |tag| { 'name' => tag } }
84
    rescue Docker::Error::NotFoundError
85
      []
86
    end
87

    
88
    def credentials
89
      { user: @user, password: @password }
90
    end
91

    
92
    def filter_tags(result, query)
93
      result.select do |tag_name|
94
        tag_name['name'] =~ /^#{query}/
95
      end
96
    end
97
  end
98
end