334 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			Ruby
		
	
	
	
	
	
			
		
		
	
	
			334 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			Ruby
		
	
	
	
	
	
| require "commands/status"
 | |
| require "db/mongo/models/project"
 | |
| require "workers/project_test_worker"
 | |
| require "app/api2/parsers/project"
 | |
| require "lib/project/type/types_factory"
 | |
| require "lib/executors/server_executor"
 | |
| 
 | |
| require_relative "../helpers/version_2.rb"
 | |
| require_relative "request_handler"
 | |
| 
 | |
| module Devops
 | |
|   module API2_0
 | |
|     module Handler
 | |
|       class Project < RequestHandler
 | |
| 
 | |
|         set_parser Devops::API2_0::Parser::ProjectParser
 | |
| 
 | |
|         include Devops::API2_0::Helpers
 | |
| 
 | |
|         extend StatusCommands
 | |
| 
 | |
|         def project_types
 | |
|           Devops::TypesFactory.types_names
 | |
|         end
 | |
| 
 | |
|         def projects
 | |
|           Devops::Db.connector.projects(nil, nil, parser.projects, parser.archived_projects)
 | |
|         end
 | |
| 
 | |
|         def project id
 | |
|           Devops::Db.connector.project(id)
 | |
|         end
 | |
| 
 | |
|         def project_deploy_envs(id)
 | |
|           project = Devops::Db.connector.project(id)
 | |
|           project.deploy_envs
 | |
|         end
 | |
| 
 | |
|         def project_deploy_env(project_id, env)
 | |
|           project = Devops::Db.connector.project(project_id)
 | |
|           project.deploy_env(env)
 | |
|         end
 | |
| 
 | |
|         def project_servers id
 | |
|           Devops::Db.connector.project(id)
 | |
|           Devops::Db.connector.servers(id, parser.project_servers)
 | |
|         end
 | |
| 
 | |
|         def project_stacks id
 | |
|           # check if project exists
 | |
|           Devops::Db.connector.project(id)
 | |
|           options = {project: id}
 | |
|           deploy_env = parser.project_stacks
 | |
|           options[:deploy_env] = deploy_env if deploy_env
 | |
|           Devops::Db.connector.stacks(options)
 | |
|         end
 | |
| 
 | |
|         def create_project
 | |
|           p = parser.create_project
 | |
|           raise InvalidRecord.new("Project '#{p.id}' already exist") if Devops::Db.connector.is_project_exists?(p)
 | |
| 
 | |
|           p.deploy_envs.each do |env|
 | |
|             env.add_users [parser.current_user]
 | |
|           end
 | |
|           res = p.create
 | |
|           info = if p.multi?
 | |
|             "Project '#{p.id}' with type 'multi' created"
 | |
|           else
 | |
|             "Project '#{p.id}' created."
 | |
|           end
 | |
| #          info << " " + res[:before] if res[:before]
 | |
| #          info << " " + res[:after] if res[:after]
 | |
|           info
 | |
|         end
 | |
| 
 | |
|         def set_project_components id
 | |
|           body = parser.set_project_components
 | |
|           project = Devops::Db.connector.project(id)
 | |
|           project.components = body["components"]
 | |
|           project.validate_components
 | |
|           Devops::Db.connector.project_update_field id, "components", body["components"]
 | |
|           "Updated project '#{project.id}' with components '#{body["components"].inspect}'"
 | |
|         end
 | |
| 
 | |
|         def add_deploy_env id
 | |
|           project = Devops::Db.connector.project(id)
 | |
|           env = parser.add_deploy_env
 | |
|           env.add_users [parser.current_user]
 | |
|           env.validate!
 | |
|           begin
 | |
|             db_env = project.deploy_env(env.identifier)
 | |
|             raise InvalidRecord.new("Can not add new environment for project '#{id}'. Environment '#{env.identifier}' already exist")
 | |
|           rescue RecordNotFound => e
 | |
|             res = project.add_deploy_env env
 | |
|             return "Deploy environment '#{env.identifier}' has been added to project '#{project.id}'." + res, env
 | |
|           end
 | |
|         end
 | |
| 
 | |
|         def update_deploy_env_field id, deploy_env, field
 | |
|           project = Devops::Db.connector.project(id)
 | |
|           db_env = project.deploy_env(deploy_env)
 | |
|           value = parser.update_deploy_env_field
 | |
|           if db_env.respond_to?(field + "=")
 | |
|             if field == "identifier"
 | |
|               db_env.rename id, value
 | |
|               "Environment '#{deploy_env}' has been renamed to '#{value}'"
 | |
|             else
 | |
|               db_env.update_field(id, field, value)
 | |
|               "Environment's field '#{field}' has been updated"
 | |
|             end
 | |
|           else
 | |
|             raise RecordNotFound.new("Field '#{field}' does not exist")
 | |
|           end
 | |
|         end
 | |
| 
 | |
|         def update_deploy_env id, deploy_env
 | |
|           project = Devops::Db.connector.project(id)
 | |
|           db_env = project.deploy_env(deploy_env)
 | |
|           env = parser.update_deploy_env
 | |
|           env.identifier = deploy_env if env.identifier.nil?
 | |
|           begin
 | |
|             unless env.identifier == deploy_env
 | |
|               servers = Devops::Db.connector.servers_by_project_and_deploy_env(id, deploy_env)
 | |
|               raise InvalidRecord.new("Environment '#{deploy_env}' can't be updated: it has #{servers.size} running servers.") unless servers.empty?
 | |
|             end
 | |
|             begin
 | |
|               project.deploy_env(env.identifier)
 | |
|               raise InvalidRecord.new("Environment '#{deploy_env}' can't be renamed to '#{env.identifier}', environment '#{env.identifier}' already exists") unless deploy_env == env.identifier
 | |
|             rescue RecordNotFound => e
 | |
|             end
 | |
|             env.validate!
 | |
|             project.delete_deploy_env(deploy_env)
 | |
|             project.add_deploy_env(env)
 | |
|             "Deploy environment '#{deploy_env}' has been updated in project '#{project.id}'"
 | |
|           rescue RecordNotFound => e
 | |
|             env.identifier = deploy_env
 | |
|             res = project.add_deploy_env env
 | |
|             "Deploy environment '#{env.identifier}' has been added to project '#{project.id}'." + res
 | |
|           end
 | |
|         end
 | |
| 
 | |
|         def delete_deploy_env id, deploy_env
 | |
|           project = Devops::Db.connector.project(id)
 | |
|           servers = Devops::Db.connector.servers_by_project_and_deploy_env(id, deploy_env)
 | |
|           raise InvalidRecord.new("Can not delete environment '#{deploy_env}', there are #{servers.size} servers on it") unless servers.empty?
 | |
|           project.delete_deploy_env(deploy_env)
 | |
|         end
 | |
| 
 | |
|         def update_project id
 | |
|           body = parser.update
 | |
|           old_project = Devops::Db.connector.project id
 | |
|           Devops::Db.connector.project_update id, body
 | |
|         end
 | |
| 
 | |
|         # TODO: multi project
 | |
|         def update_project_users id
 | |
|           deploy_env, users = parser.project_users
 | |
|           project = Devops::Db.connector.project(id)
 | |
|           Validators::Helpers::Users.new(users).validate!
 | |
|           project.add_authorized_user users, deploy_env
 | |
|           info = "Users '#{users.join("', '")}' has been added to '#{id}' project's authorized users."
 | |
|           info
 | |
|         end
 | |
| 
 | |
|         # TODO: multi project
 | |
|         def delete_project_users id
 | |
|           deploy_env, users = parser.project_users
 | |
|           project = Devops::Db.connector.project(id)
 | |
|           project.remove_authorized_user users, deploy_env
 | |
|           "Users '#{users.join("', '")}' have been removed from '#{id}' project's authorized users"
 | |
|         end
 | |
| 
 | |
|         def set_project_run_list id
 | |
|           list = parser.run_list
 | |
|           project = Devops::Db.connector.project(id)
 | |
|           Devops::Db.connector.set_project_run_list id, list
 | |
|           "Updated project with run_list '#{list.inspect}'"
 | |
|         end
 | |
| 
 | |
|         def set_project_env_run_list id, deploy_env
 | |
|           list = parser.run_list
 | |
|           project = Devops::Db.connector.project(id)
 | |
|           env = project.deploy_env deploy_env
 | |
|           Devops::Db.connector.set_project_env_run_list id, deploy_env, list
 | |
|           "Updated environment '#{env.identifier}' with run_list '#{list.inspect}' in project '#{project.id}'"
 | |
|         end
 | |
| 
 | |
|         def delete_project id
 | |
|           deploy_env = parser.delete
 | |
|           project = Devops::Db.connector.project(id)
 | |
|           if deploy_env.nil?
 | |
|             servers = Devops::Db.connector.servers id
 | |
|             raise DependencyError.new "Deleting project #{id} is forbidden: Project has servers" unless servers.empty?
 | |
|             project.delete
 | |
|             "Project '#{id}' is deleted"
 | |
|           else
 | |
|             servers = Devops::Db.connector.servers id, deploy_env
 | |
|             raise DependencyError.new "Deleting deploy_env #{deploy_env} is forbidden: Project has servers" unless servers.empty?
 | |
|             project.delete_deploy_env(deploy_env)
 | |
|             "Project '#{id}'. Deploy environment '#{deploy_env}' has been deleted"
 | |
|           end
 | |
|         end
 | |
| 
 | |
|         def deploy_project_stream out, id
 | |
|           # check if project exist
 | |
|           project = Devops::Db.connector.project(id)
 | |
|           deploy_env, servers = parser.deploy
 | |
|           keys = {}
 | |
|           dbserver = Devops::Db.connector.servers(id, deploy_env, servers, true)
 | |
|           out << (dbservers.empty? ? "No reserved servers to deploy\n" : "Deploy servers: '#{dbservers.map{|s| s.chef_node_name}.join("', '")}'\n")
 | |
|           status = []
 | |
|           deploy_info_buf = {}
 | |
|           dbservers.each do |s|
 | |
|             begin
 | |
|               Devops::Db.connector.check_project_auth s.project, s.deploy_env, parser.current_user
 | |
|             rescue InvalidPrivileges, RecordNotFound  => e
 | |
|               out << e.message + "\n"
 | |
|               status.push 2
 | |
|               next
 | |
|             end
 | |
|             deploy_env_model = project.deploy_env(s.deploy_env)
 | |
|             deploy_info = if deploy_info_buf[s.deploy_env]
 | |
|               deploy_info_buf[s.deploy_env]
 | |
|             else
 | |
|               # мы не можем указать один build_number для всех окружений, поэтому nil
 | |
|               deploy_info_buf[s.deploy_env] = project.deploy_info(deploy_env_model, nil)
 | |
|             end
 | |
|             status.push(Devops::Executor::ServerExecutor.new(s, out, current_user: parser.current_user).deploy_server(deploy_info))
 | |
|           end
 | |
|           status
 | |
|         end
 | |
| 
 | |
|         def deploy_project id
 | |
|           # check if project exist
 | |
|           project_model = Devops::Db.connector.project(id)
 | |
|           deploy_env, servers = parser.deploy
 | |
|           files = []
 | |
|           dbservers = Devops::Db.connector.servers(id, deploy_env, servers, true)
 | |
|           #out << (dbservers.empty? ? "No reserved servers to deploy\n" : "Deploy servers: '#{dbservers.map{|s| s.chef_node_name}.join("', '")}'\n")
 | |
|           deploy_info_buf = {}
 | |
|           dbservers.each do |s|
 | |
|             begin
 | |
|               Devops::Db.connector.check_project_auth s.project, s.deploy_env, parser.current_user
 | |
|             rescue InvalidPrivileges, RecordNotFound  => e
 | |
|               next
 | |
|             end
 | |
| 
 | |
|             deploy_env_model = project_model.deploy_env(s.deploy_env)
 | |
|             deploy_info = if deploy_info_buf[s.deploy_env]
 | |
|               deploy_info_buf[s.deploy_env]
 | |
|             else
 | |
|               # мы не можем указать один build_number для всех окружений, поэтому nil
 | |
|               deploy_info_buf[s.deploy_env] = project_model.deploy_info(deploy_env_model, nil)
 | |
|             end
 | |
| 
 | |
|             jid = Worker.start_async(DeployWorker,
 | |
|               server_attrs: s.to_hash,
 | |
|               owner: parser.current_user,
 | |
|               tags: [],
 | |
|               deploy_info: deploy_info
 | |
|             )
 | |
|             files.push jid
 | |
|           end
 | |
|           files
 | |
|         end
 | |
| 
 | |
|         def archive_project id
 | |
|           project = Devops::Db.connector.project(id)
 | |
|           Devops::Db.connector.archive_project(id)
 | |
|           msg = "Project '#{id}' has been archived"
 | |
|           DevopsLogger.logger.info msg
 | |
|           msg
 | |
|         end
 | |
| 
 | |
|         def unarchive_project id
 | |
|           project = Devops::Db.connector.project(id)
 | |
|           Devops::Db.connector.unarchive_project(id)
 | |
|           msg = "Project '#{id}' has been unarchived"
 | |
|           DevopsLogger.logger.info msg
 | |
|           msg
 | |
|         end
 | |
| 
 | |
|         def test_project id, deploy_env
 | |
|           project = Devops::Db.connector.project(id)
 | |
|           env = project.deploy_env deploy_env
 | |
|           DevopsLogger.logger.info "Test project '#{project.id}' and environment '#{env.identifier}'"
 | |
|           if env.provider == ::Provider::Static::PROVIDER
 | |
|             msg = "Can not test environment with provider '#{::Provider::Static::PROVIDER}'"
 | |
|             Logger.warn msg
 | |
|             raise InvalidRecord.new(msg)
 | |
|           end
 | |
| 
 | |
|           jid = Worker.start_async(ProjectTestWorker,
 | |
|             project: project.id,
 | |
|             deploy_env: env.identifier,
 | |
|             user: @request.env['REMOTE_USER']
 | |
|           )
 | |
| 
 | |
|           sleep 1
 | |
|           return [jid]
 | |
|         end
 | |
| 
 | |
|         def delete_project_servers(project_id)
 | |
|           env_id, dry_run = parser.delete_project_servers
 | |
|           Devops::Db.connector.project(project_id)
 | |
|           servers = Devops::Db.connector.servers(project_id, env_id)
 | |
|           info = {to_delete: servers.map(&:id)}
 | |
|           if !dry_run
 | |
|             info.merge!(delete_chosen_servers!(servers))
 | |
|           end
 | |
|           info
 | |
|         end
 | |
| 
 | |
|         private
 | |
| 
 | |
|         def delete_chosen_servers!(servers)
 | |
|           deleted, failed = [], []
 | |
|           servers.each do |server|
 | |
|             begin
 | |
|               Devops::Executor::ServerExecutor.new(server, '').delete_server
 | |
|               deleted << server.id
 | |
|             rescue
 | |
|               failed << server.id
 | |
|             end
 | |
|           end
 | |
|           {deleted: deleted, failed: failed}
 | |
|         end
 | |
| 
 | |
|       end
 | |
|     end
 | |
|   end
 | |
| end
 | |
| 
 | 
