Class: RubyYacht::Runner::BuildImages

Inherits:
Command
  • Object
show all
Defined in:
lib/ruby_yacht/runner/build_images.rb

Overview

This command builds the images for the system.

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from Command

#backtick, #default_project, #docker, #get_machine_info, #log, #option_parser, #parse_positional_arguments, #project_named, #projects, short_script_name, #system

Class Method Details

.commandObject

The identifier for the command.


7
# File 'lib/ruby_yacht/runner/build_images.rb', line 7

def self.command; 'build_images'; end

.descriptionObject

The description for the command.


10
11
12
# File 'lib/ruby_yacht/runner/build_images.rb', line 10

def self.description
  "Build images for your environment"
end

Instance Method Details

#build_image(folder_name, image_name = nil) ⇒ Object

This method builds an image.

This will copy a Dockerfile template from a folder underneath the images folder, as well as any other files in that folder, into the tmp folder. It will then evaluate the Dockerfile.erb file, using the binding from the current context, and write it to the Dockerfile in the tmp folder. It will then build the image, and clear out the tmp folder.

Depending on the image type, it may also copy and interpret other template files. For instance, for app containers we also have erb files for the startup.bash and before_startup.bash scripts.

Parameters

  • folder_name: String The name of the folder containing the Dockerfile and related files.
  • image_name: String The name for the new image. If this is not provided, the image name will be the current project's prefix, followed by a dash, followed by the folder name.

75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
# File 'lib/ruby_yacht/runner/build_images.rb', line 75

def build_image(folder_name, image_name = nil)
  Dir[File.join(File.dirname(File.dirname(__FILE__)), 'images', folder_name, '*')].each do |path|
    FileUtils.cp(path, File.join('tmp', File.basename(path)))
  end

  set_image_settings(folder_name)

  @hook_events.each do |event|
    @server_types.each do |server_type|
      RubyYacht.configuration.fetch_hooks(server_type: server_type, event_type: event).each do |hook|
        next unless hook.copied_file_path
        FileUtils.cp hook.copied_file_path, "tmp"
      end
    end
  end

  @templates.each do |template_name|
    File.open(File.join('tmp', template_name), 'w') do |file|
      template_contents = File.read(File.join('tmp', template_name + '.erb'))
      file_contents = ERB.new(template_contents, nil, '<>').result(binding)
      file_contents.gsub!(/\n\n\n+/, "\n\n")
      file_contents.gsub!(/\n*\Z/, "")
      file.write(file_contents)
    end
  end
  
  image_name ||= "#{@project.system_prefix}-#{folder_name}"

  docker "build -t #{image_name} tmp"
  
  FileUtils.rm(Dir[File.join("tmp", "*")])
end

#copy_hooks(event_types) ⇒ Object

This method includes commands for copying script files for the hooks for the current app type.

Parameters

  • event_types: [Symbol] The events whose hooks we should include.

Returns

A String with the contents of the Dockerfile for copying the script.


217
218
219
220
221
222
223
224
225
# File 'lib/ruby_yacht/runner/build_images.rb', line 217

def copy_hooks(event_types)
  result = ""
  RubyYacht.configuration.fetch_hooks(server_type: @server_type.name).each do |hook|
    next if hook.copied_file_name == ''
    next unless event_types.include?(hook.event_type)
    result += "COPY #{hook.copied_file_name} /var/docker/#{hook.copied_file_name}\n"
  end
  result
end

#include_environment_variables(image_type) ⇒ Object

This method includes the app environment variables for the current app type.

Parameters

  • image_type: Symbol The image type that we're building. This can be app_dependencies, app, or database.

Returns

A String with the contents of the Dockerfile for adding the environment variables.


199
200
201
202
203
204
205
# File 'lib/ruby_yacht/runner/build_images.rb', line 199

def include_environment_variables(image_type)
  result = ""
  @server_type.environment_variables.select { |variable| variable[:image] == image_type }.each do |variable|
    result += "ENV #{variable[:name]} #{instance_eval(&variable[:block])}\n"
  end
  result
end

#include_event(event_type, times = [:before, :during, :after], options = {}) ⇒ Object

This method includes the hooks for an event in a Dockerfile.

It will run the commands for the before hooks, then the during hooks, then the after hooks.

Parameters

  • event_type: Symbol The event whose hooks we are running.
  • times: [Symbol] The event times whose hooks we want to include. You can also pass a symbol to this method, which will cause it to include only that event time.
  • options: [Hash] Additional flags for customizing the output. At this time, the only option is in_bash, which indicates whether the commands are running in bash rather than a Dockerfile.
  • block This also takes a block, which should yield fixed contents for the "during" section of the event.

Returns

A String with the contents of the Dockerfile for running the hooks.


164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
# File 'lib/ruby_yacht/runner/build_images.rb', line 164

def include_event(event_type, times = [:before, :during, :after], options = {})
  result = ""
  if times.is_a?(Symbol)
    times = [times]
  end
  times.each do |time|
    if time == :during && block_given?
      result += yield
      result += "\n"
      next
    end
    RubyYacht.configuration.fetch_hooks(server_type: @server_type.name, event_type: event_type, event_time: time).each do |hook|
      if options[:in_bash]
        result += "#{hook.command};\n"
      else
        result += "RUN #{hook.command}\n"
      end
    end
  end
  
  result
end

#runObject

This method runs the logic for the command.


15
16
17
18
19
20
21
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
47
48
49
50
51
52
53
# File 'lib/ruby_yacht/runner/build_images.rb', line 15

def run
  FileUtils.mkdir_p 'tmp'
  
  default_system_prefix = projects.first.system_prefix
  docker "network create #{default_system_prefix} 2> /dev/null"
  
  projects.each do |project|
    log "Building images for #{project.name}"
    @project = project
    
    id_path = File.join(ENV['HOME'], '.ssh', 'id_rsa')
    tmp_id_path = File.join('tmp', 'id_rsa')
    FileUtils.cp(id_path, tmp_id_path) if File.exist?(id_path)
  
    project.apps.map(&:server_type).uniq.each do |type_name|
      @server_type = RubyYacht.configuration.find_server_type(type_name)
      build_image 'app-dependencies', "#{@project.system_prefix}-#{@server_type.name}-app-dependencies"
    end
    
    @app_server_type = RubyYacht.configuration.find_server_type(project.apps.first.server_type)
    project.databases.select(&:local?).each do |database|
      @database = database
      @server_type = RubyYacht.configuration.find_server_type(@database.server_type)
      build_image 'database', @database.container_name(@project)
    end
    
    @project.apps.each do |app|
      @app = app
      @server_type = RubyYacht.configuration.find_server_type(@app.server_type)
      build_image 'app', @app.container_name(@project)
    end
    @app = nil
  end
  
  @projects = projects
  build_image 'web', "#{default_system_prefix}-web"
  
  true
end

#set_image_settings(folder_name) ⇒ Object

This method establishes settings for building an image.

This will set the @templates, @hook_events, and @server_types instance variables.

Parameters

  • folder_name: String The name of the folder containing the image files.

117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
# File 'lib/ruby_yacht/runner/build_images.rb', line 117

def set_image_settings(folder_name)
  @templates = 
    case folder_name
    when 'app' then ['Dockerfile', 'before_startup.bash', 'startup.bash']
    when 'database' then ['Dockerfile', 'startup.bash']
    else ['Dockerfile']
    end

  @hook_events =
    case folder_name
    when 'app' then [:startup, :build_checkout]
    when 'app-dependencies' then [:install_libraries]
    when 'database' then [:create_databases, :install_libraries, :load_database_seeds]
    else []
    end
    
  @server_types =
    case folder_name
    when 'database' then [@server_type.name] + @project.apps.map(&:server_type).uniq
    else [@server_type.name]
    end
end

#with_each_app_typeObject

This method goes through all the app types for the apps in the project, sets each one as the @server_type instance variable, and then yields to the block passed to the method.


230
231
232
233
234
235
236
237
# File 'lib/ruby_yacht/runner/build_images.rb', line 230

def with_each_app_type
  original_server_type = @server_type
  @project.apps.map(&:server_type).uniq.each do |server_type|
    @server_type = RubyYacht.configuration.find_server_type(server_type)
    yield
  end
  @server_type = original_server_type
end