Project

General

Profile

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

foreman-docker / app / models / foreman_docker / docker.rb @ cc6d0d73

1
require 'uri'
2

    
3
module ForemanDocker
4
  class Docker < ::ComputeResource
5
    validates :url, :format => { :with => URI.regexp }
6
    validates :email, :format => { :with => /.+@.+\..+/i }, :allow_blank => true
7

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

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

    
17
    def capabilities
18
      []
19
    end
20

    
21
    def supports_update?
22
      false
23
    end
24

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

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

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

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

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

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

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

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

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

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

    
76
    def provider_friendly_name
77
      'Docker'
78
    end
79

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

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

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

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

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

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

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

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

    
132
    protected
133

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

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

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

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