Class: PicsolveDockerBuilder::Frame

Inherits:
Object
  • Object
show all
Includes:
Base
Defined in:
lib/picsolve_docker_builder/frame.rb

Overview

Docker image building template rubocop:disable Metrics/ClassLength

Direct Known Subclasses

NodeJs, Scala

Instance Method Summary collapse

Methods included from Base

#base_dir, #config, #config_file, #config_path, #read_config

Constructor Details

#initializeFrame

Returns a new instance of Frame.



13
14
15
16
17
18
19
# File 'lib/picsolve_docker_builder/frame.rb', line 13

def initialize
  # TODO: @christiansimon please report that upstream, second time
  # i am facing that bug
  Docker.options[:read_timeout] = 3600
  Excon.defaults[:read_timeout] = 3600
  config
end

Instance Method Details

#asset_buildObject



142
143
# File 'lib/picsolve_docker_builder/frame.rb', line 142

def asset_build
end

#asset_imageObject



327
328
329
# File 'lib/picsolve_docker_builder/frame.rb', line 327

def asset_image
  @asset_image ||= fetch_asset_image
end

#buildObject



145
146
147
148
149
150
151
152
# File 'lib/picsolve_docker_builder/frame.rb', line 145

def build
  asset_build
  if dest_image_name.nil?
    log.info 'Skip building docker image as no dest_image is set'
    return
  end
  docker_build
end

#build_dirObject



233
234
235
# File 'lib/picsolve_docker_builder/frame.rb', line 233

def build_dir
  '/_build'
end

#build_modeObject



45
46
47
48
49
50
51
# File 'lib/picsolve_docker_builder/frame.rb', line 45

def build_mode
  return :template unless image_name.nil?

  return :dockerfile if dockerfile_exists?

  log.fatal 'No image_name configured and no Dockerfile present'
end

#build_userObject



229
230
231
# File 'lib/picsolve_docker_builder/frame.rb', line 229

def build_user
  'build'
end

#build_user_homeObject



225
226
227
# File 'lib/picsolve_docker_builder/frame.rb', line 225

def build_user_home
  '/home/build'
end

#build_user_uidObject



221
222
223
# File 'lib/picsolve_docker_builder/frame.rb', line 221

def build_user_uid
  Process.uid.to_s
end

#containerObject



237
238
239
# File 'lib/picsolve_docker_builder/frame.rb', line 237

def container
  @container ||= create_container
end

#create_containerObject



260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
# File 'lib/picsolve_docker_builder/frame.rb', line 260

def create_container
  command = ['/bin/sleep', '3600']
  c = Docker::Container.create(
    'Image'      => asset_image.id,
    'Cmd'        => command,
    'OpenStdin'  => false,
    'WorkingDir' => '/_build',
    'Env'        => environment
  )
  at_exit do
    stop
  end
  log.debug "created a new container image=#{image_name} " \
            "id=#{c.id} cmd=#{command}"
  c
end

#create_loggerObject



331
332
333
334
335
# File 'lib/picsolve_docker_builder/frame.rb', line 331

def create_logger
  log = Logger.new(STDOUT)
  log.level = Logger::DEBUG
  log
end

#default_configObject



21
22
23
# File 'lib/picsolve_docker_builder/frame.rb', line 21

def default_config
  { 'docker' => {} }
end

#dest_image_nameObject



277
278
279
# File 'lib/picsolve_docker_builder/frame.rb', line 277

def dest_image_name
  config['docker']['image_name']
end

#docker_buildObject



134
135
136
137
138
139
140
# File 'lib/picsolve_docker_builder/frame.rb', line 134

def docker_build
  dockerfile

  log.info "start docker image building with path #{base_dir}"

  @docker_build = docker_build_build
end

#docker_build_buildObject



124
125
126
127
128
129
130
131
132
# File 'lib/picsolve_docker_builder/frame.rb', line 124

def docker_build_build
  Docker::Image.build_from_dir(base_dir) do |stream|
    s = JSON.parse(stream)['stream']
    log.debug s.strip unless s.nil?
  end
rescue StandardError => e
  log.fatal "docker building failed: #{e}"
  exit 1
end

#dockerfileObject



158
159
160
161
162
163
164
165
166
167
# File 'lib/picsolve_docker_builder/frame.rb', line 158

def dockerfile
  return unless build_mode == :template

  File.open('Dockerfile', 'w') do |file|
    dockerfile_template.each_line do |line|
      log.debug "Dockerfile: #{line.strip}"
    end
    file.write(dockerfile_template)
  end
end

#dockerfile_exists?Boolean

Returns:

  • (Boolean)


169
170
171
# File 'lib/picsolve_docker_builder/frame.rb', line 169

def dockerfile_exists?
  File.exist? dockerfile_path
end

#dockerfile_hooks_asset_build_earlyObject



65
66
67
68
69
# File 'lib/picsolve_docker_builder/frame.rb', line 65

def dockerfile_hooks_asset_build_early
  config['docker']['dockerfile_hooks']['asset_build']['early']
rescue NoMethodError
  ''
end

#dockerfile_hooks_asset_build_lateObject



71
72
73
74
75
# File 'lib/picsolve_docker_builder/frame.rb', line 71

def dockerfile_hooks_asset_build_late
  config['docker']['dockerfile_hooks']['asset_build']['late']
rescue NoMethodError
  ''
end

#dockerfile_hooks_docker_build_earlyObject



53
54
55
56
57
# File 'lib/picsolve_docker_builder/frame.rb', line 53

def dockerfile_hooks_docker_build_early
  config['docker']['dockerfile_hooks']['docker_build']['early']
rescue NoMethodError
  ''
end

#dockerfile_hooks_docker_build_lateObject



59
60
61
62
63
# File 'lib/picsolve_docker_builder/frame.rb', line 59

def dockerfile_hooks_docker_build_late
  config['docker']['dockerfile_hooks']['docker_build']['late']
rescue NoMethodError
  ''
end

#dockerfile_pathObject



154
155
156
# File 'lib/picsolve_docker_builder/frame.rb', line 154

def dockerfile_path
  File.join(base_dir, 'Dockerfile')
end

#dockerfile_templateObject



173
174
175
# File 'lib/picsolve_docker_builder/frame.rb', line 173

def dockerfile_template
  fail NotImplementedError
end

#dockerignore_templateObject



177
178
179
# File 'lib/picsolve_docker_builder/frame.rb', line 177

def dockerignore_template
  fail NotImplementedError
end

#environmentObject



241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
# File 'lib/picsolve_docker_builder/frame.rb', line 241

def environment
  blacklist = %w(
    SSH_CLIENT
    SSH_CONNECTION
    LD_LIBRARY_PATH
    PATH
    NVM_DIR
    NVM_NODEJS_ORG_MIRROR)

  keys = ENV.keys
  keys = keys.reject do |key|
    blacklist.include? key
  end

  keys.map do |key|
    "#{key}=#{ENV[key]}"
  end
end

#execute(cmd) ⇒ Object



25
26
27
28
29
30
# File 'lib/picsolve_docker_builder/frame.rb', line 25

def execute(cmd)
  r = container.exec(cmd)
  fail "Execution of cmd=#{cmd} failed" unless r[2] == 0
  log.debug "executed container id=#{container.id} cmd=#{cmd} result=#{r}"
  r
end

#execute_attach(cmd) ⇒ Object



32
33
34
35
36
37
38
39
40
41
42
43
# File 'lib/picsolve_docker_builder/frame.rb', line 32

def execute_attach(cmd)
  log.debug "execute and attach container id=#{container.id} cmd=#{cmd}"
  r = container.exec(
    cmd
  ) do |_stream, chunk|
    $stdout.write chunk
    $stdout.flush
  end
  fail "Execution of cmd=#{cmd} failed" unless r[2] == 0
  log.debug 'executed and attached container ' \
            "id=#{container.id} cmd=#{cmd} exitcode=#{r[2]}"
end

#fetch_asset_imageObject



305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
# File 'lib/picsolve_docker_builder/frame.rb', line 305

def fetch_asset_image
  log.debug "pulling image '#{image_name}' from registry"
  Docker::Image.create({'fromImage' => image_name}, Composer::Registry.creds)
  log.debug "building asset image from '#{image_name}'"
  dockerfile_asset = "FROM \#{image_name}\nMAINTAINER Picsolve Onlineops <[email protected]>\n\#{dockerfile_hooks_asset_build_early}\nRUN useradd -m -d \#{build_user_home} -u \#{build_user_uid} \#{build_user}\n\#{dockerfile_hooks_asset_build_late}\n"
  begin
    Docker::Image.build(dockerfile_asset) do |stream|
      s = JSON.parse(stream)['stream']
      log.debug s.strip unless s.nil?
    end
  rescue StandardError => e
    log.fatal "asset building failed: #{e}"
    exit 1
  end
end

#image_nameObject



293
294
295
296
297
298
299
300
301
302
303
# File 'lib/picsolve_docker_builder/frame.rb', line 293

def image_name
  name = config['docker']['base_image']

  if name.match(/:[a-z0-9\-_]+$/)
    name
  else
    "#{name}:latest"
  end
rescue NoMethodError
  nil
end

#jenkins_build_numberObject



77
78
79
80
81
# File 'lib/picsolve_docker_builder/frame.rb', line 77

def jenkins_build_number
  n = ENV['BUILD_NUMBER']
  return nil if n.nil?
  n.to_i
end

#logObject



337
338
339
# File 'lib/picsolve_docker_builder/frame.rb', line 337

def log
  @logger ||= create_logger
end

#pushObject



101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
# File 'lib/picsolve_docker_builder/frame.rb', line 101

def push
  fail 'No image found to be pushed' if @docker_build.nil?
  tags.each do |tag|
    repotag = "#{dest_image_name}:#{tag}"
    log.info "pushing image with #{repotag}"
    @docker_build.push(
      Composer::Registry.creds,
      tag: tag
    ) do |resp|
      resp = JSON.parse resp

      if resp.key? 'errorDetail'
        message = "pushing image #{repotag} failed: #{resp['errorDetail']}"
        log.fatal message
        fail message
      end

      log.info "status pushing image #{repotag}: #{resp['status']}" \
        if resp.key? 'status'
    end
  end
end

#runtime_image_nameObject



281
282
283
284
285
286
287
288
289
290
291
# File 'lib/picsolve_docker_builder/frame.rb', line 281

def runtime_image_name
  name = config['docker']['runtime_image'] || image_name

  if name.match(/:[a-z0-9\-_]+$/)
    name
  else
    "#{name}:latest"
  end
rescue NoMethodError
  nil
end

#startObject



189
190
191
192
193
# File 'lib/picsolve_docker_builder/frame.rb', line 189

def start
  container.start('Binds' => volumes)

  log.debug "started container id=#{container.id} volumes=#{volumes}"
end

#stopObject



195
196
197
198
199
200
201
202
# File 'lib/picsolve_docker_builder/frame.rb', line 195

def stop
  return if @container.nil?
  container.stop
  log.debug "stopped container id=#{container.id}"
  container.remove
  log.debug "removed container id=#{container.id}"
  @container = nil
end

#tagObject



89
90
91
92
93
94
95
96
97
98
99
# File 'lib/picsolve_docker_builder/frame.rb', line 89

def tag
  fail 'No image found to tag' if @docker_build.nil?
  tags.each do |tag|
    log.info "tagging image with #{dest_image_name}:#{tag}"
    @docker_build.tag(
      repo: dest_image_name,
      tag: tag,
      force: true
    )
  end
end

#tagsObject



83
84
85
86
87
# File 'lib/picsolve_docker_builder/frame.rb', line 83

def tags
  t = ['latest']
  t << "jenkins-#{jenkins_build_number}" unless jenkins_build_number.nil?
  t
end

#validate_config(c) ⇒ Object



181
182
183
# File 'lib/picsolve_docker_builder/frame.rb', line 181

def validate_config(c)
  validate_config_docker(c)
end

#validate_config_docker(c) ⇒ Object



185
186
187
# File 'lib/picsolve_docker_builder/frame.rb', line 185

def validate_config_docker(c)
  c
end

#volume_workspaceObject



204
205
206
207
208
209
# File 'lib/picsolve_docker_builder/frame.rb', line 204

def volume_workspace
  [
    base_dir,
    build_dir
  ]
end

#volumesObject



215
216
217
218
219
# File 'lib/picsolve_docker_builder/frame.rb', line 215

def volumes
  volumes_array.map do |volume|
    volume.join ':'
  end
end

#volumes_arrayObject



211
212
213
# File 'lib/picsolve_docker_builder/frame.rb', line 211

def volumes_array
  [volume_workspace]
end