class Docker::Rails::App
Attributes
compose_config[R]
compose_filename[R]
config[R]
exit_code[R]
Public Class Methods
configured(target, options)
click to toggle source
# File lib/docker/rails/app.rb, line 12 def configured(target, options) app = App.instance if app.is_configured? # puts "Already configured" else app.configure(Thor::CoreExt::HashWithIndifferentAccess.new(target: target).merge(options)) end app end
new()
click to toggle source
# File lib/docker/rails/app.rb, line 23 def initialize end
Public Instance Methods
after_build_command()
click to toggle source
# File lib/docker/rails/app.rb, line 157 def after_build_command after_build_command = @config['after_build_command'] (exec after_build_command unless after_build_command.nil?) end
bash_connect(service_name)
click to toggle source
# File lib/docker/rails/app.rb, line 253 def bash_connect(service_name) # docker exec -it 2ed97d0bb938 bash container = get_container(service_name) if container.nil? puts "#{service_name} does not appear to be running for build #{build}" return end exec "docker exec -it #{container.id} bash" container end
before_command()
click to toggle source
# File lib/docker/rails/app.rb, line 152 def before_command before_command = @config['before_command'] (exec before_command unless before_command.nil?) end
compose()
click to toggle source
# File lib/docker/rails/app.rb, line 73 def compose # Write a docker-compose.yml with interpolated variables @compose_filename = compose_filename_from project_name rm_compose @config.write_docker_compose_file(@compose_filename) @compose_config = Docker::Rails::ComposeConfig.new @compose_config.load!(nil, @compose_filename) # check the exit_code if @config['exit_code'].nil? first_defined_service = @compose_config.services.keys[0] puts "exit_code not set in configuration, using exit code from first defined service: #{first_defined_service}" @config['exit_code'] = first_defined_service end end
compose_build()
click to toggle source
# File lib/docker/rails/app.rb, line 175 def compose_build # Run the compose configuration exec_compose 'build' end
configure(options)
click to toggle source
# File lib/docker/rails/app.rb, line 26 def configure(options) # Allow CLI option `build` to fallback to an env variable DOCKER_RAILS_BUILD. Note that CLI provides a default build value of 1, so check against the default and existence of the env var. build = options[:build] build = ENV['DOCKER_RAILS_BUILD'] if build.to_i == 1 && !ENV['DOCKER_RAILS_BUILD'].nil? ENV['DOCKER_RAILS_BUILD'] = build target = options[:target] # load the docker-rails.yml @config = Docker::Rails::Config.new({build: build, target: target}) @config.load!(target) @is_configured = true end
create_dockito_vault()
click to toggle source
Create a dockito vault container for serving private keys
https://github.com/dockito/vault
# File lib/docker/rails/app.rb, line 42 def create_dockito_vault begin Docker::Container.get(dockito_vault_name) puts "Dockito vault container #{dockito_vault_name} already exists." rescue Docker::Error::NotFoundError => e # docker run --detach --name vault -p 14242:3000 -v ~/.ssh:/vault/.ssh dockito/vault:latest exec "docker run --detach --name #{dockito_vault_name} -p 14242:3000 -v ~/.ssh:/vault/.ssh dockito/vault:latest" puts "Dockito vault container #{dockito_vault_name} created." end end
dockito_vault_enabled?()
click to toggle source
# File lib/docker/rails/app.rb, line 68 def dockito_vault_enabled? @config[:dockito][:vault] || false end
dockito_vault_name()
click to toggle source
FIXME this needs to by dynamic to this run?
# File lib/docker/rails/app.rb, line 64 def dockito_vault_name 'vault' #@config[:dockito][:vault][:name] end
down(options = '')
click to toggle source
# File lib/docker/rails/app.rb, line 167 def down(options = '') # `compose down` doesn't support force removing images, so we use `rm --force` exec_compose 'rm', false, '--force -v' # Stop and remove all the linked services and network exec_compose 'down', false, options end
extract(container, service_name, extractions)
click to toggle source
# File lib/docker/rails/app.rb, line 127 def extract(container, service_name, extractions) extractions.each do |extraction| if extraction =~ /:/ tokens = extraction.split(':') from = tokens[0] to = tokens[1] else from = extraction to = '.' end puts "\nExtracting #{service_name} #{from} to #{to}" begin extract_files(container, from, to) rescue => e puts e.message end end end
extract_all()
click to toggle source
# File lib/docker/rails/app.rb, line 96 def extract_all # For each container, process extractions # Containers are defined in compose, extractions are defined at root under container name e.g.: # web: # extract: # - '<from_container>:<to_host>' # - '/project/target:.' # - '/project/vcr' # same as extract to '.' # - '/project/tmp' # - '/project/spec/dummy/log:spec/dummy' # - '/project/tmp/parallel_runtime_cucumber.log:./tmp' # - '/project/tmp/parallel_runtime_rspec.log:./tmp' @compose_config.services.each_key do |service_name| service_config = @config[service_name] extractions = service_config[:extract] unless service_config.nil? next if extractions.nil? puts "\n\nProcessing extract for #{service_name}:" puts '---------------------------------' container = get_container(service_name) rescue nil if container.nil? puts 'none.' next end extract(container, service_name, extractions) end end
is_configured?()
click to toggle source
# File lib/docker/rails/app.rb, line 92 def is_configured? @is_configured || false end
ps()
click to toggle source
# File lib/docker/rails/app.rb, line 180 def ps # Run the compose configuration exec_compose 'ps' end
ps_all()
click to toggle source
# File lib/docker/rails/app.rb, line 185 def ps_all puts "\n\nAll remaining containers..." puts '-----------------------------' exec 'docker ps -a' end
rm_compose()
click to toggle source
# File lib/docker/rails/app.rb, line 147 def rm_compose # Delete old docker compose files exec "rm #{compose_filename_from '*'}" rescue '' end
rm_dangling()
click to toggle source
def rm_volumes
puts "\n\nRemoving container volumes..." puts '-----------------------------' # http://docs.docker.com/v1.7/reference/api/docker_remote_api_v1.19/#remove-a-container containers = Docker::Container.all(all: true) containers.each do |container| if is_project_container?(container) puts container.name rm_v(container) end end puts 'Done.'
end
# File lib/docker/rails/app.rb, line 228 def rm_dangling puts "\n\nCleaning up dangling images..." puts '-----------------------------' list_images_cmd = 'docker images --filter dangling=true -q' output = exec(list_images_cmd, true) # if there are any dangling, let's clean them up. exec("#{list_images_cmd} | xargs docker rmi", false, true) if !output.nil? && output.length > 0 puts 'Done.' end
rm_dockito_vault()
click to toggle source
# File lib/docker/rails/app.rb, line 54 def rm_dockito_vault begin container = Docker::Container.get(dockito_vault_name) rm_v(container) rescue Docker::Error::NotFoundError => e puts "Dockito vault container #{dockito_vault_name} does not exist." end end
rm_exited()
click to toggle source
# File lib/docker/rails/app.rb, line 240 def rm_exited puts "\n\nCleaning up exited containers..." puts '-----------------------------' exec('docker rm -v $(docker ps -a -q -f status=exited)', false, true) puts 'Done.' end
run_service_command(service_name, command)
click to toggle source
# File lib/docker/rails/app.rb, line 248 def run_service_command(service_name, command) # Run the compose configuration exec_compose("run #{service_name} #{command}", false, '', true) end
up(options = '')
click to toggle source
# File lib/docker/rails/app.rb, line 162 def up(options = '') # Run the compose configuration exec_compose 'up', false, options #unless skip? :up end
Protected Instance Methods
build()
click to toggle source
# File lib/docker/rails/app.rb, line 384 def build @config[:build] end
compose_filename_from(project_name)
click to toggle source
accessible so that we can delete patterns
# File lib/docker/rails/app.rb, line 312 def compose_filename_from(project_name) "docker-compose-#{project_name}.yml" end
exec(cmd, capture = false, ignore_errors = false)
click to toggle source
# File lib/docker/rails/app.rb, line 267 def exec(cmd, capture = false, ignore_errors = false) puts "Running `#{cmd}`" if verbose? if capture output = %x[#{cmd}] else system cmd end (raise "Failed to execute: `#{cmd}`" unless $?.success?) unless ignore_errors output end
exec_compose(cmd, capture = false, options = '', ignore_errors = false)
click to toggle source
convenience to execute docker-compose with file and project params
# File lib/docker/rails/app.rb, line 280 def exec_compose(cmd, capture = false, options = '', ignore_errors = false) # in the case of running a bash session, this file may dissappear, just make sure it is there. compose unless File.exists?(@compose_filename) exec("docker-compose -f #{@compose_filename} -p #{project_name} #{cmd} #{options}", capture, ignore_errors) end
extract_files(container, from, to)
click to toggle source
# File lib/docker/rails/app.rb, line 316 def extract_files(container, from, to) # or something like tar_stringio = StringIO.new container.copy(from) do |chunk| tar_stringio.write(chunk) end tar_stringio.rewind input = Archive::Tar::Minitar::Input.new(tar_stringio) input.each { |entry| # Need to check the file name length to prevent some very bad things from happening. if entry.full_name.length > 255 puts "ERROR - file name length is > 255 characters: #{entry.full_name}" elsif entry.full_name.length <= 0 puts "ERROR - file name length is too small: #{entry.full_name}" else puts "Extracting #{entry.full_name}" input.extract_entry(to, entry) end } end
get_container(service_name)
click to toggle source
# File lib/docker/rails/app.rb, line 287 def get_container(service_name) containers = Docker::Container.all(all: true) containers.each do |container| if is_project_container?(container) && container.compose.service.eql?(service_name.to_s) return container end end nil end
is_project_container?(container)
click to toggle source
# File lib/docker/rails/app.rb, line 298 def is_project_container?(container) # labels = container.info['Labels'] # build = labels['com.docker.compose.project'] return false if container.compose.nil? return true if project_name.eql? container.compose.project false end
kill(container)
click to toggle source
kill container, progressively more forceful from -1, -9, then full Chuck Norris.
# File lib/docker/rails/app.rb, line 359 def kill(container) %w(SIGHUP SIGKILL SIGSTOP).each do |signal| if container.up? printf "killing(#{signal})" container.kill(signal: signal) 10.times do |i| printf '.' if container.down? printf "done.\n" break end sleep 1 end end end end
project_name()
click to toggle source
# File lib/docker/rails/app.rb, line 380 def project_name @config[:project_name] end
rm_v(container)
click to toggle source
# File lib/docker/rails/app.rb, line 376 def rm_v(container) container.remove(v: true, force: true) end
stop(container)
click to toggle source
# File lib/docker/rails/app.rb, line 340 def stop(container) printf "#{container.name}.." # Stop it container.stop 60.times do |i| printf '.' if container.down? printf "done.\n" break end sleep 1 end # kill it if necessary kill(container) end
target()
click to toggle source
# File lib/docker/rails/app.rb, line 388 def target @config[:target] end
verbose?()
click to toggle source
# File lib/docker/rails/app.rb, line 307 def verbose? @verbose ||= (@config['verbose'] unless @config.nil?) || false end