routes handlers
This commit is contained in:
parent
79e2811e0c
commit
de2842f2a4
1
.gitignore
vendored
1
.gitignore
vendored
@ -1,2 +1,3 @@
|
||||
devops-service/tests/features/support/config.yml
|
||||
.devops_files/
|
||||
devops-service/plugins
|
||||
|
||||
@ -15,7 +15,9 @@ gem "bson_ext"
|
||||
gem "multi_json", "1.7.8"
|
||||
gem "rufus-scheduler", "2.0.24"
|
||||
gem "sidekiq", "3.2.6"
|
||||
gem 'wisper'
|
||||
|
||||
gem "devops-nibr", :path => "/home/amartynov/workspace/github/devops-service/devops-service/plugins/devops-nibr"
|
||||
|
||||
group :test do
|
||||
gem 'cucumber'
|
||||
|
||||
@ -1,40 +1,42 @@
|
||||
PATH
|
||||
remote: plugins/devops-nibr
|
||||
specs:
|
||||
devops-nibr (0.0.1)
|
||||
|
||||
GEM
|
||||
remote: https://rubygems.org/
|
||||
specs:
|
||||
addressable (2.3.5)
|
||||
atomic (1.1.14)
|
||||
CFPropertyList (2.2.8)
|
||||
addressable (2.3.6)
|
||||
backports (3.6.4)
|
||||
bson (1.9.2)
|
||||
bson_ext (1.9.2)
|
||||
bson (~> 1.9.2)
|
||||
bson (1.11.1)
|
||||
bson_ext (1.11.1)
|
||||
bson (~> 1.11.1)
|
||||
builder (3.2.2)
|
||||
celluloid (0.15.2)
|
||||
timers (~> 1.1.0)
|
||||
chef (11.10.4)
|
||||
chef-zero (~> 1.7, >= 1.7.2)
|
||||
chef (12.0.3)
|
||||
chef-zero (~> 3.2)
|
||||
diff-lcs (~> 1.2, >= 1.2.4)
|
||||
erubis (~> 2.7)
|
||||
ffi-yajl (~> 1.2)
|
||||
highline (~> 1.6, >= 1.6.9)
|
||||
json (>= 1.4.4, <= 1.8.1)
|
||||
mime-types (~> 1.16)
|
||||
mixlib-authentication (~> 1.3)
|
||||
mixlib-cli (~> 1.4)
|
||||
mixlib-config (~> 2.0)
|
||||
mixlib-log (~> 1.3)
|
||||
mixlib-shellout (~> 1.3)
|
||||
mixlib-shellout (>= 2.0.0.rc.0, < 3.0)
|
||||
net-ssh (~> 2.6)
|
||||
net-ssh-multi (~> 1.1)
|
||||
ohai (~> 6.0)
|
||||
ohai (~> 8.0)
|
||||
plist (~> 3.1.0)
|
||||
pry (~> 0.9)
|
||||
puma (~> 1.6)
|
||||
rest-client (>= 1.0.4, < 1.7.0)
|
||||
yajl-ruby (~> 1.1)
|
||||
chef-zero (1.7.3)
|
||||
chef-zero (3.2.1)
|
||||
ffi-yajl (~> 1.1)
|
||||
hashie (~> 2.0)
|
||||
json
|
||||
mixlib-log (~> 1.3)
|
||||
moneta (< 0.7.0)
|
||||
rack
|
||||
uuidtools (~> 2.1)
|
||||
coderay (1.1.0)
|
||||
connection_pool (2.1.0)
|
||||
cucumber (1.3.17)
|
||||
@ -50,73 +52,140 @@ GEM
|
||||
eventmachine (>= 0.12.9)
|
||||
erubis (2.7.0)
|
||||
eventmachine (1.0.3)
|
||||
excon (0.31.0)
|
||||
fog (1.20.0)
|
||||
excon (0.42.1)
|
||||
ffi (1.9.6)
|
||||
ffi-yajl (1.3.1)
|
||||
ffi (~> 1.5)
|
||||
libyajl2 (~> 1.2)
|
||||
fission (0.5.0)
|
||||
CFPropertyList (~> 2.2)
|
||||
fog (1.26.0)
|
||||
fog-atmos
|
||||
fog-brightbox (~> 0.4)
|
||||
fog-core (~> 1.27, >= 1.27.1)
|
||||
fog-ecloud
|
||||
fog-json
|
||||
fog-profitbricks
|
||||
fog-radosgw (>= 0.0.2)
|
||||
fog-sakuracloud (>= 0.0.4)
|
||||
fog-softlayer
|
||||
fog-storm_on_demand
|
||||
fog-terremark
|
||||
fog-vmfusion
|
||||
fog-voxel
|
||||
fog-xml (~> 0.1.1)
|
||||
ipaddress (~> 0.5)
|
||||
nokogiri (~> 1.5, >= 1.5.11)
|
||||
fog-atmos (0.1.0)
|
||||
fog-core
|
||||
fog-xml
|
||||
fog-brightbox (0.7.1)
|
||||
fog-core (~> 1.22)
|
||||
fog-json
|
||||
inflecto (~> 0.0.2)
|
||||
fog-core (1.27.2)
|
||||
builder
|
||||
excon (~> 0.31.0)
|
||||
formatador (~> 0.2.0)
|
||||
excon (~> 0.38)
|
||||
formatador (~> 0.2)
|
||||
mime-types
|
||||
multi_json (~> 1.0)
|
||||
net-scp (~> 1.1)
|
||||
net-ssh (>= 2.1.3)
|
||||
nokogiri (>= 1.5.11)
|
||||
formatador (0.2.4)
|
||||
fog-ecloud (0.0.2)
|
||||
fog-core
|
||||
fog-xml
|
||||
fog-json (1.0.0)
|
||||
multi_json (~> 1.0)
|
||||
fog-profitbricks (0.0.1)
|
||||
fog-core
|
||||
fog-xml
|
||||
nokogiri
|
||||
fog-radosgw (0.0.3)
|
||||
fog-core (>= 1.21.0)
|
||||
fog-json
|
||||
fog-xml (>= 0.0.1)
|
||||
fog-sakuracloud (0.1.1)
|
||||
fog-core
|
||||
fog-json
|
||||
fog-softlayer (0.3.25)
|
||||
fog-core
|
||||
fog-json
|
||||
fog-storm_on_demand (0.1.0)
|
||||
fog-core
|
||||
fog-json
|
||||
fog-terremark (0.0.3)
|
||||
fog-core
|
||||
fog-xml
|
||||
fog-vmfusion (0.0.1)
|
||||
fission
|
||||
fog-core
|
||||
fog-voxel (0.0.2)
|
||||
fog-core
|
||||
fog-xml
|
||||
fog-xml (0.1.1)
|
||||
fog-core
|
||||
nokogiri (~> 1.5, >= 1.5.11)
|
||||
formatador (0.2.5)
|
||||
gherkin (2.12.2)
|
||||
multi_json (~> 1.3)
|
||||
hashie (2.0.5)
|
||||
highline (1.6.20)
|
||||
httpclient (2.4.0)
|
||||
hashie (2.1.2)
|
||||
highline (1.6.21)
|
||||
httpclient (2.5.3.3)
|
||||
inflecto (0.0.2)
|
||||
ipaddress (0.8.0)
|
||||
json (1.8.1)
|
||||
libyajl2 (1.2.0)
|
||||
method_source (0.8.2)
|
||||
mime-types (1.25.1)
|
||||
mini_portile (0.5.2)
|
||||
mini_portile (0.6.1)
|
||||
mixlib-authentication (1.3.0)
|
||||
mixlib-log
|
||||
mixlib-cli (1.4.0)
|
||||
mixlib-cli (1.5.0)
|
||||
mixlib-config (2.1.0)
|
||||
mixlib-log (1.6.0)
|
||||
mixlib-shellout (1.3.0)
|
||||
moneta (0.6.0)
|
||||
mongo (1.9.2)
|
||||
bson (~> 1.9.2)
|
||||
mixlib-shellout (2.0.0)
|
||||
mongo (1.11.1)
|
||||
bson (= 1.11.1)
|
||||
multi_json (1.7.8)
|
||||
multi_test (0.1.1)
|
||||
net-scp (1.1.2)
|
||||
net-dhcp (1.3.2)
|
||||
net-scp (1.2.1)
|
||||
net-ssh (>= 2.6.5)
|
||||
net-ssh (2.8.0)
|
||||
net-ssh (2.9.1)
|
||||
net-ssh-gateway (1.2.0)
|
||||
net-ssh (>= 2.6.5)
|
||||
net-ssh-multi (1.2.0)
|
||||
net-ssh (>= 2.6.5)
|
||||
net-ssh-gateway (>= 1.2.0)
|
||||
nokogiri (1.6.1)
|
||||
mini_portile (~> 0.5.0)
|
||||
ohai (6.20.0)
|
||||
nokogiri (1.6.5)
|
||||
mini_portile (~> 0.6.0)
|
||||
ohai (8.0.1)
|
||||
ffi (~> 1.9)
|
||||
ffi-yajl (~> 1.1)
|
||||
ipaddress
|
||||
mime-types (~> 1.16)
|
||||
mixlib-cli
|
||||
mixlib-config
|
||||
mixlib-config (~> 2.0)
|
||||
mixlib-log
|
||||
mixlib-shellout
|
||||
systemu (~> 2.5.2)
|
||||
yajl-ruby
|
||||
power_assert (0.2.1)
|
||||
pry (0.9.12.6)
|
||||
coderay (~> 1.0)
|
||||
method_source (~> 0.8)
|
||||
mixlib-shellout (~> 2.0)
|
||||
net-dhcp
|
||||
rake (~> 10.1)
|
||||
systemu (~> 2.6.4)
|
||||
wmi-lite (~> 1.0)
|
||||
plist (3.1.0)
|
||||
power_assert (0.2.2)
|
||||
pry (0.10.1)
|
||||
coderay (~> 1.1.0)
|
||||
method_source (~> 0.8.1)
|
||||
slop (~> 3.4)
|
||||
puma (1.6.3)
|
||||
rack (~> 1.2)
|
||||
rack (1.5.2)
|
||||
rack-protection (1.5.2)
|
||||
rack (1.6.0)
|
||||
rack-protection (1.5.3)
|
||||
rack
|
||||
rack-test (0.6.2)
|
||||
rack (>= 1.0)
|
||||
redis (3.1.0)
|
||||
rake (10.4.2)
|
||||
redis (3.2.0)
|
||||
redis-namespace (1.5.1)
|
||||
redis (~> 3.0, >= 3.0.4)
|
||||
rest-client (1.6.7)
|
||||
mime-types (>= 1.16)
|
||||
rufus-scheduler (2.0.24)
|
||||
tzinfo (>= 0.3.22)
|
||||
sidekiq (3.2.6)
|
||||
@ -136,25 +205,26 @@ GEM
|
||||
rack-test
|
||||
sinatra (~> 1.4.0)
|
||||
tilt (~> 1.3)
|
||||
sinatra-websocket (0.3.0)
|
||||
sinatra-websocket (0.3.1)
|
||||
em-websocket (~> 0.3.6)
|
||||
eventmachine
|
||||
thin (>= 1.3.1)
|
||||
slop (3.4.7)
|
||||
systemu (2.5.2)
|
||||
test-unit (3.0.7)
|
||||
thin (>= 1.3.1, < 2.0.0)
|
||||
slop (3.6.0)
|
||||
systemu (2.6.4)
|
||||
test-unit (3.0.8)
|
||||
power_assert
|
||||
thin (1.5.1)
|
||||
daemons (>= 1.0.9)
|
||||
eventmachine (>= 0.12.6)
|
||||
rack (>= 1.0.0)
|
||||
thread_safe (0.1.3)
|
||||
atomic
|
||||
thread_safe (0.3.4)
|
||||
tilt (1.4.1)
|
||||
timers (1.1.0)
|
||||
tzinfo (1.1.0)
|
||||
tzinfo (1.2.2)
|
||||
thread_safe (~> 0.1)
|
||||
yajl-ruby (1.2.0)
|
||||
uuidtools (2.1.5)
|
||||
wisper (1.6.0)
|
||||
wmi-lite (1.0.0)
|
||||
|
||||
PLATFORMS
|
||||
ruby
|
||||
@ -163,6 +233,7 @@ DEPENDENCIES
|
||||
bson_ext
|
||||
chef (>= 11)
|
||||
cucumber
|
||||
devops-nibr!
|
||||
fog (~> 1.20)
|
||||
httpclient
|
||||
mime-types (~> 1.25.1)
|
||||
@ -176,3 +247,4 @@ DEPENDENCIES
|
||||
sinatra-websocket (~> 0.3.0)
|
||||
test-unit
|
||||
thin (~> 1.5.1)
|
||||
wisper
|
||||
|
||||
@ -4,39 +4,33 @@ require "rubygems"
|
||||
require "sinatra/base"
|
||||
require "sinatra/streaming"
|
||||
require "fileutils"
|
||||
require "wisper"
|
||||
|
||||
$:.push File.dirname(__FILE__)
|
||||
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 "loader"
|
||||
|
||||
require "routes/v2.0"
|
||||
require "helpers/version_2"
|
||||
|
||||
require "routes/v2.0/provider"
|
||||
require "routes/v2.0/user"
|
||||
require "test_subscriber"
|
||||
require "test_subscriber_2"
|
||||
|
||||
class DevopsService < Sinatra::Base
|
||||
|
||||
helpers Sinatra::Streaming
|
||||
helpers Devops::Version2_0::Helpers
|
||||
|
||||
register Devops::Version2_0::Core::ProviderRoutes
|
||||
register Devops::Version2_0::Core::BootstrapTemplatesRoutes
|
||||
register Devops::Version2_0::Core::UserRoutes
|
||||
register Devops::Version2_0::Core::FilterRoutes
|
||||
register Devops::Version2_0::Core::FlavorRoutes
|
||||
register Devops::Version2_0::Core::GroupRoutes
|
||||
register Devops::Version2_0::Core::ImageRoutes
|
||||
register Devops::Version2_0::Core::KeyRoutes
|
||||
register Devops::Version2_0::Core::NetworkRoutes
|
||||
register Devops::Version2_0::Core::ProjectRoutes
|
||||
register Devops::Version2_0::Core::ScriptRoutes
|
||||
register Devops::Version2_0::Core::ServerRoutes
|
||||
register Devops::Version2_0::Core::StatusRoutes
|
||||
register Devops::Version2_0::Core::TagRoutes
|
||||
include Wisper::Publisher
|
||||
|
||||
helpers Devops::Version2_0::Helpers
|
||||
include Devops::Loader
|
||||
register Devops::Version2_0::Routes
|
||||
|
||||
def initialize config
|
||||
super()
|
||||
@ -61,6 +55,8 @@ class DevopsService < Sinatra::Base
|
||||
mongo.create_root_user
|
||||
::Provider::ProviderFactory.init(config)
|
||||
#set_up_providers_keys!(::Provider::ProviderFactory.all, mongo)
|
||||
Wisper::GlobalListeners.subscribe(TestSubscriber2.new)
|
||||
Wisper.subscribe(TestSubscriber.new)
|
||||
end
|
||||
|
||||
@@mongo
|
||||
@ -83,6 +79,10 @@ class DevopsService < Sinatra::Base
|
||||
end
|
||||
end
|
||||
|
||||
def self.create_method name, &block
|
||||
send(:generate_method, name, &block)
|
||||
end
|
||||
|
||||
include Sinatra::JSON
|
||||
|
||||
configure :production do
|
||||
@ -187,3 +187,5 @@ class DevopsService < Sinatra::Base
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
require "wisper_fix"
|
||||
|
||||
50
devops-service/loader.rb
Normal file
50
devops-service/loader.rb
Normal file
@ -0,0 +1,50 @@
|
||||
require "json"
|
||||
|
||||
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/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"
|
||||
|
||||
module Devops
|
||||
module Loader
|
||||
def Loader.included(mod)
|
||||
puts "#{self} included in #{mod}"
|
||||
|
||||
if defined?(Devops::Plugin)
|
||||
plugins = Devops::Plugin.constants.collect{|s| Devops::Plugin.const_get(s)}.select {|const| const.class == Module}
|
||||
puts plugins.inspect
|
||||
plugins.each do |p|
|
||||
p.init(mod)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
@ -1,35 +1,25 @@
|
||||
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"
|
||||
module Devops
|
||||
module Version2_0
|
||||
module Routes
|
||||
|
||||
module Version2_0
|
||||
class V2_0
|
||||
|
||||
# Initialize modules of devops API v2.0
|
||||
def initialize app
|
||||
stack = Rack::Builder.new
|
||||
[FlavorRoutes, ImageRoutes, FilterRoutes, NetworkRoutes, GroupRoutes, DeployRoutes,
|
||||
ProjectRoutes, KeyRoutes, UserRoutes, ProviderRoutes, TagRoutes, ServerRoutes, ScriptRoutes, BootstrapTemplatesRoutes, StatusRoutes].each do |m|
|
||||
stack.use m
|
||||
end
|
||||
stack.run app
|
||||
@app = stack.to_app
|
||||
def self.registered(app)
|
||||
app.register Devops::Version2_0::Routes::ProviderRoutes
|
||||
app.register Devops::Version2_0::Routes::BootstrapTemplatesRoutes
|
||||
app.register Devops::Version2_0::Routes::UserRoutes
|
||||
app.register Devops::Version2_0::Routes::FilterRoutes
|
||||
app.register Devops::Version2_0::Routes::FlavorRoutes
|
||||
app.register Devops::Version2_0::Routes::GroupRoutes
|
||||
app.register Devops::Version2_0::Routes::ImageRoutes
|
||||
app.register Devops::Version2_0::Routes::KeyRoutes
|
||||
app.register Devops::Version2_0::Routes::NetworkRoutes
|
||||
app.register Devops::Version2_0::Routes::ProjectRoutes
|
||||
app.register Devops::Version2_0::Routes::ScriptRoutes
|
||||
app.register Devops::Version2_0::Routes::ServerRoutes
|
||||
app.register Devops::Version2_0::Routes::StatusRoutes
|
||||
app.register Devops::Version2_0::Routes::TagRoutes
|
||||
app.register Devops::Version2_0::Routes::DeployRoutes
|
||||
end
|
||||
|
||||
def call(env)
|
||||
@app.call env
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@ -1,16 +1,18 @@
|
||||
require "json"
|
||||
require "providers/provider_factory"
|
||||
require "commands/bootstrap_templates"
|
||||
|
||||
module Devops
|
||||
module Version2_0
|
||||
module Core
|
||||
module Routes
|
||||
module BootstrapTemplatesRoutes
|
||||
|
||||
extend BootstrapTemplatesCommands
|
||||
|
||||
def self.registered(app)
|
||||
|
||||
app.before "/templates" do
|
||||
check_headers :accept
|
||||
check_privileges("templates", "r")
|
||||
broadcast(:cancel_order_failed, "hello")
|
||||
end
|
||||
|
||||
# Get list of available bootstrap templates
|
||||
#
|
||||
# * *Request*
|
||||
@ -22,11 +24,7 @@ module Devops
|
||||
# [
|
||||
# "omnibus"
|
||||
# ]
|
||||
app.get "/templates" do
|
||||
check_headers :accept
|
||||
check_privileges("templates", "r")
|
||||
json BootstrapTemplatesRoutes.get_templates
|
||||
end
|
||||
app.get "/templates", &Devops::Version2_0::Handler::BootstrapTemplates.get_bootstrap_templates
|
||||
|
||||
puts "Bootstrap templates routes initialized"
|
||||
end
|
||||
|
||||
@ -1,23 +1,18 @@
|
||||
require "commands/knife_commands"
|
||||
require "routes/v2.0/base_routes"
|
||||
require "providers/provider_factory"
|
||||
require "commands/deploy"
|
||||
require "commands/status"
|
||||
require "workers/deploy_worker"
|
||||
|
||||
module Version2_0
|
||||
class DeployRoutes < BaseRoutes
|
||||
module Devops
|
||||
module Version2_0
|
||||
module Routes
|
||||
module DeployRoutes
|
||||
|
||||
include DeployCommands
|
||||
include StatusCommands
|
||||
|
||||
def initialize wrapper
|
||||
super wrapper
|
||||
puts "Deploy routes initialized"
|
||||
def self.registered(app)
|
||||
app.after "/deploy" do
|
||||
statistic
|
||||
end
|
||||
|
||||
after "/deploy" do
|
||||
statistic
|
||||
app.before "/deploy" do
|
||||
check_headers :content_type
|
||||
check_privileges("server", "x")
|
||||
broadcast(:devops_deploy, "deploy")
|
||||
end
|
||||
|
||||
# Run chef-client on reserved server
|
||||
@ -34,57 +29,12 @@ module Version2_0
|
||||
# }
|
||||
#
|
||||
# * *Returns* : text stream
|
||||
post "/deploy" do
|
||||
check_headers :content_type
|
||||
check_privileges("server", "x")
|
||||
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) || []
|
||||
app.post "/deploy", &Devops::Version2_0::Handler::Deploy.deploy
|
||||
|
||||
servers = BaseRoutes.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
|
||||
BaseRoutes.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, BaseRoutes.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
|
||||
BaseRoutes.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
|
||||
puts "Deploy routes initialized"
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
|
||||
module Devops
|
||||
module Version2_0
|
||||
module Core
|
||||
module Routes
|
||||
module FilterRoutes
|
||||
|
||||
def self.registered(app)
|
||||
@ -19,6 +18,11 @@ module Devops
|
||||
statistic
|
||||
end
|
||||
|
||||
app.before "/filter/:provider/images" do
|
||||
check_headers :accept
|
||||
check_privileges("filter", "r")
|
||||
check_provider(params[:provider])
|
||||
end
|
||||
# Get list of images filters for :provider
|
||||
#
|
||||
# Devops can works with images from filters list only
|
||||
@ -37,12 +41,7 @@ module Devops
|
||||
# [
|
||||
# "36dc7618-4178-4e29-be43-286fbfe90f50"
|
||||
# ]
|
||||
app.get "/filter/:provider/images" do
|
||||
check_headers :accept
|
||||
check_privileges("filter", "r")
|
||||
check_provider(params[:provider])
|
||||
json settings.mongo.available_images(params[:provider])
|
||||
end
|
||||
app.get "/filter/:provider/images", &Devops::Version2_0::Handler::Filter.get_filters
|
||||
|
||||
# Add image ids to filter for :provider
|
||||
#
|
||||
@ -57,9 +56,7 @@ module Devops
|
||||
# ] -> array of image ids to add to filter
|
||||
#
|
||||
# * *Returns* : list of images filters for :provider
|
||||
app.put "/filter/:provider/image" do
|
||||
create_response("Updated", {:images => settings.mongo.add_available_images(@images, params[:provider])})
|
||||
end
|
||||
app.put "/filter/:provider/image", &Devops::Version2_0::Handler::Filter.add_filter
|
||||
|
||||
# Delete image ids from filter for :provider
|
||||
#
|
||||
@ -74,9 +71,7 @@ module Devops
|
||||
# ] -> array of image ids to delete from filter
|
||||
#
|
||||
# * *Returns* : list of images filters for :provider
|
||||
app.delete "/filter/:provider/image" do
|
||||
create_response("Deleted", {:images => settings.mongo.delete_available_images(@images, params[:provider])})
|
||||
end
|
||||
app.delete "/filter/:provider/image", &Devops::Version2_0::Handler::Filter.delete_filter
|
||||
|
||||
puts "Filter routes initialized"
|
||||
end
|
||||
|
||||
@ -1,13 +1,15 @@
|
||||
require "json"
|
||||
require "providers/provider_factory"
|
||||
|
||||
module Devops
|
||||
module Version2_0
|
||||
module Core
|
||||
module Routes
|
||||
module FlavorRoutes
|
||||
|
||||
def self.registered(app)
|
||||
|
||||
app.before "/flavors/:provider" do
|
||||
check_headers :accept
|
||||
check_privileges("flavor", "r")
|
||||
check_provider(params[:provider])
|
||||
end
|
||||
# Get list of flavors for :provider
|
||||
#
|
||||
# * *Request*
|
||||
@ -35,13 +37,7 @@ module Devops
|
||||
# "disk": 20
|
||||
# }
|
||||
# ]
|
||||
app.get "/flavors/:provider" do
|
||||
check_headers :accept
|
||||
check_privileges("flavor", "r")
|
||||
check_provider(params[:provider])
|
||||
p = ::Provider::ProviderFactory.get params[:provider]
|
||||
json p.flavors
|
||||
end
|
||||
app.get "/flavors/:provider", &Devops::Version2_0::Handler::Flavor.get_flavors
|
||||
|
||||
puts "Flavor routes initialized"
|
||||
end
|
||||
|
||||
@ -1,13 +1,16 @@
|
||||
# encoding: UTF-8
|
||||
require "json"
|
||||
require "providers/provider_factory"
|
||||
|
||||
module Devops
|
||||
module Version2_0
|
||||
module Core
|
||||
module Routes
|
||||
module GroupRoutes
|
||||
|
||||
def self.registered(app)
|
||||
|
||||
app.before "/groups/:provider" do
|
||||
check_headers :accept
|
||||
check_privileges("group", "r")
|
||||
check_provider(params[:provider])
|
||||
end
|
||||
# Get security groups for :provider
|
||||
#
|
||||
# * *Request*
|
||||
@ -46,13 +49,7 @@ module Devops
|
||||
# }
|
||||
# }
|
||||
# TODO: vpc support for ec2
|
||||
app.get "/groups/:provider" do
|
||||
check_headers :accept
|
||||
check_privileges("group", "r")
|
||||
check_provider(params[:provider])
|
||||
p = ::Provider::ProviderFactory.get params[:provider]
|
||||
json p.groups(params)
|
||||
end
|
||||
app.get "/groups/:provider", &Devops::Version2_0::Handler::Group.get_groups
|
||||
|
||||
puts "Group routes initialized"
|
||||
end
|
||||
|
||||
18
devops-service/routes/v2.0/handlers/bootstrap_templates.rb
Normal file
18
devops-service/routes/v2.0/handlers/bootstrap_templates.rb
Normal file
@ -0,0 +1,18 @@
|
||||
require "commands/bootstrap_templates"
|
||||
|
||||
module Devops
|
||||
module Version2_0
|
||||
module Handler
|
||||
class BootstrapTemplates
|
||||
extend BootstrapTemplatesCommands
|
||||
|
||||
def self.get_bootstrap_templates
|
||||
lambda {
|
||||
json BootstrapTemplates.get_templates
|
||||
}
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
67
devops-service/routes/v2.0/handlers/deploy.rb
Normal file
67
devops-service/routes/v2.0/handlers/deploy.rb
Normal file
@ -0,0 +1,67 @@
|
||||
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 {
|
||||
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
|
||||
|
||||
28
devops-service/routes/v2.0/handlers/filter.rb
Normal file
28
devops-service/routes/v2.0/handlers/filter.rb
Normal file
@ -0,0 +1,28 @@
|
||||
module Devops
|
||||
module Version2_0
|
||||
module Handler
|
||||
class Filter
|
||||
|
||||
def self.get_filters
|
||||
lambda {
|
||||
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
|
||||
|
||||
17
devops-service/routes/v2.0/handlers/flavor.rb
Normal file
17
devops-service/routes/v2.0/handlers/flavor.rb
Normal file
@ -0,0 +1,17 @@
|
||||
require "providers/provider_factory"
|
||||
|
||||
module Devops
|
||||
module Version2_0
|
||||
module Handler
|
||||
class Flavor
|
||||
def self.get_flavors
|
||||
lambda {
|
||||
p = ::Provider::ProviderFactory.get params[:provider]
|
||||
json p.flavors
|
||||
}
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
17
devops-service/routes/v2.0/handlers/group.rb
Normal file
17
devops-service/routes/v2.0/handlers/group.rb
Normal file
@ -0,0 +1,17 @@
|
||||
require "providers/provider_factory"
|
||||
|
||||
module Devops
|
||||
module Version2_0
|
||||
module Handler
|
||||
class Group
|
||||
def self.get_groups
|
||||
lambda {
|
||||
p = ::Provider::ProviderFactory.get params[:provider]
|
||||
json p.groups(params)
|
||||
}
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
67
devops-service/routes/v2.0/handlers/image.rb
Normal file
67
devops-service/routes/v2.0/handlers/image.rb
Normal file
@ -0,0 +1,67 @@
|
||||
require "providers/provider_factory"
|
||||
require "commands/image"
|
||||
|
||||
module Devops
|
||||
module Version2_0
|
||||
module Handler
|
||||
class Image
|
||||
|
||||
extend ImageCommands
|
||||
|
||||
def self.get_images
|
||||
lambda {
|
||||
images = settings.mongo.images(params[:provider])
|
||||
json(images.map {|i| i.to_hash})
|
||||
}
|
||||
end
|
||||
|
||||
def self.get_provider_images
|
||||
lambda {
|
||||
json get_images(settings.mongo, params[:provider])
|
||||
}
|
||||
end
|
||||
|
||||
def self.get_image
|
||||
lambda {
|
||||
json settings.mongo.image(params[:image_id])
|
||||
}
|
||||
end
|
||||
|
||||
def self.create_image
|
||||
lambda {
|
||||
image = create_object_from_json_body
|
||||
settings.mongo.image_insert Image.new(image)
|
||||
create_response "Created", nil, 201
|
||||
}
|
||||
end
|
||||
|
||||
def self.update_image
|
||||
lambda {
|
||||
settings.mongo.image params[:image_id]
|
||||
image = 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 {
|
||||
projects = settings.mongo.projects_by_image params[:image_id]
|
||||
unless projects.empty?
|
||||
ar = []
|
||||
projects.each do |p|
|
||||
ar += p.deploy_envs.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
|
||||
|
||||
57
devops-service/routes/v2.0/handlers/key.rb
Normal file
57
devops-service/routes/v2.0/handlers/key.rb
Normal file
@ -0,0 +1,57 @@
|
||||
module Devops
|
||||
module Version2_0
|
||||
module Handler
|
||||
class Key
|
||||
|
||||
def self.get_keys
|
||||
lambda {
|
||||
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 {
|
||||
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(DevopsService.config[: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 = Key.new({"path" => file_name, "id" => kname})
|
||||
settings.mongo.key_insert key
|
||||
create_response("Created", nil, 201)
|
||||
}
|
||||
end
|
||||
|
||||
def self.delete_key
|
||||
lambda {
|
||||
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
|
||||
|
||||
18
devops-service/routes/v2.0/handlers/network.rb
Normal file
18
devops-service/routes/v2.0/handlers/network.rb
Normal file
@ -0,0 +1,18 @@
|
||||
require "providers/provider_factory"
|
||||
|
||||
module Devops
|
||||
module Version2_0
|
||||
module Handler
|
||||
class Network
|
||||
|
||||
def self.get_networks
|
||||
lambda {
|
||||
p = ::Provider::ProviderFactory.get params[:provider]
|
||||
json p.networks_detail
|
||||
}
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
256
devops-service/routes/v2.0/handlers/project.rb
Normal file
256
devops-service/routes/v2.0/handlers/project.rb
Normal file
@ -0,0 +1,256 @@
|
||||
require "commands/deploy"
|
||||
require "commands/status"
|
||||
require "commands/server"
|
||||
require "db/mongo/models/project"
|
||||
require "db/mongo/models/deploy_env"
|
||||
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 {
|
||||
fields = []
|
||||
if params.key?("fields") and params["fields"].is_a?(Array)
|
||||
Project.fields.each do |k|
|
||||
fields.push k if params["fields"].include?(k)
|
||||
end
|
||||
end
|
||||
json settings.mongo.projects(nil, nil, fields).map {|p| p.to_hash}
|
||||
}
|
||||
end
|
||||
|
||||
def self.get_project
|
||||
lambda {
|
||||
json settings.mongo.project(params[:project])
|
||||
}
|
||||
end
|
||||
|
||||
def self.get_project_servers
|
||||
lambda {
|
||||
settings.mongo.project(params[:project])
|
||||
json settings.mongo.servers(params[:project], params[:deploy_env]).map{|s| s.to_hash}
|
||||
}
|
||||
end
|
||||
|
||||
# TODO: multi project
|
||||
def self.create_project
|
||||
lambda {
|
||||
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 = 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']]
|
||||
settings.mongo.project_insert p
|
||||
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 {
|
||||
project = Project.new(create_object_from_json_body)
|
||||
project.id = params[:id]
|
||||
old_project = settings.mongo.project params[:id]
|
||||
settings.mongo.project_update project
|
||||
roles = 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 {
|
||||
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 {
|
||||
@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 {
|
||||
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 {
|
||||
servers = settings.mongo.servers params[:id]
|
||||
raise DependencyError.new "Deleting #{params[:id]} 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
|
||||
info = if deploy_env.nil?
|
||||
settings.mongo.project_delete(params[:id])
|
||||
"Project '#{params[:id]}' is deleted"
|
||||
else
|
||||
project = settings.mongo.project(params[:id])
|
||||
project.remove_env params[:deploy_env]
|
||||
settings.mongo.project_update project
|
||||
"Project '#{params[:id]}'. Deploy environment '#{params[:deploy_env]}' has been deleted"
|
||||
end
|
||||
create_response(info)
|
||||
}
|
||||
end
|
||||
|
||||
def self.deploy_project
|
||||
lambda {
|
||||
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 = 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, [], 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
|
||||
json files
|
||||
end
|
||||
}
|
||||
end
|
||||
|
||||
def self.test_project
|
||||
lambda {
|
||||
project = settings.mongo.project(params[:id])
|
||||
env = project.deploy_env params[:env]
|
||||
logger.info "Test project '#{project.id}' and environment '#{env.identifier}'"
|
||||
|
||||
dir = DevopsService.config[: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, DevopsService.config)
|
||||
logger.info "Job '#{jid}' has been created"
|
||||
uri.path = "#{DevopsService.config[: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
|
||||
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
|
||||
|
||||
15
devops-service/routes/v2.0/handlers/provider.rb
Normal file
15
devops-service/routes/v2.0/handlers/provider.rb
Normal file
@ -0,0 +1,15 @@
|
||||
require "providers/provider_factory"
|
||||
|
||||
module Devops
|
||||
module Version2_0
|
||||
module Handler
|
||||
class Provider
|
||||
def self.get_providers
|
||||
lambda {
|
||||
json ::Provider::ProviderFactory.providers
|
||||
}
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
116
devops-service/routes/v2.0/handlers/script.rb
Normal file
116
devops-service/routes/v2.0/handlers/script.rb
Normal file
@ -0,0 +1,116 @@
|
||||
require "providers/provider_factory"
|
||||
require "fileutils"
|
||||
require "commands/status"
|
||||
|
||||
module Devops
|
||||
module Version2_0
|
||||
module Handler
|
||||
class Script
|
||||
|
||||
def self.get_scripts
|
||||
lambda {
|
||||
res = []
|
||||
Dir.foreach(DevopsService.config[:scripts_dir]) {|f| res.push(f) unless f.start_with?(".")}
|
||||
json res
|
||||
}
|
||||
end
|
||||
|
||||
def self.execute_command
|
||||
lambda {
|
||||
user = request.env['REMOTE_USER']
|
||||
s = BaseRoutes.mongo.server_by_chef_node_name params[:node_name]
|
||||
BaseRoutes.mongo.check_project_auth s.project, s.deploy_env, user
|
||||
cert = BaseRoutes.mongo.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 {
|
||||
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 = BaseRoutes.mongo.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|
|
||||
BaseRoutes.mongo.check_project_auth s.project, s.deploy_env, user
|
||||
end
|
||||
stream() do |out|
|
||||
begin
|
||||
status = []
|
||||
servers.each do |s|
|
||||
cert = begin
|
||||
BaseRoutes.mongo.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 {
|
||||
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 {
|
||||
FileUtils.rm(@file)
|
||||
create_response("File '#{params[:script_name]}' deleted")
|
||||
}
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
328
devops-service/routes/v2.0/handlers/server.rb
Normal file
328
devops-service/routes/v2.0/handlers/server.rb
Normal file
@ -0,0 +1,328 @@
|
||||
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/deploy_env"
|
||||
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 {
|
||||
fields = []
|
||||
if params.key?("fields") and params["fields"].is_a?(Array)
|
||||
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 {
|
||||
json KnifeCommands.chef_node_list
|
||||
}
|
||||
end
|
||||
|
||||
def self.get_provider_servers
|
||||
lambda {
|
||||
json ::Provider::ProviderFactory.get(params[:provider]).servers
|
||||
}
|
||||
end
|
||||
|
||||
def self.get_server
|
||||
lambda {
|
||||
json Server.get_server_by_key(params[:name], params[:key]).to_hash
|
||||
}
|
||||
end
|
||||
|
||||
def self.delete_server
|
||||
lambda {
|
||||
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 {
|
||||
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 = 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 = DevopsService.config[: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'], 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
|
||||
|
||||
def self.pause_server
|
||||
lambda {
|
||||
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 {
|
||||
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 {
|
||||
s = Server.get_server_by_key(params[:node_name], params[: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.reserve_server
|
||||
lambda {
|
||||
s = Server.get_server_by_key(params[:node_name], params[: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 {
|
||||
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 = DevopsService.config[: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'], DevopsService.config)
|
||||
logger.info "Job '#{jid}' has been started"
|
||||
uri.path = "#{DevopsService.config[: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 {
|
||||
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 = 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
|
||||
key == "instance" ? settings.mongo.server_by_instance_id(id) : settings.mongo.server_by_chef_node_name(id)
|
||||
end
|
||||
|
||||
def self.check_chef_node_name name, provider
|
||||
settings.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, settings.mongo, @logger)
|
||||
rescue => e
|
||||
logger.error "ExpiredHandler error: " + e.message
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
22
devops-service/routes/v2.0/handlers/status.rb
Normal file
22
devops-service/routes/v2.0/handlers/status.rb
Normal file
@ -0,0 +1,22 @@
|
||||
require "sidekiq"
|
||||
|
||||
module Devops
|
||||
module Version2_0
|
||||
module Handler
|
||||
class Status
|
||||
|
||||
def self.get_status
|
||||
lambda {
|
||||
r = Sidekiq.redis do |connection|
|
||||
connection.hget("devops", params[:id])
|
||||
end
|
||||
return [404, "Job with id '#{params[:id]}' not found"] if r.nil?
|
||||
r
|
||||
}
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
35
devops-service/routes/v2.0/handlers/tag.rb
Normal file
35
devops-service/routes/v2.0/handlers/tag.rb
Normal file
@ -0,0 +1,35 @@
|
||||
require "commands/knife_commands"
|
||||
|
||||
module Devops
|
||||
module Version2_0
|
||||
module Handler
|
||||
class Tag
|
||||
|
||||
def self.get_tags
|
||||
lambda {
|
||||
json(KnifeCommands.tags_list(@chef_node_name))
|
||||
}
|
||||
end
|
||||
|
||||
def self.set_tags
|
||||
lambda {
|
||||
tagsStr = @tags.join(" ")
|
||||
cmd = KnifeCommands.tags_create(@chef_node_name, tagsStr)
|
||||
halt_response("Error: Cannot add tags #{tagsStr} to server #{@chef_node_name}", 500) unless cmd[1]
|
||||
create_response("Set tags for #{@chef_node_name}: #{tagsStr}")
|
||||
}
|
||||
end
|
||||
|
||||
def self.unset_tags
|
||||
lambda {
|
||||
tagsStr = @tags.join(" ")
|
||||
cmd = KnifeCommands.tags_delete(@chef_node_name, tagsStr)
|
||||
halt_response("Cannot delete tags #{tagsStr} from server #{@chef_node_name}: #{cmd[0]}", 500) unless cmd[1]
|
||||
create_response("Deleted tags for #{@chef_node_name}: #{tagsStr}")
|
||||
}
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
80
devops-service/routes/v2.0/handlers/user.rb
Normal file
80
devops-service/routes/v2.0/handlers/user.rb
Normal file
@ -0,0 +1,80 @@
|
||||
require "db/exceptions/invalid_record"
|
||||
require "db/mongo/models/user"
|
||||
|
||||
module Devops
|
||||
module Version2_0
|
||||
module Handler
|
||||
class User
|
||||
|
||||
def self.get_users
|
||||
lambda {
|
||||
users = settings.mongo.users.map {|i| i.to_hash}
|
||||
users.each {|u| u.delete("password")}
|
||||
json users
|
||||
}
|
||||
end
|
||||
|
||||
def self.create_user
|
||||
lambda {
|
||||
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
|
||||
settings.mongo.user_insert User.new(user)
|
||||
create_response("Created", nil, 201)
|
||||
}
|
||||
end
|
||||
|
||||
def self.delete_user
|
||||
lambda {
|
||||
projects = settings.mongo.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
|
||||
|
||||
r = settings.mongo.user_delete params[:user]
|
||||
create_response("User '#{params[:user]}' removed")
|
||||
}
|
||||
end
|
||||
|
||||
def self.change_user_privileges
|
||||
lambda {
|
||||
data = create_object_from_json_body
|
||||
user = settings.mongo.user params[:user]
|
||||
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) || ""
|
||||
user.grant(cmd, privileges)
|
||||
settings.mongo.user_update user
|
||||
create_response("Updated")
|
||||
}
|
||||
end
|
||||
|
||||
def self.change_user_email_or_password
|
||||
lambda {
|
||||
action = File.basename(request.path)
|
||||
u = File.basename(File.dirname(request.path))
|
||||
raise InvalidPrivileges.new("Access denied for '#{request.env['REMOTE_USER']}'") if u == User::ROOT_USER_NAME and request.env['REMOTE_USER'] != 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")
|
||||
user = settings.mongo.user u
|
||||
user.send("#{action}=", p)
|
||||
settings.mongo.user_update user
|
||||
create_response("Updated")
|
||||
}
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@ -1,18 +1,18 @@
|
||||
require "providers/provider_factory"
|
||||
require "commands/image"
|
||||
|
||||
module Devops
|
||||
module Version2_0
|
||||
module Core
|
||||
module Routes
|
||||
module ImageRoutes
|
||||
|
||||
extend ImageCommands
|
||||
|
||||
def self.registered(app)
|
||||
app.after %r{\A/image(/[\w]+)?\z} do
|
||||
statistic
|
||||
end
|
||||
|
||||
app.before "/images" do
|
||||
check_headers :accept
|
||||
check_privileges("image", "r")
|
||||
check_provider(params[:provider]) if params[:provider]
|
||||
end
|
||||
# Get devops images list
|
||||
#
|
||||
# * *Request*
|
||||
@ -32,14 +32,13 @@ module Devops
|
||||
# "id": "36dc7618-4178-4e29-be43-286fbfe90f50"
|
||||
# }
|
||||
# ]
|
||||
app.get "/images" do
|
||||
app.get "/images", &Devops::Version2_0::Handler::Image.get_images
|
||||
|
||||
app.before "/images/provider/:provider" do
|
||||
check_headers :accept
|
||||
check_privileges("image", "r")
|
||||
check_provider(params[:provider]) if params[:provider]
|
||||
images = settings.mongo.images(params[:provider])
|
||||
json(images.map {|i| i.to_hash})
|
||||
check_provider(params[:provider])
|
||||
end
|
||||
|
||||
# Get raw images for :provider
|
||||
#
|
||||
# * *Request*
|
||||
@ -64,13 +63,18 @@ module Devops
|
||||
# "status": "ACTIVE"
|
||||
# }
|
||||
# ]
|
||||
app.get "/images/provider/:provider" do
|
||||
app.get "/images/provider/:provider", &Devops::Version2_0::Handler::Image.get_provider_images
|
||||
|
||||
app.before "/image/:image_id" do
|
||||
case request.method
|
||||
when "get"
|
||||
check_headers :accept
|
||||
check_privileges("image", "r")
|
||||
check_provider(params[:provider])
|
||||
json get_images(settings.mongo, params[:provider])
|
||||
when "delete", "put"
|
||||
check_headers
|
||||
check_privileges("image", "w")
|
||||
end
|
||||
end
|
||||
|
||||
# Get devops image by id
|
||||
#
|
||||
# * *Request*
|
||||
@ -86,12 +90,12 @@ module Devops
|
||||
# "bootstrap_template": null,
|
||||
# "id": "36dc7618-4178-4e29-be43-286fbfe90f50"
|
||||
# }
|
||||
app.get "/image/:image_id" do
|
||||
check_headers :accept
|
||||
check_privileges("image", "r")
|
||||
json settings.mongo.image(params[:image_id])
|
||||
end
|
||||
app.get "/image/:image_id", &Devops::Version2_0::Handler::Image.get_image
|
||||
|
||||
app.before "/image" do
|
||||
check_headers
|
||||
check_privileges("image", "w")
|
||||
end
|
||||
# Create devops image
|
||||
#
|
||||
# * *Request*
|
||||
@ -110,13 +114,7 @@ module Devops
|
||||
#
|
||||
# * *Returns* :
|
||||
# 201 - Created
|
||||
app.post "/image" do
|
||||
check_headers
|
||||
check_privileges("image", "w")
|
||||
image = create_object_from_json_body
|
||||
settings.mongo.image_insert Image.new(image)
|
||||
create_response "Created", nil, 201
|
||||
end
|
||||
app.post "/image", &Devops::Version2_0::Handler::Image.create_image
|
||||
|
||||
# Update devops image
|
||||
#
|
||||
@ -136,15 +134,7 @@ module Devops
|
||||
#
|
||||
# * *Returns* :
|
||||
# 200 - Updated
|
||||
app.put "/image/:image_id" do
|
||||
check_headers
|
||||
check_privileges("image", "w")
|
||||
settings.mongo.image params[:image_id]
|
||||
image = 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
|
||||
app.put "/image/:image_id", &Devops::Version2_0::Handler::Image.update_image
|
||||
|
||||
# Delete devops image
|
||||
#
|
||||
@ -155,21 +145,7 @@ module Devops
|
||||
#
|
||||
# * *Returns* :
|
||||
# 200 - Deleted
|
||||
app.delete "/image/:image_id" do
|
||||
check_headers
|
||||
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.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
|
||||
app.delete "/image/:image_id", &Devops::Version2_0::Handler::Image.delete_image
|
||||
|
||||
puts "Image routes initialized"
|
||||
end
|
||||
|
||||
@ -5,23 +5,29 @@ require "fileutils"
|
||||
|
||||
module Devops
|
||||
module Version2_0
|
||||
module Core
|
||||
module Routes
|
||||
module KeyRoutes
|
||||
|
||||
def self.registered(app)
|
||||
app.before %r{\A/key(/[\w]+)?\z} do
|
||||
if request.delete?
|
||||
check_headers :accept
|
||||
else
|
||||
check_headers :accept, :content_type
|
||||
end
|
||||
check_privileges("key", "w")
|
||||
end
|
||||
|
||||
app.after %r{\A/key(/[\w]+)?\z} do
|
||||
statistic
|
||||
end
|
||||
|
||||
app.before "/keys" do
|
||||
check_headers :accept
|
||||
check_privileges("key", "r")
|
||||
end
|
||||
|
||||
app.before "/key" do
|
||||
check_headers :accept, :content_type
|
||||
check_privileges("key", "w")
|
||||
end
|
||||
|
||||
app.before "/key/:key" do
|
||||
check_headers :accept
|
||||
check_privileges("key", "w")
|
||||
end
|
||||
# Get list of available ssh keys
|
||||
#
|
||||
# * *Request*
|
||||
@ -36,13 +42,7 @@ module Devops
|
||||
# "id": "devops"
|
||||
# }
|
||||
# ]
|
||||
app.get "/keys" do
|
||||
check_headers :accept
|
||||
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
|
||||
app.get "/keys", &Devops::Version2_0::Handler::Key.get_keys
|
||||
|
||||
# Create ssh key on devops server
|
||||
#
|
||||
@ -60,22 +60,7 @@ module Devops
|
||||
#
|
||||
# * *Returns* :
|
||||
# 201 - Created
|
||||
app.post "/key" do
|
||||
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(DevopsService.config[: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 = Key.new({"path" => file_name, "id" => kname})
|
||||
settings.mongo.key_insert key
|
||||
create_response("Created", nil, 201)
|
||||
end
|
||||
app.post "/key", &Devops::Version2_0::Handler::Key.create_key
|
||||
|
||||
# Delete ssh key from devops server
|
||||
#
|
||||
@ -86,23 +71,7 @@ module Devops
|
||||
#
|
||||
# * *Returns* :
|
||||
# 200 - Deleted
|
||||
app.delete "/key/:key" do
|
||||
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
|
||||
app.delete "/key/:key", &Devops::Version2_0::Handler::Key.delete_key
|
||||
|
||||
puts "Key routes initialized"
|
||||
end
|
||||
|
||||
@ -1,13 +1,16 @@
|
||||
# encoding: UTF-8
|
||||
require "json"
|
||||
require "providers/provider_factory"
|
||||
|
||||
module Devops
|
||||
module Version2_0
|
||||
module Core
|
||||
module Routes
|
||||
module NetworkRoutes
|
||||
|
||||
def self.registered(app)
|
||||
|
||||
app.before "/networks/:provider" do
|
||||
check_headers :accept
|
||||
check_privileges("network", "r")
|
||||
check_provider(params[:provider])
|
||||
end
|
||||
# Get list of networks for :provider
|
||||
#
|
||||
# * *Request*
|
||||
@ -34,13 +37,7 @@ module Devops
|
||||
# "id": "b14f8df9-ac27-48e2-8d65-f7ef78dc2654"
|
||||
# }
|
||||
# ]
|
||||
app.get "/networks/:provider" do
|
||||
check_headers :accept
|
||||
check_privileges("network", "r")
|
||||
check_provider(params[:provider])
|
||||
p = ::Provider::ProviderFactory.get params[:provider]
|
||||
json p.networks_detail
|
||||
end
|
||||
app.get "/networks/:provider", &Devops::Version2_0::Handler::Network.get_networks
|
||||
|
||||
puts "Network routes initialized"
|
||||
end
|
||||
|
||||
@ -1,22 +1,10 @@
|
||||
require "json"
|
||||
require "db/mongo/models/project"
|
||||
require "db/mongo/models/deploy_env"
|
||||
require "db/exceptions/invalid_record"
|
||||
require "commands/deploy"
|
||||
require "commands/status"
|
||||
require "commands/server"
|
||||
require "workers/project_test_worker"
|
||||
|
||||
module Devops
|
||||
module Version2_0
|
||||
module Core
|
||||
module Routes
|
||||
module ProjectRoutes
|
||||
|
||||
extend DeployCommands
|
||||
extend StatusCommands
|
||||
extend ServerCommands
|
||||
|
||||
def self.registered(app)
|
||||
|
||||
app.before "/project/:id/user" do
|
||||
check_headers :accept, :content_type
|
||||
check_privileges("project", "w")
|
||||
@ -47,17 +35,11 @@ module Devops
|
||||
# [
|
||||
# {"name" : "project_1"}
|
||||
# ]
|
||||
app.get "/projects" do
|
||||
app.before "/projects" do
|
||||
check_headers :accept
|
||||
check_privileges("project", "r")
|
||||
fields = []
|
||||
if params.key?("fields") and params["fields"].is_a?(Array)
|
||||
Project.fields.each do |k|
|
||||
fields.push k if params["fields"].include?(k)
|
||||
end
|
||||
end
|
||||
json settings.mongo.projects(nil, nil, fields).map {|p| p.to_hash}
|
||||
end
|
||||
app.get "/projects", &Devops::Version2_0::Handler::Project.get_projects
|
||||
|
||||
# Get project by id
|
||||
#
|
||||
@ -91,11 +73,18 @@ module Devops
|
||||
# ],
|
||||
# "name": "project_1"
|
||||
# }
|
||||
app.get "/project/:project" do
|
||||
app.before "/project/:project" do
|
||||
if request.get?
|
||||
check_headers :accept
|
||||
check_privileges("project", "r")
|
||||
json settings.mongo.project(params[:project])
|
||||
elsif request.put? or request.delete?
|
||||
check_headers
|
||||
check_privileges("project", "w")
|
||||
else
|
||||
return [404, "Route not found"]
|
||||
end
|
||||
end
|
||||
app.get "/project/:project", &Devops::Version2_0::Handler::Project.get_project
|
||||
|
||||
# Get project servers
|
||||
#
|
||||
@ -123,12 +112,11 @@ module Devops
|
||||
# "id": "nstance id"
|
||||
# }
|
||||
# ]
|
||||
app.get "/project/:project/servers" do
|
||||
app.before "/project/:project/servers" do
|
||||
check_headers :accept
|
||||
check_privileges("project", "r")
|
||||
settings.mongo.project(params[:project])
|
||||
json settings.mongo.servers(params[:project], params[:deploy_env]).map{|s| s.to_hash}
|
||||
end
|
||||
app.get "/project/:project/servers", &Devops::Version2_0::Handler::Project.get_project_servers
|
||||
|
||||
# Create project and chef roles
|
||||
#
|
||||
@ -165,28 +153,11 @@ module Devops
|
||||
#
|
||||
# * *Returns* :
|
||||
# 201 - Created
|
||||
# TODO: multi project
|
||||
app.post "/project" do
|
||||
app.before "/project" do
|
||||
check_headers :accept, :content_type
|
||||
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 = 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']]
|
||||
settings.mongo.project_insert p
|
||||
roles_res = ""
|
||||
if p.multi?
|
||||
logger.info "Project '#{p.id}' with type 'multi' created"
|
||||
else
|
||||
logger.info "Project '#{p.id}' created"
|
||||
roles = create_roles p.id, p.deploy_envs, logger
|
||||
roles_res = ". " + create_roles_response(roles)
|
||||
end
|
||||
res = "Created" + roles_res
|
||||
create_response(res, nil, 201)
|
||||
end
|
||||
app.post "/project", &Devops::Version2_0::Handler::Project.create_project
|
||||
|
||||
# Update project and create chef roles
|
||||
#
|
||||
@ -223,18 +194,7 @@ module Devops
|
||||
#
|
||||
# * *Returns* :
|
||||
# 200 - Updated
|
||||
# TODO: multi project
|
||||
app.put "/project/:id" do
|
||||
check_headers
|
||||
check_privileges("project", "w")
|
||||
project = Project.new(create_object_from_json_body)
|
||||
project.id = params[:id]
|
||||
old_project = settings.mongo.project params[:id]
|
||||
settings.mongo.project_update project
|
||||
roles = create_new_roles(old_project, project, logger)
|
||||
info = "Project '#{project.id}' has been updated." + create_roles_response(roles)
|
||||
create_response(info)
|
||||
end
|
||||
app.put "/project/:id", &Devops::Version2_0::Handler::Project.update_project
|
||||
|
||||
# Add users to project environment
|
||||
#
|
||||
@ -253,16 +213,7 @@ module Devops
|
||||
#
|
||||
# * *Returns* :
|
||||
# 200 - Updated
|
||||
# TODO: multi project
|
||||
app.put "/project/:id/user" do
|
||||
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
|
||||
app.put "/project/:id/user", &Devops::Version2_0::Handler::Project.update_project_users
|
||||
|
||||
# Delete users from project environment
|
||||
#
|
||||
@ -281,13 +232,7 @@ module Devops
|
||||
#
|
||||
# * *Returns* :
|
||||
# 200 - Updated
|
||||
# TODO: multi project
|
||||
app.delete "/project/:id/user" do
|
||||
@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
|
||||
app.delete "/project/:id/user", &Devops::Version2_0::Handler::Project.delete_project_users
|
||||
|
||||
# Set run_list to project environment
|
||||
#
|
||||
@ -304,18 +249,11 @@ module Devops
|
||||
#
|
||||
# * *Returns* :
|
||||
# 200 - Updated
|
||||
# TODO: multi project
|
||||
app.put "/project/:id/:env/run_list" do
|
||||
app.before "/project/:id/:env/run_list" do
|
||||
check_headers :accept, :content_type
|
||||
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
|
||||
app.put "/project/:id/:env/run_list", &Devops::Version2_0::Handler::Project.set_project_env_run_list
|
||||
|
||||
# Delete project
|
||||
#
|
||||
@ -331,26 +269,7 @@ module Devops
|
||||
#
|
||||
# * *Returns* :
|
||||
# 200 - Deleted
|
||||
app.delete "/project/:id" do
|
||||
check_headers :accept, :content_type
|
||||
check_privileges("project", "w")
|
||||
servers = settings.mongo.servers params[:id]
|
||||
raise DependencyError.new "Deleting #{params[:id]} 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
|
||||
info = if deploy_env.nil?
|
||||
settings.mongo.project_delete(params[:id])
|
||||
"Project '#{params[:id]}' is deleted"
|
||||
else
|
||||
project = settings.mongo.project(params[:id])
|
||||
project.remove_env params[:deploy_env]
|
||||
settings.mongo.project_update project
|
||||
"Project '#{params[:id]}'. Deploy environment '#{params[:deploy_env]}' has been deleted"
|
||||
end
|
||||
create_response(info)
|
||||
end
|
||||
app.delete "/project/:id", &Devops::Version2_0::Handler::Project.delete_project
|
||||
|
||||
# Run chef-client on reserved project servers
|
||||
#
|
||||
@ -367,60 +286,11 @@ module Devops
|
||||
# }
|
||||
#
|
||||
# * *Returns* : text stream
|
||||
app.post "/project/:id/deploy" do
|
||||
app.before "/project/:id/deploy" do
|
||||
check_headers :content_type
|
||||
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 = 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, [], 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
|
||||
json files
|
||||
|
||||
end
|
||||
end
|
||||
app.post "/project/:id/deploy", &Devops::Version2_0::Handler::Project.deploy_project
|
||||
|
||||
# Test project environment
|
||||
#
|
||||
@ -488,73 +358,15 @@ module Devops
|
||||
# },
|
||||
# "message": "Test project 'project_1' and environment 'prod'"
|
||||
# }
|
||||
app.post "/project/test/:id/:env" do
|
||||
app.before "/project/test/:id/:env" do
|
||||
check_headers :accept, :content_type
|
||||
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}'"
|
||||
|
||||
dir = DevopsService.config[: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, DevopsService.config)
|
||||
logger.info "Job '#{jid}' has been created"
|
||||
uri.path = "#{DevopsService.config[:url_prefix]}/v2.0/report/" + jid
|
||||
files = [uri.to_s]
|
||||
sleep 1
|
||||
json files
|
||||
end
|
||||
|
||||
app.post "/project/test/:id/:env", &Devops::Version2_0::Handler::Project.test_project
|
||||
|
||||
puts "Project routes initialized"
|
||||
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
|
||||
|
||||
@ -5,11 +5,16 @@ require "providers/provider_factory"
|
||||
|
||||
module Devops
|
||||
module Version2_0
|
||||
module Core
|
||||
module Routes
|
||||
module ProviderRoutes
|
||||
|
||||
def self.registered(app)
|
||||
|
||||
app.before "/providers" do
|
||||
check_headers :accept
|
||||
check_privileges("provider", "r")
|
||||
end
|
||||
|
||||
# Get devops providers
|
||||
#
|
||||
# * *Request*
|
||||
@ -22,16 +27,11 @@ module Devops
|
||||
# "ec2",
|
||||
# "openstack"
|
||||
# ]
|
||||
app.get "/providers" do
|
||||
check_headers :accept
|
||||
check_privileges("provider", "r")
|
||||
json ::Provider::ProviderFactory.providers
|
||||
end
|
||||
app.get "/providers", &Devops::Version2_0::Handler::Provider.get_providers
|
||||
|
||||
puts "Provider routes initialized"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
#register Version2_0::Core::ProviderRoutes
|
||||
end
|
||||
|
||||
@ -1,10 +1,7 @@
|
||||
require "providers/provider_factory"
|
||||
require "fileutils"
|
||||
require "commands/status"
|
||||
|
||||
module Devops
|
||||
module Version2_0
|
||||
module Core
|
||||
module Routes
|
||||
module ScriptRoutes
|
||||
|
||||
extend StatusCommands
|
||||
@ -37,13 +34,11 @@ module Devops
|
||||
# [
|
||||
# "script_1"
|
||||
# ]
|
||||
app.get "/scripts" do
|
||||
app.before "/scripts" do
|
||||
check_headers :accept
|
||||
check_privileges("script", "r")
|
||||
res = []
|
||||
Dir.foreach(DevopsService.config[:scripts_dir]) {|f| res.push(f) unless f.start_with?(".")}
|
||||
json res
|
||||
end
|
||||
app.get "/scripts", &Devops::Version2_0::Handler::Script.get_scripts
|
||||
|
||||
# Run command on node :node_name
|
||||
#
|
||||
@ -53,30 +48,10 @@ module Devops
|
||||
# command to run
|
||||
#
|
||||
# * *Returns* : text stream
|
||||
app.post "/script/command/:node_name" do
|
||||
app.before "/script/command/:node_name" do
|
||||
check_privileges("script", "x")
|
||||
user = request.env['REMOTE_USER']
|
||||
s = BaseRoutes.mongo.server_by_chef_node_name params[:node_name]
|
||||
BaseRoutes.mongo.check_project_auth s.project, s.deploy_env, user
|
||||
cert = BaseRoutes.mongo.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
|
||||
app.post "/script/command/:node_name", &Devops::Version2_0::Handler::Script.execute_command
|
||||
|
||||
# Run script :script_name on nodes
|
||||
#
|
||||
@ -91,60 +66,11 @@ module Devops
|
||||
# }
|
||||
#
|
||||
# * *Returns* : text stream
|
||||
app.post "/script/run/:script_name" do
|
||||
app.before "/script/run/:script_name" do
|
||||
check_headers :content_type
|
||||
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 = BaseRoutes.mongo.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|
|
||||
BaseRoutes.mongo.check_project_auth s.project, s.deploy_env, user
|
||||
end
|
||||
stream() do |out|
|
||||
begin
|
||||
status = []
|
||||
servers.each do |s|
|
||||
cert = begin
|
||||
BaseRoutes.mongo.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
|
||||
app.post "/script/run/:script_name", &Devops::Version2_0::Handler::Script.run_script
|
||||
|
||||
# Create script :script_name
|
||||
#
|
||||
@ -156,10 +82,7 @@ module Devops
|
||||
#
|
||||
# * *Returns* :
|
||||
# 201 - Created
|
||||
app.put "/script/:script_name" do
|
||||
File.open(@file, "w") {|f| f.write(request.body.read)}
|
||||
create_response("File '#{params[:script_name]}' created", nil, 201)
|
||||
end
|
||||
app.put "/script/:script_name", &Devops::Version2_0::Handler::Script.create_script
|
||||
|
||||
# Delete script :script_name
|
||||
#
|
||||
@ -170,10 +93,7 @@ module Devops
|
||||
#
|
||||
# * *Returns* :
|
||||
# 200 - Deleted
|
||||
app.delete "/script/:script_name" do
|
||||
FileUtils.rm(@file)
|
||||
create_response("File '#{params[:script_name]}' deleted")
|
||||
end
|
||||
app.delete "/script/:script_name", &Devops::Version2_0::Handler::Script.delete_script
|
||||
|
||||
puts "Script routes initialized"
|
||||
end
|
||||
|
||||
@ -1,45 +1,10 @@
|
||||
require "uri"
|
||||
require "json"
|
||||
require "chef"
|
||||
require "commands/knife_commands"
|
||||
require 'rufus-scheduler'
|
||||
require "providers/provider_factory"
|
||||
require "db/mongo/models/deploy_env"
|
||||
require "commands/status"
|
||||
require "commands/server"
|
||||
require "commands/bootstrap_templates"
|
||||
require "workers/create_server_worker"
|
||||
require "workers/bootstrap_worker"
|
||||
|
||||
module Devops
|
||||
module Version2_0
|
||||
module Core
|
||||
module Routes
|
||||
module ServerRoutes
|
||||
|
||||
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, settings.mongo, @logger)
|
||||
rescue => e
|
||||
logger.error "ExpiredHandler error: " + e.message
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
extend StatusCommands
|
||||
extend ServerCommands
|
||||
extend BootstrapTemplatesCommands
|
||||
|
||||
scheduler = Rufus::Scheduler.new
|
||||
|
||||
def self.registered(app)
|
||||
app.before %r{\A/server/[\w]+/(pause|unpouse|reserve|unreserve)\z} do
|
||||
check_headers :accept, :content_type
|
||||
@ -68,18 +33,11 @@ module Devops
|
||||
# "chef_node_name": "chef name"
|
||||
# }
|
||||
# ]
|
||||
app.get "/servers" do
|
||||
app.before "/servers" do
|
||||
check_headers :accept
|
||||
check_privileges("server", "r")
|
||||
fields = []
|
||||
if params.key?("fields") and params["fields"].is_a?(Array)
|
||||
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
|
||||
app.get "/servers", &Devops::Version2_0::Handler::Server.get_servers
|
||||
|
||||
# Get chef nodes list
|
||||
#
|
||||
@ -94,11 +52,11 @@ module Devops
|
||||
# "chef_node_name": "chef name"
|
||||
# }
|
||||
# ]
|
||||
app.get "/servers/chef" do
|
||||
app.before "/servers/chef" do
|
||||
check_headers :accept
|
||||
check_privileges("server", "r")
|
||||
json KnifeCommands.chef_node_list
|
||||
end
|
||||
app.get "/servers/chef", &Devops::Version2_0::Handler::Server.get_chef_servers
|
||||
|
||||
# Get provider servers list
|
||||
#
|
||||
@ -136,11 +94,11 @@ module Devops
|
||||
# "private_ip": "172.17.0.1"
|
||||
# }
|
||||
# ]
|
||||
app.get "/servers/:provider" do
|
||||
app.before "/servers/:provider" do
|
||||
check_headers :accept
|
||||
check_privileges("server", "r")
|
||||
json ::Provider::ProviderFactory.get(params[:provider]).servers
|
||||
end
|
||||
app.get "/servers/:provider", &Devops::Version2_0::Handler::Server.get_provider_servers
|
||||
|
||||
# Get server info by :name
|
||||
#
|
||||
@ -157,11 +115,16 @@ module Devops
|
||||
# "chef_node_name": "chef name"
|
||||
# }
|
||||
# ]
|
||||
app.get "/server/:name" do
|
||||
app.before "/server/:name" do
|
||||
if request.get?
|
||||
check_headers :accept
|
||||
check_privileges("server", "r")
|
||||
json get_server(params[:name], params[:key]).to_hash
|
||||
elsif request.delete?
|
||||
check_headers
|
||||
check_privileges("server", "w")
|
||||
end
|
||||
end
|
||||
app.get "/server/:name", &Devops::Version2_0::Handler::Server.get_server
|
||||
|
||||
# Delete devops server
|
||||
#
|
||||
@ -177,17 +140,7 @@ module Devops
|
||||
#
|
||||
# * *Returns* :
|
||||
# 200 - Deleted
|
||||
app.delete "/server/:id" do
|
||||
check_headers
|
||||
check_privileges("server", "w")
|
||||
body = create_object_from_json_body(Hash, true)
|
||||
key = (body.nil? ? nil : body["key"])
|
||||
s = get_server(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
|
||||
app.delete "/server/:id", &Devops::Version2_0::Handler::Server.delete_server
|
||||
|
||||
# Create devops server
|
||||
#
|
||||
@ -209,62 +162,11 @@ module Devops
|
||||
# }
|
||||
#
|
||||
# * *Returns* : text stream
|
||||
app.post "/server" do
|
||||
app.before "/server" do
|
||||
check_headers :content_type
|
||||
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)
|
||||
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 = 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 = DevopsService.config[: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'], 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
|
||||
app.post "/server", &Devops::Version2_0::Handler::Server.create_server
|
||||
|
||||
# Pause devops server by name
|
||||
#
|
||||
@ -280,18 +182,7 @@ module Devops
|
||||
#
|
||||
# * *Returns* :
|
||||
# 200 - Paused
|
||||
app.post "/server/:node_name/pause" do
|
||||
s = get_server(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
|
||||
app.post "/server/:node_name/pause", &Devops::Version2_0::Handler::Server.pause_server
|
||||
|
||||
# Unpause devops server by name
|
||||
#
|
||||
@ -307,18 +198,7 @@ module Devops
|
||||
#
|
||||
# * *Returns* :
|
||||
# 200 - Unpaused
|
||||
app.post "/server/:node_name/unpause" do
|
||||
s = get_server(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
|
||||
app.post "/server/:node_name/unpause", &Devops::Version2_0::Handler::Server.unpause_server
|
||||
|
||||
# Reserve devops server
|
||||
#
|
||||
@ -334,15 +214,7 @@ module Devops
|
||||
#
|
||||
# * *Returns* :
|
||||
# 200 - Reserved
|
||||
app.post "/server/:node_name/reserve" do
|
||||
s = get_server(params[:node_name], params[: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
|
||||
app.post "/server/:node_name/reserve", &Devops::Version2_0::Handler::Server.reserve_server
|
||||
|
||||
# Unreserve devops server
|
||||
#
|
||||
@ -358,14 +230,7 @@ module Devops
|
||||
#
|
||||
# * *Returns* :
|
||||
# 200 - Unreserved
|
||||
app.post "/server/:node_name/unreserve" do
|
||||
s = get_server(params[:node_name], params[: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
|
||||
app.post "/server/:node_name/unreserve", &Devops::Version2_0::Handler::Server.unreserve_server
|
||||
|
||||
# Bootstrap devops server
|
||||
#
|
||||
@ -383,80 +248,11 @@ module Devops
|
||||
# }
|
||||
#
|
||||
# * *Returns* : text stream
|
||||
# TODO: check bootstrap template name
|
||||
app.post "/server/bootstrap" do
|
||||
app.before "/server/bootstrap" do
|
||||
check_headers
|
||||
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)
|
||||
|
||||
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 = DevopsService.config[: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'], DevopsService.config)
|
||||
logger.info "Job '#{jid}' has been started"
|
||||
uri.path = "#{DevopsService.config[:url_prefix]}/v2.0/report/" + jid
|
||||
uri.query = nil
|
||||
uri.fragment = nil
|
||||
files.push uri.to_s
|
||||
sleep 1
|
||||
json files
|
||||
end
|
||||
end
|
||||
app.post "/server/bootstrap", &Devops::Version2_0::Handler::Server.bootstrap_server
|
||||
|
||||
# Add external server to devops
|
||||
#
|
||||
@ -477,58 +273,15 @@ module Devops
|
||||
#
|
||||
# * *Returns* :
|
||||
# 200 - Added
|
||||
# TODO: should be refactored
|
||||
app.post "/server/add" do
|
||||
app.before "/server/add" do
|
||||
check_headers
|
||||
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 = 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
|
||||
app.post "/server/add", &Devops::Version2_0::Handler::Server.add_server
|
||||
|
||||
puts "Server routes initialized"
|
||||
end
|
||||
|
||||
|
||||
def get_server id, key
|
||||
key == "instance" ? settings.mongo.server_by_instance_id(id) : settings.mongo.server_by_chef_node_name(id)
|
||||
end
|
||||
|
||||
def check_chef_node_name name, provider
|
||||
settings.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
|
||||
end
|
||||
end
|
||||
|
||||
@ -1,19 +1,10 @@
|
||||
require "json"
|
||||
require "sidekiq"
|
||||
|
||||
module Devops
|
||||
module Version2_0
|
||||
module Core
|
||||
module Routes
|
||||
module StatusRoutes
|
||||
|
||||
def self.registered(app)
|
||||
app.get "/status/:id" do
|
||||
r = Sidekiq.redis do |connection|
|
||||
connection.hget("devops", params[:id])
|
||||
end
|
||||
return [404, "Job with id '#{params[:id]}' not found"] if r.nil?
|
||||
r
|
||||
end
|
||||
app.get "/status/:id", &Devops::Version2_0::Handler::Status.get_status
|
||||
|
||||
puts "Status routes initialized"
|
||||
end
|
||||
|
||||
@ -1,8 +1,6 @@
|
||||
require "commands/knife_commands"
|
||||
|
||||
module Devops
|
||||
module Version2_0
|
||||
module Core
|
||||
module Routes
|
||||
module TagRoutes
|
||||
|
||||
def self.registered(app)
|
||||
@ -16,7 +14,7 @@ module Devops
|
||||
@tags = create_object_from_json_body(Array)
|
||||
check_array(@tags, "Request body should be a not empty array of strings")
|
||||
end
|
||||
server = BaseRoutes.mongo.server_by_chef_node_name(params[:node_name])
|
||||
server = settings.mongo.server_by_chef_node_name(params[:node_name])
|
||||
halt_response("No servers found for name '#{params[:node_name]}'", 404) if server.nil?
|
||||
@chef_node_name = server.chef_node_name
|
||||
end
|
||||
@ -36,9 +34,7 @@ module Devops
|
||||
# [
|
||||
# "tag_1"
|
||||
# ]
|
||||
app.get "/tags/:node_name" do
|
||||
json(KnifeCommands.tags_list(@chef_node_name))
|
||||
end
|
||||
app.get "/tags/:node_name", &Devops::Version2_0::Handler::Tag.get_tags
|
||||
|
||||
# Set tags list to :node_name
|
||||
#
|
||||
@ -54,12 +50,7 @@ module Devops
|
||||
#
|
||||
# * *Returns* :
|
||||
# 200
|
||||
app.post "/tags/:node_name" do
|
||||
tagsStr = @tags.join(" ")
|
||||
cmd = KnifeCommands.tags_create(@chef_node_name, tagsStr)
|
||||
halt_response("Error: Cannot add tags #{tagsStr} to server #{@chef_node_name}", 500) unless cmd[1]
|
||||
create_response("Set tags for #{@chef_node_name}: #{tagsStr}")
|
||||
end
|
||||
app.post "/tags/:node_name", &Devops::Version2_0::Handler::Tag.set_tags
|
||||
|
||||
# Delete tags from :node_name
|
||||
#
|
||||
@ -75,12 +66,7 @@ module Devops
|
||||
#
|
||||
# * *Returns* :
|
||||
# 200
|
||||
app.delete "/tags/:node_name" do
|
||||
tagsStr = @tags.join(" ")
|
||||
cmd = KnifeCommands.tags_delete(@chef_node_name, tagsStr)
|
||||
halt_response("Cannot delete tags #{tagsStr} from server #{@chef_node_name}: #{cmd[0]}", 500) unless cmd[1]
|
||||
create_response("Deleted tags for #{@chef_node_name}: #{tagsStr}")
|
||||
end
|
||||
app.delete "/tags/:node_name", &Devops::Version2_0::Handler::Tag.unset_tags
|
||||
|
||||
puts "Tag routes initialized"
|
||||
end
|
||||
|
||||
@ -1,13 +1,9 @@
|
||||
require "db/exceptions/invalid_record"
|
||||
require "db/mongo/models/user"
|
||||
|
||||
module Devops
|
||||
module Version2_0
|
||||
module Core
|
||||
module Routes
|
||||
module UserRoutes
|
||||
|
||||
def self.registered(app)
|
||||
puts "User routes initialized"
|
||||
|
||||
app.after %r{\A/user(/[\w]+(/password)?)?\z} do
|
||||
statistic
|
||||
@ -41,13 +37,11 @@ module Devops
|
||||
# "id": "test"
|
||||
# }
|
||||
# ]
|
||||
app.get "/users" do
|
||||
app.before "/users" do
|
||||
check_headers :accept
|
||||
check_privileges("user", "r")
|
||||
users = settings.mongo.users.map {|i| i.to_hash}
|
||||
users.each {|u| u.delete("password")}
|
||||
json users
|
||||
end
|
||||
app.get "/users", &Devops::Version2_0::Handler::User.get_users
|
||||
|
||||
# Create user
|
||||
#
|
||||
@ -65,17 +59,11 @@ module Devops
|
||||
#
|
||||
# * *Returns* :
|
||||
# 201 - Created
|
||||
app.post "/user" do
|
||||
app.before "/user" do
|
||||
check_headers :accept, :content_type
|
||||
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
|
||||
#BaseRoutes.mongo.user_insert User.new(user)
|
||||
settings.mongo.user_insert User.new(user)
|
||||
create_response("Created", nil, 201)
|
||||
end
|
||||
app.post "/user", &Devops::Version2_0::Handler::User.create_user
|
||||
|
||||
# Delete user
|
||||
#
|
||||
@ -86,25 +74,15 @@ module Devops
|
||||
#
|
||||
# * *Returns* :
|
||||
# 200 - Deleted
|
||||
app.delete "/user/:user" do
|
||||
app.before "/user/:user" do
|
||||
if request.delete?
|
||||
check_headers :accept
|
||||
elsif request.put?
|
||||
check_headers :accept, :content_type
|
||||
end
|
||||
check_privileges("user", "w")
|
||||
projects = settings.mongo.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
|
||||
|
||||
r = settings.mongo.user_delete params[:user]
|
||||
create_response("User '#{params[:user]}' removed")
|
||||
end
|
||||
app.delete "/user/:user", &Devops::Version2_0::Handler::User.delete_user
|
||||
|
||||
# Change user privileges
|
||||
#
|
||||
@ -121,17 +99,7 @@ module Devops
|
||||
#
|
||||
# * *Returns* :
|
||||
# 200 - Updated
|
||||
app.put "/user/:user" do
|
||||
check_headers :accept, :content_type
|
||||
check_privileges("user", "w")
|
||||
data = create_object_from_json_body
|
||||
user = settings.mongo.user params[:user]
|
||||
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) || ""
|
||||
user.grant(cmd, privileges)
|
||||
settings.mongo.user_update user
|
||||
create_response("Updated")
|
||||
end
|
||||
app.put "/user/:user", &Devops::Version2_0::Handler::User.change_user_privileges
|
||||
|
||||
# Change user email/password
|
||||
#
|
||||
@ -147,21 +115,12 @@ module Devops
|
||||
#
|
||||
# * *Returns* :
|
||||
# 200 - Updated
|
||||
app.put %r{\A/user/[\w]+/(email|password)\z} do
|
||||
app.before %r{\A/user/[\w]+/(email|password)\z} do
|
||||
check_headers :accept, :content_type
|
||||
action = File.basename(request.path)
|
||||
u = File.basename(File.dirname(request.path))
|
||||
raise InvalidPrivileges.new("Access denied for '#{request.env['REMOTE_USER']}'") if u == User::ROOT_USER_NAME and request.env['REMOTE_USER'] != 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")
|
||||
user = settings.mongo.user u
|
||||
user.send("#{action}=", p)
|
||||
settings.mongo.user_update user
|
||||
create_response("Updated")
|
||||
end
|
||||
app.put %r{\A/user/[\w]+/(email|password)\z}, &Devops::Version2_0::Handler::User.change_user_email_or_password
|
||||
|
||||
puts "User routes initialized"
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
10
devops-service/some_class.rb
Normal file
10
devops-service/some_class.rb
Normal file
@ -0,0 +1,10 @@
|
||||
require "test_subscriber"
|
||||
class SomeClass
|
||||
|
||||
include Wisper::Publisher
|
||||
|
||||
def sbc
|
||||
self.subscribe TestSubscriber.new
|
||||
# self.call("hello 2")
|
||||
end
|
||||
end
|
||||
6
devops-service/test_subscriber.rb
Normal file
6
devops-service/test_subscriber.rb
Normal file
@ -0,0 +1,6 @@
|
||||
class TestSubscriber
|
||||
def cancel_order_failed data
|
||||
puts data
|
||||
raise data
|
||||
end
|
||||
end
|
||||
5
devops-service/test_subscriber_2.rb
Normal file
5
devops-service/test_subscriber_2.rb
Normal file
@ -0,0 +1,5 @@
|
||||
class TestSubscriber2
|
||||
def cancel_order_failed data
|
||||
puts data
|
||||
end
|
||||
end
|
||||
15
devops-service/wisper_fix.rb
Normal file
15
devops-service/wisper_fix.rb
Normal file
@ -0,0 +1,15 @@
|
||||
module Wisper
|
||||
module Publisher
|
||||
def broadcast(event, *args)
|
||||
registrations.each do | registration |
|
||||
begin
|
||||
registration.broadcast(clean_event(event), self, *args)
|
||||
rescue => e
|
||||
puts "Error: #{registration.class} #{event} #{e.message}"
|
||||
end
|
||||
end
|
||||
self
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
Loading…
Reference in New Issue
Block a user