Merge branch 'devops_3' into devops_3_achuchkalov

This commit is contained in:
Anton Chuchkalov 2015-07-27 16:01:26 +02:00
commit beca955f60
113 changed files with 2341 additions and 2199 deletions

View File

@ -0,0 +1,14 @@
require "commands/bootstrap_templates"
module Devops
module API2_0
module Handler
class BootstrapTemplates
include BootstrapTemplatesCommands
end
end
end
end

View File

@ -0,0 +1,61 @@
require "commands/deploy"
require "commands/status"
require "workers/deploy_worker"
module Devops
module API2_0
module Handler
class Deploy
extend DeployCommands
extend StatusCommands
def initialize req, params
@request = req
@params = params
end
def deploy names, tags
dir = DevopsConfig.config[:report_dir_v2]
files = []
uri = URI.parse(@request.url)
servers(names).each do |s|
project = begin
Devops::Db.connector.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, tags, @request.env['REMOTE_USER'], DevopsConfig.config)
files.push jid
end
files
end
def deploy_stream out, names, tags
status = []
servers(names).each do |s|
project = begin
Devops::Db.connector.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
res = deploy_server_proc.call(out, s, tags)
status.push(res)
end
out << create_status(status)
rescue RecordNotFound => e
out << e.message
end
def servers names
servers = Devops::Db.connector.servers(nil, nil, names, true)
raise RecordNotFound.new("No reserved servers found for names '#{names.join("', '")}'") if servers.empty?
servers.sort_by!{|s| names.index(s.chef_node_name)}
servers
end
end
end
end
end

View File

@ -0,0 +1,24 @@
require_relative "request_handler"
module Devops
module API2_0
module Handler
class Filter < RequestHandler
def available_images provider
Devops::Db.connector.available_images(provider)
end
def add_images images, provider
Devops::Db.connector.add_available_images(images, provider)
end
def delete_images images, provider
Devops::Db.connector.delete_available_images(images, provider)
end
end
end
end
end

View File

@ -0,0 +1,22 @@
require_relative "request_handler"
require "providers/provider_factory"
module Devops
module API2_0
module Handler
class Flavor < RequestHandler
def initialize request, params
@provider = params[:provider]
end
def flavors
p = ::Provider::ProviderFactory.get @provider
p.flavors
end
end
end
end
end

View File

@ -0,0 +1,20 @@
require "providers/provider_factory"
module Devops
module API2_0
module Handler
class Group
def initialize provider
@provider = provider
end
def groups params
p = ::Provider::ProviderFactory.get @provider
p.groups(params)
end
end
end
end
end

View File

@ -0,0 +1,51 @@
require "providers/provider_factory"
require "commands/image"
require_relative "request_handler"
module Devops
module API2_0
module Handler
class Image < RequestHandler
extend ImageCommands
def images provider
Devops::Db.connector.images(provider)
end
def provider_images provider
Image.get_available_provider_images(Devops::Db.connector, provider)
end
def get_image id
Devops::Db.connector.image(id)
end
def create_image image
Devops::Db.connector.image_insert Devops::Model::Image.new(image)
end
def update_image id, image
Devops::Db.connector.image id
obj = Devops::Model::Image.new(image)
obj.id = id
Devops::Db.connector.image_update image
end
def delete_image id
projects = Devops::Db.connector.projects_by_image id
unless projects.empty?
ar = []
projects.each do |p|
ar += p.deploy_envs.select{|e| e.respond_to?(:image)}.select{|e| e.image == id}.map{|e| "#{p.id}.#{e.identifier}"}
end
raise DependencyError.new "Deleting is forbidden: Image is used in #{ar.join(", ")}"
end
Devops::Db.connector.image_delete id
end
end
end
end
end

View File

@ -0,0 +1,45 @@
require "db/mongo/models/key"
require "fileutils"
module Devops
module API2_0
module Handler
class Key
def keys
keys = Devops::DB.connector.keys.map {|i| i.to_hash}
keys.each {|k| k.delete("path")} # We should not return path to the key
end
def create body, file_name
File.open(file_name, "w") do |f|
f.write(body["content"])
f.chmod(0400)
end
key = Devops::Model::Key.new({"path" => file_name, "id" => body["key_name"]})
Devops::DB.connector.key_insert key
end
def delete key_id
mongo = Devops::DB.connector
servers = mongo.servers_by_key key_id
unless servers.empty?
s_str = servers.map{|s| s.id}.join(", ")
raise DependencyError.new "Deleting is forbidden: Key is used in servers: #{s_str}"
end
k = mongo.key key_id
begin
FileUtils.rm(k.path)
rescue
logger.error "Missing key file for #{key_id} - #{k.filename}"
end
mongo.key_delete key_id
end
end
end
end
end

View File

@ -0,0 +1,17 @@
require "providers/provider_factory"
require_relative "request_handler"
module Devops
module API2_0
module Handler
class Network < RequestHandler
def networks provider
p = ::Provider::ProviderFactory.get provider
p.networks_detail
end
end
end
end
end

View File

@ -0,0 +1,231 @@
require "commands/deploy"
require "commands/status"
require "commands/server"
require "db/mongo/models/project"
require "workers/project_test_worker"
require_relative "request_handler"
module Devops
module API2_0
module Handler
class Project < RequestHandler
extend DeployCommands
extend StatusCommands
extend ServerCommands
def projects
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")
Devops::Db.connector.projects(nil, nil, fields, archived)
end
def project id
Devops::Db.connector.project(id)
end
def project_servers id
Devops::Db.connector.project(id)
Devops::Db.connector.servers(id, @params[:deploy_env])
end
# TODO: multi project
def create_project body
p = Devops::Model::Project.new(body)
halt_response("Project '#{p.id}' already exist") if Devops::Db.connector.is_project_exists?(p)
p.add_authorized_user [@request.env['REMOTE_USER']]
p.create
if p.multi?
"Project '#{p.id}' with type 'multi' created"
else
roles = create_roles p.id, p.deploy_envs, logger
"Project '#{p.id}' created. " + create_roles_response(roles)
end
end
# TODO: multi project
def update_project id, body
project = Devops::Model::Project.new(body)
project.id = id
old_project = Devops::Db.connector.project id
Devops::Db.connector.project_update project
roles = create_new_roles(old_project, project, logger)
create_roles_response(roles)
end
# TODO: multi project
def update_project_users id, deploy_env, users
project = Devops::Db.connector.project(id)
dbusers = Devops::Db.connector.users(users).map{|u| u.id}
buf = dbusers - users
project.add_authorized_user users, deploy_env
Devops::Db.connector.project_update(project)
info = "Users '#{dbusers.join("', '")}' has been added to '#{id}' project's authorized users"
info << ", invalid users: '#{buf.join("', '")}'" unless buf.empty?
info
end
# TODO: multi project
def delete_project_users id, deploy_env, users
project = Devops::Db.connector.project(id)
project.remove_authorized_user users, deploy_env
Devops::Db.connector.project_update project
"Users '#{users.join("', '")}' have been removed from '#{id}' project's authorized users"
end
# TODO: multi project
def set_project_env_run_list id, deploy_env, list
project = Devops::Db.connector.project(id)
env = project.deploy_env deploy_env
env.run_list = list
Devops::Db.connector.project_update project
"Updated environment '#{env.identifier}' with run_list '#{env.run_list.inspect}' in project '#{project.id}'"
end
def delete_project id, deploy_env
servers = Devops::Db.connector.servers id
raise DependencyError.new "Deleting #{id} is forbidden: Project has servers" if !servers.empty?
project = Devops::Db.connector.project(id)
info = if deploy_env.nil?
project.delete
"Project '#{id}' is deleted"
else
project.remove_env deploy_env
Devops::Db.connector.project_update project
"Project '#{id}'. Deploy environment '#{deploy_env}' has been deleted"
end
end
def deploy_project_stream out, id, deploy_env, servers, body
keys = {}
dbserver = servers(id, deploy_env, servers)
out << (dbservers.empty? ? "No reserved servers to deploy\n" : "Deploy servers: '#{dbservers.map{|s| s.chef_node_name}.join("', '")}'\n")
status = []
servers.each do |s|
begin
Devops::Db.connector.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 = Devops::Db.connector.key s.key
keys[s.key] = k.path
end
status.push(deploy_server(out, s, keys[s.key]))
end
status
end
def deploy_project id, deploy_env, servers, body
dir = DevopsConfig[:report_dir_v2]
files = []
uri = URI.parse(request.url)
servers(id, deploy_env, servers).each do |s|
project = begin
Devops::Db.connector.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
files
end
def servers project_id, deploy_env, servers
project = Devops::Db.connector.project(project_id)
dbservers = Devops::Db.connector.servers(project_id, deploy_env, servers, true)
end
def archive_project id
project = Devops::Db.connector.project(id)
Devops::Db.connector.archive_project(id)
"Project '#{id}' has been archived"
end
def unarchive_project id
project = Devops::Db.connector.project(id)
Devops::Db.connector.unarchive_project(id)
"Project '#{id}' has been unarchived"
end
def test_project id, deploy_env
project = Devops::Db.connector.project(id)
env = project.deploy_env deploy_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
raise InvalidRecord.new(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
sleep 1
return [uri.to_s]
end
def 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 create_new_roles old_project, new_project, logger
old_project.deploy_envs.each do |e|
new_project.remove_env(e.identifier)
end
create_roles new_project.id, new_project.deploy_envs, logger
end
def 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

View File

@ -0,0 +1,16 @@
require "providers/provider_factory"
require_relative "request_handler"
module Devops
module API2_0
module Handler
class Provider < RequestHandler
def providers
::Provider::ProviderFactory.providers
end
end
end
end
end

View File

@ -0,0 +1,64 @@
require_relative "request_handler"
module Devops
module API2_0
module Handler
class Report < RequestHandler
def initialize request, params
@params = params
end
def options
options = {}
["project", "deploy_env", "type", "created_by", "date_from", "date_to", "sort", "status", "chef_node_name", "max_number"].each do |k|
options[k] = @params[k] unless @params[k].nil?
end
attributes_keys = @params.keys.select{|k| k =~ /attributes\.*/}
attributes_keys.each do |ak|
options[ak] = @params[ak]
end
options
end
def all
Devops::Db.connector.reports(options)
end
def all_latest
Devops::Db.connector.latest_reports(options())
end
def attributes name
Devops::Db.connector.reports_attributes_values(name)
end
def report id
r = Devops::Db.connector.report(id)
file = r.file
raise RecordNotFound.new("Report '#{id}' does not exist") unless File.exists? file
return Rack::Utils.escape_html(File.read(file)), completed?(id)
rescue RecordNotFound => e
if status(id) == Worker::STATUS::IN_QUEUE
return "Task '#{id}' has been queued", false
else
raise e
end
end
def status id
Sidekiq.redis do |connection|
connection.hget("devops", id)
end
end
def completed? id
r = self.status(id)
r == "completed" or r == "failed"
end
end
end
end
end

View File

@ -0,0 +1,12 @@
module Devops
module API2_0
module Handler
class RequestHandler
def initialize request, params
@request = request
@params = params
end
end
end
end
end

View File

@ -0,0 +1,98 @@
require "providers/provider_factory"
require "fileutils"
require "commands/status"
require_relative "request_handler"
module Devops
module API2_0
module Handler
class Script < RequestHandler
def scripts
res = []
Dir.foreach(DevopsConfig.config[:scripts_dir]) {|f| res.push(f) unless f.start_with?(".")}
end
def execute_command out, cmd, node_name
user = @request.env['REMOTE_USER']
s = ::Devops::Db.connector.server_by_chef_node_name node_name
::Devops::Db.connector.check_project_auth s.project, s.deploy_env, user
cert = ::Devops::Db.connector.key s.key
addr = "#{s.remote_user}@#{s.public_ip || s.private_ip}"
ssh_cmd = "ssh -i %s #{addr} '#{cmd}'"
out << ssh_cmd % File.basename(cert.path)
out << "\n"
IO.popen((ssh_cmd % cert.path) + " 2>&1") do |so|
while line = so.gets do
out << line
end
end
out << "\nDone"
end
def run_script out, file_name, nodes, script_params
file = File.join(DevopsConfig.config[:scripts_dir], file_name)
unless File.exists?(file)
out << "File '#{file_name}' does not exist\n"
return
end
servers = ::Devops::Db.connector.servers_by_names(nodes)
if servers.empty?
out << "No servers found for names '#{nodes.join("', '")}'\n"
return
end
user = @request.env['REMOTE_USER']
servers.each do |s|
::Devops::Db.connector.check_project_auth s.project, s.deploy_env, user
end
status = []
servers.each do |s|
cert = begin
::Devops::Db.connector.key s.key
rescue
out << "No key found for '#{s.chef_node_name}'"
status.push 2
next
end
ssh_cmd = "ssh -i #{cert.path} #{s.remote_user}@#{s.public_ip || s.private_ip} 'bash -s' < %s"
out << "\nRun script on '#{s.chef_node_name}'\n"
unless script_params.nil?
ssh_cmd += " " + script_params.join(" ")
end
out << (ssh_cmd % [file_name])
out << "\n"
begin
IO.popen( (ssh_cmd % [file]) + " 2>&1") do |so|
while line = so.gets do
out << line
end
so.close
status.push $?.to_i
end
rescue IOError => e
logger.error e.message
out << e.message
status.push 3
end
end
out << create_status(status)
end
def create_script file_name
file = File.join(settings.scripts_dir, file_name)
raise RecordNotFound.new("File '#{file_name}' already exist") if File.exists?(file)
File.open(file, "w") {|f| f.write(@request.body.read)}
end
def delete_script file_name
file = File.join(settings.scripts_dir, file_nsme)
raise RecordNotFound.new("File '#{file_name}' does not exist", 404) unless File.exists?(file)
FileUtils.rm(file)
end
end
end
end
end

View File

@ -0,0 +1,269 @@
require 'rufus-scheduler'
require "uri"
require "commands/status"
require "commands/server"
require "commands/bootstrap_templates"
require "commands/knife_commands"
require "providers/provider_factory"
require "db/mongo/models/server"
require "workers/create_server_worker"
require "workers/bootstrap_worker"
module Devops
module API2_0
module Handler
class Server
extend StatusCommands
extend ServerCommands
extend BootstrapTemplatesCommands
scheduler = Rufus::Scheduler.new
def servers fields, reserved
Devops::DB.connector.servers(nil, nil, nil, reserved, fields).map {|s| s.to_hash}
end
def chef_servers
KnifeCommands.chef_node_list
end
def provider_servers provider
::Provider::ProviderFactory.get(provider).servers
end
def server id
get_server_by_key(id, @params[:key])
end
def delete id, key
s = get_server_by_key(params[:id], key)
### Authorization
Devops::Db.connector.check_project_auth s.project, s.deploy_env, request.env['REMOTE_USER']
delete_server(s, Devops::Db.connector, logger)
end
def create_server_stream out, body
status = []
prepare_create_server(body).each do |s|
res = create_server_proc.call(out, s, provider, Devops::Db.connector)
status.push res
end
status
end
def create_server body
dir = DevopsConfig[:report_dir_v2]
files = []
uri = URI.parse(request.url)
prepare_create_server(body).each do |s|
h = s.to_hash
h["options"] = s.options
jid = CreateServerWorker.perform_async(dir, env.provider, h, @request.env['REMOTE_USER'], DevopsConfig.config)
Worker.set_status jid, Worker::STATUS::IN_QUEUE
#logger.info "Job '#{jid}' has been started"
uri.path = "#{DevopsConfig[:url_prefix]}/v2.0/report/" + jid
files.push uri.to_s
end
sleep 1
files
end
def prepare_create_server body
user = @request.env['REMOTE_USER']
key_name = body["key"]
new_key = Devops::Db.connector.key(key_name) unless key_name.nil?
p = Devops::Db.connector.check_project_auth(body["project"], body["deploy_env"], user)
env = p.deploy_env(body["deploy_env"])
provider = ::Provider::ProviderFactory.get(env.provider)
server_name = body["name"]
check_chef_node_name(server_name, provider) 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
Server.extract_servers(provider, p, env, body, user, Devops::Db.connector)
end
def pause_server node_name, key
s = Server.get_server_by_key(node_name, key)
## Authorization
Devops::Db.connector.check_project_auth s.project, s.deploy_env, @request.env['REMOTE_USER']
provider = ::Provider::ProviderFactory.get(s.provider)
r = provider.pause_server s
if r.nil?
"Server with instance ID '#{s.id}' and node name '#{node_name}' is paused"
else
raise ConflictException.new("Server with instance ID '#{s.id}' and node name '#{node_name}' can not be paused, It in state '#{r}'", 409)
end
end
def unpause_server node_name, key
s = Server.get_server_by_key(params[:node_name], key)
## Authorization
Devops::Db.connector.check_project_auth s.project, s.deploy_env, @request.env['REMOTE_USER']
provider = ::Provider::ProviderFactory.get(s.provider)
r = provider.unpause_server s
if r.nil?
"Server with instance ID '#{s.id}' and node name '#{node_name}' is unpaused"
else
raise ConflictException.new("Server with instance ID '#{s.id}' and node name '#{node_name}' can not be unpaused, It in state '#{r}'")
end
end
def reserve_server node_name, key
s = get_server_by_key(node_name, key)
Devops::Db.connector.check_project_auth s.project, s.deploy_env, @request.env['REMOTE_USER']
raise ConflictException.new("Server '#{node_name}' already reserved") unless s.reserved_by.nil?
s.reserved_by = user
Devops::Db.connector.server_update(s)
end
def unreserve_server node_name, key
s = get_server_by_key(node_name, key)
Devops::Db.connector.check_project_auth s.project, s.deploy_env, @request.env['REMOTE_USER']
raise ConflictException.new("Server '#{node_name}' is not reserved") if s.reserved_by.nil?
s.reserved_by = nil
Devops::Db.connector.server_update(s)
end
# TODO: check bootstrap template name
def bootstrap_server_stream out, body
s = prepare_create_server body
status = []
cert = Devops::Db.connector.key s.key
logger.debug "Bootstrap certificate path: #{cert.path}"
bootstrap s, out, cert.path, logger
str = nil
r = if check_server(s)
Devops::Db.connector.server_set_chef_node_name s
str = "Server with id '#{s.id}' is bootstraped"
logger.info str
0
else
str = "Server with id '#{s.id}' is not bootstraped"
logger.warn str
1
end
status.push r
out << str
out << "\n"
status
end
def bootstrap_server body
s = prepare_create_server body
dir = DevopsConfig[:report_dir_v2]
files = []
uri = URI.parse(@request.url)
h = s.to_hash
h["options"] = s.options
h["_id"] = s.id
jid = BootstrapWorker.perform_async(dir, d.provider, h, @request.env['REMOTE_USER'], DevopsConfig.config)
Worker.set_status jid, Worker::STATUS::IN_QUEUE
logger.info "Job '#{jid}' has been started"
uri.path = "#{DevopsConfig[:url_prefix]}/v2.0/report/" + jid
uri.query = nil
uri.fragment = nil
files.push uri.to_s
sleep 1
files
end
def prepare_bootstrap_server body
id = body["instance_id"]
name = body["name"]
s = Devops::Db.connector.server_by_instance_id(id)
p = Devops::Db.connector.check_project_auth s.project, s.deploy_env, @request.env['REMOTE_USER']
d = p.deploy_env s.deploy_env
provider = ::Provider::ProviderFactory.get(s.provider)
check_chef_node_name(name, provider) unless name.nil?
s.options = {
:run_list => rl || d.run_list,
}
unless t.nil?
templates = get_templates
halt_response("Invalid bootstrap template '#{t}', available values: #{templates.join(", ")}", 400) unless templates.include?(t)
s.options[:bootstrap_template] = t
end
s.chef_node_name = name || provider.create_default_chef_node_name(s)
s
end
def add_server body
project = body["project"]
deploy_env = body["deploy_env"]
p = Devops::Db.connector.check_project_auth project, deploy_env, @request.env['REMOTE_USER']
d = p.deploy_env(deploy_env)
cert = Devops::Db.connector.key(body["key"])
provider = ::Provider::ProviderFactory.get("static")
s = Devops::Model::Server.new
s.provider = provider.name
s.project = project
s.deploy_env = deploy_env
s.remote_user = body["remote_user"]
s.private_ip = body["private_ip"]
s.public_ip = body["public_ip"]
s.static = true
s.id = "static_#{cert.id}-#{Time.now.to_i}"
s.key = cert.id
Devops::Db.connector.server_insert s
"Server '#{s.id}' has been added"
end
def get_server_by_key id, key
mongo = Devops::Db.connector
key == "instance" ? mongo.server_by_instance_id(id) : mongo.server_by_chef_node_name(id)
end
def check_chef_node_name name, provider
mongo = Devops::Db.connector
mongo.server_by_chef_node_name name
halt(400, "Server with name '#{name}' already exist")
rescue RecordNotFound => e
# server not found - OK
s = provider.servers.detect {|s| s["name"] == name}
halt(400, "#{provider.name} node with name '#{name}' already exist") unless s.nil?
s = KnifeCommands.chef_node_list.detect {|n| n == name}
halt(400, "Chef node with name '#{name}' already exist") unless s.nil?
s = KnifeCommands.chef_client_list.detect {|c| c == name}
halt(400, "Chef client with name '#{name}' already exist") unless s.nil?
end
end
class ExpireHandler
include ServerCommands
def initialize server, logger
@server = server
@logger = logger
end
def call(job)
@logger.info("Removing node '#{@server.chef_node_name}' form project '#{@server.project}' and env '#{@server.deploy_env}'")
begin
delete_server(@server, Devops::Db.connector, @logger)
rescue => e
logger.error "ExpiredHandler error: " + e.message
end
end
end
end
end
end

View File

@ -0,0 +1,51 @@
require 'db/mongo/models/stack/stack_factory'
require_relative "request_handler"
module Devops
module API2_0
module Handler
class Stack < RequestHandler
def stacks
Devops::Db.connector.stacks
end
def stacks_for_provider provider
Devops::Db.connector.stacks(provider)
end
def create_stack object
stack_model = Model::StackFactory.create(object['provider'], object)
Devops::Db.connector.stack_insert(stack_model)
stack_model
end
def stack id
Devops::Db.connector.stack(id)
end
def delete_stack id
stack = self.stack(id)
stack.delete_stack_in_cloud!
Devops::Db.connector.stack_delete(id)
end
def sync_details id
stack = self.stack(id)
stack.sync_details!
Devops::Db.connector.stack_update(stack)
end
def resources id
stack = Devops::Db.connector.stack(id)
stack.resources
end
def resources id, resource_id
stack = Devops::Db.connector.stack(id)
stack.resource(resource_id)
end
end
end
end
end

View File

@ -0,0 +1,28 @@
require 'json'
require 'lib/stack_presets/factory'
require_relative "request_handler"
module Devops
module API2_0
module Handler
class StackPreset < RequestHandler
def presets
Devops::StackPresetsFactory.list
end
def preset id
Devops::StackPresetsFactory.get(id)
end
def apply id, body
preset = Devops::StackPresetsFactory.get(id)
preset.create_stack_from_preset(body)
Devops::Db.connector.stack_insert(stack)
end
end
end
end
end

View File

@ -0,0 +1,34 @@
require 'db/mongo/models/stack_template/stack_template_factory'
require_relative "request_handler"
module Devops
module API2_0
module Handler
class StackTemplate < RequestHandler
def stack_templates
Devops::Db.connector.stack_templates
end
def stack_templates_for_provider provider
Devops::Db.connector.stack_templates(provider)
end
def create_stack_template body
template_model = Model::StackTemplateFactory.create(body['provider'], body)
Devops::Db.connector.stack_template_insert(template_model)
template_model
end
def get_stack_template id
Devops::Db.connector.stack_template(id)
end
def delete_stack_template id
Devops::Db.connector.stack_template_delete id
end
end
end
end
end

View File

@ -0,0 +1,34 @@
require "commands/knife_commands"
module Devops
module API2_0
module Handler
class Tag
def initialize node_name
@node_name = node_name
@server = Devops::DB.connector.server_by_chef_node_name(@node_name)
#TODO: raise
halt_response("No servers found for name '#{@node_name}'", 404) if @server.nil?
end
def tags
KnifeCommands.tags_list(@node_name)
end
def set_tags tags
tagsStr = tags.join(" ")
cmd = KnifeCommands.tags_create(@node_name, tagsStr)
halt_response("Error: Cannot add tags #{tagsStr} to server #{@node_name}", 500) unless cmd[1]
end
def self.unset_tags
tagsStr = tags.join(" ")
cmd = KnifeCommands.tags_delete(@node_name, tagsStr)
halt_response("Cannot delete tags #{tagsStr} from server #{@node_name}: #{cmd[0]}", 500) unless cmd[1]
end
end
end
end
end

View File

@ -0,0 +1,47 @@
require "db/mongo/models/user"
module Devops
module API2_0
module Handler
class User
def users
Devops::Db.connector.users
end
def create body
Devops::Db.connector.user_insert Devops::Model::User.new(body)
end
def delete user_id
Devops::Db.connector.user_delete user_id
end
def change_user_privileges user_id, cmd, privileges
change_user(user_id) do
user.grant(cmd, privileges)
end
end
def change_email user_id, val
change_user(user_id) do
user.email = val
end
end
def change_password user_id, val
change_user(user_id) do
user.password = val
end
end
def change_user user_id
user = Devops::Db.connector.user user_id
yield(user)
Devops::Db.connector.user_update user
end
end
end
end
end

View File

@ -5,7 +5,7 @@ require "sinatra/json"
require "providers/provider_factory"
module Devops
module Version2_0
module API2_0
module Helpers
def create_response msg, obj=nil, rstatus=200
@ -23,11 +23,10 @@ module Devops
def check_privileges cmd, p
# somewhy REMOTE_USER is missing
user = request.env['HTTP_REMOTE_USER'] || request.env['REMOTE_USER']
settings.mongo.check_user_privileges(user, cmd, p)
user = request.env['USER']
user.check_privileges(cmd, p)
end
def check_provider provider
list = ::Provider::ProviderFactory.providers
halt_response("Invalid provider '#{provider}', available providers: '#{list.join("', '")}'", 404) unless list.include?(provider)

View File

@ -1,5 +1,5 @@
module Devops
module Version2_0
module API2_0
module Routes
module BootstrapTemplatesRoutes
@ -18,7 +18,10 @@ module Devops
# [
# "omnibus"
# ]
app.get_with_headers "/templates", :headers => [:accept], &Devops::Version2_0::Handler::BootstrapTemplates.get_bootstrap_templates
app.get_with_headers "/templates", :headers => [:accept] do
check_privileges("templates", "r")
json Devops::API2_0::Handler::BootstrapTemplates.new.get_templates
end
puts "Bootstrap templates routes initialized"
end

View File

@ -0,0 +1,60 @@
module Devops
module API2_0
module Routes
module DeployRoutes
def self.registered(app)
# Run chef-client on reserved server
#
# * *Request*
# - method : POST
# - headers :
# - Content-Type: application/json
# - body :
# {
# "names": [], -> array of servers names to run chef-client
# "tags": [], -> array of tags to apply on each server before running chef-client
# "trace": true -> return output in stream
# }
#
# * *Returns* : text stream
app.post_with_headers "/deploy", :headers => [:content_type] do
check_privileges("server", "x")
# TODO: send message
#broadcast(:devops_deploy, "deploy")
r = create_object_from_json_body
names = check_array(r["names"], "Parameter 'names' should be a not empty array of strings")
tags = check_array(r["tags"], "Parameter 'tags' should be an array of strings", String, true) || []
if r.key?("trace")
stream() do |out|
status = []
begin
Devops::API2_0::Handler::Deploy.new(request, params).deploy_stream(out, names, tags)
rescue IOError => e
logger.error e.message
break
end
end # stream
else
ids = Devops::API2_0::Handler::Deploy.new(request, params).deploy(names, tags)
sleep 1
ids.each do |jid|
logger.info "Job '#{jid}' has been queued"
uri.path = "#{DevopsConfig.config[:url_prefix]}/v2.0/report/" + jid
files.push uri.to_s
end
json files
end
end
puts "Deploy routes initialized"
end
end
end
end
end

View File

@ -1,20 +1,10 @@
module Devops
module Version2_0
module API2_0
module Routes
module FilterRoutes
def self.registered(app)
app.before "/filter/:provider/image" do
protect!
check_headers :accept, :content_type
check_privileges("filter", "w")
check_provider(params[:provider])
@images = create_object_from_json_body(Array)
halt_response("Request body should not be an empty array") if @images.empty?
check_array(@images, "Request body should contains an array with strings")
end
# Get list of images filters for :provider
#
# Devops can works with images from filters list only
@ -33,7 +23,11 @@ module Devops
# [
# "36dc7618-4178-4e29-be43-286fbfe90f50"
# ]
app.get_with_headers "/filter/:provider/images", :headers => [:accept], &Devops::Version2_0::Handler::Filter.get_filters
app.get_with_headers "/filter/:provider/images", :headers => [:accept] do |provider|
check_privileges("filter", "r")
check_provider(provider)
json Devops::API2_0::Handler::Filter.new(request, params).available_images(provider)
end
hash = {}
@ -50,7 +44,14 @@ module Devops
# ] -> array of image ids to add to filter
#
# * *Returns* : list of images filters for :provider
hash["PUT"] = Devops::Version2_0::Handler::Filter.add_filter
hash["PUT"] = lambda { |provider|
check_privileges("filter", "w")
check_provider(provider)
images = create_object_from_json_body(Array)
halt_response("Request body should not be an empty array") if images.empty?
check_array(images, "Request body should contains an array with strings")
create_response("Updated", {:images => Devops::API2_0::Handler::Filter.new(request, params).add_images(images, provider)})
}
# Delete image ids from filter for :provider
#
@ -65,7 +66,14 @@ module Devops
# ] -> array of image ids to delete from filter
#
# * *Returns* : list of images filters for :provider
hash["DELETE"] = Devops::Version2_0::Handler::Filter.delete_filter
hash["DELETE"] = lambda { |provider|
check_privileges("filter", "w")
check_provider(provider)
images = create_object_from_json_body(Array)
halt_response("Request body should not be an empty array") if images.empty?
check_array(images, "Request body should contains an array with strings")
create_response("Deleted", {:images => Devops::API2_0::Handler::Filter.new(request, params).delete_images(images, provider)})
}
app.multi_routes "/filter/:provider/image", {:headers => [:accept, :content_type]}, hash

View File

@ -1,5 +1,5 @@
module Devops
module Version2_0
module API2_0
module Routes
module FlavorRoutes
@ -31,7 +31,12 @@ module Devops
# "disk": 20
# }
# ]
app.get_with_headers "/flavors/:provider", :headers => [:accept], &Devops::Version2_0::Handler::Flavor.get_flavors
app.get_with_headers "/flavors/:provider", :headers => [:accept] do
check_privileges("flavor", "r")
provider = params[:provider]
check_provider(provider)
json Devops::API2_0::Handler::Flavor.new(request, params).flavors
end
puts "Flavor routes initialized"
end

View File

@ -1,6 +1,6 @@
# encoding: UTF-8
module Devops
module Version2_0
module API2_0
module Routes
module GroupRoutes
@ -44,7 +44,12 @@ module Devops
# }
# }
# TODO: vpc support for ec2
app.get_with_headers "/groups/:provider", :headers => [:accept], &Devops::Version2_0::Handler::Group.get_groups
app.get_with_headers "/groups/:provider", :headers => [:accept] do#, &Devops::Version2_0::Handler::Group.get_groups
check_privileges("group", "r")
provider = params[:provider]
check_provider(provider)
json Devops::API2_0::Handler::Group.new(provider).groups(params)
end
puts "Group routes initialized"
end

View File

@ -1,12 +1,9 @@
module Devops
module Version2_0
module API2_0
module Routes
module ImageRoutes
def self.registered(app)
app.after %r{\A/image(/[\w]+)?\z} do
statistic
end
# Get devops images list
#
@ -27,7 +24,12 @@ module Devops
# "id": "36dc7618-4178-4e29-be43-286fbfe90f50"
# }
# ]
app.get_with_headers "/images", :headers => [:accept], &Devops::Version2_0::Handler::Image.get_images
app.get_with_headers "/images", :headers => [:accept] do
check_privileges("image", "r")
provider = params[:provider]
check_provider(provider) if provider
json Devops::API2_0::Handler::Image.new(request, params).images(provider).map(&:to_hash)
end
# Get raw images for :provider
#
@ -53,7 +55,11 @@ module Devops
# "status": "ACTIVE"
# }
# ]
app.get_with_headers "/images/provider/:provider", :headers => [:accept], &Devops::Version2_0::Handler::Image.get_provider_images
app.get_with_headers "/images/provider/:provider", :headers => [:accept] do |provider|
check_privileges("image", "r")
check_provider(provider)
json Devops::API2_0::Handler::Image.new(request, params).provider_images(provider)
end
# Create devops image
#
@ -73,7 +79,12 @@ module Devops
#
# * *Returns* :
# 201 - Created
app.post_with_headers "/image", :headers => [:accept, :content_type], &Devops::Version2_0::Handler::Image.create_image
app.post_with_headers "/image", :headers => [:accept, :content_type] do
check_privileges("image", "w")
image = create_object_from_json_body
Devops::API2_0::Handler::Image.new(request, params).create_image(image)
create_response "Created", nil, 201
end
hash = {}
# Get devops image by id
@ -91,7 +102,10 @@ module Devops
# "bootstrap_template": null,
# "id": "36dc7618-4178-4e29-be43-286fbfe90f50"
# }
hash["GET"] = Devops::Version2_0::Handler::Image.get_image
hash["GET"] = lambda { |image_id|
check_privileges("image", "r")
json Devops::API2_0::Handler::Image.new(request, params).image(image_id)
}
# Update devops image
#
@ -111,7 +125,12 @@ module Devops
#
# * *Returns* :
# 200 - Updated
hash["PUT"] = Devops::Version2_0::Handler::Image.update_image
hash["PUT"] = lambda {|image_id|
check_privileges("image", "w")
image = create_object_from_json_body
Devops::API2_0::Handler::Image.new(request, params).update_image(image_id, image)
create_response("Image '#{image_id}' has been updated")
}
# Delete devops image
#
@ -122,7 +141,11 @@ module Devops
#
# * *Returns* :
# 200 - Deleted
hash["DELETE"] = Devops::Version2_0::Handler::Image.delete_image
hash["DELETE"] = lambda {|image_id|
check_privileges("image", "w")
Devops::API2_0::Handler::Image.delete_image
create_response("Image '#{image_id}' has been removed")
}
app.multi_routes "/image/:image_id", {}, hash

View File

@ -0,0 +1,93 @@
require "json"
module Devops
module API2_0
module Routes
module KeyRoutes
def self.registered(app)
# Get list of available ssh keys
#
# * *Request*
# - method : GET
# - headers :
# - Accept: application/json
#
# * *Returns* : array of strings
# [
# {
# "scope": "system", -> 'system' - key was added by server, 'user' - key was added by user
# "id": "devops"
# }
# ]
app.get_with_headers "/keys", :headers => [:accept] do
check_privileges("key", "r")
json Devops::API2_0::Handler::Key.new.keys
end
# Create ssh key on devops server
#
# * *Request*
# - method : POST
# - headers :
# - Accept: application/json
# - Content-Type: application/json
# - body :
# {
# "file_name": "key file name",
# "key_name": "key name",
# "content": "key content"
# }
#
# * *Returns* :
# 201 - Created
app.post_with_headers "/key", :headers => [:accept, :content_type] do
check_privileges("key", "w")
key = create_object_from_json_body
fname = check_filename(key["file_name"], "Parameter 'file_name' must be a not empty string")
kname = check_string(key["key_name"], "Parameter 'key_name' should be a not empty string")
content = check_string(key["content"], "Parameter 'content' should be a not empty string")
file_name = File.join(settings.keys_dir, fname)
halt(400, "File '#{fname}' already exist") if File.exists?(file_name)
Devops::API2_0::Handler::Key.new.create(key, file_name)
create_response("Created", nil, 201)
end
# Delete ssh key from devops server
#
# * *Request*
# - method : DELETE
# - headers :
# - Accept: application/json
#
# * *Returns* :
# 200 - Deleted
app.delete_with_headers "/key/:key", :headers => [:accept] do
check_privileges("key", "w")
servers = settings.mongo.servers_by_key params[:key]
unless servers.empty?
s_str = servers.map{|s| s.id}.join(", ")
raise DependencyError.new "Deleting is forbidden: Key is used in servers: #{s_str}"
end
k = settings.mongo.key params[:key]
begin
FileUtils.rm(k.path)
rescue
logger.error "Missing key file for #{params[:key]} - #{k.filename}"
end
r = settings.mongo.key_delete params[:key]
r = Devops::API2_0::Handler::Key.new.delete params[:key]
return [500, r["err"].inspect] unless r["err"].nil?
create_response("Key '#{params[:key]}' removed")
end
puts "Key routes initialized"
end
end
end
end
end

View File

@ -1,6 +1,6 @@
# encoding: UTF-8
module Devops
module Version2_0
module API2_0
module Routes
module NetworkRoutes
@ -32,7 +32,11 @@ module Devops
# "id": "b14f8df9-ac27-48e2-8d65-f7ef78dc2654"
# }
# ]
app.get_with_headers "/networks/:provider", :headers => [:accept], &Devops::Version2_0::Handler::Network.get_networks
app.get_with_headers "/networks/:provider", :headers => [:accept] do |provider|
check_privileges("network", "r")
check_provider(provider)
json Devops::API2_0::Handler::Network.new(request, params).networks
end
puts "Network routes initialized"
end

View File

@ -1,5 +1,5 @@
module Devops
module Version2_0
module API2_0
module Routes
module ProjectRoutes
@ -18,7 +18,10 @@ module Devops
# [
# {"name" : "project_1"}
# ]
app.get_with_headers "/projects", :headers => [:accept], &Devops::Version2_0::Handler::Project.get_projects
app.get_with_headers "/projects", :headers => [:accept] do
check_privileges("project", "r")
json Devops::API2_0::Handler::Project.new(request, params).projects.map(&:to_hash)
end
# Get project by id
#
@ -53,7 +56,10 @@ module Devops
# "name": "project_1"
# }
hash = {}
hash["GET"] = Devops::Version2_0::Handler::Project.get_project
hash["GET"] = lambda {|project|
check_privileges("project", "r")
json Devops::API2_0::Handler::Project.new(request, params).project(project)
}
# Update project and create chef roles
#
@ -90,7 +96,13 @@ module Devops
#
# * *Returns* :
# 200 - Updated
hash["PUT"] = Devops::Version2_0::Handler::Project.update_project
hash["PUT"] = lambda { |project|
check_privileges("project", "w")
body = create_object_from_json_body
r = Devops::API2_0::Handler::Project.new(request, params).update_project project, body
info = "Project '#{project.id}' has been updated." + r
create_response(info)
}
# Delete project
#
@ -106,7 +118,15 @@ module Devops
#
# * *Returns* :
# 200 - Deleted
hash["DELETE"] = Devops::Version2_0::Handler::Project.delete_project
hash["DELETE"] = lambda {|project|
check_privileges("project", "w")
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
info = Devops::API2_0::Handler::Project.new(request, params).delete_project(project, deploy_env)
create_response(info)
}
app.multi_routes "/project/:project", {}, hash
# Get project servers
@ -135,7 +155,10 @@ module Devops
# "id": "nstance id"
# }
# ]
app.get_with_headers "/project/:project/servers", :headers => [:accept], &Devops::Version2_0::Handler::Project.get_project_servers
app.get_with_headers "/project/:project/servers", :headers => [:accept] do |project|
check_privileges("project", "r")
json Devops::API2_0::Handler::Project.new(request, params).project_servers(project).map(&:to_hash)
end
# Get project stacks
#
@ -199,7 +222,15 @@ module Devops
#
# * *Returns* :
# 201 - Created
app.post_with_headers "/project", :headers => [:accept, :content_type], &Devops::Version2_0::Handler::Project.create_project
app.post_with_headers "/project", :headers => [:accept, :content_type] do
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)
res = Devops::API2_0::Handler::Project.new(request, params).create_project body
res = "Created. " + res
create_response(res, nil, 201)
end
users_hash = {}
# Add users to project environment
@ -219,7 +250,14 @@ module Devops
#
# * *Returns* :
# 200 - Updated
users_hash["PUT"] = Devops::Version2_0::Handler::Project.update_project_users
users_hash["PUT"] = lambda { |project|
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)
info = Devops::API2_0::Handler::Project.new(request, params).update_project_users(project, deploy_env, users)
create_response(info)
}
# Delete users from project environment
#
@ -238,7 +276,14 @@ module Devops
#
# * *Returns* :
# 200 - Updated
users_hash["DELETE"] = Devops::Version2_0::Handler::Project.delete_project_users
users_hash["DELETE"] = lambda {|project|
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)
info = Devops::API2_0::Handler::Project.new(request, params).delete_project_users(project, deploy_env, users)
create_response(info)
}
app.multi_routes "/project/:id/user", {}, users_hash
# Set run_list to project environment
@ -256,7 +301,13 @@ module Devops
#
# * *Returns* :
# 200 - Updated
app.put_with_headers "/project/:id/:env/run_list", :headers => [:accept, :content_type], &Devops::Version2_0::Handler::Project.set_project_env_run_list
app.put_with_headers "/project/:id/:env/run_list", :headers => [:accept, :content_type] do |project, deploy_env|
check_privileges("project", "w")
list = create_object_from_json_body(Array)
check_array(list, "Body must contains not empty array of strings")
info = Devops::API2_0::Handler::Project.new(request, params).set_project_env_run_list(project, deploy_env, list)
create_response(info)
end
# Run chef-client on reserved project servers
#
@ -273,7 +324,25 @@ module Devops
# }
#
# * *Returns* : text stream
app.post_with_headers "/project/:id/deploy", :headers => [:content_type], &Devops::Version2_0::Handler::Project.deploy_project
app.post_with_headers "/project/:id/deploy", :headers => [:content_type] do |project|
check_privileges("project", "x")
obj = create_object_from_json_body
deploy_env = check_string(obj["deploy_env"], "Parameter 'deploy_env' should be a not empty string", true)
servers = check_array(obj["servers"], "Parameter 'servers' should be a not empty array of strings", String, true)
handler = Devops::API2_0::Handler::Project.new(request, params)
if obj.key?("trace")
stream() do |out|
begin
status = handler.deploy_project_stream out, project, deploy_env, servers
out << create_status(status)
rescue IOError => e
logger.error e.message
end
end
else
json handler.deploy_project project, deploy_env, servers
end
end
# Set project to archivated state
#
@ -281,7 +350,11 @@ module Devops
# - method : POST
# - headers :
# - Content-Type: application/json
app.post_with_headers "/project/:project/archive", :headers => [:content_type], &Devops::Version2_0::Handler::Project.archive_project
app.post_with_headers "/project/:project/archive", :headers => [:content_type] do |project|
check_privileges("project", "w")
info = Devops::API2_0::Handler::Project.new(request, params).archive_project(project)
create_response(info)
end
# Set project to normal state
#
@ -289,7 +362,11 @@ module Devops
# - method : POST
# - headers :
# - Content-Type: application/json
app.post_with_headers "/project/:project/unarchive", :headers => [:content_type], &Devops::Version2_0::Handler::Project.unarchive_project
app.post_with_headers "/project/:project/unarchive", :headers => [:content_type] do |project|
check_privileges("project", "w")
info = Devops::API2_0::Handler::Project.new(request, params).unarchive_project(project)
create_response(info)
end
# Test project environment
#
@ -357,7 +434,10 @@ module Devops
# },
# "message": "Test project 'project_1' and environment 'prod'"
# }
app.post_with_headers "/project/test/:id/:env", :headers => [:accept, :content_type], &Devops::Version2_0::Handler::Project.test_project
app.post_with_headers "/project/test/:id/:env", :headers => [:accept, :content_type] do |project, deploy_env|
check_privileges("project", "r")
json Devops::API2_0::Handler::Project.new(request, params).test_project(project, deploy_env)
end
puts "Project routes initialized"
end

View File

@ -1,10 +1,9 @@
# encoding: UTF-8
require "json"
require "providers/provider_factory"
module Devops
module Version2_0
module API2_0
module Routes
module ProviderRoutes
@ -22,7 +21,10 @@ module Devops
# "ec2",
# "openstack"
# ]
app.get_with_headers "/providers", :headers => [:accept], &Devops::Version2_0::Handler::Provider.get_providers
app.get_with_headers "/providers", :headers => [:accept] do#, &Devops::Version2_0::Handler::Provider.get_providers
check_privileges("provider", "r")
json Devops::API2_0::Handler::Provider.new(request, params).providers
end
puts "Provider routes initialized"
end

View File

@ -0,0 +1,61 @@
module Devops
module API2_0
module Routes
module ReportRoutes
def self.registered(app)
app.get_with_headers "/report/all", headers: [:accept] do
json Devops::API2_0::Handler::Report.new(request, params).all.map{|r| r.to_hash}
end
app.get_with_headers "/report/all/latest", headers: [:accept] do
json Devops::API2_0::Handler::Report.new(request, params).all_latest.map{|r| r.to_hash}
end
app.get_with_headers "/report/all/attributes/:name", headers: [:accept] do |name|
json Devops::API2_0::Handler::Report.new(request, params).attributes(name)
end
app.get_with_headers "/report/:id", headers: [:accept] do |id|
@text, @done = Devops::API2_0::Handler::Report.new(request, params).report(id)
erb :index
end
app.get "/status/:id" do
r = Devops::API2_0::Handler::Report.new(request, params).status(params[:id])
return [404, "Job with id '#{params[:id]}' not found"] if r.nil?
r
end
puts "Report routes initialized"
end
end
end
end
end
__END__
@@ layout
<html>
<head>
<% unless @done %>
<script>
function reload() {
location.reload();
}
setTimeout(reload, 5000);
</script>
<% end %>
</head>
<body>
<%= yield %>
</body>
</html>
@@ index
<pre>
<%= @text %>
</pre>

View File

@ -0,0 +1,115 @@
module Devops
module Version2_0
module Routes
module ScriptRoutes
def self.registered(app)
# Get scripts names
#
# * *Request*
# - method : GET
# - headers :
# - Accept: application/json
#
# * *Returns* :
# [
# "script_1"
# ]
app.get_with_headers "/scripts", :headers => [:accept] do
check_privileges("script", "r")
json Devops::API2_0::Handler::Script.new(request, params).scripts
end
# Run command on node :node_name
#
# * *Request*
# - method : POST
# - body :
# command to run
#
# * *Returns* : text stream
app.post_with_statistic "/script/command/:node_name" do |node_name|
check_privileges("script", "x")
stream() do |out|
begin
Devops::API2_0::Handler::Script.new(request, params).execute_command(out, request.body.read, node_name)
rescue IOError => e
logger.error e.message
end
end
end
# Run script :script_name on nodes
#
# * *Request*
# - method : POST
# - headers :
# - Content-Type: application/json
# - body :
# {
# "nodes": [], -> array of nodes names
# "params": [] -> array of script arguments
# }
#
# * *Returns* : text stream
app.post_with_headers "/script/run/:script_name", :headers => [:content_type] do |script_name|
check_privileges("script", "x")
file_name = check_filename(script_name, "Parameter 'script_name' must be a not empty string", false)
body = create_object_from_json_body
nodes = check_array(body["nodes"], "Parameter 'nodes' must be a not empty array of strings")
p = check_array(body["params"], "Parameter 'params' should be a not empty array of strings", String, true)
stream() do |out|
begin
Devops::API2_0::Handler::Script.new(request, params).run_script out, file_name, nodes, p
rescue IOError => e
logger.error e.message
end
end
end
hash = {}
# Create script :script_name
#
# * *Request*
# - method : PUT
# - headers :
# - Accept: application/json
# - body : script content
#
# * *Returns* :
# 201 - Created
hash["PUT"] = lambda {
check_privileges("script", "w")
file_name = params[:script_name]
check_filename(file_name, "Parameter 'script_name' must be a not empty string")
Devops::API2_0::Handler::Script.new(request, params).create_script(file_name)
create_response("File '#{file_name}' created", nil, 201)
}
# Delete script :script_name
#
# * *Request*
# - method : Delete
# - headers :
# - Accept: application/json
#
# * *Returns* :
# 200 - Deleted
hash["DELETE"] = lambda {
check_privileges("script", "w")
file_name = params[:script_name]
check_filename(file_name, "Parameter 'script_name' must be a not empty string")
Devops::API2_0::Handler::Script.new(request, params).delete_script file_name
create_response("File '#{file_name}' deleted")
}
app.multi_routes "/script/:script_name", {:headers => [:accept]}, hash
puts "Script routes initialized"
end
end
end
end
end

View File

@ -1,7 +1,7 @@
require "json"
module Devops
module Version2_0
module API2_0
module Routes
module ServerRoutes
@ -23,7 +23,17 @@ module Devops
# "chef_node_name": "chef name"
# }
# ]
app.get_with_headers "/servers", :headers => [:accept], &Devops::Version2_0::Handler::Server.get_servers
app.get_with_headers "/servers", :headers => [:accept] do
check_privileges("server", "r")
fields = []
if params.key?("fields") and params["fields"].is_a?(Array)
Devops::Model::Server.fields.each do |k|
fields.push k if params["fields"].include?(k)
end
end
reserved = (params.key?("reserved") ? true : nil)
json Devops::API2_0::Handler::Server.new(request, params).servers(fields, reserved)
end
# Get chef nodes list
#
@ -38,7 +48,10 @@ module Devops
# "chef_node_name": "chef name"
# }
# ]
app.get_with_headers "/servers/chef", :headers => [:accept], &Devops::Version2_0::Handler::Server.get_chef_servers
app.get_with_headers "/servers/chef", :headers => [:accept] do
check_privileges("server", "r")
json Devops::API2_0::Handler::Server.new(request, params).chef_servers
end
# Get provider servers list
#
@ -76,7 +89,10 @@ module Devops
# "private_ip": "172.17.0.1"
# }
# ]
app.get_with_headers "/servers/:provider", :headers => [:accept], &Devops::Version2_0::Handler::Server.get_provider_servers
app.get_with_headers "/servers/:provider", :headers => [:accept] do
check_privileges("server", "r")
json Devops::API2_0::Handler::Server.new(request, params).provider_servers(params[:provider])
end
# Get server info by :name
#
@ -94,7 +110,10 @@ module Devops
# }
# ]
hash = {}
hash["GET"] = Devops::Version2_0::Handler::Server.get_server
hash["GET"] = lambda {|id|
check_privileges("server", "r")
json Devops::API2_0::Handler::Server.new(request, params).server(id).to_hash
}
# Delete devops server
#
@ -110,7 +129,13 @@ module Devops
#
# * *Returns* :
# 200 - Deleted
hash["DELETE"] = Devops::Version2_0::Handler::Server.delete_server
hash["DELETE"] = lambda {|id|
check_privileges("server", "w")
body = create_object_from_json_body(Hash, true)
key = (body.nil? ? nil : body["key"])
info, r = Devops::API2_0::Handler::Server.new(request, params).delete(id, key)
create_response(info, r)
}
app.multi_routes "/server/:id", {:headers => [:accept, :content_type]}, hash
# Create devops server
@ -133,7 +158,32 @@ module Devops
# }
#
# * *Returns* : text stream
app.post_with_headers "/server", :headers => [:content_type], &Devops::Version2_0::Handler::Server.create_server
app.post_with_headers "/server", :headers => [:content_type] do
check_privileges("server", "w")
body = create_object_from_json_body
project_name = check_string(body["project"], "Parameter 'project' must be a not empty string")
env_name = check_string(body["deploy_env"], "Parameter 'deploy_env' must be a not empty string")
server_name = check_string(body["name"], "Parameter 'name' should be null or not empty string", true)
without_bootstrap = body["without_bootstrap"]
force = body["force"]
halt_response("Parameter 'without_bootstrap' should be a null or true") unless without_bootstrap.nil? or without_bootstrap == true
halt_response("Parameter 'force' should be a null or true") unless force.nil? or force == true
groups = check_array(body["groups"], "Parameter 'groups' should be null or not empty array of string", String, true)
key_name = check_string(body["key"], "Parameter 'key' should be null or not empty string", true)
handler = Devops::API2_0::Handler::Server.new(request, params)
if body.key?("trace")
stream() do |out|
begin
status = handler.create_server_stream out, body
out << create_status(status)
rescue IOError => e
logger.error e.message
end
end
else
json handler.create_server body
end
end
# Pause devops server by name
#
@ -149,7 +199,13 @@ module Devops
#
# * *Returns* :
# 200 - Paused
app.post_with_headers "/server/:node_name/pause", :headers => [:accept, :content_type], &Devops::Version2_0::Handler::Server.pause_server
app.post_with_headers "/server/:node_name/pause", :headers => [:accept, :content_type] do |node_name|
check_privileges("server", "w")
body = create_object_from_json_body(Hash, true)
key = (body.nil? ? nil : body["key"])
info = Devops::API2_0::Handler::Server.new(request, params).pause_server(node_name, key)
create_response(info)
end
# Unpause devops server by name
#
@ -165,7 +221,13 @@ module Devops
#
# * *Returns* :
# 200 - Unpaused
app.post_with_headers "/server/:node_name/unpause", :headers => [:accept, :content_type], &Devops::Version2_0::Handler::Server.unpause_server
app.post_with_headers "/server/:node_name/unpause", :headers => [:accept, :content_type] do |node_name|
check_privileges("server", "w")
body = create_object_from_json_body(Hash, true)
key = (body.nil? ? nil : body["key"])
info = Devops::API2_0::Handler::Server.new(request, params).unpause_server(node_name, key)
create_response(info)
end
# Reserve devops server
#
@ -181,7 +243,13 @@ module Devops
#
# * *Returns* :
# 200 - Reserved
app.post_with_headers "/server/:node_name/reserve", :headers => [:accept, :content_type], &Devops::Version2_0::Handler::Server.reserve_server
app.post_with_headers "/server/:node_name/reserve", :headers => [:accept, :content_type] do |node_name|
check_privileges("server", "w")
body = create_object_from_json_body(Hash, true)
key = (body.nil? ? nil : body["key"])
Devops::API2_0::Handler::Server.new(request, params).reserve_server(node_name, key)
create_response("Server '#{node_name}' has been reserved")
end
# Unreserve devops server
#
@ -197,7 +265,13 @@ module Devops
#
# * *Returns* :
# 200 - Unreserved
app.post_with_headers "/server/:node_name/unreserve", :headers => [:accept, :content_type], &Devops::Version2_0::Handler::Server.unreserve_server
app.post_with_headers "/server/:node_name/unreserve", :headers => [:accept, :content_type] do |node_name|
check_privileges("server", "w")
body = create_object_from_json_body(Hash, true)
key = (body.nil? ? nil : body["key"])
Devops::API2_0::Handler::Server.new(request, params).unreserve_server(node_name, key)
create_response("Server '#{node_name}' has been unreserved")
end
# Bootstrap devops server
#
@ -215,7 +289,32 @@ module Devops
# }
#
# * *Returns* : text stream
app.post_with_headers "/server/bootstrap", :headers => [:accept, :content_type], &Devops::Version2_0::Handler::Server.bootstrap_server
app.post_with_headers "/server/bootstrap", :headers => [:accept, :content_type] do
check_privileges("server", "w")
body = create_object_from_json_body(Hash, true)
id = check_string(body["instance_id"], "Parameter 'instance_id' must be a not empty string")
name = check_string(body["name"], "Parameter 'name' should be a not empty string", true)
rl = check_array(body["run_list"], "Parameter 'run_list' should be a not empty array of string", String, true)
unless rl.nil?
validator = Validators::Helpers::RunList.new(rl)
halt_response(validator.message) unless validator.valid?
end
t = check_string(body["bootstrap_template"], "Parameter 'bootstrap_template' should be a not empty string", true)
handler = Devops::API2_0::Handler::Server.new(request, params)
if body.key?("trace")
stream() do |out|
begin
status = handler.bootstrap_server_stream out, body
out << create_status(status)
rescue IOError => e
logger.error e.message
end
end
else
handler.bootstrap_server(body)
end
end
# Add external server to devops
#
@ -236,7 +335,19 @@ module Devops
#
# * *Returns* :
# 200 - Added
app.post_with_headers "/server/add", :headers => [:accept, :content_type], &Devops::Version2_0::Handler::Server.add_server
app.post_with_headers "/server/add", :headers => [:accept, :content_type] do
check_privileges("server", "w")
body = create_object_from_json_body
project = check_string(body["project"], "Parameter 'project' must be a not empty string")
deploy_env = check_string(body["deploy_env"], "Parameter 'deploy_env' must be a not empty string")
key = check_string(body["key"], "Parameter 'key' must be a not empty string")
remote_user = check_string(body["remote_user"], "Parameter 'remote_user' must be a not empty string")
private_ip = check_string(body["private_ip"], "Parameter 'private_ip' must be a not empty string")
public_ip = check_string(body["public_ip"], "Parameter 'public_ip' should be a not empty string", true)
info = Devops::API2_0::Handler::Server.new(request, params).add_server(body)
create_response(info)
end
puts "Server routes initialized"
end

View File

@ -0,0 +1,61 @@
module Devops
module API2_0
module Routes
module StackRoutes
def self.registered(app)
app.get_with_headers '/stacks', :headers => [:accept] do
check_privileges("stack", "r")
json Devops::API2_0::Handler::Stack.new(request, params).stacks.map(&:to_hash)
end
app.get_with_headers '/stacks/provider/:provider', :headers => [:accept] do |provider|
check_privileges("stack", "r")
check_provider(provider)
json Devops::API2_0::Handler::Stack.new(request, params).stacks_for_provider(provider).map(&:to_hash)
end
app.post_with_headers "/stack", :headers => [:accept] do
check_privileges("stack", "w")
object = create_object_from_json_body
m = Devops::API2_0::Handler::Stack.new(request, params).create_stack object
create_response "Created", m.to_hash, 201
end
hash = {}
hash['GET'] = lambda { |stack_id|
check_privileges("stack", "r")
json Devops::API2_0::Handler::Stack.new(request, params).stack(stack_id).to_hash
}
hash['DELETE'] = lambda { |stack_id|
check_privileges("stack", "w")
Devops::API2_0::Handler::Stack.new(request, params).delete_stack(stack_id)
create_response("Stack '#{stack_id}' has been removed")
}
app.multi_routes '/stack/:stack_id', {:headers => [:accept]}, hash
app.post_with_headers "/stack/:stack_id/sync_details", :headers => [:accept] do |stack_id|
check_privileges("stack", "w")
json Devops::API2_0::Handler::Stack.new(request, params).sync_details(stack_id).to_hash
end
app.get_with_headers "/stack/:stack_id/resources", :headers => [:accept] do |stack_id|
check_privileges("stack", "r")
json Devops::API2_0::Handler::Stack.new(request, params).resources(stack_id)
end
app.get_with_headers "/stack/:stack_id/resources/:resource_id", :headers => [:accept] do |stack_id, resource_id|
check_privileges("stack", "r")
json Devops::API2_0::Handler::Stack.new(request, params).resource(stack_id, resource_id)
end
puts "Stack routes initialized"
end
end
end
end
end

View File

@ -1,10 +1,10 @@
module Devops
module Version2_0
module API2_0
module Routes
module StackPresetRoutes
def self.registered(app)
# Get list of available stack_presets
# Get list of available stack_template_presets
#
# * *Request*
# - method : GET
@ -14,10 +14,12 @@ module Devops
# * *Returns* : array of hashes
# [ {id: 'preset id', template_preset_body: 'long body'} ]
#
app.get_with_headers "/stack_presets", :headers => [:accept], &Devops::Version2_0::Handler::StackPreset.get_presets
app.get_with_headers "/stack_presets", :headers => [:accept] do
# check_privileges("stack_template_presets", "r")
json Devops::API2_0::Handler::StackPreset.new(request, params).presets.map(&:to_hash)
end
# Get information about stack_preset
# Get information about stack_template_preset
#
# * *Request*
# - method : GET
@ -27,8 +29,10 @@ module Devops
# * *Returns* : hash
# {id: 'preset id', template_preset_body: 'long body'}
#
app.get_with_headers "/stack_presets/:id", :headers => [:accept], &Devops::Version2_0::Handler::StackPreset.get_preset
app.get_with_headers "/stack_presets/:id", :headers => [:accept] do |id|
# check_privileges("stack_template_presets", "r")
json Devops::API2_0::Handler::StackPreset.new(request, params).preset(id).to_hash
end
# Build stack template from preset
#
@ -38,7 +42,7 @@ module Devops
# - Accept: application/json
# - params :
# - provider: string
# - stack_id: id of stack template to create
# - stack_template_id: id of stack template to create
# - template_attrs: hash with template attributes
#
# TODO: not stack template, but stack itself
@ -50,7 +54,13 @@ module Devops
# template_body: 'long body'
# }
#
app.post_with_headers "/stack_presets/:id/apply", :headers => [:accept], &Devops::Version2_0::Handler::StackPreset.apply
app.post_with_headers "/stack_presets/:id/apply", :headers => [:accept] do |id|
# check_privileges("stack_template_presets", "r")
check_privileges('stack_template', 'w')
body = create_object_from_json_body
stack = Devops::API2_0::Handler::StackPreset.new(request, params).apply(id, body)
create_response 'Created', stack.to_hash, 201
end
puts "Stack template presets routes initialized"
end

View File

@ -0,0 +1,46 @@
module Devops
module API2_0
module Routes
module StackTemplateRoutes
def self.registered(app)
app.get_with_headers '/stack_templates', :headers => [:accept] do
check_privileges('stack_template', 'r')
json Devops::API2_0::Handler::StackTemplate.new(request, params).stack_templates.map(&:to_hash)
end
app.get_with_headers '/stack_templates/provider/:provider', :headers => [:accept] do |provider|
check_privileges('stack_template', 'r')
check_provider(provider)
json Devops::API2_0::Handler::StackTemplate.new(request, params).stack_templates_for_provider(provider).map(&:to_hash)
end
app.post_with_headers "/stack_template", :headers => [:accept] do
check_privileges('stack_template', 'w')
body = create_object_from_json_body
model = Devops::API2_0::Handler::StackTemplate.new(request, params).create_stack_template(body)
create_response 'Created', model.to_hash, 201
end
hash = {}
hash['GET'] = lambda {|stack_template_id|
check_privileges('stack_template', 'r')
json Devops::API2_0::Handler::StackTemplate.new(request, params).stack_template(stack_template_id).to_hash
}
hash['DELETE'] = lambda {|stack_template_id|
check_privileges('stack_template', 'w')
Devops::API2_0::Handler::StackTemplate.new(request, params).delete_stack_template(stack_template_id)
create_response("Template '#{stack_template_id}' has been removed")
}
app.multi_routes '/stack_template/:stack_template_id', {}, hash
puts "Stack_template routes initialized"
end
end
end
end
end

View File

@ -1,5 +1,5 @@
module Devops
module Version2_0
module API2_0
module Routes
module TagRoutes
@ -17,7 +17,10 @@ module Devops
# [
# "tag_1"
# ]
hash["GET"] = Devops::Version2_0::Handler::Tag.get_tags
hash["GET"] = lambda {
check_privileges("server", "r")
json Devops::API2_0::Handler::Tag.new(params[:node_name]).tags()
}
# Set tags list to :node_name
#
@ -33,7 +36,13 @@ module Devops
#
# * *Returns* :
# 200
hash["POST"] = Devops::Version2_0::Handler::Tag.set_tags
hash["POST"] = lambda {
check_privileges("server", "w")
tags = create_object_from_json_body(Array)
check_array(tags, "Request body should be a not empty array of strings")
Devops::Version2_0::Handler::Tag.new(params[:node_name]).set_tags(tags)
create_response("Set tags for #{params[:node_name]}", tags: tags)
}
# Delete tags from :node_name
#
@ -49,7 +58,13 @@ module Devops
#
# * *Returns* :
# 200
hash["DELETE"] = Devops::Version2_0::Handler::Tag.unset_tags
hash["DELETE"] = lambda {
check_privileges("server", "w")
tags = create_object_from_json_body(Array)
check_array(tags, "Request body should be a not empty array of strings")
Devops::Version2_0::Handler::Tag.new(params[:node_name]).unset_tags(tags)
create_response("Deleted tags for #{params[:node_name]}", tags: tags)
}
app.multi_routes "/tags/:node_name", {:headers => [:accept, :content_type]}, hash
puts "Tag routes initialized"

View File

@ -1,5 +1,5 @@
module Devops
module Version2_0
module API2_0
module Routes
module UserRoutes
@ -33,7 +33,11 @@ module Devops
# "id": "test"
# }
# ]
app.get_with_headers "/users", :headers => [:accept], &Devops::Version2_0::Handler::User.get_users
app.get_with_headers "/users", :headers => [:accept] do#, &Devops::API2_0::Handler::User.get_users
check_privileges("user", "r")
users = Devops::API2_0::Handler::User.new.users.map {|i| h = i.to_hash; h.delete("password"); h}
json users
end
# Create user
#
@ -51,7 +55,15 @@ module Devops
#
# * *Returns* :
# 201 - Created
app.post_with_headers "/user", :headers => [:accept, :content_type], &Devops::Version2_0::Handler::User.create_user
app.post_with_headers "/user", :headers => [:accept, :content_type] do#, &Devops::API2_0::Handler::User.create_user
check_privileges("user", "w")
user = create_object_from_json_body
["username", "password", "email"].each do |p|
check_string(user[p], "Parameter '#{p}' must be a not empty string")
end
Devops::API2_0::Handler::User.new.create(user)
create_response("Created", nil, 201)
end
hash = {}
# Delete user
@ -63,7 +75,24 @@ module Devops
#
# * *Returns* :
# 200 - Deleted
hash["DELETE"] = Devops::Version2_0::Handler::User.delete_user
hash["DELETE"] = lambda {
check_privileges("user", "w")
projects = Devops::Db.connector.projects_by_user params[:user]
if !projects.empty?
str = ""
projects.each do |p|
p.deploy_envs.each do |e|
str+="#{p.id}.#{e.identifier} " if e.users.include? params[:user]
end
end
logger.info projects
raise DependencyError.new "Deleting is forbidden: User is included in #{str}"
#return [400, "Deleting is forbidden: User is included in #{str}"]
end
Devops::API2_0::Handler::User.new.delete(params[:user])
create_response("User '#{params[:user]}' removed")
}
# Change user privileges
#
@ -80,7 +109,14 @@ module Devops
#
# * *Returns* :
# 200 - Updated
hash["PUT"] = Devops::Version2_0::Handler::User.change_user_privileges
hash["PUT"] = lambda {
check_privileges("user", "w")
data = create_object_from_json_body
cmd = check_string(data["cmd"], "Parameter 'cmd' should be a not empty string", true) || ""
privileges = check_string(data["privileges"], "Parameter 'privileges' should be a not empty string", true) || ""
Devops::API2_0::Handler::User.new.change_user_privileges(params[:user], cmd, privileges)
create_response("Updated")
}
app.multi_routes "/user/:user", {:headers => [:accept, :content_type]}, hash
# Change user email/password
@ -97,7 +133,20 @@ module Devops
#
# * *Returns* :
# 200 - Updated
app.put_with_headers %r{\A/user/#{DevopsConfig::OBJECT_NAME}/(email|password)\z}, :headers => [:accept, :content_type], &Devops::Version2_0::Handler::User.change_user_email_or_password
app.put_with_headers %r{\A/user/#{DevopsConfig::OBJECT_NAME}/(email|password)\z}, :headers => [:accept, :content_type] do#, &Devops::API2_0::Handler::User.change_user_email_or_password
check_privileges("user", "w")
action = File.basename(request.path)
u = File.basename(File.dirname(request.path))
raise InvalidPrivileges.new("Access denied for '#{request.env['REMOTE_USER']}'") if u == Devops::Model::User::ROOT_USER_NAME and request.env['REMOTE_USER'] != Devops::Model::User::ROOT_USER_NAME
check_privileges("user", "w") unless request.env['REMOTE_USER'] == u
body = create_object_from_json_body
p = check_string(body[action], "Parameter '#{action}' must be a not empty string")
h = Devops::API2_0::Handler::User.new
h.send("change_#{action}=", p)
create_response("Updated")
end
puts "User routes initialized"
end

View File

@ -1,20 +1,32 @@
require "sinatra/base"
require "sinatra/streaming"
require "helpers/version_2"
require "json"
require "fog"
require "auth/devops_auth"
require "exceptions/invalid_record"
require "exceptions/record_not_found"
require "exceptions/dependency_error"
require "exceptions/conflict_exception"
require 'core/devops-logger'
require_relative "../helpers/version_2"
module Devops
class Api2 < Sinatra::Base
include Sinatra::JSON
helpers Sinatra::Streaming
helpers Devops::Version2_0::Helpers
helpers Devops::API2_0::Helpers
register Sinatra::DevopsAuth
configure :production do
config = DevopsConfig.config
log_file = File.join(config[:log_dir], "devops-api2.log")
logger = DevopsLogger.create(log_file, Logger::DEBUG)
use Rack::CommonLogger, logger
disable :dump_errors
disable :show_exceptions
set :logging, Logger::INFO
@ -22,11 +34,14 @@ module Devops
end
configure :development do
set :logging, Logger::DEBUG
config = DevopsConfig.config
log_file = File.join(config[:log_dir], "devops-api2.log")
logger = DevopsLogger.create(log_file, Logger::DEBUG)
use Rack::CommonLogger, logger
disable :raise_errors
# disable :dump_errors
set :show_exceptions, :after_handler
puts "Development mode"
logger.info "Development mode"
end
not_found do
@ -58,6 +73,12 @@ module Devops
halt_response(e.message, 400)
end
error ConflictException do
e = env["sinatra.error"]
logger.warn e.message
halt_response(e.message, 409)
end
error InvalidPrivileges do
e = env["sinatra.error"]
logger.warn e.message

View File

@ -1,4 +1,6 @@
require 'sinatra/base'
require 'core/devops-logger'
require 'core/devops-config'
class Client < Sinatra::Base
@ -7,6 +9,29 @@ class Client < Sinatra::Base
@@config = DevopsConfig.config
end
configure :production do
config = DevopsConfig.config
log_file = File.join(config[:log_dir], "devops-client.log")
logger = DevopsLogger.create(log_file, Logger::INFO)
use Rack::CommonLogger, logger
disable :dump_errors
disable :show_exceptions
# set :logging, Logger::INFO
logger.info "Production mode"
end
configure :development do
config = DevopsConfig.config
log_file = File.join(config[:log_dir], "devops-client.log")
logger = DevopsLogger.create(log_file, Logger::DEBUG)
use Rack::CommonLogger, logger
# set :logging, Logger::DEBUG
disable :raise_errors
# disable :dump_errors
set :show_exceptions, :after_handler
logger.info "Development mode"
end
# Route to download devops client
get "/devops-client.gem" do
begin

View File

@ -1,28 +1,27 @@
module Devops
module Application
class DevopsApi2Application < Application
def prepare
require "routes/v2.0"
require "routes/v2.0/handlers/provider"
require "routes/v2.0/handlers/bootstrap_templates"
require "routes/v2.0/handlers/deploy"
require "routes/v2.0/handlers/filter"
require "routes/v2.0/handlers/flavor"
require "routes/v2.0/handlers/group"
require "routes/v2.0/handlers/image"
require "routes/v2.0/handlers/network"
require "routes/v2.0/handlers/key"
require "routes/v2.0/handlers/project"
require "routes/v2.0/handlers/script"
require "routes/v2.0/handlers/status"
require "routes/v2.0/handlers/tag"
require "routes/v2.0/handlers/user"
require "routes/v2.0/handlers/server"
require "routes/v2.0/handlers/stack"
require "routes/v2.0/handlers/stack_template"
require "routes/v2.0/stack_presets"
require "routes/v2.0/handlers/report"
require_relative "api2/routes/v2.0"
require_relative "api2/handlers/provider"
require_relative "api2/handlers/flavor"
require_relative "api2/handlers/filter"
require_relative "api2/handlers/group"
require_relative "api2/handlers/user"
require_relative "api2/handlers/network"
require_relative "api2/handlers/report"
require_relative "api2/handlers/deploy"
require_relative "api2/handlers/script"
require_relative "api2/handlers/bootstrap_templates"
require_relative "api2/handlers/key"
require_relative "api2/handlers/tag"
require_relative "api2/handlers/server"
require_relative "api2/handlers/image"
require_relative "api2/handlers/project"
require_relative "api2/handlers/stack"
require_relative "api2/handlers/stack_template"
require_relative "api2/handlers/stack_preset"
require 'lib/stubber'
end
@ -39,31 +38,30 @@ module Devops
Devops::Api2.settings.mongo.create_root_user
::Provider::ProviderFactory.init(config)
Stubber.stub_providers!(config[:stub_providers])
Stubber.stub_providers! if config[:stub_classes]
end
def routes
require "routes/v2.0/flavor"
require "routes/v2.0/image"
require "routes/v2.0/filter"
require "routes/v2.0/network"
require "routes/v2.0/group"
require "routes/v2.0/deploy"
require "routes/v2.0/project"
require "routes/v2.0/key"
require "routes/v2.0/user"
require "routes/v2.0/provider"
require "routes/v2.0/tag"
require "routes/v2.0/server"
require "routes/v2.0/script"
require "routes/v2.0/status"
require "routes/v2.0/bootstrap_templates"
require "routes/v2.0/stack"
require "routes/v2.0/stack_template"
require "routes/v2.0/handlers/stack_preset"
require "routes/v2.0/report"
require_relative "api2/routes/flavor"
require_relative "api2/routes/image"
require_relative "api2/routes/filter"
require_relative "api2/routes/network"
require_relative "api2/routes/group"
require_relative "api2/routes/deploy"
require_relative "api2/routes/project"
require_relative "api2/routes/key"
require_relative "api2/routes/user"
require_relative "api2/routes/provider"
require_relative "api2/routes/tag"
require_relative "api2/routes/server"
require_relative "api2/routes/script"
require_relative "api2/routes/bootstrap_templates"
require_relative "api2/routes/stack"
require_relative "api2/routes/stack_template"
require_relative "api2/routes/stack_presets"
require_relative "api2/routes/report"
routes = Devops::Version2_0::Routes.constants.collect{|s| Devops::Version2_0::Routes.const_get(s)}.select {|const| const.class == Module}
routes = Devops::API2_0::Routes.constants.collect{|s| Devops::API2_0::Routes.const_get(s)}.select {|const| const.class == Module}
routes.each do |r|
Devops::Api2.register r
end
@ -77,5 +75,4 @@ module Devops
end
end
end

View File

@ -1,28 +0,0 @@
module Devops
module Application
class Application
@@applications = []
def self.inherited(base)
@@applications << base.new
puts "Devops application '#{base}' has been added"
end
def self.applications
@@applications
end
def prepare
end
def init
end
def routes
end
end
end
end

View File

@ -1,5 +1,4 @@
module Devops
module Application
class DevopsClientApplication < Application
def prepare
@ -11,4 +10,3 @@ module Devops
end
end
end
end

View File

@ -1,5 +1,4 @@
module Devops
module Application
class DevopsVersionApplication < Application
def prepare
@ -11,5 +10,4 @@ module Devops
end
end
end
end

View File

@ -1,5 +1,7 @@
require 'core/devops-logger'
require 'core/devops-config'
module Devops
module Application
class SidekiqApplication < Application
@ -8,10 +10,13 @@ module Devops
end
def routes
config = DevopsConfig.config
log_file = File.join(config[:log_dir], "devops-sidekiq-web.log")
logger = DevopsLogger.create(log_file, Logger::INFO)
Sidekiq::Web.use Rack::CommonLogger, logger
Devops::Routes.route "/sidekiq", Sidekiq::Web
end
end
end
end

View File

@ -2,7 +2,7 @@ require 'sinatra/base'
class DevopsVersion < Sinatra::Base
VERSION = "3.0.0"
VERSION = "2.3.0"
get "/" do
VERSION

View File

@ -0,0 +1,4 @@
require "app/sidekiq_web"
require "app/devops-client"
require "app/devops-version"
require "app/devops-api2"

View File

@ -12,8 +12,9 @@ module Sinatra
if @auth.provided? and @auth.basic? and @auth.credentials
c = @auth.credentials
begin
Devops::Db.connector.user_auth(c[0], c[1])
u = Devops::Db.connector.user_auth(c[0], c[1])
request.env['REMOTE_USER'] = c[0]
request.env['USER'] = u
true
rescue RecordNotFound => e
false

View File

@ -2,7 +2,8 @@ module BootstrapTemplatesCommands
def get_templates
res = []
Dir.foreach("#{ENV["HOME"]}/.chef/bootstrap/") {|f| res.push(f[0..-5]) if f.end_with?(".erb")} if File.exists? "#{ENV["HOME"]}/.chef/bootstrap/"
dir = "#{ENV["HOME"]}/.chef/bootstrap/"
Dir.foreach(dir) {|f| res.push(f[0..-5]) if f.end_with?(".erb")} if File.exists? dir
res
end

View File

@ -1,4 +1,3 @@
require "db/exceptions/invalid_record"
require "commands/image"
module DeployEnvCommands

View File

@ -1,6 +1,6 @@
require "commands/knife_commands"
require "commands/deploy"
require "db/exceptions/record_not_found"
require "exceptions/record_not_found"
module ServerCommands

View File

@ -1,5 +1,5 @@
# path to log file
config[:log_file] = "/path/to/log"
# path to log dir
config[:log_dir] = "/path/to/log"
# path to chef knife.rb file
config[:knife_config_file] = "/path/to/.chef/knife.rb"
# role name separator

View File

@ -4,11 +4,12 @@ require "rubygems"
require "bundler/setup"
require 'byebug'
require_relative "devops-service"
require_relative "devops_config"
require_relative "devops-routes"
root = File.dirname(__FILE__)
$:.push root
require_relative "core/devops-service"
require_relative "core/devops-config"
require_relative "core/devops-routes"
# Read configuration file
DevopsConfig.read
@ -27,6 +28,10 @@ config[:report_dir_v2] = File.expand_path(File.join(config[:devops_dir], "report
DevopsService.init
puts Devops::Routes.routes
if Devops::Routes.routes.empty?
puts "No applications"
exit -1
end
Devops::Routes.routes.each do |p, c|
map(p) do
run c

View File

@ -0,0 +1,26 @@
module Devops
class Application
@@applications = []
def self.inherited(base)
@@applications << base.new
puts "Devops application '#{base}' has been added"
end
def self.applications
@@applications
end
def prepare
end
def init
end
def routes
end
end
end

View File

@ -9,7 +9,7 @@ class DevopsConfig
class << self
def read config_file=nil
if config_file.nil?
config_file = ENV['DEVOPS_CONFIG'] || ENV['CONFIG'] || File.join(File.dirname(__FILE__), 'config.rb')
config_file = ENV['DEVOPS_CONFIG'] || ENV['CONFIG'] || File.join(File.dirname(__FILE__), '../config.rb')
end
config = {:url_prefix => ""}
if File.exists? config_file

View File

@ -1,3 +1,5 @@
require "db/mongo/mongo_connector"
module Devops
class Db

View File

@ -0,0 +1,16 @@
require "logger"
class DevopsLogger
def self.create out, level=Logger::INFO, format='%a %d-%m-%Y %H%M '
@_logger = Logger.new out
@_logger.level = level
@_logger.datetime_format = format
@_logger.debug("Logger has been created")
@_logger
end
def self.logger
@_logger
end
end

View File

@ -1,29 +1,29 @@
require "wisper"
$:.push File.dirname(__FILE__)
=begin
require "db/exceptions/invalid_record"
require "db/exceptions/record_not_found"
require "exceptions/dependency_error"
require "db/validators/all"
require "db/mongo/mongo_connector"
require "providers/provider_factory"
require "fog"
require "loader"
require "devops_db"
require "devops_logger"
require_relative "routes/v2.0"
require "hooks"
require "app/devops-application"
require "app/devops-client"
require "app/sidekiq_web"
require "app/devops-version"
require "app/devops-api2"
=end
require_relative "sinatra/methods_with_headers"
require_relative "devops-loader"
require_relative "devops-db"
require_relative "devops-logger"
require_relative "devops-application"
require_relative "../sinatra/methods_with_headers"
require_relative "../applications"
#root = File.expand_path("../", __FILE__)
#$:.push root
class DevopsService
@ -51,7 +51,7 @@ class DevopsService
DevopsLogger.create STDOUT
routes
apps = Devops::Application::Application.applications
apps = Devops::Application.applications
apps.each do |a|
a.prepare
end
@ -91,4 +91,4 @@ class DevopsService
end
require "wisper_fix"
require_relative "../wisper_fix"

View File

@ -1,5 +1,5 @@
require "db/exceptions/record_not_found"
require "db/exceptions/invalid_record"
require "exceptions/record_not_found"
require "exceptions/invalid_record"
require "exceptions/invalid_command"
require "exceptions/invalid_privileges"

View File

@ -1,3 +1,4 @@
require "db/mongo/models/user"
module Connectors
class User < Base
include Helpers::InsertCommand,
@ -13,6 +14,7 @@ module Connectors
def user_auth user, password
u = collection.find('_id' => user, 'password' => password).to_a.first
raise RecordNotFound.new('Invalid username or password') if u.nil?
model_from_bson(u)
end
def users(ids=nil)
@ -33,19 +35,6 @@ module Connectors
collection.insert(root.to_mongo_hash)
end
def check_user_privileges(id, cmd, required_privelege)
user = show(id)
unless %w(r w x).include?(required_privelege)
raise InvalidPrivileges.new("Access internal problem with privilege '#{required_privelege}'")
end
unless user.can?(cmd, required_privelege)
raise InvalidPrivileges.new("Access denied for '#{user.id}'")
end
true
end
private
def model_from_bson(bson)

View File

@ -1,5 +1,4 @@
require "db/mongo/models/mongo_model"
require "db/exceptions/invalid_record"
require "providers/provider_factory"
require "commands/deploy_env"

View File

@ -1,4 +1,11 @@
require "db/mongo/models/deploy_env/deploy_env_base"
require "db/validators/deploy_env/run_list"
require "db/validators/deploy_env/expiration"
require "db/validators/deploy_env/users"
require "db/validators/deploy_env/flavor"
require "db/validators/deploy_env/image"
require "db/validators/deploy_env/subnet_belongs_to_provider"
require "db/validators/deploy_env/groups"
module Devops
module Model

View File

@ -1,5 +1,4 @@
require "db/mongo/models/mongo_model"
require "db/exceptions/invalid_record"
require "commands/deploy_env"
module Devops

View File

@ -1,5 +1,13 @@
require "db/mongo/models/deploy_env/deploy_env_base"
require "providers/provider_factory"
require "db/validators/deploy_env/run_list"
require "db/validators/deploy_env/expiration"
require "db/validators/deploy_env/users"
require "db/validators/deploy_env/flavor"
require "db/validators/deploy_env/image"
require "db/validators/deploy_env/subnet_not_empty"
require "db/validators/deploy_env/subnet_belongs_to_provider"
require "db/validators/deploy_env/groups"
module Devops
module Model

View File

@ -1,4 +1,7 @@
require "db/mongo/models/deploy_env/deploy_env_base"
require "db/validators/deploy_env/run_list"
require "db/validators/deploy_env/expiration"
require "db/validators/deploy_env/users"
module Devops
module Model

View File

@ -1,5 +1,6 @@
require "db/exceptions/invalid_record"
require "db/mongo/models/mongo_model"
require "db/validators/image/bootstrap_template"
require "db/validators/image/image_in_filter"
module Devops
module Model

View File

@ -1,6 +1,7 @@
require "db/exceptions/invalid_record"
require "db/mongo/models/mongo_model"
require "json"
require "db/validators/key/file_existence"
require "db/validators/key/scope"
module Devops
module Model

View File

@ -1,5 +1,5 @@
require "providers/provider_factory"
require "db/exceptions/invalid_record"
require "exceptions/invalid_record"
require "json"
require 'db/validators/all'

View File

@ -1,10 +1,9 @@
require "db/exceptions/invalid_record"
require "db/exceptions/record_not_found"
require "db/mongo/models/deploy_env/deploy_env_factory"
require "db/mongo/models/user"
require "db/mongo/models/deploy_env/deploy_env_multi"
require "db/mongo/models/mongo_model"
require "json"
require "hooks"
require "lib/project/handler/types_factory"
module Devops

View File

@ -1,4 +1,3 @@
require "db/exceptions/invalid_record"
require "db/mongo/models/mongo_model"
module Devops

View File

@ -1,4 +1,3 @@
require "db/exceptions/invalid_record"
require "db/mongo/models/mongo_model"
module Devops

View File

@ -1,4 +1,4 @@
require "db/exceptions/invalid_record"
require "exceptions/invalid_record"
require "exceptions/invalid_command"
require "db/mongo/models/mongo_model"
@ -70,15 +70,11 @@ module Devops
o
end
def can?(command, privilege)
p = self.privileges[command] || []
p.include?(privilege)
def check_privileges cmd, required_privelege
unless PRIVILEGES.include?(required_privelege)
raise InvalidPrivileges.new("Access internal problem with privilege '#{required_privelege}'")
end
def check_privilege cmd, priv
p = self.privileges[cmd]
return false if p.nil?
return p.include?(priv)
can?(cmd, required_privelege)
end
def self.create_root
@ -89,6 +85,12 @@ module Devops
end
private
def can?(command, privilege)
p = self.privileges[command] || []
p.include?(privilege)
end
def privileges_with_value value, options={}
privileges = {}
[

View File

@ -1,4 +1,5 @@
class Validators::Base
module Validators
class Base
def initialize(model, options={})
@model = model
@ -38,3 +39,4 @@ class Validators::Base
end
end
end

View File

@ -2,8 +2,10 @@
# not only in deploy env model
module Validators
class DeployEnv::RunList < Base
module DeployEnv
class RunList < Base
delegate_to_helper_validator { Helpers::RunList.new(@model.run_list) }
end
end
end

View File

@ -1,6 +1,9 @@
require "commands/bootstrap_templates"
require "db/validators/base"
module Validators
class Image::BootstrapTemplate < Base
module Image
class BootstrapTemplate < Base
include BootstrapTemplatesCommands
@ -18,3 +21,4 @@ module Validators
end
end
end
end

View File

@ -1,7 +1,9 @@
module Validators
class Key::FileExistence < Base
module Key
class FileExistence < Base
delegate_to_helper_validator { Helpers::FileExistence.new(@model.path) }
end
end
end

View File

@ -1,16 +0,0 @@
require "logger"
class DevopsLogger
def self.create out, level=Logger::INFO
@_logger = Logger.new out
@_logger.level = level
@_logger.datetime_format = '%a %d-%m-%Y %H%M '
@_logger.info("Logger has been created")
@_logger
end
def self.logger
@_logger
end
end

View File

@ -0,0 +1,4 @@
class ConflictException < Exception#StandardError
end

View File

@ -1,31 +0,0 @@
module Devops
module Version2_0
module Routes
module DeployRoutes
def self.registered(app)
# Run chef-client on reserved server
#
# * *Request*
# - method : POST
# - headers :
# - Content-Type: application/json
# - body :
# {
# "names": [], -> array of servers names to run chef-client
# "tags": [], -> array of tags to apply on each server before running chef-client
# "trace": true -> return output in stream
# }
#
# * *Returns* : text stream
app.post_with_headers "/deploy", :headers => [:content_type], &Devops::Version2_0::Handler::Deploy.deploy
puts "Deploy routes initialized"
end
end
end
end
end

View File

@ -1,20 +0,0 @@
require "commands/bootstrap_templates"
module Devops
module Version2_0
module Handler
class BootstrapTemplates
extend BootstrapTemplatesCommands
def self.get_bootstrap_templates
lambda {
check_privileges("templates", "r")
# broadcast(:cancel_order_failed, "hello")
json BootstrapTemplates.get_templates
}
end
end
end
end
end

View File

@ -1,70 +0,0 @@
require "commands/deploy"
require "commands/status"
require "workers/deploy_worker"
module Devops
module Version2_0
module Handler
class Deploy
extend DeployCommands
extend StatusCommands
def self.deploy
lambda {
check_privileges("server", "x")
# TODO: send message
#broadcast(:devops_deploy, "deploy")
r = create_object_from_json_body
names = check_array(r["names"], "Parameter 'names' should be a not empty array of strings")
tags = check_array(r["tags"], "Parameter 'tags' should be an array of strings", String, true) || []
servers = settings.mongo.servers(nil, nil, names, true)
halt(404, "No reserved servers found for names '#{names.join("', '")}'") if servers.empty?
keys = {}
servers.sort_by!{|s| names.index(s.chef_node_name)}
if r.key?("trace")
stream() do |out|
status = []
begin
servers.each do |s|
project = 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
res = deploy_server_proc.call(out, s, settings.mongo, tags)
status.push(res)
end
out << create_status(status)
rescue IOError => e
logger.error e.message
break
end
end # stream
else
dir = DevopsService.config[: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, tags, request.env['REMOTE_USER'], DevopsService.config)
logger.info "Job '#{jid}' has been started"
uri.path = "#{DevopsService.config[:url_prefix]}/v2.0/report/" + jid
files.push uri.to_s
end
sleep 1
json files
end
}
end
end
end
end
end

View File

@ -1,30 +0,0 @@
module Devops
module Version2_0
module Handler
class Filter
def self.get_filters
lambda {
check_privileges("filter", "r")
check_provider(params[:provider])
json settings.mongo.available_images(params[:provider])
}
end
def self.add_filter
lambda {
create_response("Updated", {:images => settings.mongo.add_available_images(@images, params[:provider])})
}
end
def self.delete_filter
lambda {
create_response("Deleted", {:images => settings.mongo.delete_available_images(@images, params[:provider])})
}
end
end
end
end
end

View File

@ -1,19 +0,0 @@
require "providers/provider_factory"
module Devops
module Version2_0
module Handler
class Flavor
def self.get_flavors
lambda {
check_privileges("flavor", "r")
check_provider(params[:provider])
p = ::Provider::ProviderFactory.get params[:provider]
json p.flavors
}
end
end
end
end
end

View File

@ -1,19 +0,0 @@
require "providers/provider_factory"
module Devops
module Version2_0
module Handler
class Group
def self.get_groups
lambda {
check_privileges("group", "r")
check_provider(params[:provider])
p = ::Provider::ProviderFactory.get params[:provider]
json p.groups(params)
}
end
end
end
end
end

View File

@ -1,75 +0,0 @@
require "providers/provider_factory"
require "commands/image"
module Devops
module Version2_0
module Handler
class Image
extend ImageCommands
def self.get_images
lambda {
check_privileges("image", "r")
check_provider(params[:provider]) if params[:provider]
images = settings.mongo.images(params[:provider])
json(images.map {|i| i.to_hash})
}
end
def self.get_provider_images
lambda {
check_privileges("image", "r")
check_provider(params[:provider])
json Image.get_available_provider_images(settings.mongo, params[:provider])
}
end
def self.get_image
lambda {
check_privileges("image", "r")
json settings.mongo.image(params[:image_id])
}
end
def self.create_image
lambda {
check_privileges("image", "w")
image = create_object_from_json_body
settings.mongo.image_insert Devops::Model::Image.new(image)
create_response "Created", nil, 201
}
end
def self.update_image
lambda {
check_privileges("image", "w")
settings.mongo.image params[:image_id]
image = Devops::Model::Image.new(create_object_from_json_body)
image.id = params[:image_id]
settings.mongo.image_update image
create_response("Image '#{params[:image_id]}' has been updated")
}
end
def self.delete_image
lambda {
check_privileges("image", "w")
projects = settings.mongo.projects_by_image params[:image_id]
unless projects.empty?
ar = []
projects.each do |p|
ar += p.deploy_envs.select{|e| e.respond_to?(:image)}.select{|e| e.image == params[:image_id]}.map{|e| "#{p.id}.#{e.identifier}"}
end
raise DependencyError.new "Deleting is forbidden: Image is used in #{ar.join(", ")}"
end
r = settings.mongo.image_delete params[:image_id]
create_response("Image '#{params[:image_id]}' has been removed")
}
end
end
end
end
end

View File

@ -1,60 +0,0 @@
module Devops
module Version2_0
module Handler
class Key
def self.get_keys
lambda {
check_privileges("key", "r")
keys = settings.mongo.keys.map {|i| i.to_hash}
keys.each {|k| k.delete("path")} # We should not return path to the key
json keys
}
end
def self.create_key
lambda {
check_privileges("key", "w")
key = create_object_from_json_body
fname = check_filename(key["file_name"], "Parameter 'file_name' must be a not empty string")
kname = check_string(key["key_name"], "Parameter 'key_name' should be a not empty string")
content = check_string(key["content"], "Parameter 'content' should be a not empty string")
file_name = File.join(settings.keys_dir, fname)
halt(400, "File '#{fname}' already exist") if File.exists?(file_name)
File.open(file_name, "w") do |f|
f.write(content)
f.chmod(0400)
end
key = Devops::Model::Key.new({"path" => file_name, "id" => kname})
settings.mongo.key_insert key
create_response("Created", nil, 201)
}
end
def self.delete_key
lambda {
check_privileges("key", "w")
servers = settings.mongo.servers_by_key params[:key]
unless servers.empty?
s_str = servers.map{|s| s.id}.join(", ")
raise DependencyError.new "Deleting is forbidden: Key is used in servers: #{s_str}"
end
k = settings.mongo.key params[:key]
begin
FileUtils.rm(k.path)
rescue
logger.error "Missing key file for #{params[:key]} - #{k.filename}"
end
r = settings.mongo.key_delete params[:key]
return [500, r["err"].inspect] unless r["err"].nil?
create_response("Key '#{params[:key]}' removed")
}
end
end
end
end
end

View File

@ -1,20 +0,0 @@
require "providers/provider_factory"
module Devops
module Version2_0
module Handler
class Network
def self.get_networks
lambda {
check_privileges("network", "r")
check_provider(params[:provider])
p = ::Provider::ProviderFactory.get params[:provider]
json p.networks_detail
}
end
end
end
end
end

View File

@ -1,315 +0,0 @@
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

View File

@ -1,16 +0,0 @@
require "providers/provider_factory"
module Devops
module Version2_0
module Handler
class Provider
def self.get_providers
lambda {
check_privileges("provider", "r")
json ::Provider::ProviderFactory.providers
}
end
end
end
end
end

View File

@ -1,63 +0,0 @@
module Devops
module Version2_0
module Handler
class Report
def self.reports_all
lambda {
options = {}
["project", "deploy_env", "type", "created_by", "date_from", "date_to", "sort", "status", "max_number", "chef_node_name"].each do |k|
options[k] = params[k] unless params[k].nil?
end
attributes_keys = params.keys.select{|k| k =~ /attributes\.*/}
attributes_keys.each do |ak|
options[ak] = params[ak]
end
json Devops::Db.connector.reports(options).map{|r| r.to_hash}
}
end
def self.reports_latest
lambda {
options = {}
["project", "deploy_env", "type", "created_by", "date_from", "date_to", "sort", "status", "chef_node_name"].each do |k|
options[k] = params[k] unless params[k].nil?
end
attributes_keys = params.keys.select{|k| k =~ /attributes\.*/}
attributes_keys.each do |ak|
options[ak] = params[ak]
end
json Devops::Db.connector.latest_reports(options).map{|r| r.to_hash}
}
end
def self.attributes_all
lambda{
json Devops::Db.connector.reports_attributes_values(params["name"])
}
end
def self.report
lambda{
begin
r = Devops::Db.connector.report(params[:id])
file = r.file
return [404, "Report '#{params[:id]}' does not exist"] unless File.exists? file
@text = Rack::Utils.escape_html(File.read(file))
@done = completed?(params[:id])
rescue RecordNotFound => e
if task_status(params[:id]) == Worker::STATUS::IN_QUEUE
@text = "Task '#{params[:id]}' has been queued"
@done = false
else
raise e
end
end
erb :index
}
end
end
end
end
end

View File

@ -1,127 +0,0 @@
require "providers/provider_factory"
require "fileutils"
require "commands/status"
module Devops
module Version2_0
module Handler
class Script
def self.get_scripts
lambda {
check_privileges("script", "r")
res = []
Dir.foreach(DevopsService.config[:scripts_dir]) {|f| res.push(f) unless f.start_with?(".")}
json res
}
end
def self.execute_command
lambda {
check_privileges("script", "x")
user = request.env['REMOTE_USER']
s = ::Devops::Db.connector.server_by_chef_node_name params[:node_name]
::Devops::Db.connector.check_project_auth s.project, s.deploy_env, user
cert = ::Devops::Db.connector.key s.key
cmd = request.body.read
addr = "#{s.remote_user}@#{s.public_ip || s.private_ip}"
ssh_cmd = "ssh -i %s #{addr} '#{cmd}'"
stream() do |out|
begin
out << ssh_cmd % File.basename(cert.path)
out << "\n"
IO.popen((ssh_cmd % cert.path) + " 2>&1") do |so|
while line = so.gets do
out << line
end
end
out << "\nDone"
rescue IOError => e
logger.error e.message
end
end
}
end
def self.run_script
lambda {
check_privileges("script", "x")
file_name = params[:script_name]
@file = File.join(DevopsService.config[:scripts_dir], check_filename(file_name, "Parameter 'script_name' must be a not empty string", false))
halt(404, "File '#{file_name}' does not exist") unless File.exists?(@file)
body = create_object_from_json_body
nodes = check_array(body["nodes"], "Parameter 'nodes' must be a not empty array of strings")
p = check_array(body["params"], "Parameter 'params' should be a not empty array of strings", String, true)
servers = ::Devops::Db.connector.servers_by_names(nodes)
return [404, "No servers found for names '#{nodes.join("', '")}'"] if servers.empty?
user = request.env['REMOTE_USER']
servers.each do |s|
::Devops::Db.connector.check_project_auth s.project, s.deploy_env, user
end
stream() do |out|
begin
status = []
servers.each do |s|
cert = begin
::Devops::Db.connector.key s.key
rescue
out << "No key found for '#{s.chef_node_name}'"
status.push 2
next
end
ssh_cmd = "ssh -i #{cert.path} #{s.remote_user}@#{s.public_ip || s.private_ip} 'bash -s' < %s"
out << "\nRun script on '#{s.chef_node_name}'\n"
unless p.nil?
ssh_cmd += " " + p.join(" ")
end
out << (ssh_cmd % [params[:script_name]])
out << "\n"
begin
IO.popen( (ssh_cmd % [@file]) + " 2>&1") do |so|
while line = so.gets do
out << line
end
so.close
status.push $?.to_i
end
rescue IOError => e
logger.error e.message
out << e.message
status.push 3
end
end
out << create_status(status)
rescue IOError => e
logger.error e.message
end
end
}
end
def self.create_script
lambda {
check_privileges("script", "w")
file_name = params[:script_name]
file = File.join(settings.scripts_dir, check_filename(file_name, "Parameter 'script_name' must be a not empty string"))
halt_response("File '#{file_name}' already exist") if File.exists?(file)
File.open(file, "w") {|f| f.write(request.body.read)}
create_response("File '#{params[:script_name]}' created", nil, 201)
}
end
def self.delete_script
lambda {
check_privileges("script", "w")
file_name = params[:script_name]
file = File.join(settings.scripts_dir, check_filename(file_name, "Parameter 'script_name' must be a not empty string"))
halt_response("File '#{file_name}' does not exist", 404) unless File.exists?(file)
FileUtils.rm(file)
create_response("File '#{params[:script_name]}' deleted")
}
end
end
end
end
end

View File

@ -1,349 +0,0 @@
require 'rufus-scheduler'
require "uri"
require "commands/status"
require "commands/server"
require "commands/bootstrap_templates"
require "commands/knife_commands"
require "providers/provider_factory"
require "db/mongo/models/server"
require "workers/create_server_worker"
require "workers/bootstrap_worker"
module Devops
module Version2_0
module Handler
class Server
extend StatusCommands
extend ServerCommands
extend BootstrapTemplatesCommands
scheduler = Rufus::Scheduler.new
def self.get_servers
lambda {
check_privileges("server", "r")
fields = []
if params.key?("fields") and params["fields"].is_a?(Array)
Devops::Model::Server.fields.each do |k|
fields.push k if params["fields"].include?(k)
end
end
reserved = (params.key?("reserved") ? true : nil)
json settings.mongo.servers(nil, nil, nil, reserved, fields).map {|s| s.to_hash}
}
end
def self.get_chef_servers
lambda {
check_privileges("server", "r")
json KnifeCommands.chef_node_list
}
end
def self.get_provider_servers
lambda {
check_privileges("server", "r")
json ::Provider::ProviderFactory.get(params[:provider]).servers
}
end
def self.get_server
lambda {
check_privileges("server", "r")
json Server.get_server_by_key(params[:name], params[:key]).to_hash
}
end
def self.delete_server
lambda {
check_privileges("server", "w")
body = create_object_from_json_body(Hash, true)
key = (body.nil? ? nil : body["key"])
s = Server.get_server_by_key(params[:id], key)
### Authorization
settings.mongo.check_project_auth s.project, s.deploy_env, request.env['REMOTE_USER']
info, r = delete_server(s, settings.mongo, logger)
create_response(info, r)
}
end
def self.create_server
lambda {
check_privileges("server", "w")
body = create_object_from_json_body
user = request.env['REMOTE_USER']
project_name = check_string(body["project"], "Parameter 'project' must be a not empty string")
env_name = check_string(body["deploy_env"], "Parameter 'deploy_env' must be a not empty string")
server_name = check_string(body["name"], "Parameter 'name' should be null or not empty string", true)
without_bootstrap = body["without_bootstrap"]
halt_response("Parameter 'without_bootstrap' should be a null or true") unless without_bootstrap.nil? or without_bootstrap == true
force = body["force"]
halt_response("Parameter 'force' should be a null or true") unless force.nil? or force == true
groups = check_array(body["groups"], "Parameter 'groups' should be null or not empty array of string", String, true)
key_name = check_string(body["key"], "Parameter 'key' should be null or not empty string", true)
new_key = settings.mongo.key(key_name) unless key_name.nil?
p = settings.mongo.check_project_auth(project_name, env_name, user)
env = p.deploy_env(env_name)
provider = ::Provider::ProviderFactory.get(env.provider)
Server.check_chef_node_name(server_name, provider) unless server_name.nil?
unless groups.nil?
buf = groups - provider.groups.keys
halt_response("Invalid security groups '#{buf.join("', '")}' for provider '#{provider.name}'") if buf.empty?
end
servers = Server.extract_servers(provider, p, env, body, user, settings.mongo)
if body.key?("trace")
stream() do |out|
begin
status = []
servers.each do |s|
res = create_server_proc.call(out, s, provider, settings.mongo)
status.push res
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|
h = s.to_hash
h["options"] = s.options
jid = CreateServerWorker.perform_async(dir, env.provider, h, request.env['REMOTE_USER'], DevopsConfig.config)
Worker.set_status jid, Worker::STATUS::IN_QUEUE
logger.info "Job '#{jid}' has been started"
uri.path = "#{DevopsConfig[:url_prefix]}/v2.0/report/" + jid
files.push uri.to_s
end
sleep 1
json files
end
}
end
def self.pause_server
lambda {
check_privileges("server", "w")
body = create_object_from_json_body(Hash, true)
key = (body.nil? ? nil : body["key"])
s = Server.get_server_by_key(params[:node_name], key)
## Authorization
settings.mongo.check_project_auth s.project, s.deploy_env, request.env['REMOTE_USER']
provider = ::Provider::ProviderFactory.get(s.provider)
r = provider.pause_server s
if r.nil?
create_response("Server with instance ID '#{s.id}' and node name '#{params[:node_name]}' is paused")
else
halt_response("Server with instance ID '#{s.id}' and node name '#{params[:node_name]}' can not be paused, It in state '#{r}'", 409)
end
}
end
def self.unpause_server
lambda {
check_privileges("server", "w")
body = create_object_from_json_body(Hash, true)
key = (body.nil? ? nil : body["key"])
s = Server.get_server_by_key(params[:node_name], key)
## Authorization
settings.mongo.check_project_auth s.project, s.deploy_env, request.env['REMOTE_USER']
provider = ::Provider::ProviderFactory.get(s.provider)
r = provider.unpause_server s
if r.nil?
create_response("Server with instance ID '#{s.id}' and node name '#{params[:node_name]}' is unpaused")
else
halt_response("Server with instance ID '#{s.id}' and node name '#{params[:node_name]}' can not be unpaused, It in state '#{r}'", 409)
end
}
end
def self.reserve_server
lambda {
check_privileges("server", "w")
body = create_object_from_json_body(Hash, true)
key = (body.nil? ? nil : body["key"])
s = Server.get_server_by_key(params[:node_name], key)
user = request.env['REMOTE_USER']
settings.mongo.check_project_auth s.project, s.deploy_env, user
halt_response(400, "Server '#{params[:node_name]}' already reserved") unless s.reserved_by.nil?
s.reserved_by = user
settings.mongo.server_update(s)
create_response("Server '#{params[:node_name]}' has been reserved")
}
end
def self.unreserve_server
lambda {
check_privileges("server", "w")
body = create_object_from_json_body(Hash, true)
key = (body.nil? ? nil : body["key"])
s = Server.get_server_by_key(params[:node_name], key)
settings.mongo.check_project_auth s.project, s.deploy_env, request.env['REMOTE_USER']
halt_response(400, "Server '#{params[:node_name]}' is not reserved") if s.reserved_by.nil?
s.reserved_by = nil
settings.mongo.server_update(s)
create_response("Server '#{params[:node_name]}' has been unreserved")
}
end
# TODO: check bootstrap template name
def self.bootstrap_server
lambda {
check_privileges("server", "w")
body = create_object_from_json_body(Hash, true)
id = check_string(body["instance_id"], "Parameter 'instance_id' must be a not empty string")
name = check_string(body["name"], "Parameter 'name' should be a not empty string", true)
rl = check_array(body["run_list"], "Parameter 'run_list' should be a not empty array of string", String, true)
unless rl.nil?
validator = Validators::Helpers::RunList.new(rl)
halt_response(validator.message) unless validator.valid?
end
t = check_string(body["bootstrap_template"], "Parameter 'bootstrap_template' should be a not empty string", true)
s = settings.mongo.server_by_instance_id(id)
p = settings.mongo.check_project_auth s.project, s.deploy_env, request.env['REMOTE_USER']
d = p.deploy_env s.deploy_env
provider = ::Provider::ProviderFactory.get(s.provider)
Server.check_chef_node_name(name, provider) unless name.nil?
s.options = {
:run_list => rl || d.run_list,
}
unless t.nil?
templates = get_templates
halt_response("Invalid bootstrap template '#{t}', available values: #{templates.join(", ")}", 400) unless templates.include?(t)
s.options[:bootstrap_template] = t
end
s.chef_node_name = name || provider.create_default_chef_node_name(s)
logger.debug "Chef node name: '#{s.chef_node_name}'"
status = []
if body.key?("trace")
stream() do |out|
begin
cert = settings.mongo.key s.key
logger.debug "Bootstrap certificate path: #{cert.path}"
bootstrap s, out, cert.path, logger
str = nil
r = if check_server(s)
settings.mongo.server_set_chef_node_name s
str = "Server with id '#{s.id}' is bootstraped"
logger.info str
0
else
str = "Server with id '#{s.id}' is not bootstraped"
logger.warn str
1
end
status.push r
out << str
out << "\n"
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)
h = s.to_hash
h["options"] = s.options
h["_id"] = s.id
jid = BootstrapWorker.perform_async(dir, d.provider, h, request.env['REMOTE_USER'], DevopsConfig.config)
Worker.set_status jid, Worker::STATUS::IN_QUEUE
logger.info "Job '#{jid}' has been started"
uri.path = "#{DevopsConfig[:url_prefix]}/v2.0/report/" + jid
uri.query = nil
uri.fragment = nil
files.push uri.to_s
sleep 1
json files
end
}
end
def self.add_server
lambda {
check_privileges("server", "w")
body = create_object_from_json_body
project = check_string(body["project"], "Parameter 'project' must be a not empty string")
deploy_env = check_string(body["deploy_env"], "Parameter 'deploy_env' must be a not empty string")
key = check_string(body["key"], "Parameter 'key' must be a not empty string")
remote_user = check_string(body["remote_user"], "Parameter 'remote_user' must be a not empty string")
private_ip = check_string(body["private_ip"], "Parameter 'private_ip' must be a not empty string")
public_ip = check_string(body["public_ip"], "Parameter 'public_ip' should be a not empty string", true)
p = settings.mongo.check_project_auth project, deploy_env, request.env['REMOTE_USER']
d = p.deploy_env(deploy_env)
cert = settings.mongo.key(key)
provider = ::Provider::ProviderFactory.get("static")
s = Devops::Model::Server.new
s.provider = provider.name
s.project = project
s.deploy_env = deploy_env
s.remote_user = remote_user
s.private_ip = private_ip
s.public_ip = public_ip
s.static = true
s.id = "static_#{cert.id}-#{Time.now.to_i}"
s.key = cert.id
settings.mongo.server_insert s
create_response("Server '#{s.id}' has been added")
}
end
def self.get_server_by_key id, key
mongo = Devops::Db.connector
key == "instance" ? mongo.server_by_instance_id(id) : mongo.server_by_chef_node_name(id)
end
def self.check_chef_node_name name, provider
mongo = Devops::Db.connector
mongo.server_by_chef_node_name name
halt(400, "Server with name '#{name}' already exist")
rescue RecordNotFound => e
# server not found - OK
s = provider.servers.detect {|s| s["name"] == name}
halt(400, "#{provider.name} node with name '#{name}' already exist") unless s.nil?
s = KnifeCommands.chef_node_list.detect {|n| n == name}
halt(400, "Chef node with name '#{name}' already exist") unless s.nil?
s = KnifeCommands.chef_client_list.detect {|c| c == name}
halt(400, "Chef client with name '#{name}' already exist") unless s.nil?
end
end
class ExpireHandler
include ServerCommands
def initialize server, logger
@server = server
@logger = logger
end
def call(job)
@logger.info("Removing node '#{@server.chef_node_name}' form project '#{@server.project}' and env '#{@server.deploy_env}'")
begin
delete_server(@server, Devops::Db.connector, @logger)
rescue => e
logger.error "ExpiredHandler error: " + e.message
end
end
end
end
end
end

View File

@ -1,88 +0,0 @@
require 'db/mongo/models/stack/stack_factory'
module Devops
module Version2_0
module Handler
class Stack
def self.get_stacks
lambda {
check_privileges("stack", "r")
stacks = settings.mongo.stacks
json stacks.map(&:to_hash)
}
end
def self.get_stacks_for_provider
lambda {
check_privileges("stack", "r")
check_provider(params[:provider])
stacks = settings.mongo.stacks(provider: params[:provider])
json stacks.map(&:to_hash)
}
end
def self.create_stack
lambda {
check_privileges("stack", "w")
object = create_object_from_json_body
stack_model = Model::StackFactory.create(object['provider'], object)
settings.mongo.stack_insert(stack_model)
create_response "Created", stack_model.to_hash, 201
}
end
def self.get_stack
lambda {
check_privileges("stack", "r")
stack = settings.mongo.stack(params[:stack_id])
json stack.to_hash
}
end
def self.delete_stack
lambda {
check_privileges("stack", "w")
stack = settings.mongo.stack(params[:stack_id])
stack.delete_stack_in_cloud!
settings.mongo.stack_delete(params[:stack_id])
create_response("Stack '#{params[:stack_id]}' has been removed")
}
end
def self.sync_details
lambda {
check_privileges("stack", "w")
stack = settings.mongo.stack(params[:stack_id])
stack.sync_details!
settings.mongo.stack_update(stack)
json stack.to_hash
}
end
def self.resources
lambda {
check_privileges("stack", "r")
stack = settings.mongo.stack(params[:stack_id])
json stack.resources
}
end
def self.resource
lambda {
check_privileges("stack", "r")
stack = settings.mongo.stack(params[:stack_id])
json stack.resource(params[:resource_id])
}
end
end
end
end
end

View File

@ -1,51 +0,0 @@
require 'json'
require 'lib/stack_presets/factory'
require 'workers/stack_sync_worker'
require 'workers/job_starter'
module Devops
module Version2_0
module Handler
class StackPreset
def self.get_presets
lambda {
# check_privileges("stack_presets", "r")
json Devops::StackPresetsFactory.list.map(&:to_hash)
}
end
def self.get_preset
lambda {
# check_privileges("stack_presets", "r")
json Devops::StackPresetsFactory.get(params['id']).to_hash
}
end
def self.apply
lambda {
# check_privileges("stack_presets", "r")
check_privileges('stack_template', 'w')
attrs = create_object_from_json_body
preset = Devops::StackPresetsFactory.get(attrs.fetch('id'))
stack = preset.create_stack_from_preset(attrs)
settings.mongo.stack_insert(stack)
file = JobStarter.start_job(:worker, :sync_stack_till_not_in_progress,
provider: stack.provider,
stack_id: stack.id,
request: request
)
puts "Syncing report is located here: #{file}"
create_response 'Created', stack.to_hash, 201
}
end
end
end
end
end

View File

@ -1,57 +0,0 @@
require 'db/mongo/models/stack_template/stack_template_factory'
module Devops
module Version2_0
module Handler
class StackTemplate
def self.get_stack_templates
lambda {
check_privileges('stack_template', 'r')
stack_templates = settings.mongo.stack_templates
json stack_templates.map(&:to_hash)
}
end
def self.get_stack_templates_for_provider
lambda {
check_privileges('stack_template', 'r')
check_provider(params[:provider])
stack_templates = settings.mongo.stack_templates(params[:provider])
json stack_templates.map(&:to_hash)
}
end
def self.create_stack_template
lambda {
check_privileges('stack_template', 'w')
attrs = create_object_from_json_body
template_model = Model::StackTemplateFactory.create(attrs['provider'], attrs)
settings.mongo.stack_template_insert(template_model)
create_response 'Created', template_model.to_hash, 201
}
end
def self.get_stack_template
lambda {
check_privileges('stack_template', 'r')
stack_template = settings.mongo.stack_template(params[:stack_template_id])
json stack_template.to_hash
}
end
def self.delete_stack_template
lambda {
check_privileges('stack_template', 'w')
settings.mongo.stack_template_delete params[:stack_template_id]
create_response("Template '#{params[:stack_template_id]}' has been removed")
}
end
end
end
end
end

Some files were not shown because too many files have changed in this diff Show More