| 
									
										
										
										
											2015-07-20 18:59:26 +03:00
										 |  |  | require "commands/stack" | 
					
						
							|  |  |  | require "db/mongo/models/stack/stack_factory" | 
					
						
							| 
									
										
										
										
											2015-07-30 02:14:45 +03:00
										 |  |  | require "db/mongo/models/project" | 
					
						
							| 
									
										
										
										
											2015-07-20 18:59:26 +03:00
										 |  |  | require "db/mongo/models/report" | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-09-21 15:54:33 +03:00
										 |  |  | class StackCreatingError < StandardError; end | 
					
						
							|  |  |  | class BootstrapingStackServerError < StandardError; end | 
					
						
							|  |  |  | class DeployingStackServerError < StandardError; end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-07-30 13:18:55 +03:00
										 |  |  | class StackBootstrapWorker < Worker | 
					
						
							| 
									
										
										
										
											2015-07-20 18:59:26 +03:00
										 |  |  |   include StackCommands | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-07-23 12:54:36 +03:00
										 |  |  |   def perform(options) | 
					
						
							| 
									
										
										
										
											2015-09-01 16:31:31 +03:00
										 |  |  |     stack_attrs = options.fetch('stack_attributes') | 
					
						
							| 
									
										
										
										
											2015-08-14 17:48:07 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-11-03 12:05:07 +03:00
										 |  |  |     call() do |out, file| | 
					
						
							| 
									
										
										
										
											2015-09-21 15:54:33 +03:00
										 |  |  |       @out = out | 
					
						
							| 
									
										
										
										
											2015-09-01 16:31:31 +03:00
										 |  |  |       without_bootstrap = stack_attrs.delete('without_bootstrap') | 
					
						
							| 
									
										
										
										
											2015-09-24 15:06:02 +03:00
										 |  |  |       @out.puts "Received 'without_bootstrap' option" if without_bootstrap | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-09-17 11:50:35 +03:00
										 |  |  |       report = save_report(file, stack_attrs) | 
					
						
							| 
									
										
										
										
											2015-09-01 16:31:31 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-09-21 15:54:33 +03:00
										 |  |  |       begin | 
					
						
							| 
									
										
										
										
											2015-11-03 12:05:07 +03:00
										 |  |  |         stack = create_stack(stack_attrs) | 
					
						
							| 
									
										
										
										
											2015-07-20 18:59:26 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-11-17 16:21:28 +03:00
										 |  |  |         #TODO: errors | 
					
						
							|  |  |  |         begin | 
					
						
							|  |  |  |           servers_with_priority = persist_stack_servers!(stack) | 
					
						
							|  |  |  |           unless without_bootstrap | 
					
						
							|  |  |  |             sorted_keys = servers_with_priority.keys.sort{|x,y| y <=> x} | 
					
						
							|  |  |  |             sorted_keys.each do |key| | 
					
						
							|  |  |  |               @out.puts "Servers with priority '#{key}':" | 
					
						
							|  |  |  |               bootstrap_servers!(servers_with_priority[key], report) | 
					
						
							|  |  |  |             end | 
					
						
							| 
									
										
										
										
											2015-11-03 13:08:31 +03:00
										 |  |  |           end | 
					
						
							| 
									
										
										
										
											2015-11-17 16:21:28 +03:00
										 |  |  |           @out.puts "Done." | 
					
						
							|  |  |  |           0
 | 
					
						
							|  |  |  |         rescue BootstrapingStackServerError | 
					
						
							|  |  |  |           @out.puts "\nAn error occured during bootstraping stack servers. Initiating stack rollback." | 
					
						
							|  |  |  |           rollback_stack!(stack) | 
					
						
							|  |  |  |           2
 | 
					
						
							|  |  |  |         rescue DeployingStackServerError => e | 
					
						
							|  |  |  |           @out.puts "\nStack was launched, but an error occured during deploying stack servers." | 
					
						
							|  |  |  |           @out.puts "You can redeploy stack after fixing the error." | 
					
						
							|  |  |  |           3
 | 
					
						
							|  |  |  |         rescue StandardError => e | 
					
						
							|  |  |  |           @out.puts "\nAn error occured. Initiating stack rollback." | 
					
						
							|  |  |  |           rollback_stack!(stack) | 
					
						
							|  |  |  |           raise e | 
					
						
							| 
									
										
										
										
											2015-11-03 13:08:31 +03:00
										 |  |  |         end | 
					
						
							| 
									
										
										
										
											2015-11-17 16:21:28 +03:00
										 |  |  |       rescue StackCreatingError | 
					
						
							|  |  |  |         @out.puts "Stack creating error" | 
					
						
							| 
									
										
										
										
											2015-09-21 15:54:33 +03:00
										 |  |  |         1
 | 
					
						
							| 
									
										
										
										
											2015-08-12 12:24:48 +03:00
										 |  |  |       end | 
					
						
							| 
									
										
										
										
											2015-07-20 18:59:26 +03:00
										 |  |  |     end | 
					
						
							|  |  |  |   end | 
					
						
							| 
									
										
										
										
											2015-07-30 02:14:45 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  |   private | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-09-21 15:54:33 +03:00
										 |  |  |   def rollback_stack!(stack) | 
					
						
							|  |  |  |     @out.puts "\nStart rollback of a stack" | 
					
						
							|  |  |  |     stack.delete_stack_in_cloud! | 
					
						
							|  |  |  |     Devops::Db.connector.stack_servers_delete(stack.name) | 
					
						
							|  |  |  |     Devops::Db.connector.stack_delete(stack.id) | 
					
						
							| 
									
										
										
										
											2015-09-22 15:07:56 +03:00
										 |  |  |     @out.puts "Rollback has been completed" | 
					
						
							| 
									
										
										
										
											2015-09-21 15:54:33 +03:00
										 |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-11-03 12:05:07 +03:00
										 |  |  |   def create_stack(stack_attrs) | 
					
						
							|  |  |  |     stack = Devops::Model::StackFactory.create(stack_attrs["provider"], stack_attrs, @out) | 
					
						
							| 
									
										
										
										
											2015-09-21 15:54:33 +03:00
										 |  |  |     mongo.stack_insert(stack) | 
					
						
							|  |  |  |     operation_result = sync_stack_proc.call(@out, stack, mongo) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if operation_result == 0
 | 
					
						
							|  |  |  |       @out.puts "\nStack '#{stack.name}' has been created" | 
					
						
							|  |  |  |       @out.flush | 
					
						
							|  |  |  |       stack | 
					
						
							|  |  |  |     else | 
					
						
							|  |  |  |       human_readable_code = StackCommands.result_codes.key(operation_result) | 
					
						
							|  |  |  |       @out.puts "An error ocurred during stack creating" | 
					
						
							|  |  |  |       @out.puts "Stack creating operation result was #{human_readable_code}" | 
					
						
							|  |  |  |       raise StackCreatingError | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   def bootstrap_servers!(servers, report) | 
					
						
							|  |  |  |     @out << "\nStart bootstraping stack servers\n" | 
					
						
							| 
									
										
										
										
											2015-11-03 12:05:07 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-11-03 13:08:31 +03:00
										 |  |  |     subreports = [] | 
					
						
							| 
									
										
										
										
											2015-11-03 12:05:07 +03:00
										 |  |  |     data = {} | 
					
						
							| 
									
										
										
										
											2015-09-21 15:54:33 +03:00
										 |  |  |     servers.each do |server| | 
					
						
							| 
									
										
										
										
											2015-11-03 12:05:07 +03:00
										 |  |  |       sjid = Worker.start_async(BootstrapWorker, | 
					
						
							|  |  |  |         server_attrs: server.to_mongo_hash, | 
					
						
							|  |  |  |         bootstrap_template: 'omnibus', | 
					
						
							|  |  |  |         owner: server.created_by | 
					
						
							|  |  |  |       ) | 
					
						
							|  |  |  |       subreports << sjid | 
					
						
							|  |  |  |       @out.puts "Bootstraping server '#{server.id}'... job id: #{sjid}" | 
					
						
							|  |  |  |       data[server.id] = sjid | 
					
						
							| 
									
										
										
										
											2015-09-21 15:54:33 +03:00
										 |  |  |     end | 
					
						
							| 
									
										
										
										
											2015-11-03 12:05:07 +03:00
										 |  |  |     @out.puts | 
					
						
							|  |  |  |     @out.flush | 
					
						
							|  |  |  |     mongo.add_report_subreports(jid, subreports) | 
					
						
							|  |  |  |     results = [] | 
					
						
							|  |  |  |     data.each do |server_id, subreport_id| | 
					
						
							|  |  |  |       begin | 
					
						
							|  |  |  |         sleep(5) | 
					
						
							|  |  |  |         subreport = mongo.report(subreport_id) | 
					
						
							|  |  |  |         status = subreport.status | 
					
						
							|  |  |  |         if status == Worker::STATUS::COMPLETED | 
					
						
							|  |  |  |           @out.puts "Server '#{server_id}' has been bootstraped with job #{subreport_id}" | 
					
						
							|  |  |  |           break | 
					
						
							|  |  |  |         elsif status == Worker::STATUS::FAILED | 
					
						
							|  |  |  |           results << subreport.job_result_code | 
					
						
							|  |  |  |           @out.puts "Server '#{server_id}' hasn't been bootstraped with job #{subreport_id}. Job result code is '#{subreport.job_result_code}'" | 
					
						
							|  |  |  |           break | 
					
						
							|  |  |  |         end | 
					
						
							|  |  |  |       end while(true) | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  |     @out.flush | 
					
						
							|  |  |  |     results.empty? ? 0 : -5
 | 
					
						
							| 
									
										
										
										
											2015-09-21 15:54:33 +03:00
										 |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   def check_bootstrap_results!(results) | 
					
						
							|  |  |  |     if results.values.all?(&:zero?) | 
					
						
							|  |  |  |       # everything is OK | 
					
						
							|  |  |  |       @out.puts "Stack servers have been bootstraped" | 
					
						
							|  |  |  |       @out.flush | 
					
						
							|  |  |  |       return 0
 | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-09-22 15:07:56 +03:00
										 |  |  |     @out.puts | 
					
						
							| 
									
										
										
										
											2015-09-21 15:54:33 +03:00
										 |  |  |     results.each do |chef_node_name, code| | 
					
						
							| 
									
										
										
										
											2015-09-22 15:07:56 +03:00
										 |  |  |       human_readable_code = Devops::Executor::ServerExecutor.symbolic_result_code(code) | 
					
						
							| 
									
										
										
										
											2015-09-21 15:54:33 +03:00
										 |  |  |       @out.puts "Operation result for #{chef_node_name}: #{human_readable_code}" | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-09-25 17:31:10 +03:00
										 |  |  |     if errors_in_bootstrapping_present?(results.values) | 
					
						
							| 
									
										
										
										
											2015-09-22 15:07:56 +03:00
										 |  |  |       raise BootstrapingStackServerError # will cause rollback of a stack | 
					
						
							| 
									
										
										
										
											2015-09-21 15:54:33 +03:00
										 |  |  |     else | 
					
						
							| 
									
										
										
										
											2015-09-22 15:07:56 +03:00
										 |  |  |       raise DeployingStackServerError #will not cause rollback of a stack | 
					
						
							| 
									
										
										
										
											2015-09-21 15:54:33 +03:00
										 |  |  |     end | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-09-25 17:31:10 +03:00
										 |  |  |   def errors_in_bootstrapping_present?(result_codes) | 
					
						
							|  |  |  |     bootstrap_error_codes = [] | 
					
						
							|  |  |  |     [:server_bootstrap_fail, :server_not_in_chef_nodes, :server_bootstrap_unknown_error].each do |symbolic_code| | 
					
						
							|  |  |  |       bootstrap_error_codes << Devops::Executor::ServerExecutor.result_code(symbolic_code) | 
					
						
							| 
									
										
										
										
											2015-09-01 16:31:31 +03:00
										 |  |  |     end | 
					
						
							| 
									
										
										
										
											2015-09-25 17:31:10 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  |     (bootstrap_error_codes & result_codes).size > 0
 | 
					
						
							| 
									
										
										
										
											2015-09-01 16:31:31 +03:00
										 |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   def save_report(file, stack_attrs) | 
					
						
							|  |  |  |     report = ::Devops::Model::Report.new( | 
					
						
							|  |  |  |       "file" => file, | 
					
						
							|  |  |  |       "_id" => jid, | 
					
						
							|  |  |  |       "created_by" => stack_attrs['owner'], | 
					
						
							|  |  |  |       "project" => stack_attrs["project"], | 
					
						
							|  |  |  |       "deploy_env" => stack_attrs["deploy_env"], | 
					
						
							| 
									
										
										
										
											2015-11-05 16:47:12 +03:00
										 |  |  |       "type" => ::Devops::Model::Report::STACK_TYPE, | 
					
						
							|  |  |  |       "subreports" => [], | 
					
						
							|  |  |  |       "stack" => stack_attrs['name'] | 
					
						
							| 
									
										
										
										
											2015-09-01 16:31:31 +03:00
										 |  |  |     ) | 
					
						
							|  |  |  |     mongo.save_report(report) | 
					
						
							| 
									
										
										
										
											2015-09-17 11:50:35 +03:00
										 |  |  |     report | 
					
						
							| 
									
										
										
										
											2015-09-01 16:31:31 +03:00
										 |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-11-03 13:08:31 +03:00
										 |  |  |   # returns | 
					
						
							|  |  |  |   # { | 
					
						
							|  |  |  |   #   "priority" => [Servers] | 
					
						
							|  |  |  |   # } | 
					
						
							| 
									
										
										
										
											2015-11-03 12:05:07 +03:00
										 |  |  |   def persist_stack_servers!(stack) | 
					
						
							| 
									
										
										
										
											2015-09-21 15:54:33 +03:00
										 |  |  |     @out.puts "Start syncing stack servers with CID" | 
					
						
							|  |  |  |     @out.flush | 
					
						
							| 
									
										
										
										
											2015-07-30 02:14:45 +03:00
										 |  |  |     project = mongo.project(stack.project) | 
					
						
							|  |  |  |     deploy_env = project.deploy_env(stack.deploy_env) | 
					
						
							| 
									
										
										
										
											2015-11-03 12:05:07 +03:00
										 |  |  |     provider = stack.provider_instance | 
					
						
							| 
									
										
										
										
											2015-07-30 02:14:45 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-11-06 11:55:36 +03:00
										 |  |  |     stack_servers = provider.stack_servers(stack) | 
					
						
							|  |  |  |     stack_servers.each do |info| | 
					
						
							|  |  |  |       info["tags"]["cid:priority"] = info["tags"]["cid:priority"].to_i | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  |     stack_servers_info = stack_servers.group_by{|info| info["tags"]["cid:priority"]} | 
					
						
							| 
									
										
										
										
											2015-11-03 13:08:31 +03:00
										 |  |  |     stack_servers_with_priority = {} | 
					
						
							|  |  |  |     stack_servers_info.each do |priority, info_array| | 
					
						
							|  |  |  |       stack_servers_with_priority[priority] = info_array.map do |extended_info| | 
					
						
							|  |  |  |         server_attrs = { | 
					
						
							|  |  |  |           'provider' => provider.name, | 
					
						
							|  |  |  |           'project' => project.id, | 
					
						
							|  |  |  |           'deploy_env' => deploy_env.identifier, | 
					
						
							|  |  |  |           'remote_user' => mongo.image(deploy_env.image).remote_user, | 
					
						
							|  |  |  |           'key' => extended_info["key_name"] || provider.ssh_key, | 
					
						
							|  |  |  |           '_id' => extended_info["id"], | 
					
						
							|  |  |  |           'chef_node_name' => extended_info["name"], | 
					
						
							|  |  |  |           'private_ip' => extended_info["private_ip"], | 
					
						
							|  |  |  |           'public_ip' => extended_info["public_ip"], | 
					
						
							|  |  |  |           'created_by' => stack.owner, | 
					
						
							|  |  |  |           'run_list' => stack.run_list || [], | 
					
						
							|  |  |  |           'stack' => stack.name | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         server = ::Devops::Model::Server.new(server_attrs) | 
					
						
							|  |  |  |         mongo.server_insert(server) | 
					
						
							|  |  |  |         # server.chef_node_name =  provider.create_default_chef_node_name(server) | 
					
						
							|  |  |  |         server | 
					
						
							|  |  |  |       end | 
					
						
							| 
									
										
										
										
											2015-07-30 02:14:45 +03:00
										 |  |  |     end | 
					
						
							| 
									
										
										
										
											2015-09-21 15:54:33 +03:00
										 |  |  |     @out.puts "Stack servers have been synced with CID" | 
					
						
							| 
									
										
										
										
											2015-11-05 16:47:12 +03:00
										 |  |  |     stack_servers_with_priority.each do |priority, servers| | 
					
						
							| 
									
										
										
										
											2015-11-06 11:55:36 +03:00
										 |  |  |       @out.puts "Servers with priority '#{priority}': #{servers.map(&:id).join(", ")}" | 
					
						
							| 
									
										
										
										
											2015-11-03 13:08:31 +03:00
										 |  |  |     end | 
					
						
							| 
									
										
										
										
											2015-09-21 15:54:33 +03:00
										 |  |  |     @out.flush | 
					
						
							| 
									
										
										
										
											2015-11-03 13:08:31 +03:00
										 |  |  |     stack_servers_with_priority | 
					
						
							| 
									
										
										
										
											2015-07-30 02:14:45 +03:00
										 |  |  |   end | 
					
						
							| 
									
										
										
										
											2015-08-05 18:26:21 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-07-20 18:59:26 +03:00
										 |  |  | end |