229 lines
		
	
	
		
			7.6 KiB
		
	
	
	
		
			Ruby
		
	
	
	
	
	
			
		
		
	
	
			229 lines
		
	
	
		
			7.6 KiB
		
	
	
	
		
			Ruby
		
	
	
	
	
	
| require "lib/executors/server_executor"
 | |
| require "app/api3/parsers/stack"
 | |
| require 'db/mongo/models/stack/stack_factory'
 | |
| require 'workers/stack_bootstrap_worker'
 | |
| require_relative "request_handler"
 | |
| 
 | |
| module Devops
 | |
|   module API3
 | |
|     module Handler
 | |
|       class Stack < RequestHandler
 | |
| 
 | |
|         set_parser Devops::API3::Parser::StackParser
 | |
| 
 | |
|         def stacks
 | |
|           Model::StackAws.all
 | |
|         end
 | |
| 
 | |
|         # We support only aws, actually
 | |
|         def stacks_for_provider provider
 | |
|           Model::StackAws.all
 | |
|         end
 | |
| 
 | |
|         def create_stack
 | |
|           object = parser.create
 | |
|           attrs = object['stack_attributes']
 | |
|           env, category = fetch_env_and_category(attrs)
 | |
|           fill_attributes_from_category(attrs, env, category)
 | |
|           jid = Worker.start_async(StackBootstrapWorker,
 | |
|             stack_attributes: attrs,
 | |
|             without_bootstrap: object['without_bootstrap'],
 | |
|             skip_rollback: object['skip_rollback']
 | |
|           )
 | |
|           [jid]
 | |
|         end
 | |
| 
 | |
|         def stack name
 | |
|           Model::StackAws.where(name: name).first
 | |
|         end
 | |
| 
 | |
|         def delete_stack name
 | |
|           stack = self.stack(name)
 | |
|           stack.delete_stack_in_cloud!
 | |
|           Model::Server.where(stack: stack.id).delete_all
 | |
|           stack.delete
 | |
|         end
 | |
| 
 | |
|         def sync id
 | |
|           stack = self.stack(id)
 | |
|           stack.sync_status_and_events!
 | |
|           Devops::Db.connector.stack_update(stack)
 | |
| 
 | |
|           stack
 | |
|         end
 | |
| 
 | |
|         def stack_servers name
 | |
|           stack = Devops::Db.connector.stack(name)
 | |
|           Devops::Db.connector.stack_servers(stack.id)
 | |
|         end
 | |
| 
 | |
|         def set_run_list id
 | |
|           Devops::Db.connector.set_stack_run_list(id, parser.run_list)
 | |
|         end
 | |
| 
 | |
|         def set_tags id
 | |
|           tags = parser.tags
 | |
|           prepare_tags do |id, provider|
 | |
|             provider.set_tags id, tags
 | |
|           end
 | |
|         end
 | |
| 
 | |
|         def unset_tags id
 | |
|           tags = parser.tags
 | |
|           prepare_tags do |id, provider|
 | |
|             provider.unset_tags id, tags
 | |
|           end
 | |
|         end
 | |
| 
 | |
|         def prepare_tags node_name
 | |
|           stack = Devops::Db.connector.stack(id)
 | |
|           Devops::Db.connector.check_project_auth stack.project, stack.deploy_env, parser.current_user
 | |
|           stack_servers = Devops::Db.connector.stack_servers(id)
 | |
|           provider = stack.provider_instance
 | |
|           stack_servers.each do |s|
 | |
|             yield s.id, provider
 | |
|           end
 | |
|         end
 | |
| 
 | |
|         def deploy id
 | |
|           stack = self.stack(id)
 | |
|           owner = parser.current_user
 | |
|           project = Devops::Db.connector.check_project_auth(stack.project, stack.deploy_env, owner)
 | |
|           deploy_env_model = project.deploy_env(stack.deploy_env)
 | |
|           body = parser.deploy
 | |
|           names = body["names"]
 | |
|           tags = body["tags"] || []
 | |
|           files = []
 | |
|           jid = nil
 | |
|           servers = Devops::Db.connector.stack_servers(id, true)
 | |
|           servers.each do |s|
 | |
|             begin
 | |
|               deploy_info = project.deploy_info(deploy_env_model, nil)
 | |
|               jid = Worker.start_async(DeployWorker,
 | |
|                 server_attrs: s.to_hash,
 | |
|                 owner: owner,
 | |
|                 tags: tags,
 | |
|                 deploy_info: deploy_info
 | |
|               )
 | |
|             rescue DeployInfoError => e
 | |
|               msg = "Can not get deploy info: " + e.message
 | |
|               DevopsLogger.logger.error msg
 | |
|               jid = "error_#{s.chef_node_name}_#{Time.new.to_i}"
 | |
|               dir = DevopsConfig.config[:report_dir_v2]
 | |
|               file = File.jon(dir, jid)
 | |
|               File.open(file, "w") do |out|
 | |
|                 out.write msg
 | |
|               end
 | |
|               o = {
 | |
|                 "file" => file,
 | |
|                 "_id" => jid,
 | |
|                 "created_by" => owner,
 | |
|                 "project" => s.project,
 | |
|                 "deploy_env" => s.deploy_env,
 | |
|                 "type" => JobTask::DEPLOY_TYPE,
 | |
|                 "status" => Worker::STATUS::FAILED
 | |
|               }
 | |
|               JobTask.create(o)
 | |
|             end
 | |
|             files.push jid
 | |
|           end
 | |
|           files
 | |
|         end
 | |
| 
 | |
|         def deploy_stream id, out
 | |
|           stack = self.stack(id)
 | |
|           owner = parser.current_user
 | |
|           status = []
 | |
|           project = Devops::Db.connector.check_project_auth(stack.project, stack.deploy_env, owner)
 | |
|           body = parser.deploy
 | |
|           #TODO: deploy servers names
 | |
| #          names = body["names"]
 | |
|           tags = body["tags"] || []
 | |
|           # find all stack reserved servers
 | |
|           servers = Devops::Db.connector.stack_servers(stack_id, true)
 | |
|           deploy_info = project.deploy_info(stack.deploy_env, nil)
 | |
|           servers.each do |s|
 | |
|             begin
 | |
|               res = Devops::Executor::ServerExecutor.new(s, out, current_user: owner).deploy_server_with_tags(tags, deploy_info)
 | |
|               status.push(res)
 | |
|             rescue DeployInfoError => e
 | |
|               msg = "Can not get deploy info: " + e.message
 | |
|               DevopsLogger.logger.error msg
 | |
|               out << msg + "\n"
 | |
|               status.push 2
 | |
|               next
 | |
|             end
 | |
|           end
 | |
|           status
 | |
|         rescue RecordNotFound  => e
 | |
|           out << e.message
 | |
|           [-10]
 | |
|         end
 | |
| 
 | |
|         def reserve_servers(stack_id)
 | |
|           stack = self.stack(stack_id)
 | |
|           user = parser.current_user
 | |
|           Devops::Db.connector.check_project_auth stack.project, stack.deploy_env, user
 | |
| 
 | |
|           # check if none of servers are reserved by somebody else
 | |
|           servers = Devops::Db.connector.stack_servers(stack_id)
 | |
|           servers.each do |server|
 | |
|             if server.reserved_by.present? && server.reserved_by != user
 | |
|               raise ConflictException.new("Server '#{server.chef_node_name}' already reserved by #{server.reserved_by}")
 | |
|             end
 | |
|           end
 | |
| 
 | |
|           # reserve them
 | |
|           servers.each do |server|
 | |
|             server.reserved_by = user
 | |
|             Devops::Db.connector.server_update(server)
 | |
|           end
 | |
|         end
 | |
| 
 | |
|         def unreserve_servers(stack_id)
 | |
|           stack = self.stack(stack_id)
 | |
|           user = parser.current_user
 | |
|           Devops::Db.connector.check_project_auth stack.project, stack.deploy_env, user
 | |
| 
 | |
|           servers = Devops::Db.connector.stack_servers(stack_id)
 | |
|           servers.each do |server|
 | |
|             server.reserved_by = nil
 | |
|             Devops::Db.connector.server_update(server)
 | |
|           end
 | |
|         end
 | |
| 
 | |
|         def change_stack_template(stack_id)
 | |
|           stack_template_id = parser.change_stack_template
 | |
|           Devops::Db.connector.stack_template(stack_template_id)
 | |
|           stack = Devops::Db.connector.stack(stack_id)
 | |
|           stack.change_stack_template!(stack_template_id)
 | |
|         end
 | |
| 
 | |
|         private
 | |
| 
 | |
|         # env is used in devops-nibr
 | |
|         def fill_attributes_from_category(stack_attrs, env, category)
 | |
|           stack_attrs['stack_template'] = category.provider.stack_template
 | |
|           stack_attrs['owner'] = parser.current_user
 | |
|           stack_attrs['provider'] = category.provider.name
 | |
|           stack_attrs['provider_account'] = category.provider.account
 | |
|         end
 | |
| 
 | |
|         def fetch_env_and_category(attrs)
 | |
|           project = Model::Project.find_with_category(*attrs.values_at('project', 'environment', 'category'))
 | |
|           unless project
 | |
|             raise InvalidRecord.new("Project '#{attrs['project']}' has no env '#{attrs['environment']}' or category '#{attrs['category']}")
 | |
|           end
 | |
|           env = project.environment(attrs['environment'])
 | |
|           category = env.get_category!(attrs['category'])
 | |
|           if category.provider.type != Model::CategoryProvider::STACK_TYPE
 | |
|             raise InvalidRecord.new("Category '#{category.id}' type isn't 'stack'")
 | |
|           end
 | |
|           [env, category]
 | |
|         end
 | |
| 
 | |
|       end
 | |
|     end
 | |
|   end
 | |
| end
 | 
