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 "workers/delete_server_worker" 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) current_user = parser.current_user reports = servers.map do |server| Worker.start_async(DeleteServerWorker, 'server_id' => server.id, 'current_user' => current_user) end {reports: reports} end end end end end