224 lines
6.2 KiB
Ruby
224 lines
6.2 KiB
Ruby
|
|
require "json"
|
||
|
|
require "db/exceptions/record_not_found"
|
||
|
|
require "db/exceptions/invalid_record"
|
||
|
|
require "exceptions/dependency_error"
|
||
|
|
require "exceptions/invalid_privileges"
|
||
|
|
require "fog"
|
||
|
|
require "logger"
|
||
|
|
require "providers/provider_factory"
|
||
|
|
require "sinatra/json"
|
||
|
|
require "sinatra/base"
|
||
|
|
|
||
|
|
module Version2_0
|
||
|
|
# Basic class for devops routes classes
|
||
|
|
class BaseRoutes < Sinatra::Base
|
||
|
|
|
||
|
|
helpers do
|
||
|
|
def create_response msg, obj=nil, rstatus=200
|
||
|
|
logger.info(msg)
|
||
|
|
status rstatus
|
||
|
|
obj = {} if obj.nil?
|
||
|
|
obj[:message] = msg
|
||
|
|
json(obj)
|
||
|
|
end
|
||
|
|
|
||
|
|
def halt_response msg, rstatus=400
|
||
|
|
obj = {:message => msg}
|
||
|
|
halt(rstatus, json(obj))
|
||
|
|
end
|
||
|
|
|
||
|
|
def check_privileges cmd, p=nil
|
||
|
|
if p != "r" and p != "w"
|
||
|
|
p = request.get? ? "r" : "w"
|
||
|
|
end
|
||
|
|
BaseRoutes.mongo.check_user_privileges(request.env['REMOTE_USER'], cmd, p)
|
||
|
|
end
|
||
|
|
|
||
|
|
# Check request headers
|
||
|
|
def check_headers *headers
|
||
|
|
ha = (headers.empty? ? [:accept, :content_type] : headers)
|
||
|
|
ha.each do |h|
|
||
|
|
case h
|
||
|
|
when :accept, "accept"
|
||
|
|
accept_json
|
||
|
|
when :content_type, "content_type"
|
||
|
|
request_json
|
||
|
|
end
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
# Check Accept header
|
||
|
|
#
|
||
|
|
# Can client works with JSON?
|
||
|
|
def accept_json
|
||
|
|
logger.debug(request.accept)
|
||
|
|
unless request.accept? 'application/json'
|
||
|
|
response.headers['Accept'] = 'application/json'
|
||
|
|
halt_response("Accept header should contains 'application/json' type", 406)
|
||
|
|
end
|
||
|
|
rescue NoMethodError => e
|
||
|
|
#error in sinatra 1.4.4 (https://github.com/sinatra/sinatra/issues/844, https://github.com/sinatra/sinatra/pull/805)
|
||
|
|
response.headers['Accept'] = 'application/json'
|
||
|
|
halt_response("Accept header should contains 'application/json' type", 406)
|
||
|
|
end
|
||
|
|
|
||
|
|
# Check Content-Type header
|
||
|
|
def request_json
|
||
|
|
halt_response("Content-Type should be 'application/json'", 415) if request.media_type.nil? or request.media_type != 'application/json'
|
||
|
|
end
|
||
|
|
|
||
|
|
def check_provider provider
|
||
|
|
list = ::Version2_0::Provider::ProviderFactory.providers
|
||
|
|
halt_response("Invalid provider '#{provider}', available providers: '#{list.join("', '")}'", 404) unless list.include?(provider)
|
||
|
|
end
|
||
|
|
|
||
|
|
def create_object_from_json_body type=Hash, empty_body=false
|
||
|
|
json = request.body.read.strip
|
||
|
|
return nil if json.empty? and empty_body
|
||
|
|
@body_json = begin
|
||
|
|
JSON.parse(json)
|
||
|
|
rescue => e
|
||
|
|
logger.error e.message
|
||
|
|
logger.debug(json)
|
||
|
|
halt_response("Invalid JSON")
|
||
|
|
end
|
||
|
|
halt_response("Invalid JSON, it should be an #{type == Array ? "array" : "object"}") unless @body_json.is_a?(type)
|
||
|
|
@body_json
|
||
|
|
end
|
||
|
|
|
||
|
|
def check_string val, msg, _nil=false, empty=false
|
||
|
|
check_param val, String, msg, _nil, empty
|
||
|
|
end
|
||
|
|
|
||
|
|
def check_array val, msg, vals_type=String, _nil=false, empty=false
|
||
|
|
check_param val, Array, msg, _nil, empty
|
||
|
|
val.each {|v| halt_response(msg) unless v.is_a?(vals_type)} unless val.nil?
|
||
|
|
val
|
||
|
|
end
|
||
|
|
|
||
|
|
def check_filename file_name, not_string_msg, json_resp=true
|
||
|
|
check_string file_name, not_string_msg
|
||
|
|
r = Regexp.new("^[\\w _\\-.]{1,255}$", Regexp::IGNORECASE)
|
||
|
|
if r.match(file_name).nil?
|
||
|
|
msg = "Invalid file name '#{file_name}'. Expected name with 'a'-'z', '0'-'9', ' ', '_', '-', '.' symbols with length greate then 0 and less then 256 "
|
||
|
|
if json_resp
|
||
|
|
halt_response(msg)
|
||
|
|
else
|
||
|
|
halt(400, msg)
|
||
|
|
end
|
||
|
|
end
|
||
|
|
file_name
|
||
|
|
end
|
||
|
|
|
||
|
|
def check_param val, type, msg, _nil=false, empty=false
|
||
|
|
if val.nil?
|
||
|
|
if _nil
|
||
|
|
return val
|
||
|
|
else
|
||
|
|
halt_response(msg)
|
||
|
|
end
|
||
|
|
end
|
||
|
|
if val.is_a?(type)
|
||
|
|
halt_response(msg) if val.empty? and !empty
|
||
|
|
val
|
||
|
|
else
|
||
|
|
halt_response(msg)
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
# Save information about requests with methods POST, PUT, DELETE
|
||
|
|
def statistic msg=nil
|
||
|
|
unless request.get?
|
||
|
|
BaseRoutes.mongo.statistic request.env['REMOTE_USER'], request.path, request.request_method, @body_json, response.status
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
end
|
||
|
|
|
||
|
|
include Sinatra::JSON
|
||
|
|
|
||
|
|
configure :production do
|
||
|
|
disable :dump_errors
|
||
|
|
disable :show_exceptions
|
||
|
|
set :logging, Logger::INFO
|
||
|
|
end
|
||
|
|
|
||
|
|
configure :development do
|
||
|
|
set :logging, Logger::DEBUG
|
||
|
|
disable :raise_errors
|
||
|
|
# disable :dump_errors
|
||
|
|
set :show_exceptions, :after_handler
|
||
|
|
end
|
||
|
|
|
||
|
|
not_found do
|
||
|
|
"Not found"
|
||
|
|
end
|
||
|
|
|
||
|
|
error RecordNotFound do
|
||
|
|
e = env["sinatra.error"]
|
||
|
|
logger.warn e.message
|
||
|
|
halt_response(e.message, 404)
|
||
|
|
end
|
||
|
|
|
||
|
|
error InvalidRecord do
|
||
|
|
e = env["sinatra.error"]
|
||
|
|
logger.warn e.message
|
||
|
|
logger.warn "Request body: #{request.body.read}"
|
||
|
|
halt_response(e.message, 400)
|
||
|
|
end
|
||
|
|
|
||
|
|
error InvalidCommand do
|
||
|
|
e = env["sinatra.error"]
|
||
|
|
logger.warn e.message
|
||
|
|
halt_response(e.message, 400)
|
||
|
|
end
|
||
|
|
|
||
|
|
error DependencyError do
|
||
|
|
e = env["sinatra.error"]
|
||
|
|
logger.warn e.message
|
||
|
|
halt_response(e.message, 400)
|
||
|
|
end
|
||
|
|
|
||
|
|
error InvalidPrivileges do
|
||
|
|
e = env["sinatra.error"]
|
||
|
|
logger.warn e.message
|
||
|
|
halt_response(e.message, 401)
|
||
|
|
end
|
||
|
|
|
||
|
|
error Excon::Errors::Unauthorized do
|
||
|
|
e = env["sinatra.error"]
|
||
|
|
resp = e.response
|
||
|
|
ct = resp.headers["Content-Type"]
|
||
|
|
msg = unless ct.nil?
|
||
|
|
if ct.include?("application/json")
|
||
|
|
json = ::Chef::JSONCompat.from_json(resp.body)
|
||
|
|
m = "ERROR: Unauthorized (#{json['error']['code']}): #{json['error']['message']}"
|
||
|
|
logger.error(m)
|
||
|
|
else
|
||
|
|
end
|
||
|
|
m
|
||
|
|
else
|
||
|
|
"Unauthorized: #{e.inspect}"
|
||
|
|
end
|
||
|
|
halt_response(msg, 500)
|
||
|
|
end
|
||
|
|
|
||
|
|
error Fog::Compute::AWS::Error do
|
||
|
|
e = env["sinatra.error"]
|
||
|
|
logger.error e.message
|
||
|
|
halt_response(e.message, 500)
|
||
|
|
end
|
||
|
|
|
||
|
|
error do
|
||
|
|
e = env["sinatra.error"]
|
||
|
|
logger.error e.message
|
||
|
|
halt_response(e.message, 500)
|
||
|
|
end
|
||
|
|
|
||
|
|
def self.mongo
|
||
|
|
DevopsService.mongo
|
||
|
|
end
|
||
|
|
|
||
|
|
end
|
||
|
|
end
|