Class: Ufo::Docker::Builder

Inherits:
Object
  • Object
show all
Includes:
Util
Defined in:
lib/ufo/docker/builder.rb

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Util

#default_cluster, #display_params, #execute, #pretty_time, #settings, #task_definition_arns, #user_params

Constructor Details

#initialize(options = {}) ⇒ Builder

Returns a new instance of Builder.



16
17
18
19
20
# File 'lib/ufo/docker/builder.rb', line 16

def initialize(options={})
  @options = options
  @dockerfile = options[:dockerfile] || 'Dockerfile'
  @image_namespace = options[:image_namespace] || 'ufo'
end

Class Method Details

.build(options) ⇒ Object



8
9
10
11
12
13
14
# File 'lib/ufo/docker/builder.rb', line 8

def self.build(options)
  builder = Builder.new(options) # outside if because it need builder.full_image_name
  builder.build
  pusher = Pusher.new(nil, options)
  pusher.push
  builder
end

Instance Method Details

#buildObject



22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
# File 'lib/ufo/docker/builder.rb', line 22

def build
  start_time = Time.now
  store_full_image_name

  command = "docker build #{build_options}-t #{full_image_name} -f #{@dockerfile} ."
  say "Building docker image with:".color(:green)
  say "  #{command}".color(:green)
  compile_dockerfile_erb
  check_dockerfile_exists
  update_auth_token
  command = "cd #{Ufo.root} && #{command}"
  success = execute(command, use_system: true)
  unless success
    docker_version_success = system("docker version > /dev/null 2>&1")
    unless docker_version_success
      docker_version_message = "  Are you sure the docker daemon is available?  Try running: docker version."
    end
    puts "ERROR: The docker image fail to build.#{docker_version_message}".color(:red)
    exit 1
  end

  took = Time.now - start_time
  say "Docker image #{full_image_name} built.  "
  say "Docker build took #{pretty_time(took)}.".color(:green)
end

#build_optionsObject



48
49
50
51
52
# File 'lib/ufo/docker/builder.rb', line 48

def build_options
  options = ENV['UFO_DOCKER_BUILD_OPTIONS']
  options += " " if options
  options
end

#check_dockerfile_existsObject



98
99
100
101
102
103
# File 'lib/ufo/docker/builder.rb', line 98

def check_dockerfile_exists
  unless File.exist?("#{Ufo.root}/#{@dockerfile}")
    puts "#{@dockerfile} does not exist.  Are you sure it exists?"
    exit 1
  end
end

#compileObject



89
90
91
92
93
94
95
96
# File 'lib/ufo/docker/builder.rb', line 89

def compile
  erb_path = "#{Ufo.root}/#{@dockerfile}.erb"
  if File.exist?(erb_path)
    compile_dockerfile_erb
  else
    puts "File #{erb_path.color(:green)} does not exist. Cannot compile it if it doesnt exist"
  end
end

#docker_name_pathObject



139
140
141
142
# File 'lib/ufo/docker/builder.rb', line 139

def docker_name_path
  # output gets entirely wiped by tasks builder so dotn use that folder
  "#{Ufo.root}/.ufo/data/docker_image_name_#{@image_namespace}.txt"
end

#ecr_image_names(path) ⇒ Object



67
68
69
# File 'lib/ufo/docker/builder.rb', line 67

def ecr_image_names(path)
  from_image_names(path).select { |i| i =~ /\.amazonaws\.com/ }
end

#from_image_names(path) ⇒ Object



71
72
73
74
75
76
77
78
# File 'lib/ufo/docker/builder.rb', line 71

def from_image_names(path)
  lines = IO.readlines(path)
  froms = lines.select { |l| l =~ /^FROM/ }
  froms.map do |l|
    md = l.match(/^FROM (.*)/)
    md[1]
  end.compact
end

#full_image_nameObject

full_image - Includes the tag. Examples:

123456789.dkr.ecr.us-west-2.amazonaws.com/myapp:ufo-2018-04-20T09-29-08-b7d51df
tongueroo/demo-ufo:ufo-2018-04-20T09-29-08-b7d51df


113
114
115
116
117
118
119
120
121
122
# File 'lib/ufo/docker/builder.rb', line 113

def full_image_name
  return generate_name if @options[:generate]
  return "tongueroo/demo-ufo:ufo-12345678" if ENV['TEST']

  unless File.exist?(docker_name_path)
    puts "Unable to find #{docker_name_path} which contains the last docker image name that was used as a part of `ufo docker build`.  Please run `ufo docker build` first."
    exit 1
  end
  IO.read(docker_name_path).strip
end

#generate_nameObject



135
136
137
# File 'lib/ufo/docker/builder.rb', line 135

def generate_name
  "#{image_name}:#{@image_namespace}-#{timestamp}-#{git_sha}"
end

#git_shaObject



148
149
150
151
152
153
# File 'lib/ufo/docker/builder.rb', line 148

def git_sha
  return @git_sha if @git_sha
  # always call this and dont use the execute method because of the noop option
  @git_sha = `cd #{Ufo.root} && git rev-parse --short HEAD`
  @git_sha.strip!
end

#image_nameObject

full_image - does not include the tag



106
107
108
# File 'lib/ufo/docker/builder.rb', line 106

def image_name
  settings[:image]
end

#pusherObject



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

def pusher
  @pusher ||= Pusher.new(full_image_name, @options)
end

#say(msg) ⇒ Object



164
165
166
# File 'lib/ufo/docker/builder.rb', line 164

def say(msg)
  puts msg unless @options[:mute]
end

#store_full_image_nameObject

Store this in a file because this name gets reference in other tasks later and we want the image name to stay the same when the commands are run separate in different processes. So we store the state in a file. Only when a new docker build command gets run will the image name state be updated.



128
129
130
131
132
133
# File 'lib/ufo/docker/builder.rb', line 128

def store_full_image_name
  dirname = File.dirname(docker_name_path)
  FileUtils.mkdir_p(dirname) unless File.exist?(dirname)
  full_image_name = generate_name
  IO.write(docker_name_path, full_image_name)
end

#timestampObject



144
145
146
# File 'lib/ufo/docker/builder.rb', line 144

def timestamp
  @timestamp ||= Time.now.strftime('%Y-%m-%dT%H-%M-%S')
end

#update_auth_tokenObject

Parse Dockerfile for FROM instruction. If the starting image is from an ECR repository, it’s likely an private image so we authorize ECR for pulling.



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

def update_auth_token
  ecr_image_names = ecr_image_names("#{Ufo.root}/#{@dockerfile}")
  return if ecr_image_names.empty?

  ecr_image_names.each do |ecr_image_name|
    auth = Ufo::Ecr::Auth.new(ecr_image_name)
    # wont update auth token unless the image being pushed in the ECR image format
    auth.update
  end
end

#update_dockerfileObject



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

def update_dockerfile
  updater = if File.exist?("#{Ufo.root}/Dockerfile.erb") # dont use @dockerfile on purpose
    Variables.new(full_image_name, @options)
  else
    Dockerfile.new(full_image_name, @options)
  end
  updater.update
end