Project

General

Profile

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

foreman-docker / app / models / foreman_docker / docker.rb @ 977f7c5a

1
require 'uri'
2

    
3
module ForemanDocker
4
  class Docker < ::ComputeResource
5
    attr_accessible :email
6

    
7
    validates :url, :format => { :with => URI.regexp }
8
    validates :email, :format => { :with => /.+@.+\..+/i }, :allow_blank => true
9

    
10
    def self.model_name
11
      ComputeResource.model_name
12
    end
13

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

    
19
    def capabilities
20
      []
21
    end
22

    
23
    def supports_update?
24
      false
25
    end
26

    
27
    def provided_attributes
28
      super.merge(:mac => :mac)
29
    end
30

    
31
    def max_memory
32
      16 * 1024 * 1024 * 1024
33
    end
34

    
35
    def max_cpu_count
36
      ::Docker.info['NCPU'] || 1
37
    end
38

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

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

    
47
    def tags_for_local_image(image)
48
      image.info['RepoTags'].map do |image_tag|
49
        _, tag = image_tag.split(':')
50
        tag
51
      end
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(local_images(image_name).first)
65
      else
66
        # If image is not found in the compute resource, get the tags from the Hub
67
        hub_api_url = "https://index.docker.io/v1/repositories/#{image_name}/tags"
68
        JSON.parse(URI.parse(hub_api_url).read).map do |tag|
69
          tag['name']
70
        end
71
      end
72
    end
73

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

    
78
    def provider_friendly_name
79
      'Docker'
80
    end
81

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

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

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

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

    
112
    def api_version
113
      ::Docker.version(docker_connection)
114
    end
115

    
116
    def authenticate!
117
      ::Docker.authenticate!(credentials, docker_connection)
118
    end
119

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

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

    
134
    protected
135

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

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

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

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