diff --git a/devops-service/Gemfile b/devops-service/Gemfile index 2b14f50..91f848c 100644 --- a/devops-service/Gemfile +++ b/devops-service/Gemfile @@ -21,7 +21,7 @@ gem 'rack-accept-media-types' gem 'rack', '1.5.2' gem 'hooks' -# gem "devops-nibr", :path => "plugins/devops-nibr" +#gem "devops-nibr", :path => "../../devops-nibr" group :test do gem 'cucumber' diff --git a/devops-service/app/api2/handlers/project.rb b/devops-service/app/api2/handlers/project.rb index 65fc409..fa47a59 100644 --- a/devops-service/app/api2/handlers/project.rb +++ b/devops-service/app/api2/handlers/project.rb @@ -26,14 +26,7 @@ module Devops end def projects - fields = [] - if @params.key?("fields") and @params["fields"].is_a?(Array) - Devops::Model::Project.fields.each do |k| - fields.push k if @params["fields"].include?(k) - end - end - archived = @params.include?("archived") - Devops::Db.connector.projects(nil, nil, fields, archived) + Devops::Db.connector.projects(nil, nil, parser.projects, parser.archived_projects) end def project id diff --git a/devops-service/app/api2/handlers/server.rb b/devops-service/app/api2/handlers/server.rb index c00f29c..2a8ce2b 100644 --- a/devops-service/app/api2/handlers/server.rb +++ b/devops-service/app/api2/handlers/server.rb @@ -64,11 +64,11 @@ module Devops def create_server dir = DevopsConfig[:report_dir_v2] files = [] - uri = URI.parse(request.url) + uri = URI.parse(parser.request.url) prepare_create_server.each do |s| h = s.to_hash h["options"] = s.options - jid = CreateServerWorker.perform_async(dir, env.provider, h, parser.current_user, DevopsConfig.config) + jid = CreateServerWorker.perform_async(dir, s.provider, h, parser.current_user, DevopsConfig.config) Worker.set_status jid, Worker::STATUS::IN_QUEUE #logger.info "Job '#{jid}' has been started" uri.path = "#{DevopsConfig[:url_prefix]}/v2.0/report/" + jid @@ -96,7 +96,7 @@ module Devops halt_response("Invalid security groups '#{buf.join("', '")}' for provider '#{provider.name}'") if buf.empty? end - Server.extract_servers(provider, p, env, body, user, Devops::Db.connector) + Server.extract_servers(provider, p, env, body, user) end def pause_server node_name diff --git a/devops-service/app/api2/handlers/user.rb b/devops-service/app/api2/handlers/user.rb index 4e875d9..356755c 100644 --- a/devops-service/app/api2/handlers/user.rb +++ b/devops-service/app/api2/handlers/user.rb @@ -10,7 +10,7 @@ module Devops set_parser Devops::API2_0::Parser::UserParser def users - Devops::Db.connector.users({}, {password: false}) + Devops::Db.connector.users({}, fields: {password: false}) end def create diff --git a/devops-service/app/api2/helpers/parser.rb b/devops-service/app/api2/helpers/parser.rb new file mode 100644 index 0000000..ebf0d5e --- /dev/null +++ b/devops-service/app/api2/helpers/parser.rb @@ -0,0 +1,73 @@ +require "json" +require "exceptions/parser_error" +require "exceptions/validation_error" + +module Devops + module API2_0 + module ParserHelpers + + 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 ::JSON::ParserError => e + DevopsLogger.logger.error e.message + raise Devops::ParserError.new("Invalid JSON: #{e.message}") + end + raise Devops::ParserError.new("Invalid JSON, it should be an #{type == Array ? "array" : "object"}") unless @body_json.is_a?(type) + @body_json + end + + def check_provider provider + list = ::Provider::ProviderFactory.providers + raise Devops::ValidationError.new("Invalid provider '#{provider}', available providers: '#{list.join("', '")}'") unless list.include?(provider) + 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| raise Devops::ValidationError.new(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 " + raise Devops::ValidationError.new(msg, json_resp) +=begin + if json_resp + halt_response(msg) + else + halt(400, msg) + end +=end + end + file_name + end + + def check_param val, type, msg, _nil=false, empty=false + if val.nil? + if _nil + return val + else + raise Devops::ValidationError.new(msg) + end + end + if val.is_a?(type) + raise Devops::ValidationError.new(msg) if val.empty? and !empty + val + else + raise Devops::ValidationError.new(msg) + end + end + + end + end +end + diff --git a/devops-service/app/api2/helpers/version_2.rb b/devops-service/app/api2/helpers/version_2.rb index c201032..3e301c9 100644 --- a/devops-service/app/api2/helpers/version_2.rb +++ b/devops-service/app/api2/helpers/version_2.rb @@ -8,6 +8,8 @@ module Devops module API2_0 module Helpers + include Sinatra::JSON + def create_response msg, obj=nil, rstatus=200 logger.info(msg) status rstatus @@ -22,7 +24,6 @@ module Devops end def check_privileges cmd, p - # somewhy REMOTE_USER is missing user = request.env['USER'] user.check_privileges(cmd, p) end @@ -32,59 +33,6 @@ module Devops 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 ::JSON::ParserError => e - logger.error e.message - halt_response("Invalid JSON: #{e.message}") - 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? diff --git a/devops-service/app/api2/parsers/project.rb b/devops-service/app/api2/parsers/project.rb index fcdb4e6..98a6886 100644 --- a/devops-service/app/api2/parsers/project.rb +++ b/devops-service/app/api2/parsers/project.rb @@ -1,3 +1,4 @@ +require "app/api2/helpers/version_2" require_relative "request_parser" module Devops @@ -5,6 +6,22 @@ module Devops module Parser class ProjectParser < RequestParser + include Devops::API2_0::Helpers + + def projects + fields = [] + if @params.key?("fields") and @params["fields"].is_a?(Array) + Devops::Model::Project.fields.each do |k| + fields.push k if @params["fields"].include?(k) + end + end + fields + end + + def archived_projects + @params.include?("archived") + end + def project_servers @params[:deploy_env] end diff --git a/devops-service/app/api2/parsers/request_parser.rb b/devops-service/app/api2/parsers/request_parser.rb index 40a4d55..621a69f 100644 --- a/devops-service/app/api2/parsers/request_parser.rb +++ b/devops-service/app/api2/parsers/request_parser.rb @@ -1,11 +1,11 @@ -require "app/api2/helpers/version_2" +require "app/api2/helpers/parser" module Devops module API2_0 module Parser class RequestParser - include Devops::API2_0::Helpers + include Devops::API2_0::ParserHelpers def initialize request @request = request @@ -20,6 +20,10 @@ module Devops @request end + def body + @params + end + end end end diff --git a/devops-service/app/api2/routes/deploy.rb b/devops-service/app/api2/routes/deploy.rb index 7c86474..496bbf8 100644 --- a/devops-service/app/api2/routes/deploy.rb +++ b/devops-service/app/api2/routes/deploy.rb @@ -16,15 +16,14 @@ module Devops # { # "names": [], -> array of servers names to run chef-client # "tags": [], -> array of tags to apply on each server before running chef-client - # "build_number": "", -> string, build number to deploy - # "trace": true -> return output in stream if true + # "build_number": "" -> string, build number to deploy # } # # * *Returns* : text stream app.post_with_headers "/deploy", :headers => [:content_type] do check_privileges("server", "x") - if r.key?("trace") + if request["X-Stream"] stream() do |out| status = [] begin diff --git a/devops-service/app/api2/routes/project.rb b/devops-service/app/api2/routes/project.rb index 24e1847..b8aa929 100644 --- a/devops-service/app/api2/routes/project.rb +++ b/devops-service/app/api2/routes/project.rb @@ -321,6 +321,7 @@ module Devops # * *Request* # - method : POST # - headers : + # - X-Stream: true -> return output in text stream # - Content-Type: application/json # - body : # { @@ -334,7 +335,7 @@ module Devops app.post_with_headers "/project/:id/deploy", :headers => [:content_type] do |project| check_privileges("project", "x") handler = Devops::API2_0::Handler::Project.new(request) - if obj.key?("trace") + if request["X-Stream"] stream() do |out| begin status = handler.deploy_project_stream out, project diff --git a/devops-service/app/api2/routes/report.rb b/devops-service/app/api2/routes/report.rb index 155e150..461c36f 100644 --- a/devops-service/app/api2/routes/report.rb +++ b/devops-service/app/api2/routes/report.rb @@ -19,7 +19,7 @@ module Devops app.get_with_headers "/report/:id", headers: [:accept] do |id| @text, @done = Devops::API2_0::Handler::Report.new(request).report(id) - erb :index + erb :report end app.get "/status/:id" do |id| @@ -36,26 +36,3 @@ module Devops end end -__END__ - -@@ layout - - - <% unless @done %> - - <% end %> - - - <%= yield %> - - - -@@ index -
-<%= @text %>
-
diff --git a/devops-service/app/api2/routes/server.rb b/devops-service/app/api2/routes/server.rb index 69afbad..b384eeb 100644 --- a/devops-service/app/api2/routes/server.rb +++ b/devops-service/app/api2/routes/server.rb @@ -132,6 +132,7 @@ module Devops # * *Request* # - method : POST # - headers : + # - X-Stream: true -> return output in text stream # - Accept: application/json # - Content-Type: application/json # - body : @@ -142,15 +143,14 @@ module Devops # "without_bootstrap": null, -> do not install chef on instance if true # "force": null, -> do not delete server on error # "groups": [], -> specify special security groups, overrides value from project env - # "key": "ssh key", -> specify ssh key for server, overrides value from project env - # "trace": true -> return output in stream + # "key": "ssh key" -> specify ssh key for server, overrides value from project env # } # # * *Returns* : text stream - app.post_with_headers "/server", :headers => [:content_type] do + app.post_with_headers "/server", :headers => [:accept, :content_type] do check_privileges("server", "w") handler = Devops::API2_0::Handler::Server.new(request) - if body.key?("trace") + if request["X-Stream"] stream() do |out| begin status = handler.create_server_stream out @@ -249,6 +249,7 @@ module Devops # * *Request* # - method : POST # - headers : + # - X-Stream: true -> return output in text stream # - Accept: application/json # - Content-Type: application/json # - body : @@ -264,7 +265,7 @@ module Devops check_privileges("server", "w") handler = Devops::API2_0::Handler::Server.new(request) - if body.key?("trace") + if request["X-Stream"] stream() do |out| begin status = handler.bootstrap_server_stream out diff --git a/devops-service/app/api2/routes/v2.0.rb b/devops-service/app/api2/routes/v2.0.rb index f39a344..a8cd0de 100644 --- a/devops-service/app/api2/routes/v2.0.rb +++ b/devops-service/app/api2/routes/v2.0.rb @@ -9,6 +9,8 @@ require "exceptions/invalid_record" require "exceptions/record_not_found" require "exceptions/dependency_error" require "exceptions/conflict_exception" +require "exceptions/parser_error" +require "exceptions/validation_error" require 'core/devops-logger' require_relative "../helpers/version_2" @@ -39,8 +41,9 @@ module Devops logger = DevopsLogger.create(log_file, Logger::DEBUG) use Rack::CommonLogger, logger disable :raise_errors - # disable :dump_errors - set :show_exceptions, :after_handler + #set :show_exceptions, :after_handler + set :show_exceptions, false + #set :dump_errors, false logger.info "Development mode" end @@ -48,6 +51,18 @@ module Devops "Not found" end + error Devops::ValidationError do + e = env["sinatra.error"] + #logger.warn e.message + halt_response(e.message, 400) + end + + error Devops::ParserError do + e = env["sinatra.error"] + #logger.warn e.message + halt_response(e.message, 400) + end + error RecordNotFound do e = env["sinatra.error"] logger.warn e.message diff --git a/devops-service/app/api2/routes/views/report.erb b/devops-service/app/api2/routes/views/report.erb new file mode 100644 index 0000000..a0d27c0 --- /dev/null +++ b/devops-service/app/api2/routes/views/report.erb @@ -0,0 +1,18 @@ + + + <% unless @done %> + + <% end %> + + +
+      <%= @text %>
+    
+ + + diff --git a/devops-service/db/mongo/connectors/user.rb b/devops-service/db/mongo/connectors/user.rb index bf83e69..526839d 100644 --- a/devops-service/db/mongo/connectors/user.rb +++ b/devops-service/db/mongo/connectors/user.rb @@ -17,10 +17,10 @@ module Connectors model_from_bson(u) end - def users(ids=nil) + def users(ids=nil, options={}) query = {} query['_id'] = {'$in' => ids} if ids.is_a?(Array) - list(query) + list(query, options) end def users_names(ids=nil) diff --git a/devops-service/exceptions/parser_error.rb b/devops-service/exceptions/parser_error.rb new file mode 100644 index 0000000..3afda7a --- /dev/null +++ b/devops-service/exceptions/parser_error.rb @@ -0,0 +1,4 @@ +module Devops + class ParserError < Exception + end +end diff --git a/devops-service/exceptions/validation_error.rb b/devops-service/exceptions/validation_error.rb new file mode 100644 index 0000000..9f275e9 --- /dev/null +++ b/devops-service/exceptions/validation_error.rb @@ -0,0 +1,12 @@ +module Devops + class ValidationError < Exception + + attr_accessor :json + + def initialize msg, json=true + super(msg) + json = json + end + end + +end diff --git a/devops-service/providers/openstack.rb b/devops-service/providers/openstack.rb index 95fd1f5..8e74171 100644 --- a/devops-service/providers/openstack.rb +++ b/devops-service/providers/openstack.rb @@ -1,3 +1,4 @@ +require "chef/json_compat" require "providers/base_provider" module Provider diff --git a/devops-service/sinatra/methods_with_headers.rb b/devops-service/sinatra/methods_with_headers.rb index aeafdf9..45ce393 100644 --- a/devops-service/sinatra/methods_with_headers.rb +++ b/devops-service/sinatra/methods_with_headers.rb @@ -6,7 +6,6 @@ module Sinatra class Base class << self - # TODO: add protect! method def get_with_headers path, opt={}, &block headers = opt.delete(:headers) || [] before path do diff --git a/devops-service/workers/create_server_worker.rb b/devops-service/workers/create_server_worker.rb index 26bc3f0..e9892e2 100644 --- a/devops-service/workers/create_server_worker.rb +++ b/devops-service/workers/create_server_worker.rb @@ -12,9 +12,10 @@ class CreateServerWorker < Worker include ServerCommands def perform(dir, e_provider, server, owner, conf) + logger.info "Create server" call(conf, e_provider, dir) do |provider, out, file| mongo = Devops::Db.connector - s = Server.new(server) + s = Devops::Model::Server.new(server) s.options = convert_config(server["options"]) o = { "file" => file, @@ -22,9 +23,9 @@ class CreateServerWorker < Worker "created_by" => owner, "project" => s.project, "deploy_env" => s.deploy_env, - "type" => Report::SERVER_TYPE + "type" => Devops::Model::Report::SERVER_TYPE } - mongo.save_report(Report.new(o)) + mongo.save_report(Devops::Model::Report.new(o)) status = create_server_proc.call(out, s, provider) status diff --git a/devops-service/workers/worker.rb b/devops-service/workers/worker.rb index 73b8ddc..db21c27 100644 --- a/devops-service/workers/worker.rb +++ b/devops-service/workers/worker.rb @@ -52,7 +52,7 @@ class Worker begin Devops::Db.init unless e_provider.nil? - ::Provider::ProviderFactory.init(config) + ::Provider::ProviderFactory.init(DevopsConfig.config) provider = ::Provider::ProviderFactory.get(e_provider) end rescue Exception => e