Class: Dockly::Docker

Inherits:
Object
  • Object
show all
Includes:
Util::DSL, Util::Logger::Mixin
Defined in:
lib/dockly/docker.rb

Defined Under Namespace

Classes: Registry

Instance Method Summary collapse

Instance Method Details

#add_git_archive(image) ⇒ Object



144
145
146
147
148
149
150
151
152
153
# File 'lib/dockly/docker.rb', line 144

def add_git_archive(image)
  return image if git_archive.nil?
  info "adding the git archive"
  new_image = image.insert_local(
    'localPath' => git_archive_tar,
    'outputPath' => '/'
  )
  info "successfully added the git archive"
  new_image
end

#build_image(image) ⇒ Object



155
156
157
158
159
160
161
# File 'lib/dockly/docker.rb', line 155

def build_image(image)
  ensure_present! :name, :build
  info "running custom build steps, starting with id: #{image.id}"
  out_image = ::Docker::Image.build("from #{image.id}\n#{build}")
  info "finished running custom build steps, result id: #{out_image.id}"
  out_image.tap { |img| img.tag(:repo => repo, :tag => tag) }
end

#cleanup(images) ⇒ Object



67
68
69
70
71
72
73
74
75
76
77
78
# File 'lib/dockly/docker.rb', line 67

def cleanup(images)
  info 'Cleaning up intermediate images'
  ::Docker::Container.all(:all => true).each do |container|
    image_id = container.json['Image']
    if images.any? { |image| image.id.start_with?(image_id) || image_id.start_with?(image.id) }
      container.kill
      container.delete
    end
  end
  images.each { |image| image.remove rescue nil }
  info 'Done cleaning images'
end

#ensure_tar(file_name) ⇒ Object



98
99
100
101
102
103
104
105
106
# File 'lib/dockly/docker.rb', line 98

def ensure_tar(file_name)
  if Dockly::Util::Tar.is_tar?(file_name)
    file_name
  elsif Dockly::Util::Tar.is_gzip?(file_name)
    file_name
  else
    raise "Expected a (possibly gzipped) tar: #{file_name}"
  end
end

#export_filenameObject



80
81
82
# File 'lib/dockly/docker.rb', line 80

def export_filename
  "#{name}-image.tgz"
end

#export_image(image) ⇒ Object



174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
# File 'lib/dockly/docker.rb', line 174

def export_image(image)
  ensure_present! :name
  if registry.nil?
    ensure_present! :build_dir
    info "Exporting the image with id #{image.id} to file #{File.expand_path(tar_path)}"
    container = image.run('true')
    info "created the container: #{container.id}"
    if ENV['SHELL_EXPORT']
      command = "docker export #{container.id} | gzip > #{tar_path}"
      info "running '#{command}' to export #{container.id}"
      system(command)
      raise "Could not export image, exit code: #{$?}" unless $?.success?
    else
      Zlib::GzipWriter.open(tar_path) do |file|
        container.export do |chunk, remaining, total|
          file.write(chunk)
        end
      end
    end
    info "done writing the docker tar: #{export_filename}"
  else
    push_to_registry(image)
  end
end

#fetch_importObject



210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
# File 'lib/dockly/docker.rb', line 210

def fetch_import
  ensure_present! :import
  path = "/tmp/dockly-docker-import.#{name}.#{File.basename(import)}"

  if File.exist?(path)
    debug "already fetched #{import}"
  else
    debug "fetching #{import}"
    File.open("#{path}.tmp", 'wb') do |file|
      case import
        when /^s3:\/\/(?<bucket_name>.+?)\/(?<object_path>.+)$/
          connection.get_object(Regexp.last_match[:bucket_name],
                                Regexp.last_match[:object_path]) do |chunk, remaining, total|
            file.write(chunk)
          end
        when /^https?:\/\//
          Excon.get(import, :response_block => lambda { |chunk, remaining, total|
            file.write(chunk)
          })
        else
          raise "You can only import from S3 or a public url"
      end
    end
    FileUtils.mv("#{path}.tmp", path, :force => true)
  end
  path
end

#generate!Object



28
29
30
31
32
33
# File 'lib/dockly/docker.rb', line 28

def generate!
  image = generate_build
  export_image(image)
ensure
  cleanup([image]) if cleanup_images
end

#generate_buildObject



35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
# File 'lib/dockly/docker.rb', line 35

def generate_build
  Docker.options = { :read_timeout => timeout, :write_timeout => timeout }
  images = {}

  if registry_import.nil?
    docker_tar = File.absolute_path(ensure_tar(fetch_import))
    images[:one] = import_base(docker_tar)
  else
    registry.authenticate! unless registry.nil?
    full_name = "#{registry_import[:name]}:#{registry_import[:tag]}"
    info "Pulling #{full_name}"
    images[:one] = ::Docker::Image.create('fromImage' => registry_import[:name], 'tag' => registry_import[:tag])
    info "Successfully pulled #{full_name}"
  end

  images[:two] = add_git_archive(images[:one])
  images[:three] = run_build_caches(images[:two])
  build_image(images[:three])
ensure
  cleanup(images.values.compact) if cleanup_images
end

#git_archive_dirObject



125
126
127
# File 'lib/dockly/docker.rb', line 125

def git_archive_dir
  @git_archive_dir ||= File.join(build_dir, "gitarc")
end

#git_archive_pathObject



129
130
131
# File 'lib/dockly/docker.rb', line 129

def git_archive_path
  "#{git_archive_dir}/#{name}.tar"
end

#git_archive_tarObject



133
134
135
# File 'lib/dockly/docker.rb', line 133

def git_archive_tar
  git_archive && File.absolute_path(make_git_archive)
end

#import_base(docker_tar) ⇒ Object



137
138
139
140
141
142
# File 'lib/dockly/docker.rb', line 137

def import_base(docker_tar)
  info "importing the docker image from #{docker_tar}"
  image = ::Docker::Image.import(docker_tar)
  info "imported initial docker image: #{image.id}"
  image
end

#make_git_archiveObject



108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
# File 'lib/dockly/docker.rb', line 108

def make_git_archive
  ensure_present! :git_archive
  info "initializing"

  prefix = git_archive
  prefix += '/' unless prefix.end_with?('/')

  FileUtils.rm_rf(git_archive_dir)
  FileUtils.mkdir_p(git_archive_dir)
  info "archiving #{Dockly::Util::Git.git_sha}"
  Grit::Git.with_timeout(120) do
    Dockly::Util::Git.git_repo.archive_to_file(Dockly::Util::Git.git_sha, prefix, git_archive_path, 'tar', 'cat')
  end
  info "made the git archive for sha #{Dockly::Util::Git.git_sha}"
  git_archive_path
end

#push_to_registry(image) ⇒ Object



199
200
201
202
203
204
205
206
207
208
# File 'lib/dockly/docker.rb', line 199

def push_to_registry(image)
  ensure_present! :registry
  info "Exporting #{image.id} to Docker registry at #{registry.server_address}"
  registry.authenticate!
  image = Docker::Image.all(:all => true).find { |img|
    img.id.start_with?(image.id) || image.id.start_with?(img.id)
  }
  raise "Could not find image after authentication" if image.nil?
  image.push(registry.to_h, :registry => registry.server_address)
end

#registry_import(img_name = nil, opts = {}) ⇒ Object



57
58
59
60
61
62
63
64
65
# File 'lib/dockly/docker.rb', line 57

def registry_import(img_name = nil, opts = {})
  if img_name
    @registry_import ||= {}
    @registry_import[:name] = img_name
    @registry_import[:tag] = opts[:tag] || 'latest'
  else
    @registry_import
  end
end

#repoObject



163
164
165
166
167
168
169
170
171
172
# File 'lib/dockly/docker.rb', line 163

def repo
  @repo ||= case
  when registry.nil?
    name
  when registry.default_server_address?
    "#{registry.username}/#{name}"
  else
    "#{registry.server_address}/#{name}"
  end
end

#repository(value = nil) ⇒ Object



238
239
240
# File 'lib/dockly/docker.rb', line 238

def repository(value = nil)
  name(value)
end

#run_build_caches(image) ⇒ Object



84
85
86
87
88
89
90
91
92
# File 'lib/dockly/docker.rb', line 84

def run_build_caches(image)
  info "starting build caches"
  (build_cache || []).each do |cache|
    cache.image = image
    image = cache.execute!
  end
  info "finished build caches"
  image
end

#tar_pathObject



94
95
96
# File 'lib/dockly/docker.rb', line 94

def tar_path
  File.join(build_dir, export_filename)
end