require "commands/deploy" require "commands/status" require "commands/server" require "db/mongo/models/project" require "workers/project_test_worker" module Devops module Version2_0 module Handler class Project extend DeployCommands extend StatusCommands extend ServerCommands def self.get_projects lambda { check_privileges("project", "r") fields = [] if params.key?("fields") and params["fields"].is_a?(Array) Devops::Model::Project.fields.each do |k| fields.push k if params["fields"].include?(k) end end archived = params.include?("archived") json settings.mongo.projects(nil, nil, fields, archived).map {|p| p.to_hash} } end def self.get_project lambda { check_privileges("project", "r") json settings.mongo.project(params[:project]) } end def self.get_project_servers lambda { check_privileges("project", "r") settings.mongo.project(params[:project]) json settings.mongo.servers(params[:project], params[:deploy_env]).map{|s| s.to_hash} } end def self.get_project_stacks lambda { check_privileges("project", "r") settings.mongo.project(params[:project]) options = {project: params[:project]} options[:deploy_env] = params[:deploy_env] if params[:deploy_env] json settings.mongo.stacks(options).map{|s| s.to_hash} } end # TODO: multi project def self.create_project lambda { check_privileges("project", "w") body = create_object_from_json_body check_string(body["name"], "Parameter 'name' must be a not empty string") check_array(body["deploy_envs"], "Parameter 'deploy_envs' must be a not empty array of objects", Hash) p = Devops::Model::Project.new(body) halt_response("Project '#{p.id}' already exist") if settings.mongo.is_project_exists?(p) p.add_authorized_user [request.env['REMOTE_USER']] p.create roles_res = "" if p.multi? logger.info "Project '#{p.id}' with type 'multi' created" else logger.info "Project '#{p.id}' created" roles = Project.create_roles p.id, p.deploy_envs, logger roles_res = ". " + Project.create_roles_response(roles) end res = "Created" + roles_res create_response(res, nil, 201) } end # TODO: multi project def self.update_project lambda { check_privileges("project", "w") project = Devops::Model::Project.new(create_object_from_json_body) project.id = params[:project] old_project = settings.mongo.project params[:project] settings.mongo.project_update project roles = Devops::Version2_0::Handler::Project.create_new_roles(old_project, project, logger) info = "Project '#{project.id}' has been updated." + Project.create_roles_response(roles) create_response(info) } end # TODO: multi project def self.update_project_users lambda { check_privileges("project", "w") body = create_object_from_json_body users = check_array(body["users"], "Parameter 'users' must be a not empty array of strings") deploy_env = check_string(body["deploy_env"], "Parameter 'deploy_env' must be a not empty string", true) project = settings.mongo.project(params[:id]) users = settings.mongo.users(users).map{|u| u.id} buf = users - users project.add_authorized_user users, deploy_env settings.mongo.project_update(project) info = "Users '#{users.join("', '")}' have been added to '#{params[:id]}' project's authorized users" info << ", invalid users: '#{buf.join("', '")}'" unless buf.empty? create_response(info) } end # TODO: multi project def self.delete_project_users lambda { check_privileges("project", "w") @project.remove_authorized_user @users, @deploy_env settings.mongo.project_update @project info = "Users '#{@users.join("', '")}' have been removed from '#{params[:id]}' project's authorized users" create_response(info) } end # TODO: multi project def self.set_project_env_run_list lambda { check_privileges("project", "w") list = create_object_from_json_body(Array) check_array(list, "Body must contains not empty array of strings") project = settings.mongo.project(params[:id]) env = project.deploy_env params[:env] env.run_list = list settings.mongo.project_update project create_response("Updated environment '#{env.identifier}' with run_list '#{env.run_list.inspect}' in project '#{project.id}'") } end def self.delete_project lambda { check_privileges("project", "w") servers = settings.mongo.servers params[:project] raise DependencyError.new "Deleting #{params[:project]} is forbidden: Project has servers" if !servers.empty? body = create_object_from_json_body(Hash, true) deploy_env = unless body.nil? check_string(body["deploy_env"], "Parameter 'deploy_env' should be a not empty string", true) end project = settings.mongo.project(params[:project]) info = if deploy_env.nil? project.delete "Project '#{params[:project]}' is deleted" else project.remove_env deploy_env settings.mongo.project_update project "Project '#{params[:project]}'. Deploy environment '#{deploy_env}' has been deleted" end create_response(info) } end def self.deploy_project lambda { check_privileges("project", "x") obj = create_object_from_json_body check_string(obj["deploy_env"], "Parameter 'deploy_env' should be a not empty string", true) check_array(obj["servers"], "Parameter 'servers' should be a not empty array of strings", String, true) project = settings.mongo.project(params[:id]) servers = settings.mongo.servers(params[:id], obj["deploy_env"], obj["servers"], true) keys = {} if obj.key?("trace") stream() do |out| begin out << (servers.empty? ? "No reserved servers to deploy\n" : "Deploy servers: '#{servers.map{|s| s.chef_node_name}.join("', '")}'\n") status = [] servers.each do |s| logger.debug "Deploy server: #{s.inspect}" begin settings.mongo.check_project_auth s.project, s.deploy_env, request.env['REMOTE_USER'] rescue InvalidPrivileges, RecordNotFound => e out << e.message + "\n" status.push 2 next end unless keys.key? s.key k = settings.mongo.key s.key keys[s.key] = k.path end status.push(deploy_server(out, s, keys[s.key])) end out << create_status(status) rescue IOError => e logger.error e.message end end else dir = DevopsConfig[:report_dir_v2] files = [] uri = URI.parse(request.url) servers.each do |s| project = begin settings.mongo.check_project_auth s.project, s.deploy_env, request.env['REMOTE_USER'] rescue InvalidPrivileges, RecordNotFound => e next end jid = DeployWorker.perform_async(dir, s.to_hash, [], DevopsConfig.config) logger.info "Job '#{jid}' has been started" uri.path = "#{DevopsConfig[:url_prefix]}/v2.0/report/" + jid files.push uri.to_s end json files end } end def self.archive_project lambda { check_privileges("project", "w") project = settings.mongo.project(params[:project]) if project.nil? create_response("Project '#{params[:project]}' not found", nil, 404) else settings.mongo.archive_project(params[:project]) info = "Project '#{params[:project]}' has been archived" create_response(info) end } end def self.unarchive_project lambda { check_privileges("project", "w") project = settings.mongo.project(params[:project]) if project.nil? create_response("Project '#{params[:project]}' not found", nil, 404) else settings.mongo.unarchive_project(params[:project]) info = "Project '#{params[:project]}' has been unarchived" create_response(info) end } end def self.test_project lambda { check_privileges("project", "r") project = settings.mongo.project(params[:id]) env = project.deploy_env params[:env] 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 return [400, msg] end dir = DevopsConfig[:report_dir_v2] uri = URI.parse(request.url) p = { :project => project.id, :env => env.identifier, :user => request.env['REMOTE_USER'] } jid = ProjectTestWorker.perform_async(dir, p, DevopsConfig.config) Worker.set_status jid, Worker::STATUS::IN_QUEUE logger.info "Job '#{jid}' has been created" uri.path = "#{DevopsConfig[:url_prefix]}/v2.0/report/" + jid files = [uri.to_s] sleep 1 json files } end def self.create_roles project_id, envs, logger all_roles = KnifeCommands.roles return " Can't get roles list" if all_roles.nil? roles = {:new => [], :error => [], :exist => []} envs.each do |e| role_name = KnifeCommands.role_name(project_id, e.identifier) begin if all_roles.include? role_name roles[:exist].push role_name else KnifeCommands.create_role role_name, project_id, e.identifier roles[:new].push role_name logger.info "Role '#{role_name}' created" end rescue => er roles[:error].push role_name logger.error "Role '#{role_name}' can not be created: #{er.message}" end end roles end def self.create_new_roles old_project, new_project, logger old_project.deploy_envs.each do |e| new_project.remove_env(e.identifier) end Devops::Version2_0::Handler::Project.create_roles new_project.id, new_project.deploy_envs, logger end def self.create_roles_response roles if roles.is_a?(String) roles else info = "" info += " Project roles '#{roles[:new].join("', '")}' have been automaticaly created" unless roles[:new].empty? info += " Project roles '#{roles[:exist].join("', '")}' weren't created because they exist" unless roles[:exist].empty? info += " Project roles '#{roles[:error].join("', '")}' weren't created because of internal error" unless roles[:error].empty? info end end end end end end