Project

General

Profile

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

foreman_docker / app / models / foreman_docker / docker.rb @ 329cfcba

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, tag = nil)
46
      result = image.info['RepoTags'].map do |image_tag|
47
        _, tag = image_tag.split(':')
48
        tag
49
      end
50
      result = filter_tags(result, tag) if tag
51
      result
52
    end
53

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

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

    
62
    def tags(image_name)
63
      if exist?(image_name)
64
        tags_for_local_image(image(image_name))
65
      else
66
        Service::RegistryApi.docker_hub.tags(image_name).map { |tag| tag['name'] }
67
      end
68
    end
69

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

    
74
    def provider_friendly_name
75
      'Docker'
76
    end
77

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

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

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

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

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

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

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

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

    
130
    protected
131

    
132
    def filter_tags(result, query)
133
      result.select do |tag_name|
134
        tag_name['name'] =~ /^#{query}/
135
      end
136
    end
137

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

    
148
    def bootstrap(args)
149
      client.servers.bootstrap vm_instance_defaults.merge(args.to_hash)
150
    rescue Fog::Errors::Error => e
151
      errors.add(:base, e.to_s)
152
      false
153
    end
154

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

    
166
    def credentials
167
      @credentials ||= {}.tap do |options|
168
        options[:username] = user if user.present?
169
        options[:password] = password if password.present?
170
        options[:email] = email if email.present?
171
      end
172
    end
173
  end
174
end