Project

General

Profile

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

foreman_docker / app / models / foreman_docker / docker.rb @ bc82d5d5

1
require 'uri'
2

    
3
module ForemanDocker
4
  class Docker < ::ComputeResource
5
    validates :url, :format => { :with => URI.regexp }
6

    
7
    def self.model_name
8
      ComputeResource.model_name
9
    end
10

    
11
    def self.get_container(container)
12
      conn = container.compute_resource.docker_connection
13
      ::Docker::Container.get(container.uuid, {}, conn)
14
    end
15

    
16
    def capabilities
17
      [:image]
18
    end
19

    
20
    def supports_update?
21
      false
22
    end
23

    
24
    def provided_attributes
25
      super.merge(:mac => :mac)
26
    end
27

    
28
    def max_memory
29
      16 * 1024 * 1024 * 1024
30
    end
31

    
32
    def max_cpu_count
33
      ::Docker.info['NCPU'] || 1
34
    end
35

    
36
    def available_images
37
      ::Docker::Image.all({}, docker_connection)
38
    end
39

    
40
    def local_images(filter = '')
41
      ::Docker::Image.all({ 'filter' => filter }, docker_connection)
42
    end
43

    
44
    def tags_for_local_image(image)
45
      image.info['RepoTags'].map do |image_tag|
46
        _, tag = image_tag.split(':')
47
        tag
48
      end
49
    end
50

    
51
    def exist?(name)
52
      ::Docker::Image.exist?(name, {}, docker_connection)
53
    end
54

    
55
    def image(id)
56
      ::Docker::Image.get(id, {}, docker_connection)
57
    end
58

    
59
    def tags(image_name)
60
      if exist?(image_name)
61
        tags_for_local_image(local_images(image_name).first)
62
      else
63
        # If image is not found in the compute resource, get the tags from the Hub
64
        hub_api_url = "https://index.docker.io/v1/repositories/#{image_name}/tags"
65
        JSON.parse(URI.parse(hub_api_url).read).map do |tag|
66
          tag['name']
67
        end
68
      end
69
    end
70

    
71
    def search(term = '')
72
      client.images.image_search(:term => term)
73
    end
74

    
75
    def provider_friendly_name
76
      'Docker'
77
    end
78

    
79
    def create_container(args = {})
80
      options = vm_instance_defaults.merge(args)
81
      logger.debug("Creating container with the following options: #{options.inspect}")
82
      docker_command do
83
        ::Docker::Container.create(options, docker_connection)
84
      end
85
    end
86

    
87
    def create_image(args = {})
88
      logger.debug("Creating docker image with the following options: #{args.inspect}")
89
      docker_command do
90
        ::Docker::Image.create(args, credentials, docker_connection)
91
      end
92
    end
93

    
94
    def vm_instance_defaults
95
      ActiveSupport::HashWithIndifferentAccess.new('name' => "foreman_#{Time.now.to_i}",
96
                                                   'Cmd' => ['/bin/bash'])
97
    end
98

    
99
    def console(uuid)
100
      test_connection
101
      container = ::Docker::Container.get(uuid, {}, docker_connection)
102
      {
103
        :name       => container.info['Name'],
104
        'timestamp' => Time.now.utc,
105
        'output'    => container.logs(:stdout => true, :tail => 100)
106
      }
107
    end
108

    
109
    def api_version
110
      ::Docker.version(docker_connection)
111
    end
112

    
113
    def authenticate!
114
      ::Docker.authenticate!(credentials, docker_connection)
115
    end
116

    
117
    def test_connection(options = {})
118
      super
119
      api_version
120
      credentials.empty? ? true : authenticate!
121
    # This should only rescue Fog::Errors, but Fog returns all kinds of errors...
122
    rescue => e
123
      errors[:base] << e.message
124
      false
125
    end
126

    
127
    def docker_connection
128
      @docker_connection ||= ::Docker::Connection.new(url, credentials)
129
    end
130

    
131
    protected
132

    
133
    def docker_command
134
      yield
135
    rescue Excon::Errors::Error, ::Docker::Error::DockerError => e
136
      logger.debug "Fog error: #{e.message}\n " + e.backtrace.join("\n ")
137
      errors.add(:base,
138
                 _("Error creating communicating with Docker. Check the Foreman logs: %s") %
139
                 e.message.to_s)
140
      false
141
    end
142

    
143
    def bootstrap(args)
144
      client.servers.bootstrap vm_instance_defaults.merge(args.to_hash)
145
    rescue Fog::Errors::Error => e
146
      errors.add(:base, e.to_s)
147
      false
148
    end
149

    
150
    def client
151
      opts = {
152
        :provider => 'fogdocker',
153
        :docker_url => url
154
      }
155
      opts[:docker_username] = user if user.present?
156
      opts[:docker_password] = password if password.present?
157
      opts[:docker_email] = email if email.present?
158
      @client ||= ::Fog::Compute.new(opts)
159
    end
160

    
161
    def credentials
162
      @credentials ||= {}.tap do |options|
163
        options[:username] = user if user.present?
164
        options[:password] = password if password.present?
165
        options[:email] = email if email.present?
166
      end
167
    end
168
  end
169
end