Project

General

Profile

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

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

1
require 'uri'
2

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

    
7
    validates :url, :format => { :with => URI.regexp }
8

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

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

    
18
    def capabilities
19
      []
20
    end
21

    
22
    def supports_update?
23
      false
24
    end
25

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

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

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

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

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

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

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

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

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

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

    
77
    def provider_friendly_name
78
      'Docker'
79
    end
80

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

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

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

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

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

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

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

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

    
133
    protected
134

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

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

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

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