391 lines
13 KiB
Ruby
391 lines
13 KiB
Ruby
|
|
require "uri"
|
||
|
|
|
||
|
|
require "commands/status"
|
||
|
|
require "commands/bootstrap_templates"
|
||
|
|
require 'exceptions/conflict_exception'
|
||
|
|
require "lib/executors/server_executor"
|
||
|
|
|
||
|
|
require "db/mongo/models/server"
|
||
|
|
|
||
|
|
require "workers/create_server_worker"
|
||
|
|
require "workers/delete_server_worker"
|
||
|
|
require "workers/bootstrap_worker"
|
||
|
|
require "workers/unbootstrap_worker"
|
||
|
|
require "app/api3/parsers/server"
|
||
|
|
require_relative "request_handler"
|
||
|
|
|
||
|
|
module Devops
|
||
|
|
module API3
|
||
|
|
module Handler
|
||
|
|
class Server < RequestHandler
|
||
|
|
|
||
|
|
set_parser Devops::API3::Parser::ServerParser
|
||
|
|
|
||
|
|
extend StatusCommands
|
||
|
|
extend BootstrapTemplatesCommands
|
||
|
|
|
||
|
|
def servers
|
||
|
|
Devops::Model::Server.where(parser.servers).all
|
||
|
|
end
|
||
|
|
|
||
|
|
def provider_servers provider
|
||
|
|
provider_servers_with_account provider, nil
|
||
|
|
end
|
||
|
|
|
||
|
|
def provider_servers_with_account provider, account
|
||
|
|
::Provider.get_connector(provider, account).servers
|
||
|
|
end
|
||
|
|
|
||
|
|
def server id
|
||
|
|
Devops::Model::Server.find(id)
|
||
|
|
rescue Mongoid::Errors::DocumentNotFound
|
||
|
|
raise Devops::Exception::RecordNotFound.new("Server '#{id}' not found")
|
||
|
|
end
|
||
|
|
|
||
|
|
# ids - array of servers ids
|
||
|
|
# returns array of jid
|
||
|
|
def delete ids
|
||
|
|
user = parser.current_user
|
||
|
|
jids = []
|
||
|
|
ids.each do |id|
|
||
|
|
DevopsLogger.logger.debug("Trying to delete server '#{id}'")
|
||
|
|
begin
|
||
|
|
s = server(id)
|
||
|
|
Devops::Model::Project.check_user_authorization(s.project, s.environment, user)
|
||
|
|
jid = Worker.start_async(DeleteServerWorker,
|
||
|
|
server_id: s.id,
|
||
|
|
user: user
|
||
|
|
)
|
||
|
|
jids << jid
|
||
|
|
rescue Devops::Exception::RecordNotFound, Devops::Exception::Unauthorized => e
|
||
|
|
DevopsLogger.logger.warn(e.message)
|
||
|
|
end
|
||
|
|
end
|
||
|
|
jids
|
||
|
|
end
|
||
|
|
|
||
|
|
def server_id_by_name name
|
||
|
|
s = Devops::Model::Server.find_by(name: name)
|
||
|
|
s.id
|
||
|
|
rescue Mongoid::Errors::DocumentNotFound
|
||
|
|
raise Devops::Exception::RecordNotFound.new("Server with name '#{name}' not found")
|
||
|
|
end
|
||
|
|
|
||
|
|
# ids - array of servers ids
|
||
|
|
def delete_stream ids, out
|
||
|
|
user = parser.current_user
|
||
|
|
ids.each do |id|
|
||
|
|
begin
|
||
|
|
s = server(id)
|
||
|
|
### Authorization
|
||
|
|
Devops::Model::Project.check_user_authorization(s.project, s.environment, user)
|
||
|
|
Devops::Executor::ServerExecutor.new(s, out).delete_server
|
||
|
|
rescue Devops::Exception::RecordNotFound
|
||
|
|
out.puts "Server '#{id}' not found"
|
||
|
|
rescue Devops::Exception::Unauthorized
|
||
|
|
out.puts "User '#{user}' can not delete server '#{id}'"
|
||
|
|
end
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
def create_server_stream out
|
||
|
|
status = []
|
||
|
|
prepare_create_server do |project, env, user, body|
|
||
|
|
e = Devops::Executor::ServerExecutor.new(nil, out)
|
||
|
|
e.project = project
|
||
|
|
e.environment = env
|
||
|
|
body["created_by"] = user
|
||
|
|
res = e.create_server(body)
|
||
|
|
status.push res
|
||
|
|
end
|
||
|
|
status
|
||
|
|
end
|
||
|
|
|
||
|
|
def create_server
|
||
|
|
body = parser.create
|
||
|
|
user = parser.current_user
|
||
|
|
|
||
|
|
check_if_server_attrs_are_valid(body, user)
|
||
|
|
jid = Worker.start_async(CreateServerWorker,
|
||
|
|
server_attrs: body,
|
||
|
|
owner: user
|
||
|
|
)
|
||
|
|
[jid]
|
||
|
|
end
|
||
|
|
|
||
|
|
def deploy id
|
||
|
|
call_deploy(id) do |options|
|
||
|
|
[ Worker.start_async(DeployWorker, options) ]
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
def call_stream out
|
||
|
|
yield
|
||
|
|
rescue Devops::Exception::RecordNotFound => e
|
||
|
|
out << e.message
|
||
|
|
NOT_FOUND
|
||
|
|
rescue Devops::Exception::ConflictError => e
|
||
|
|
out << e.message
|
||
|
|
CONFLICT
|
||
|
|
rescue Devops::Exception::Unauthorized => e
|
||
|
|
out << e.message
|
||
|
|
UNAUTHORIZED
|
||
|
|
end
|
||
|
|
|
||
|
|
def deploy_stream id, out
|
||
|
|
call_stream(out) do
|
||
|
|
call_deploy(id) do |options|
|
||
|
|
Worker.start_sync(DeployWorker, options, out)
|
||
|
|
end
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
def call_deploy id
|
||
|
|
body = parser.deploy
|
||
|
|
tags = body["tags"] || []
|
||
|
|
run_list = body["run_list"]
|
||
|
|
owner = parser.current_user
|
||
|
|
s = server(id)
|
||
|
|
project = Devops::Model::Project.check_user_authorization(s.project, s.environment, owner)
|
||
|
|
deploy_info = create_deploy_info(s, project, body["build_number"])
|
||
|
|
deploy_info["run_list"] = run_list if run_list
|
||
|
|
|
||
|
|
yield({
|
||
|
|
server_id: id,
|
||
|
|
owner: owner,
|
||
|
|
tags: tags,
|
||
|
|
deploy_info: deploy_info
|
||
|
|
})
|
||
|
|
end
|
||
|
|
|
||
|
|
def create_deploy_info server, project, build_number
|
||
|
|
env_model = project.environment(server.environment)
|
||
|
|
project.deploy_info(env_model, build_number)
|
||
|
|
end
|
||
|
|
|
||
|
|
def pause_server id
|
||
|
|
s = Devops::Model::Server.find(id)
|
||
|
|
## Authorization
|
||
|
|
Devops::Model::Project.check_user_authorization(s.project, s.environment, parser.current_user)
|
||
|
|
provider = s.provider_instance
|
||
|
|
r = provider.pause_server s
|
||
|
|
if r.nil?
|
||
|
|
set_last_operation_and_save(s, Devops::Model::Server::OperationType::PAUSE)
|
||
|
|
"Server with instance ID '#{s.id}' has been paused"
|
||
|
|
else
|
||
|
|
raise Devops::Exception::ConflictError.new("Server with instance ID '#{s.id}' can not be paused, It in state '#{r}'")
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
def unpause_server id
|
||
|
|
s = Devops::Model::Server.find(id)
|
||
|
|
## Authorization
|
||
|
|
Devops::Model::Project.check_user_authorization(s.project, s.environment, parser.current_user)
|
||
|
|
provider = s.provider_instance
|
||
|
|
r = provider.unpause_server s
|
||
|
|
if r.nil?
|
||
|
|
set_last_operation_and_save(s, Devops::Model::Server::OperationType::UNPAUSE)
|
||
|
|
"Server with instance ID '#{s.id}' has been unpaused"
|
||
|
|
else
|
||
|
|
raise Devops::Exception::ConflictError.new("Server with instance ID '#{s.id}' can not be unpaused, It in state '#{r}'")
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
def reserve_server id
|
||
|
|
s = Devops::Model::Server.find(id)
|
||
|
|
user = parser.current_user
|
||
|
|
Devops::Model::Project.check_user_authorization(s.project, s.environment, user)
|
||
|
|
raise Devops::Exception::ConflictError.new("Server '#{id}' already reserved") unless s.reserved_by.nil?
|
||
|
|
s.reserved_by = user
|
||
|
|
set_last_operation_and_save(s, Devops::Model::Server::OperationType::RESERVE)
|
||
|
|
end
|
||
|
|
|
||
|
|
def unreserve_server id
|
||
|
|
s = Devops::Model::Server.find(id)
|
||
|
|
user = parser.current_user
|
||
|
|
Devops::Model::Project.check_user_authorization(s.project, s.environment, user)
|
||
|
|
raise Devops::Exception::ConflictError.new("Server '#{id}' is not reserved") if s.reserved_by.nil?
|
||
|
|
s.reserved_by = nil
|
||
|
|
set_last_operation_and_save(s, Devops::Model::Server::OperationType::UNRESERVE)
|
||
|
|
end
|
||
|
|
|
||
|
|
# TODO: check bootstrap template name
|
||
|
|
def bootstrap_server_stream id, out
|
||
|
|
call_stream(out) do
|
||
|
|
call_bootstrap(id) do |options|
|
||
|
|
Worker.start_sync(BootstrapWorker, options, out)
|
||
|
|
end
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
def bootstrap_server(id)
|
||
|
|
call_bootstrap(id) do |options|
|
||
|
|
Worker.start_async(BootstrapWorker, options)
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
def call_bootstrap id
|
||
|
|
body = parser.bootstrap
|
||
|
|
name = body["cm_name"]
|
||
|
|
rl = body["run_list"]
|
||
|
|
t = body["bootstrap_template"]
|
||
|
|
s = server(id)
|
||
|
|
|
||
|
|
user = parser.current_user
|
||
|
|
p = Devops::Model::Project.check_user_authorization(s.project, s.environment, user)
|
||
|
|
raise Devops::Exception::ConflictError.new("Server '#{id}' already bootstrapped") unless s.cm_name.nil?
|
||
|
|
attrs = {
|
||
|
|
server_id: id,
|
||
|
|
owner: user
|
||
|
|
}
|
||
|
|
|
||
|
|
d = p.environment(s.environment)
|
||
|
|
|
||
|
|
provider = s.provider_instance
|
||
|
|
|
||
|
|
if name
|
||
|
|
d.get_category(s.category).cm_tool.check_node_name(name)
|
||
|
|
attrs[:cm_name] = name
|
||
|
|
end
|
||
|
|
unless t.nil?
|
||
|
|
templates = get_templates
|
||
|
|
raise ValidationError.new("Invalid bootstrap template '#{t}', available values: #{templates.join(", ")}") unless templates.include?(t)
|
||
|
|
attrs[:bootstrap_template] = t
|
||
|
|
end
|
||
|
|
attrs[:run_list] = rl if rl
|
||
|
|
|
||
|
|
yield(attrs)
|
||
|
|
end
|
||
|
|
|
||
|
|
def unbootstrap_server id
|
||
|
|
call_unbootstrap(id) do |options|
|
||
|
|
Worker.start_async(UnbootstrapWorker, options)
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
def unbootstrap_server_stream id, out
|
||
|
|
call_stream(out) do
|
||
|
|
call_unbootstrap(id) do |options|
|
||
|
|
Worker.start_sync(UnbootstrapWorker, options)
|
||
|
|
end
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
def call_unbootstrap id
|
||
|
|
s = server(id)
|
||
|
|
user = parser.current_user
|
||
|
|
### Authorization
|
||
|
|
Devops::Model::Project.check_user_authorization(s.project, s.environment, user)
|
||
|
|
raise Devops::Exception::ConflictError.new("Server '#{id}' is not bootstrapped") if s.cm_name.nil?
|
||
|
|
attrs = {
|
||
|
|
server_id: id,
|
||
|
|
owner: parser.current_user
|
||
|
|
}
|
||
|
|
yield(attrs)
|
||
|
|
end
|
||
|
|
|
||
|
|
def add_server
|
||
|
|
body = parser.add_server
|
||
|
|
user = parser.current_user
|
||
|
|
project = Devops::Model::Project.check_user_authorization(body[:project], body[:environment], user)
|
||
|
|
env = project.environment(body[:environment])
|
||
|
|
category = env.get_category!(body[:category])
|
||
|
|
raise 'Provider should be static' if category.provider.name != 'static'
|
||
|
|
provider_account = Model::ProviderAccount.find(category.provider.account)
|
||
|
|
provider = ::Provider.provider('static')
|
||
|
|
Devops::Model::Server.create!(
|
||
|
|
"provider" => provider.name,
|
||
|
|
"provider_account" => provider_account.id,
|
||
|
|
"project" => project.id,
|
||
|
|
"environment" => env.id,
|
||
|
|
"category" => category.id,
|
||
|
|
"remote_user" => body[:remote_user],
|
||
|
|
"private_ip" => body[:private_ip],
|
||
|
|
"public_ip" => body[:public_ip],
|
||
|
|
"id" => "static_#{provider_account.ssh_key}-#{Time.now.to_i}",
|
||
|
|
"ssh_key" => provider_account.ssh_key,
|
||
|
|
'created_by' => user,
|
||
|
|
'cm_name' => nil,
|
||
|
|
'name' => body[:name]
|
||
|
|
)
|
||
|
|
end
|
||
|
|
|
||
|
|
def set_tags id
|
||
|
|
tags = parser.tags
|
||
|
|
prepare_tags(id) do |provider|
|
||
|
|
provider.set_tags id, tags
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
def unset_tags id
|
||
|
|
tags = parser.tags
|
||
|
|
prepare_tags(id) do |provider|
|
||
|
|
provider.unset_tags id, tags
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
def prepare_tags id
|
||
|
|
s = Devops::Model::Server.find(id)
|
||
|
|
p = Devops::Model::Project.check_user_authorization(s.project, s.environment, parser.current_user)
|
||
|
|
provider = s.provider_instance
|
||
|
|
yield provider
|
||
|
|
end
|
||
|
|
|
||
|
|
def set_run_list id
|
||
|
|
s = Devops::Model::Server.find(id)
|
||
|
|
Devops::Model::Project.check_user_authorization(s.project, s.environment, parser.current_user)
|
||
|
|
s.set(run_list: parser.run_list)
|
||
|
|
end
|
||
|
|
|
||
|
|
private
|
||
|
|
|
||
|
|
def check_if_server_attrs_are_valid(body, user)
|
||
|
|
if body["project"].nil? or body["environment"].nil? or body["category"].nil?
|
||
|
|
raise Devops::Exception::ValidationError.new("Properties 'project', 'environment' and 'category' are mandatory")
|
||
|
|
end
|
||
|
|
|
||
|
|
key_name = body["ssh_key"]
|
||
|
|
unless key_name.nil?
|
||
|
|
begin
|
||
|
|
Devops::Model::Key.find(key_name)
|
||
|
|
rescue Mongoid::Errors::DocumentNotFound
|
||
|
|
raise Devops::Exception::ValidationError.new("Key with id '#{key_name}' not found")
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
project = Devops::Model::Project.check_user_authorization(body["project"], body["environment"], user)
|
||
|
|
env = project.environment(body["environment"])
|
||
|
|
category = env.get_category(body["category"])
|
||
|
|
if body["name"]
|
||
|
|
begin
|
||
|
|
Devops::Model::Server.find_by(name: body["name"])
|
||
|
|
raise Devops::Exception::ValidationError.new("Server with name '#{body["name"]}' already exists" )
|
||
|
|
rescue Mongoid::Errors::DocumentNotFound
|
||
|
|
category.provider.provider_instance.check_node_name(body["name"])
|
||
|
|
category.cm_tool.check_node_name(body["name"])
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
=begin
|
||
|
|
provider = env.provider_instance
|
||
|
|
server_name = body["name"]
|
||
|
|
check_chef_node_name(server_name, provider, KnifeFactory.instance) unless server_name.nil?
|
||
|
|
groups = body["groups"]
|
||
|
|
unless groups.nil?
|
||
|
|
buf = groups - provider.groups.keys
|
||
|
|
halt_response("Invalid security groups '#{buf.join("', '")}' for provider '#{provider.name}'") if buf.empty?
|
||
|
|
end
|
||
|
|
=end
|
||
|
|
end
|
||
|
|
|
||
|
|
def set_last_operation_and_save(server, operation_type)
|
||
|
|
server.set_last_operation(operation_type, parser.current_user, nil)
|
||
|
|
server.save
|
||
|
|
end
|
||
|
|
|
||
|
|
end
|
||
|
|
end
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|