require 'fileutils' class Fanforce::PluginFactory::CLI::Iron include Fanforce::PluginFactory::CLI::Utils require_gem 'iron_worker', 'iron_worker' attr_reader :plugin def initialize(plugin) @plugin = plugin end def workers_dir @workers_dir ||= "#{plugin.dir}/workers" end def dockerize(environment, worker_filename=nil) return log "#{'Skipped '.format(:bold)} no workers folder was found" if !File.directory?(workers_dir) worker_filename = worker_filename.gsub('.worker', '') if worker_filename env_vars = Fanforce::PluginFactory::CLI::Env.new(plugin).vars(environment) || {} return puts "#{'Skipped '.format(:bold)} #{environment.to_s.titleize} is missing IRON_TOKEN and/or IRON_PROJECT_ID env variables" if env_vars['IRON_TOKEN'].blank? or env_vars['IRON_PROJECT_ID'].blank? Dir.chdir(workers_dir) do workers = Dir['*.rb'] return puts "#{'Skipped '.format(:bold)} #{environment.to_s.titleize} has 0 workers" if workers.size == 0 upload_processes = [] workers.each do |filename| next if worker_filename and !filename.include?(worker_filename) dockerize_worker(filename, environment, env_vars) end end end def dockerize_and_upload(environment, worker_filename=nil) return log "#{'Skipped '.format(:bold)} no workers folder was found" if !File.directory?(workers_dir) worker_filename = worker_filename.gsub('.worker', '') if worker_filename env_vars = Fanforce::PluginFactory::CLI::Env.new(plugin).vars(environment) || {} return puts "#{'Skipped '.format(:bold)} #{environment.to_s.titleize} is missing IRON_TOKEN and/or IRON_PROJECT_ID env variables" if env_vars['IRON_TOKEN'].blank? or env_vars['IRON_PROJECT_ID'].blank? Dir.chdir(workers_dir) do workers = Dir['*.rb'] return puts "#{'Skipped '.format(:bold)} #{environment.to_s.titleize} has 0 workers" if workers.size == 0 upload_processes = [] workers.each do |filename| next if worker_filename and !filename.include?(worker_filename) zipped_filepath = dockerize_worker(filename, environment, env_vars) upload_processes << upload_worker(filename, environment, env_vars, zipped_filepath) end upload_processes.each { |pid| Process.waitpid(pid) } end end ###################################################################################################################### def dockerize_worker(filename, environment, env_vars) puts "#{'Compiling'.format(:green,:bold)} #{filename.gsub('.rb', '')} to #{environment.to_s.titleize}..." code_name = filename.gsub('.rb', '') dockerized_dir = "#{workers_dir}/dockerized" dockerized_dir_relative = 'workers/dockerized' Dir.mkdir(dockerized_dir) if !File.directory?(dockerized_dir) dockerized_worker_dir = "#{dockerized_dir}/#{code_name}" dockerized_worker_dir_relative = "#{dockerized_dir_relative}/#{code_name}" zipped_dir = "#{workers_dir}/zipped" zipped_filename = "#{code_name}.#{env(environment)}.zip" zipped_filepath = "#{zipped_dir}/#{zipped_filename}" zipped_filepath_relative = "workers/zipped/#{zipped_filename}" Dir.mkdir(zipped_dir) if !File.directory?(zipped_dir) if !File.directory?(dockerized_worker_dir) puts "Creating #{dockerized_worker_dir_relative}/" Dir.mkdir(dockerized_worker_dir) end # worker.ru puts "Creating #{dockerized_worker_dir_relative}/worker.ru" File.open("#{dockerized_worker_dir}/worker.ru", 'w') do |f| f.write [ "require_relative 'bundle/bundler/setup'", "$: << File.expand_path('../', __FILE__)", "load '#{filename}'" ].join("\n") end # Executable puts "Copying /workers/#{filename} to #{dockerized_worker_dir_relative}/#{filename}" File.open("#{dockerized_worker_dir}/#{filename}", 'w') do |f| f.write File.read("#{plugin.dir}/workers/#{filename}") end # config.json puts "Copying /config.json to #{dockerized_worker_dir_relative}/config.json" File.open("#{dockerized_worker_dir}/config.json", 'w') do |f| f.write File.read("#{plugin.dir}/config.json") end # Gemfile puts "Copying /Gemfile to #{dockerized_worker_dir_relative}/Gemfile" File.open("#{dockerized_worker_dir}/Gemfile", 'w') do |f| f.write File.read("#{plugin.dir}/Gemfile").gsub("ruby '2.1.6'", "ruby '2.1.4'") end # Gemfile.lock puts "Copying /Gemfile.lock to #{dockerized_worker_dir_relative}/Gemfile.lock" File.open("#{dockerized_worker_dir}/Gemfile.lock", 'w') do |f| f.write File.read("#{plugin.dir}/Gemfile.lock") end # lib/ if File.directory?("#{plugin.dir}/lib") puts "Copying /lib/ to #{dockerized_worker_dir_relative}/lib/" FileUtils.rm_r("#{dockerized_worker_dir}/lib") if File.directory?("#{dockerized_worker_dir}/lib") FileUtils.copy_entry("#{plugin.dir}/lib", "#{dockerized_worker_dir}/lib") end # mailers/ if File.directory?("#{plugin.dir}/mailers") puts "Copying /mailers/ to #{dockerized_worker_dir_relative}/mailers/" FileUtils.rm_r("#{dockerized_worker_dir}/mailers") if File.directory?("#{dockerized_worker_dir}/mailers") FileUtils.copy_entry("#{plugin.dir}/mailers", "#{dockerized_worker_dir}/mailers") end # ENV puts "Setting up ENV for #{environment.to_s.titleize} (#{env_vars.size} variables)" File.open("#{dockerized_worker_dir}/env.#{env(environment)}.rb", 'w') {|f| f.write Fanforce::PluginFactory::CLI::Env.convert_hash_to_ruby_env(env_vars) } # Bundle puts "Dockerizing #{dockerized_worker_dir_relative}" bundle_output = console_command("docker run --rm -v \"#{File.expand_path(dockerized_worker_dir)}\":/worker -w /worker iron/images:ruby-2.1 sh -c 'bundle install --standalone --clean'", true) # Zip It print "Zipping to #{zipped_filepath_relative}... " File.delete(zipped_filepath) if File.exists?(zipped_filepath) Dir.chdir(dockerized_worker_dir) do console_command("zip -r #{zipped_filepath} .") end zipped_filesize = (File.size(zipped_filepath).to_f / 2**20).round(2) puts "#{zipped_filesize} MB" return zipped_filepath end def upload_worker(filename, environment, env_vars, zipped_filepath) code_name = filename.gsub('.rb', '') puts "#{'Uploading'.format(:green,:bold)} #{code_name} to #{environment.to_s.titleize}..." fork do begin iron_cli_version = console_command('iron -version').gsub(/^v/, '') if Gem::Version.new(iron_cli_version) >= Gem::Version.new('0.0.10') # Command format for v0.0.10+ command = "iron --project-id #{env_vars['IRON_PROJECT_ID']} --token #{env_vars['IRON_TOKEN']} worker upload --zip #{zipped_filepath} --name #{code_name} iron/images:ruby-2.1 ruby worker.ru" else # Command format for old versions command = "iron --project-id #{env_vars['IRON_PROJECT_ID']} --token #{env_vars['IRON_TOKEN']} worker upload --stack ruby-2.1 --name #{code_name} #{zipped_filepath} ruby worker.ru" end puts command puts console_command(command) rescue Exception => e puts "#{'Aborted '.format(:red,:bold)} upload of #{code_name} to #{environment.to_s.titleize}..." puts e.message puts e.backtrace puts '' end end end def current_factory_version `bundle list`.lines.each do |line| return $1 if line =~ /fanforce-plugin-factory \(([A-Za-z0-9.-]+)\)/ end error 'fanforce-plugin-factory version was not found in `bundle list`' end def upload_iron_worker(iron_worker, code, filename, environment) end end