306 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			Ruby
		
	
	
	
	
	
			
		
		
	
	
			306 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			Ruby
		
	
	
	
	
	
| 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
 | |
| 
 | |
|         # 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
 | |
| 
 | 
