Class: PicsolveDockerBuilder::Frame

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

Overview

Docker image building template

Direct Known Subclasses

Scala

Instance Method Summary collapse

Methods included from Base

#base_dir, #config, #config_path, #read_config

Constructor Details

#initializeFrame

Returns a new instance of Frame.



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

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_imageObject



284
285
286
# File 'lib/picsolve_docker_builder/frame.rb', line 284

def asset_image
  @asset_image ||= fetch_asset_image
end

#buildObject



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

def build
  docker_build
end

#build_dirObject



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

def build_dir
  '/_build'
end

#build_modeObject



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

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



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

def build_user
  'build'
end

#build_user_homeObject



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

def build_user_home
  '/home/build'
end

#build_user_uidObject



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

def build_user_uid
  Process.uid.to_s
end

#containerObject



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

def container
  @container ||= create_container
end

#create_containerObject



232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
# File 'lib/picsolve_docker_builder/frame.rb', line 232

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

#create_loggerObject



288
289
290
291
292
# File 'lib/picsolve_docker_builder/frame.rb', line 288

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

#default_configObject



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

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

#dest_image_nameObject



248
249
250
# File 'lib/picsolve_docker_builder/frame.rb', line 248

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

#docker_buildObject



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

def docker_build
  dockerfile

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

  @docker_build = docker_build_build
end

#docker_build_buildObject



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

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



149
150
151
152
153
154
155
156
157
158
# File 'lib/picsolve_docker_builder/frame.rb', line 149

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)


160
161
162
# File 'lib/picsolve_docker_builder/frame.rb', line 160

def dockerfile_exists?
  File.exist? dockerfile_path
end

#dockerfile_hooks_asset_build_earlyObject



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

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

#dockerfile_hooks_asset_build_lateObject



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

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

#dockerfile_hooks_docker_build_earlyObject



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

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

#dockerfile_hooks_docker_build_lateObject



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

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

#dockerfile_pathObject



145
146
147
# File 'lib/picsolve_docker_builder/frame.rb', line 145

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

#dockerfile_templateObject



164
165
166
# File 'lib/picsolve_docker_builder/frame.rb', line 164

def dockerfile_template
  fail NotImplementedError
end

#dockerignore_templateObject



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

def dockerignore_template
  fail NotImplementedError
end

#execute(cmd) ⇒ Object



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

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



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

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



264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
# File 'lib/picsolve_docker_builder/frame.rb', line 264

def fetch_asset_image
  log.debug "pulling image '#{image_name}' from registry"
  dockerfile_asset = <<EOS
FROM #{image_name}
MAINTAINER Picsolve Onlineops <[email protected]>
#{dockerfile_hooks_asset_build_early}
RUN useradd -d #{build_user_home} -u #{build_user_uid} #{build_user}
#{dockerfile_hooks_asset_build_late}
EOS
  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



252
253
254
255
256
257
258
259
260
261
262
# File 'lib/picsolve_docker_builder/frame.rb', line 252

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



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

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

#logObject



294
295
296
# File 'lib/picsolve_docker_builder/frame.rb', line 294

def log
  @logger ||= create_logger
end

#pushObject



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

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

#startObject



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

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

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

#stopObject



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

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



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

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



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

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

#validate_config(c) ⇒ Object



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

def validate_config(c)
  validate_config_docker(c)
end

#validate_config_docker(c) ⇒ Object



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

def validate_config_docker(c)
  c
end

#volume_workspaceObject



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

def volume_workspace
  [
    base_dir,
    build_dir
  ]
end

#volumesObject



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

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

#volumes_arrayObject



202
203
204
# File 'lib/picsolve_docker_builder/frame.rb', line 202

def volumes_array
  [volume_workspace]
end