diff --git a/devops-client/lib/devops-client.rb b/devops-client/lib/devops-client.rb index 9c581eb..dc13200 100644 --- a/devops-client/lib/devops-client.rb +++ b/devops-client/lib/devops-client.rb @@ -12,14 +12,12 @@ module DevopsClient DEVOPS_HOME = "#{ENV["HOME"]}/.devops/" # properties file key=value @@config_file = File.join(DEVOPS_HOME, "devops-client.conf") - #CONFIG_FILE="#{ENV["HOME"]}/.devops/devops-client.conf" def self.config_file @@config_file end def self.run - DevopsClient::get_config_file_option config = DevopsClient::read_config(@@config_file) @@ -55,7 +53,7 @@ module DevopsClient puts e.message exit(11) rescue NotFound => e - puts "Not found: #{e.message}" + puts e.message exit(12) rescue InvalidQuery => e puts "Invalid query: #{e.message}" @@ -109,7 +107,7 @@ module DevopsClient def self.set_default_config file locales = I18n.locales - config = {:api => "v2.0", :locale => "en"} + config = {:api => "v3", :locale => "en"} I18n.language = config[:locale] puts I18n.t("log.warn", :msg => I18n.t("config.not_exist", :file => file)) config[:locale] = begin diff --git a/devops-client/lib/devops-client/handler/bootstrap_templates.rb b/devops-client/lib/devops-client/handler/bootstrap_templates.rb deleted file mode 100644 index 65a4df5..0000000 --- a/devops-client/lib/devops-client/handler/bootstrap_templates.rb +++ /dev/null @@ -1,29 +0,0 @@ -require "devops-client/handler/handler" -require "devops-client/options/bootstrap_templates_options" -require "json" -require "devops-client/output/bootstrap_templates" - -class BootstrapTemplates < Handler - - output_with Output::BootstrapTemplates - - def initialize(host, def_options={}) - @host, @options = host, def_options - @options_parser = BootstrapTemplatesOptions.new(ARGV, def_options) - end - - def handle - case ARGV[1] - when "list" - @options, @args = @options_parser.parse_options_for!(:list) - list_handler - output - end - end - - def list_handler - @list = get("/templates") - end - -end - diff --git a/devops-client/lib/devops-client/handler/category.rb b/devops-client/lib/devops-client/handler/category.rb new file mode 100644 index 0000000..5ed390e --- /dev/null +++ b/devops-client/lib/devops-client/handler/category.rb @@ -0,0 +1,232 @@ +require "devops-client/handler/handler" +require "devops-client/handler/helpers/validators" +require "devops-client/options/category_options" +require "set" +require "devops-client/output/category" + +class Category < Handler + + output_with Output::Category + + def initialize(host, def_options={}) + @host = host + @options = def_options + end + + def handle + @options_parser = CategoryOptions.new(ARGV, @options) + @command, @options, @args = @options_parser.parse_options_for! + extract_parameters + case @command + when :create + create_handler + when :delete + delete_handler + when :deploy + deploy_handler + when :list + list_handler + output(project: @project_id, env: @environment) + when :servers_list + servers_handler + output(project: @project_id, env: @environment) + when :stacks + stacks_handler + output + when :set_run_list + set_run_list_handler + when :show + show_handler + output(project: @project_id, env: @environment, cat: @category) + when :update + update_handler + when :servers_delete + delete_servers_handler + end + end + + def list_handler + @list = get "/project/#{@project_id}/environment/#{@environment}/categories" + end + + def delete_handler + delete "/project/#{@project_id}/environment/#{@environment}/category/#{@category}" if question(I18n.t("handler.category.question.delete", env: @environment, cat: @category, project: @project_id)) + end + + def show_handler + @show = get("/project/#{@project_id}/environment/#{@environment}/category/#{@category}") + end + + def update_handler args + r = inspect_parameters @options_parser.update_params, args[2], args[3] + unless r.nil? + @options_parser.invalid_update_command + abort(r) + end + update_object_from_file "project", args[2], args[3] + end + + def create_handler + file = self.options[:file] + json = nil + unless file.nil? + json = File.read(file) + begin + JSON.parse(json) + rescue JSON::ParserError => e + abort(I18n.t("handler.category.create.invalid_json", :file => file)) + end + else + cat = create_category + json = JSON.pretty_generate(cat) + end + post_body("/project/#{@project_id}/environment/#{@environment}/category", json) if question(I18n.t("handler.category.question.create")){puts json} + end + + def servers_handler + @list = get "/project/#{@project_id}/environment/#{@environment}/servers" + end + + def stacks_handler + @list = get "/project/#{@project_id}/environment/#{@environment}/stacks" + end + + def set_run_list_handler + run_list = @run_list || [] + if run_list.empty? + exit unless question(I18n.t("handler.project.question.run_list.empty")) + else + exit unless Validators.validate_run_list(run_list) + end + + post "/project/#{@project_id}/environment/#{@environment}/run_list", run_list + end + + def deploy_handler args + q = {} + q[:servers] = options[:servers] unless options[:servers].nil? + job_ids = post "/project/#{args[2]}/deploy", q + reports_urls(job_ids) + end + + def test_handler args + r = inspect_parameters @options_parser.test_params, args[2], args[3] + unless r.nil? + @options_parser.invalid_test_command + abort(r) + end + job_ids = post "/project/test/#{args[2]}/#{args[3]}" + reports_urls(job_ids) + end + +protected + def get_project_info_obj project_id + get("/project/#{project_id}") + end + + def create_category + cat = {id: @category, provider: {}, cm_tool: {}} + + case (self.options[:provider] || resources_selector.select_available_provider) + when 'static' + create_static_category_provider(cat[:provider]) + when 'aws' + create_aws_category_provider(cat[:provider]) + end + fill_configuration_manager_tool(cat[:cm_tool]) + cat + end + + def create_static_category_provider cat_provider + fill_category_provider("static", cat_provider) + end + + def create_aws_category_provider cat_provider + fill_category_provider("aws", cat_provider) + cat_provider[:type] = choose_item_from_list(I18n.t('headers.category_type'), %w(server stack)) + if cat_provider[:type] == 'server' + fill_category_cloud_provider cat_provider do + cat_provider[:vpc_id] = self.options[:vpc_id] || resources_selector.select_available_vpc(provider: cat_provider[:name], account: cat_provider[:account]) + cat_provider[:subnet] = self.options[:subnet] || resources_selector.select_available_network(provider: cat_provider[:name], account: cat_provider[:account], vpc_id: cat_provider[:vpc_id]) + end + else + cat_provider[:stack_template] = self.options[:stack_template] || resources_selector.select_available_stack_template(provider: 'aws') + end + end + + def fill_category_provider provider_name, cat_provider + cat_provider[:name] = provider_name + cat_provider[:account] = self.options[:account] || resources_selector.select_available_provider_account(cat_provider[:name])["account_name"] + end + + def fill_category_cloud_provider cat_provider + cat_provider[:flavor] = self.options[:flavor] || resources_selector.select_available_flavor(provider: cat_provider[:name], account: cat_provider[:account]) + cat_provider[:image] = self.options[:image] || resources_selector.select_available_image(provider: cat_provider[:name], account: cat_provider[:account]) + yield + cat_provider[:security_groups] = self.options[:security_groups] || resources_selector.select_available_security_groups(provider: cat_provider[:name], account: cat_provider[:account], vpc_id: cat_provider[:vpc_id]) +#TODO cat_provider[:stack_template] = self.options[:stack_template] || resources_selector.select_available_stack_template(provider: cat_provider[:name], account: cat_provider[:account]) + end + + def set_identifier d, names + set_parameter d, :id do + begin + n = enter_parameter I18n.t("handler.environment.create.id") + ": " + if names.include?(n) + puts I18n.t("handler.environment.create.id_exists", :env => n) + raise ArgumentError + else + names.push n + n + end + rescue ArgumentError + retry + end + end + end + + def set_parameter obj, key + if self.options[key].nil? + obj[key] = yield + else + obj[key] = self.options[key] + end + end + + def data_to_output + @list || @show || @test + end + + def delete_servers_handler + ask_for_delete_servers(@project_id, @environment) + body = { + dry_run: false + } + response = post("/project/#{@project_id}/environment/#{@environment}/servers/delete", body) + reports_urls(response['reports']) + end + + def fill_configuration_manager_tool tool + tool[:name] = "chef" + tool[:bootstrap_template] = self.options[:bootstrap_template] || resources_selector.select_available_bootstrap_template + tool[:chef_env] = enter_parameter(I18n.t('handler.category.create.chef_env')) + end + private + + def ask_for_delete_servers(project, env) + body = { + dry_run: true + } + to_delete = post("/project/#{project}/environment/#{env}/servers/delete", body) + if to_delete.empty? + abort "There are no servers to delete." + else + puts "Servers to delete:\n----\n" + puts to_delete.join("\n") + puts '----' + end + if @options[:dry_run] || !question('Are you sure to delete them') + abort + end + end + +end diff --git a/devops-client/lib/devops-client/handler/chef.rb b/devops-client/lib/devops-client/handler/chef.rb new file mode 100644 index 0000000..49db406 --- /dev/null +++ b/devops-client/lib/devops-client/handler/chef.rb @@ -0,0 +1,36 @@ +require "devops-client/handler/handler" +require "devops-client/options/chef_options" +require "json" +require "devops-client/output/chef" + +class Chef < Handler + + output_with Output::Chef + + def initialize(host, def_options={}) + @host, @options = host, def_options + @options_parser = ChefOptions.new(ARGV, def_options) + end + + def handle + @command, @options, @args = @options_parser.parse_options_for! + extract_parameters + case @command + when :bootstrap_templates + bootstrap_templates_handler + when :tags_list + tags_list_handler + end + output + end + + def bootstrap_templates_handler + @list = get("/chef/bootstrap_templates") + end + + def tags_list_handler + @list = get("/chef/tags/#{@cm_name}") + end + +end + diff --git a/devops-client/lib/devops-client/handler/deploy_envs/deploy_env.rb b/devops-client/lib/devops-client/handler/deploy_envs/deploy_env.rb index 7994799..ebbcbc6 100644 --- a/devops-client/lib/devops-client/handler/deploy_envs/deploy_env.rb +++ b/devops-client/lib/devops-client/handler/deploy_envs/deploy_env.rb @@ -71,14 +71,6 @@ class DeployEnv d[:users] = d[:users].to_a end - def self.validate_run_list run_list - return true if run_list.empty? - rl = /\Arole|recipe\[[\w-]+(::[\w-]+)?\]\Z/ - e = run_list.select {|l| (rl =~ l).nil?} - res = e.empty? - puts I18n.t("handler.project.create.run_list.invalid", :list => e.join(", ")) unless res - res - end private diff --git a/devops-client/lib/devops-client/handler/environment.rb b/devops-client/lib/devops-client/handler/environment.rb new file mode 100644 index 0000000..a5f86a4 --- /dev/null +++ b/devops-client/lib/devops-client/handler/environment.rb @@ -0,0 +1,239 @@ +require "devops-client/handler/handler" +require "devops-client/handler/helpers/validators" +require "devops-client/options/environment_options" +require "set" +require "devops-client/output/environment" + +class Environment < Handler + + output_with Output::Environment + + def initialize(host, def_options={}) + @host = host + @options = def_options + @options_parser = EnvironmentOptions.new(ARGV, def_options) + end + + def handle + @command, @options, @args = @options_parser.parse_options_for! + extract_parameters + case @command + when :create + create_handler + when :delete + delete_handler + when :deploy + deploy_handler + when :list + list_handler + output(project: @project_id) + when :servers_list + servers_handler + output + when :stacks + stacks_handler + output + when :set_run_list + set_run_list_handler + when :show + show_handler + output(project: @project_id, env: @environment) + when :update + update_handler + when :user_add + user_add_handler + when :user_delete + user_delete_handler + when :servers_delete + delete_servers_handler + end + end + + def list_handler + @list = get "/project/#{@project_id}/environments" + end + + def delete_handler + if question(I18n.t("handler.project.question.delete", name: @environment)) + delete "/project/#{@project_id}/environment/#{@environment}" + end + end + + def show_handler + @show = get("/project/#{@project_id}/environment/#{@environment}") + end + + def update_handler args + update_object_from_file "project", args[2], args[3] + end + + def create_handler + file = self.options[:file] + json = nil + unless file.nil? + json = File.read(file) + begin + JSON.parse(json) + rescue JSON::ParserError => e + abort(I18n.t("handler.environment.create.invalid_json", :file => file)) + end + else + json = JSON.pretty_generate(create_environment) + end + post_body("/project/#{@project_id}/environment", json) if question(I18n.t("handler.environment.question.create")){puts json} + end + + def servers_handler + @list = get "/project/#{@project_id}/environment/#{@environment}/servers" + end + + def stacks_handler + @list = get "/project/#{@project_id}/environment/#{@environment}/stacks" + end + + def user_add_handler + project = get_project_info_obj(@project_id) + users = environment_users(project) + post "/project/#{@project_id}/environment/#{@environment}/users/add", users + end + + def user_delete_handler + post "/project/#{@project_id}/environment/#{@environment}/users/delete", @users + end + + def set_run_list_handler + run_list = @run_list || [] + if run_list.empty? + exit unless question(I18n.t("handler.project.question.run_list.empty")) + else + exit unless Validators.validate_run_list(run_list) + end + + post "/project/#{@project_id}/environment/#{@environment}/run_list", run_list + end + + def deploy_handler args + r = inspect_parameters @options_parser.deploy_params, args[2], args[3] + unless r.nil? + @options_parser.invalid_deploy_command + abort(r) + end + q = {} + q[:servers] = options[:servers] unless options[:servers].nil? + q[:deploy_env] = args[3] unless args[3].nil? + job_ids = post "/project/#{args[2]}/deploy", q + reports_urls(job_ids) + end + + def test_handler args + r = inspect_parameters @options_parser.test_params, args[2], args[3] + unless r.nil? + @options_parser.invalid_test_command + abort(r) + end + job_ids = post "/project/test/#{args[2]}/#{args[3]}" + reports_urls(job_ids) + end + +protected + def get_project_info_obj project_id + get("/project/#{project_id}") + end + + def create_environment + project = get_project_info_obj(@project_id) + names = project["environments"].map{|env| env["id"]} + abort(I18n.t("handler.environment.create.id_exists")) if names.include?(@environment) + e = {categories: [], id: @environment} +# set_identifier(e, names) + + e[:run_list] = if self.options[:run_list] + abort("Invalid run list: '#{self.options[:run_list].join(",")}'") unless Validators.validate_run_list(self.options[:run_list]) + self.options[:run_list] + else + input_run_list + end + + e[:users] = environment_users(project) + + unless self.options[:no_expires] + set_parameter e, :expires do + s = enter_parameter_or_empty(I18n.t("options.project.create.expires") + ": ").strip + s.empty? ? nil : s + end + end + e + end + + def environment_users project + if self.options[:users] + self.options[:users] + else + if question(I18n.t("handler.project.create.question.users_choose")) + #choose + resources_selector.select_available_users(label: I18n.t("handler.project.create.users"), data: project["project_users"] + [project["owner"]]) + else + #enter + get_comma_separated_list(I18n.t("input.message.input_list", cmd: I18n.t("input.user.list"))) + end + end + end + + def set_identifier d, names + set_parameter d, :id do + begin + n = enter_parameter I18n.t("handler.environment.create.id") + ": " + if names.include?(n) + puts I18n.t("handler.environment.create.id_exists", :env => n) + raise ArgumentError + else + names.push n + n + end + rescue ArgumentError + retry + end + end + end + + def set_parameter obj, key + if self.options[key].nil? + obj[key] = yield + else + obj[key] = self.options[key] + end + end + + def data_to_output + @list || @show || @test + end + + def delete_servers_handler + ask_for_delete_servers(@project_id, @environment) + body = { + dry_run: false + } + response = post("/project/#{@project_id}/environment/#{@environment}/servers/delete", body) + reports_urls(response['reports']) + end + + private + + def ask_for_delete_servers(project, env) + body = { + dry_run: true + } + to_delete = post("/project/#{project}/environment/#{env}/servers/delete", body) + if to_delete.empty? + abort "There are no servers to delete." + else + puts "Servers to delete:\n----\n" + puts to_delete.join("\n") + puts '----' + end + if @options[:dry_run] || !question('Are you sure to delete them') + abort + end + end + +end diff --git a/devops-client/lib/devops-client/handler/filter.rb b/devops-client/lib/devops-client/handler/filter.rb index 45a5fbc..1a2010f 100644 --- a/devops-client/lib/devops-client/handler/filter.rb +++ b/devops-client/lib/devops-client/handler/filter.rb @@ -8,57 +8,29 @@ class Filter < Handler output_with Output::Filters def initialize(host, def_options) - self.host = host + @host, @options = host, def_options @options_parser = FilterOptions.new(ARGV, def_options) end def handle - case ARGV[1] - when "image" - provider = ARGV[3] - case ARGV[2] - when "list" - self.options = @options_parser.image_list_options - check_provider provider - @list = get("/filter/#{provider}/images") + @command, @options, @args = @options_parser.parse_options_for! + extract_parameters + case @command + when :image_list + @list = get("/filter/#{@provider}/images") output - when "add" - self.options = @options_parser.image_add_options - check_provider provider - @list = put_body("/filter/#{provider}/image", get_images(ARGV).to_json) + when :image_add + @list = post_body("/filter/#{@provider}/images/add", @image.to_json) @list = @list["images"] unless @list.nil? output - when "delete" - self.options = @options_parser.image_delete_options - check_provider provider - images = get_images(ARGV) - if question(I18n.t("handler.filter.question.delete", :name => images.join("', '"))) - @list = delete_body("/filter/#{provider}/image", images.to_json) + when :image_delete + if question(I18n.t("handler.filter.question.delete", :name => @image.join("', '"))) + @list = post_body("/filter/#{@provider}/images/delete", @image.to_json) @list = @list["images"] unless @list.nil? output end - else - @options_parser.invalid_image_command - abort("Invalid image parameter: #{ARGV[2]}, it should be 'add' or 'delete' or 'list'") - end end end - def check_provider provider - if provider != "ec2" and provider != "openstack" - @options_parser.invalid_image_command - abort("Invalid image parameter: provider '#{provider}', it should be 'ec2' or 'openstack'") - end - end - - def get_images args - images = args[4..-1] - if images.empty? - @options_parser.invalid_image_command - abort("Images list is empty") - end - images - end - end diff --git a/devops-client/lib/devops-client/handler/flavor.rb b/devops-client/lib/devops-client/handler/flavor.rb deleted file mode 100644 index a39d0e4..0000000 --- a/devops-client/lib/devops-client/handler/flavor.rb +++ /dev/null @@ -1,34 +0,0 @@ -require "devops-client/handler/handler" -require "devops-client/options/flavor_options" -require "json" -require "devops-client/output/flavors" - -class Flavor < Handler - - output_with Output::Flavors - - def initialize(host, def_options={}) - @host, @options = host, def_options - @options_parser = FlavorOptions.new(ARGV, def_options) - end - - def handle - case ARGV[1] - when "list" - @options, @args = @options_parser.parse_options_for!(:list) - list_handler - output - end - end - - def list_handler(provider=nil) - provider ||= @args[2] - r = inspect_parameters @options_parser.list_params, provider - unless r.nil? - @options_parser.invalid_list_command - abort(r) - end - @list = get("/flavors/#{provider}").sort!{|x,y| x["id"] <=> y["id"]} - end - -end diff --git a/devops-client/lib/devops-client/handler/group.rb b/devops-client/lib/devops-client/handler/group.rb deleted file mode 100644 index 87c87ff..0000000 --- a/devops-client/lib/devops-client/handler/group.rb +++ /dev/null @@ -1,35 +0,0 @@ -require "devops-client/handler/handler" -require "devops-client/options/group_options" -require "json" -require "devops-client/output/groups" - -class Group < Handler - - output_with Output::Groups - - def initialize(host, def_options={}) - @host, @options = host, def_options - @options_parser = GroupOptions.new(ARGV, def_options) - end - - def handle - case ARGV[1] - when "list" - @options, @args = @options_parser.parse_options_for!(:list) - list_handler(@args[2], @args[3]) - output - end - end - - def list_handler(provider=nil, vpc_id=nil) - r = inspect_parameters @options_parser.list_params, provider - unless r.nil? - @options_parser.invalid_list_command - abort(r) - end - p = {} - p["vpc-id"] = vpc_id unless vpc_id.nil? - @list = get("/groups/#{provider}", p) - end - -end diff --git a/devops-client/lib/devops-client/handler/handler.rb b/devops-client/lib/devops-client/handler/handler.rb index cfd75d3..adaca3d 100644 --- a/devops-client/lib/devops-client/handler/handler.rb +++ b/devops-client/lib/devops-client/handler/handler.rb @@ -23,7 +23,7 @@ class Handler attr_reader :options attr_writer :host - attr_accessor :auth + attr_accessor :auth, :command def host if @host.start_with?('http') @@ -35,11 +35,11 @@ class Handler #TODO: only basic auth now def username - self.options[:username] || self.auth[:username] + self.auth[:username] end def password - self.options[:password] || self.auth[:password] + self.auth[:password] end def options= o @@ -57,13 +57,36 @@ protected @fetcher ||= Helpers::ResourcesFetcher.new(host: @host, handler_options: @options, auth: @auth) end - - def inspect_parameters names, *args + # Parameters + # PARAM - mandatory parameter, will be available by variable @param + # [PARAM] - not mandatory parameter, will be available by variable @param (can be nil) + # PARAM... - mandatory parameters, will be available by variable @param, it is array with one or more elements + # [PARAM...] - not mandatory parameters, will be available by variable @param, it is array with one or more elements or nil + def extract_parameters + cmd = @command + names = @options_parser.send("#{cmd}_params") + return unless names names.each_with_index do |name, i| - next if name.start_with? "[" and name.end_with? "]" - if args[i].nil? or args[i].empty? - return "\n" + I18n.t("handler.error.parameter.undefined", :name => name) + if name.start_with? "[" and name.end_with? "]" + param_name = name.delete("[]") + if param_name.end_with? "..." + param_name = param_name.delete(".") + instance_variable_set "@" + param_name.downcase, @args[i..-1] + return + end + elsif name.end_with? "..." + param_name = name.delete(".") + instance_variable_set "@" + param_name.downcase, @args[i..-1] + return + else + if @args[i].nil? or @args[i].empty? + @options_parser.send("invalid_#{cmd}_command") + res = "\n" + I18n.t("handler.error.parameter.undefined", :name => name) + abort(res) + end + param_name = name end + instance_variable_set "@" + param_name.downcase, @args[i] end nil end @@ -78,8 +101,4 @@ protected end end - def current_command - ARGV[1].to_sym if ARGV[1] - end - end diff --git a/devops-client/lib/devops-client/handler/handler_factory.rb b/devops-client/lib/devops-client/handler/handler_factory.rb index 03ac0a4..572c31f 100644 --- a/devops-client/lib/devops-client/handler/handler_factory.rb +++ b/devops-client/lib/devops-client/handler/handler_factory.rb @@ -1,57 +1,55 @@ +require "devops-client/options/main" + class HandlerFactory def self.create cmd, host, auth, def_options klass = case cmd - when "flavor" - require "devops-client/handler/flavor" - Flavor - when "image" + when ImageOptions::COMMAND_NAME require "devops-client/handler/image" Image - when "filter" + when FilterOptions::COMMAND_NAME require "devops-client/handler/filter" Filter - when "group" - require "devops-client/handler/group" - Group - when "deploy" + when DeployOptions::COMMAND_NAME require "devops-client/handler/deploy" Deploy - when "project" + when ProjectOptions::COMMAND_NAME require "devops-client/handler/project" Project - when "network" - require "devops-client/handler/network" - Network - when "key" + when EnvironmentOptions::COMMAND_NAME + require "devops-client/handler/environment" + Environment + when CategoryOptions::COMMAND_NAME + require "devops-client/handler/category" + Category + when KeyOptions::COMMAND_NAME require "devops-client/handler/key" Key - when "user" + when UserOptions::COMMAND_NAME require "devops-client/handler/user" User - when "provider" + when ProviderOptions::COMMAND_NAME require "devops-client/handler/provider" Provider - when "tag" - require "devops-client/handler/tag" - Tag - when "server" + when ServerOptions::COMMAND_NAME require "devops-client/handler/server" Server - when "script" + when ScriptOptions::COMMAND_NAME require "devops-client/handler/script" Script - when "templates" - require "devops-client/handler/bootstrap_templates" - BootstrapTemplates - when "stack_template" + when ChefOptions::COMMAND_NAME + require "devops-client/handler/chef" + Chef + when StackTemplateOptions::COMMAND_NAME require "devops-client/handler/stack_template" StackTemplate - when "stack" + when StackOptions::COMMAND_NAME require "devops-client/handler/stack" Stack + when RoleOptions::COMMAND_NAME + require "devops-client/handler/role" + Role else - require "devops-client/options/main" Main.new(ARGV, def_options).info exit(10) end diff --git a/devops-client/lib/devops-client/handler/helpers/http_utils.rb b/devops-client/lib/devops-client/handler/helpers/http_utils.rb index 6fcaebc..29445e7 100644 --- a/devops-client/lib/devops-client/handler/helpers/http_utils.rb +++ b/devops-client/lib/devops-client/handler/helpers/http_utils.rb @@ -9,7 +9,7 @@ module HttpUtils end def get path, params={} - get_with_headers path, params, self.headers("Content-Type") + get_with_headers path, params, headers() end def get_with_headers path, params={}, headers={} @@ -108,6 +108,9 @@ module HttpUtils return (res.contenttype.include?("application/json") ? JSON.parse(res.body) : res.body) end case res.status + when 422 + puts res.body + raise InvalidQuery.new(extract_message(res)) when 404 raise NotFound.new(extract_message(res)) when 400 @@ -165,4 +168,4 @@ module HttpUtils r end -end \ No newline at end of file +end diff --git a/devops-client/lib/devops-client/handler/helpers/input_utils.rb b/devops-client/lib/devops-client/handler/helpers/input_utils.rb index 3324cbd..924c9f5 100644 --- a/devops-client/lib/devops-client/handler/helpers/input_utils.rb +++ b/devops-client/lib/devops-client/handler/helpers/input_utils.rb @@ -1,3 +1,5 @@ +require "devops-client/handler/helpers/validators" + module InputUtils def question str @@ -8,7 +10,7 @@ module InputUtils res = false #system("stty raw -echo") begin - print "#{str} (y/n): " + print "#{str}? (y/n): " s = STDIN.gets.strip if s == "y" res = true @@ -25,6 +27,17 @@ module InputUtils res end + def input_run_list + begin + run_list = get_comma_separated_list(I18n.t("input.run_list.label") + ": ") + raise ArgumentError.new(I18n.t("input.run_list.invalid", list: run_list.join(","))) unless Validators.validate_run_list(run_list) + run_list + rescue ArgumentError => e + puts e.message + retry + end + end + def choose_image_cmd images, t=nil abort(I18n.t("handler.error.list.empty", :name => "Image")) if images.empty? if options[:image_id].nil? @@ -84,7 +97,7 @@ module InputUtils puts table end begin - print "#{title}: " + print "#{I18n.t("handler.message.choose", :name => title.downcase)}: " buf = STDIN.gets.strip if buf.empty? and !default.nil? return default @@ -96,6 +109,10 @@ module InputUtils return i - 1 end + def choose_item_from_list(title, items) + items[ choose_number_from_list(title, items) ] + end + def choose_indexes_from_list title, list, table=nil, default=nil, defindex=nil abort(I18n.t("handler.error.list.empty", :name => title)) if list.empty? ar = nil @@ -111,7 +128,7 @@ module InputUtils I18n.t("handler.message.choose_list_default", :name => title, :default => default) end begin - ar = get_comma_separated_list(msg).map do |g| + ar = get_comma_separated_list(msg + ": ").map do |g| n = Integer g.strip raise ArgumentError.new(I18n.t("handler.error.number.invalid")) if n < 1 or n > list.size n @@ -125,4 +142,13 @@ module InputUtils ar.map{|i| i - 1} end + def select_item_from_table(title, items, table) + items[ choose_number_from_list(title, items, table) ] + end + + def select_items_from_table(title, items, table, options={}) + indexes = choose_indexes_from_list(title, items, table, options[:default], options[:default_index]) + items.values_at(*indexes) + end + end diff --git a/devops-client/lib/devops-client/handler/helpers/outputtable.rb b/devops-client/lib/devops-client/handler/helpers/outputtable.rb index aed1478..34dc146 100644 --- a/devops-client/lib/devops-client/handler/helpers/outputtable.rb +++ b/devops-client/lib/devops-client/handler/helpers/outputtable.rb @@ -6,7 +6,7 @@ module Outputtable def outputter raise 'You should use "output_with" method to define outputter' unless self.class.outputter_class - @outputter ||= self.class.outputter_class.new(data_to_output, options.merge(current_command: current_command)) + @outputter ||= self.class.outputter_class.new(data_to_output, options.merge(current_command: @command)) end def output(options={}) @@ -14,7 +14,7 @@ module Outputtable end def report_url(job_id) - create_url "report/#{job_id}" + create_url "task/#{job_id}/report" end def reports_urls(job_ids) @@ -24,7 +24,6 @@ module Outputtable end.join("\n") end - def self.included(base) base.extend(ClassMethods) end @@ -36,4 +35,4 @@ module Outputtable end end -end \ No newline at end of file +end diff --git a/devops-client/lib/devops-client/handler/helpers/resources_fetcher.rb b/devops-client/lib/devops-client/handler/helpers/resources_fetcher.rb index 4514741..8c381d9 100644 --- a/devops-client/lib/devops-client/handler/helpers/resources_fetcher.rb +++ b/devops-client/lib/devops-client/handler/helpers/resources_fetcher.rb @@ -25,9 +25,24 @@ module Helpers def fetch_with_table(collection_name, *args) handler = build_handler(collection_name) + handler.command = :list [handler.list_handler(*args), handler.outputter.table] end + def show_list_data_with_table(collection_name, data) + handler = build_handler(collection_name) + handler.command = :list + handler.instance_variable_set('@list', data) + [data, handler.outputter.table] + end + + def fetch_by_command_with_table(collection_name, command, args={}, options={}) + handler = build_handler(collection_name) + handler.command = command + args.each {|key, val| handler.instance_variable_set("@#{key}", val) } + return handler.send("#{command}_handler"), handler.outputter.output(options) + end + def fetch_project(project_id) @fetched_projects = {} if cached = @fetched_projects[project_id] @@ -37,12 +52,24 @@ module Helpers end end + def fetch_provider_accounts(provider) + handler = build_handler('provider') + [handler.accounts_handler(provider), handler.outputter.output(output_type: :accounts, provider: provider)] + end + + def fetch_category(project, environment_name, category) + environment = fetch_project(project)['environments'].detect do |env| + env['id'] == environment_name + end + environment['categories'].detect {|cat| cat['id'] == category } + end + private def build_handler(collection_name) require_handler_file(collection_name) - handler = resource_handler_klass(collection_name).new(host, options) + handler = resource_handler_klass(collection_name).new(host, self.options) handler.auth = @auth handler end @@ -56,4 +83,4 @@ module Helpers Object.const_get(class_name) end end -end \ No newline at end of file +end diff --git a/devops-client/lib/devops-client/handler/helpers/resources_selector.rb b/devops-client/lib/devops-client/handler/helpers/resources_selector.rb index 33d76c6..a21f558 100644 --- a/devops-client/lib/devops-client/handler/helpers/resources_selector.rb +++ b/devops-client/lib/devops-client/handler/helpers/resources_selector.rb @@ -12,10 +12,25 @@ module Helpers @fetcher = fetcher end - def select_available_provider - providers, table = @fetcher.fetch_with_table('provider') - # somewhy returns provider name as String. - select_item_from_table(I18n.t("headers.provider"), providers, table) + def select_available_provider(options={}) + providers = @fetcher.fetch('provider') + providers -= options[:except] if options[:except] + choose_item_from_list(I18n.t("headers.provider"), providers) + end + + def select_available_bootstrap_template + templates, table = @fetcher.fetch_by_command_with_table('chef', :bootstrap_templates) + select_item_from_table(I18n.t("headers.bootstrap_templates"), templates, table) + end + + def select_available_provider_account provider + accounts, table = @fetcher.fetch_by_command_with_table('provider', :accounts, {provider: provider}) + select_item_from_table(I18n.t("headers.provider_account"), accounts, table) + end + + def select_available_provider_account_image provider, provider_account + images, table = @fetcher.fetch_by_command_with_table('provider', :images, {provider: provider, account: provider_account}) + select_item_from_table(I18n.t("headers.image"), images, table) end def select_available_project @@ -37,41 +52,61 @@ module Helpers stack_template['id'] end - def select_available_flavor(options={}) - flavors, table = @fetcher.fetch_with_table('flavor', options[:provider]) - abort(I18n.t("handler.flavor.list.empty")) if flavors.empty? + def select_available_flavor(args) + flavors, table = @fetcher.fetch_by_command_with_table('provider', :flavors, args, {provider: args[:provider], account: args[:account]}) + abort(I18n.t("handler.provider.flavor.list.empty")) if flavors.empty? - flavors_descriptions = flavors.map {|f| "#{f["id"]}. #{f["name"]} - #{f["ram"]}, #{f["disk"]}, #{f["v_cpus"]} CPU"} - index = choose_number_from_list(I18n.t("headers.flavor"), flavors_descriptions, table) - - flavors[index]['id'] + select_item_from_table(I18n.t("choose.flavor"), flavors, table)["id"] end - def select_available_image(options={}) - images, table = @fetcher.fetch_with_table('image', options[:provider]) - image = select_item_from_table(I18n.t("headers.image"), images, table) - image['id'] + def select_available_image(args) + images, table = @fetcher.fetch_by_command_with_table('image', :list, args, {provider: args[:provider], account: args[:account]}) + abort(I18n.t("handler.provider.images.list.empty")) if images.empty? + + select_item_from_table(I18n.t("choose.image"), images, table)["id"] end - def select_available_network(options={}) - networks, table = @fetcher.fetch_with_table('network', options[:provider]) - table_title = options[:table_title] || I18n.t("headers.network") + def select_available_vpc(args) + vpcs, table = @fetcher.fetch_by_command_with_table('provider', :vpc, args) + abort(I18n.t("handler.provider.vpc.list.empty")) if vpcs.empty? - selected_networks = select_items_from_table(table_title, networks, table) + select_item_from_table(I18n.t("choose.vpc"), vpcs, table)["vpc_id"] + end + + def select_available_network(args, options={}) + networks, table = @fetcher.fetch_by_command_with_table('provider', :networks, args) + select_item_from_table(I18n.t("choose.network"), networks, table)["subnetId"] + end + + def select_available_networks(args) + networks, table = @fetcher.fetch_by_command_with_table('provider', :networks, args) + + selected_networks = select_items_from_table(I18n.t("choose.networks"), networks, table) selected_networks.map {|network| network['name']} end + # options: + # :data - list of strings def select_available_users(options={}) - title = options[:table_title] || I18n.t("handler.project.create.user") - users, table = @fetcher.fetch_with_table('user') + title = options[:label] || I18n.t("input.users.label") + users, table = if options[:data] + @fetcher.show_list_data_with_table('user', options[:data].map{|v| {'id' => v}}) + else + @fetcher.fetch_with_table('user') + end users = select_items_from_table(title, users, table) users.map {|user| user['id']} end - def select_available_groups(options={}) - title = options[:table_title] || I18n.t("options.project.create.groups") - groups, table = @fetcher.fetch_with_table('group', options[:provider], options[:vpc_id]) + def select_available_ssh_keys(options={}) + ssh_keys, table = @fetcher.fetch_with_table('key') + + select_item_from_table(I18n.t("choose.ssh_key"), ssh_keys, table)['id'] + end + + def select_available_security_groups(args) + groups, table = @fetcher.fetch_by_command_with_table('provider', :security_groups, args) # somewhy groups returned as a hash, not array groups_array = [] @@ -81,19 +116,22 @@ module Helpers end default_index = groups_array.index {|t| t['id'] == 'default'} - select_items_from_table(title, groups_array, table, default: 'default', default_index: default_index) + select_items_from_table(I18n.t("choose.security_groups"), groups_array, table, default: 'default', default_index: default_index).map{|g| g["id"]} end - private - - def select_item_from_table(title, items, table) - items[ choose_number_from_list(title, items, table) ] + def select_available_roles used_roles=[] + roles, table = @fetcher.fetch_with_table('role') + roles.delete_if{|role| used_roles.include?(role["id"])} unless used_roles.empty? + roles = select_items_from_table(I18n.t("headers.role"), roles, table) + roles.map{|r| r['id']} end - def select_items_from_table(title, items, table, options={}) - indexes = choose_indexes_from_list(title, items, table, options[:default], options[:default_index]) - items.values_at(*indexes) + def select_user_roles used_roles + roles, table = @fetcher.fetch_with_table('role') + roles.select{|role| used_roles.include?(role["id"])} + roles = select_items_from_table(I18n.t("headers.role"), roles, table) + roles.map{|r| r['id']} end end -end \ No newline at end of file +end diff --git a/devops-client/lib/devops-client/handler/helpers/validators.rb b/devops-client/lib/devops-client/handler/helpers/validators.rb new file mode 100644 index 0000000..862adc5 --- /dev/null +++ b/devops-client/lib/devops-client/handler/helpers/validators.rb @@ -0,0 +1,16 @@ +class Validators + + class << self + + def validate_run_list run_list + return true if run_list.empty? + rl = /\Arole|recipe\[[\w-]+(::[\w-]+)?\]\Z/ + e = run_list.select {|l| (rl =~ l).nil?} + res = e.empty? + puts I18n.t("handler.project.create.run_list.invalid", :list => e.join(", ")) unless res + res + end + + end + +end diff --git a/devops-client/lib/devops-client/handler/image.rb b/devops-client/lib/devops-client/handler/image.rb index 40c245b..054ea7f 100644 --- a/devops-client/lib/devops-client/handler/image.rb +++ b/devops-client/lib/devops-client/handler/image.rb @@ -1,22 +1,21 @@ require "devops-client/handler/handler" require "devops-client/options/image_options" require "devops-client/output/image" -require "devops-client/handler/bootstrap_templates" class Image < Handler output_with Output::Image def initialize(host, def_options={}) - # QUESTION: - # why we set @options variable here while we always reset it in #handle method? - @host, @options = host, def_options - @options_parser = ImageOptions.new(ARGV, def_options) + @host = host + @options = def_options end def handle - @options, @args = @options_parser.parse_options_for!(current_command) - case current_command + @options_parser = ImageOptions.new(ARGV, @options) + @command, @options, @args = @options_parser.parse_options_for! + extract_parameters + case @command when :list list_handler output @@ -32,109 +31,52 @@ class Image < Handler end end - def get_templates - bt = BootstrapTemplates.new(@host, self.options) - bt.auth = self.auth - list = bt.list_handler - return list, nil if list.empty? - [list, bt.outputter.table] - end - def create_handler q = {} q[:provider] = options[:provider] || resources_selector.select_available_provider + q[:provider_account] = options[:provider_account] || resources_selector.select_available_provider_account(q[:provider])["account_name"] + image = resources_selector.select_available_provider_account_image(q[:provider], q[:provider_account]) - provider_images(q[:provider]) - - # QUESTION: - # why we select image in create image handler? - image = nil - if options[:image_id].nil? - image = choose_image_cmd(@list, self.outputter.table) - else - image = @list.detect{|i| i["id"] == options[:image_id]} - abort("Invalid image id '#{options[:image_id]}'") if image.nil? - end q["name"] = image["name"] q["id"] = image["id"] + q["image_id"] = q["id"] q["remote_user"] = options[:ssh_username] || enter_parameter(I18n.t("handler.image.create.ssh_user") + ": ") - q["bootstrap_template"] = if options[:bootstrap_template].nil? and options[:no_bootstrap_template] == false - bt, bt_t = get_templates - if bt.empty? - puts I18n.t("handler.image.create.template_empty") - nil - else - # QUESTION: - # what does this '-1' mean? - i = choose_number_from_list(I18n.t("handler.image.create.template"), bt, bt_t, -1) - if i == -1 - nil - else - bt[i] - end - end - else - nil - end json = JSON.pretty_generate(q) post_body "/image", json if question(I18n.t("handler.image.question.create")){puts json} end - def list_handler(provider=nil) - provider ||= @options[:given_provider] - @list = if provider - provider_images(provider) - else - get("/images") + def list_handler + path = "/images" + params = {} + params["provider"] = @provider if @provider + params["account"] = @account if @account + unless params.empty? + path += "?" + params.map{|k,v| "#{k}=#{v}"}.join("&") end + @list = get(path) end - def provider_images provider + def provider_images provider, provider_account if provider == 'static' @options_parser.invalid_list_command abort() end - if @options[:provider_account] - @list = get("/images/provider/#{provider}/#{@options[:provider_account]}") - else - @list = get("/images/provider/#{provider}") - end + @list = get("/provider/#{provider}/account/#{provider_account}/images") end def show_handler - id = @args[2] - r = inspect_parameters @options_parser.show_params, id - unless r.nil? - @options_parser.invalid_show_command - abort(r) - end - @show = get "/image/#{id}" + @show = get "/image/#{@image}" end def delete_handler - id = @args[2] - r = inspect_parameters @options_parser.delete_params, id - unless r.nil? - @options_parser.invalid_delete_command - abort(r) - end - if question(I18n.t("handler.image.question.delete", :name => id)) - delete "/image/#{id}" - end + delete "/image/#{@image}" if question(I18n.t("handler.image.question.delete", :name => @image)) end - # QUESTION: - # what does inspect_parameters do and what do args[2] and args[3] actually mean? def update_handler - r = inspect_parameters @options_parser.update_params, @args[2], @args[3] - unless r.nil? - @options_parser.invalid_update_command - abort(r) - end - update_object_from_file "image", @args[2], @args[3] + update_object_from_file "image", @image, @file end end diff --git a/devops-client/lib/devops-client/handler/key.rb b/devops-client/lib/devops-client/handler/key.rb index 9b85043..0d339d1 100644 --- a/devops-client/lib/devops-client/handler/key.rb +++ b/devops-client/lib/devops-client/handler/key.rb @@ -13,8 +13,9 @@ class Key < Handler end def handle - @options, @args = @options_parser.parse_options_for!(current_command) - case current_command + @command, @options, @args = @options_parser.parse_options_for! + extract_parameters + case @command when :list list_handler output @@ -26,30 +27,18 @@ class Key < Handler end def add_handler - r = inspect_parameters @options_parser.add_params, @args[2], @args[3] - unless r.nil? - @options_parser.invalid_add_command - abort(r) - end - - content = File.read(@args[3]) + content = File.read(@file) q = { - "key_name" => @args[2], - "file_name" => File.basename(@args[3]), + "key_name" => @key_name, + "file_name" => File.basename(@file), "content" => content } - post "/key", q + json = JSON.pretty_generate(q) + post_body "/key", json if question(I18n.t("handler.key.question.create")){puts json} end def delete_handler - r = inspect_parameters @options_parser.delete_params, @args[2] - unless r.nil? - @options_parser.invalid_delete_command - abort(r) - end - if question(I18n.t("handler.key.question.delete", :name => @args[2])) - delete "/key/#{@args[2]}" - end + delete "/key/#{@key_name}" if question(I18n.t("handler.key.question.delete", :name => @key_name)) end def list_handler diff --git a/devops-client/lib/devops-client/handler/network.rb b/devops-client/lib/devops-client/handler/network.rb deleted file mode 100644 index 4a79e7e..0000000 --- a/devops-client/lib/devops-client/handler/network.rb +++ /dev/null @@ -1,35 +0,0 @@ -require "devops-client/handler/handler" -require "devops-client/options/network_options" -require "json" -require "devops-client/output/network" - -class Network < Handler - - output_with Output::Network - - def initialize(host, def_options={}) - @host, @options = host, def_options - @options_parser = NetworkOptions.new(ARGV, def_options) - end - - def handle - current_command = ARGV[1].to_sym - @options, @args = @options_parser.parse_options_for!(current_command) - case current_command - when :list - list_handler(@args[2]) - output - end - end - - def list_handler(provider=nil) - r = inspect_parameters @options_parser.list_params, provider - unless r.nil? - @options_parser.invalid_list_command - abort(r) - end - @list = get("/networks/#{provider}").sort!{|x,y| x["name"] <=> y["name"]} - end - -end - diff --git a/devops-client/lib/devops-client/handler/project.rb b/devops-client/lib/devops-client/handler/project.rb index c372e3a..11f38af 100644 --- a/devops-client/lib/devops-client/handler/project.rb +++ b/devops-client/lib/devops-client/handler/project.rb @@ -1,94 +1,57 @@ require "devops-client/handler/provider" require "devops-client/handler/image" -require "devops-client/handler/flavor" -require "devops-client/handler/network" -require "devops-client/handler/group" require "devops-client/handler/user" +require "devops-client/handler/helpers/validators" require "devops-client/options/project_options" require "json" require "set" require "devops-client/output/project" -require "devops-client/handler/deploy_envs/deploy_env_factory" class Project < Handler - attr_accessor :def_options output_with Output::Project def initialize(host, def_options={}) - self.host = host - self.def_options = self.options = def_options + @host = host @options_parser = ProjectOptions.new(ARGV, def_options) end def handle - case ARGV[1] - when "create" - self.options = @options_parser.create_options - create_handler @options_parser.args - when "delete" - self.options = @options_parser.delete_options - delete_handler @options_parser.args - when "deploy" - self.options = @options_parser.deploy_options - deploy_handler @options_parser.args - when "list" - self.options = @options_parser.list_options + @command, @options, @args = @options_parser.parse_options_for! + extract_parameters + case @command + when :create + create_handler + when :delete + delete_handler + when :list list_handler output - when "multi" - case ARGV[2] - when "create" - self.options = @options_parser.multi_create_options - multi_create_handler @options_parser.args - else - @options_parser.invalid_multi_command - abort(I18n.t("handler.project.invalid_subcommand", :cmd => ARGV[1], :scmd => ARGV[2])) - end - when "servers" - self.options = @options_parser.servers_options - servers_handler @options_parser.args - output(output_type: :servers) - when "stacks" - self.options = @options_parser.stacks_options - stacks_handler @options_parser.args - output(output_type: :stacks) - when "set" - case ARGV[2] - when "run_list" - self.options = @options_parser.set_run_list_options - set_run_list_handler @options_parser.args - else - @options_parser.invalid_set_command - abort(I18n.t("handler.project.invalid_subcommand", :cmd => ARGV[1], :scmd => ARGV[2])) - end - when "show" - self.options = @options_parser.show_options - show_handler @options_parser.args - output(output_type: :show) - when "update" - self.options = @options_parser.update_options - update_handler @options_parser.args - when "user" - case ARGV[2] - when "add" - self.options = @options_parser.user_add_options - user_add_handler @options_parser.args - when "delete" - self.options = @options_parser.user_delete_options - user_delete_handler @options_parser.args - else - @options_parser.invalid_user_command - abort(I18n.t("handler.project.invalid_subcommand", :cmd => ARGV[1], :scmd => ARGV[2])) - end + when :servers + servers_handler + output + when :stacks + stacks_handler + output + when :set_run_list + set_run_list_handler + when :show + show_handler + output + when :update + puts "TODO: update" + exit + update_handler + when :user_add + user_add_handler + when :user_delete + user_delete_handler + when :archive + archive_handler + when :unarchive + unarchive_handler when "test" - self.options = @options_parser.test_options - test_handler @options_parser.args - when "delete_servers" - self.options = @options_parser.delete_servers_options - delete_servers_handler @options_parser.args - else - @options_parser.invalid_command + test_handler end end @@ -96,32 +59,23 @@ class Project < Handler @list = get "/projects" end - def delete_handler args - r = inspect_parameters @options_parser.delete_params, args[2], args[3] - unless r.nil? - @options_parser.invalid_delete_command - abort(r) - end - o = {} - o[:deploy_env] = args[3] unless args[3].nil? - - message = args[2] - message += ".#{args[3]}" unless args[3].nil? - if question(I18n.t("handler.project.question.delete", :name => message)) - delete "/project/#{args[2]}", o - end + def delete_handler + delete "/project/#{@project_id}" if question(I18n.t("handler.project.question.delete", :name => @project_id)) end - def show_handler args - r = inspect_parameters @options_parser.show_params, args[2] - unless r.nil? - @options_parser.invalid_show_command - abort(r) - end - @show = get_project_info_obj(args[2]) + def show_handler + @show = get("/project/#{@project_id}") end - def update_handler args + def archive_handler + post "/project/#{@project_id}/archive" + end + + def unarchive_handler + post "/project/#{@project_id}/unarchive" + end + + def update_handler r = inspect_parameters @options_parser.update_params, args[2], args[3] unless r.nil? @options_parser.invalid_update_command @@ -130,7 +84,7 @@ class Project < Handler update_object_from_file "project", args[2], args[3] end - def create_handler args + def create_handler file = self.options[:file] unless file.nil? json = File.read(file) @@ -141,145 +95,34 @@ class Project < Handler end post_body("/project", json) else - r = inspect_parameters @options_parser.create_params, args[2] - unless r.nil? - @options_parser.invalid_create_command - abort(r) - end - unless self.options[:username].nil? || self.options[:password].nil? - self.auth[:username] = self.options[:username] - self.auth[:password] = self.options[:password] - self.def_options[:username] = self.auth[:username] - end - create_project args, :create_project_deploy_env_cmd + create_project end end - def servers_handler args - r = inspect_parameters @options_parser.servers_params, args[2], args[3] - unless r.nil? - @options_parser.invalid_servers_command - abort(r) - end - o = {} - unless args[3].nil? - o[:deploy_env] = args[3] - end - @servers = get "/project/#{args[2]}/servers", o + def servers_handler + @list = get "/project/#{@project_id}/servers" end - def stacks_handler args - project, deploy_env = args[2], args[3] - r = inspect_parameters @options_parser.stacks_params, project, deploy_env - unless r.nil? - @options_parser.invalid_stacks_command - abort(r) - end - options = {} - unless deploy_env.nil? - options[:deploy_env] = deploy_env - end - @list = get "/project/#{args[2]}/stacks", options + def stacks_handler + @list = get "/project/#{@project_id}/stacks" end - def user_add_handler args - r = inspect_parameters @options_parser.user_add_params, args[3], args[4] - unless r.nil? - @options_parser.invalid_user_add_command - abort(r) - end - q = {:users => args[4..-1]} - q[:deploy_env] = options[:deploy_env] unless options[:deploy_env].nil? - put "/project/#{args[3]}/user", q + def user_add_handler + post "/project/#{@project_id}/users/add", @user_name end - def user_delete_handler args - r = inspect_parameters @options_parser.user_delete_params, args[3], args[4] - unless r.nil? - @options_parser.invalid_user_delete_command - abort(r) - end - q = {:users => args[4..-1]} - q[:deploy_env] = options[:deploy_env] unless options[:deploy_env].nil? - delete_body "/project/#{args[3]}/user", q.to_json + def user_delete_handler + post "/project/#{@project_id}/users/delete", @user_name end - def multi_create_handler args - r = inspect_parameters @options_parser.multi_create_params, args[3] - unless r.nil? - @options_parser.invalid_multi_create_command - abort(r) - end - - create_project args, :create_project_multi_deploy_env_cmd, :multi - - i = Image.new(@host, self.def_options) - images, ti = i.list_handler, i.table - f = Flavor.new(@host, self.def_options) - flavors, tf = f.list_handler, f.table - g = Group.new(@host, self.def_options) - groups, tg = g.list_handler, g.table - - list = list_handler - info, multi = {}, {:type => "multi", :name => args[3], :deploy_envs => []} - begin # Add environment - nodes, projects, servers = [], [], {} - deploy_env = {:identifier => enter_parameter("Deploy environment identifier: ")} - begin # Add server - server_name = args[3] + "_" + enter_parameter("Server name: " + args[3] + "_") - s = servers[server_name] = {} - s[:groups] = choose_indexes_from_list("Security groups", list, tg, "default", list.index("default")).map{|i| list[i]} - s[:flavor] = choose_flavor_cmd(flavors, tf)["name"] - s[:image] = choose_image_cmd(images, ti)["id"] - subprojects = s[:subprojects] = [] - - begin # Add project - o = {} - o[:project_id] = project_id = choose_project(list, table) - info[project_id] = get_project_info_obj(project_id) unless info.has_key?(project_id) - envs = info[project_id]["deploy_envs"].map{|de| de["identifier"]} - o[:project_env] = ( envs.size > 1 ? choose_project_env(envs) : envs[0] ) - subprojects.push o - end while question("Add project?") - - end while question("Add server?") - - deploy_env[:servers] = servers - multi[:deploy_envs].push deploy_env - end while question(I18n.t("handler.project.question.add_env")) - puts JSON.pretty_generate(multi) - post "/project", :json => multi.to_json if question(I18n.t("handler.project.question.create")) - end - - def set_run_list_handler args - r = inspect_parameters @options_parser.set_run_list_params, args[3], args[4], args[5] - unless r.nil? - @options_parser.invalid_set_run_list_command - abort(r) - end - run_list = [] - args[5..args.size].each do |e| - run_list += e.split(",") - end + def set_run_list_handler + run_list = @run_list || [] if run_list.empty? - exit unless question(I18n.t("handler.project.run_list.empty")) + exit unless question(I18n.t("handler.project.question.run_list.empty")) else - exit unless DeployEnv.validate_run_list(run_list) + exit unless Validators.validate_run_list(run_list) end - put "/project/#{args[3]}/#{args[4]}/run_list", run_list - end - - def deploy_handler args - r = inspect_parameters @options_parser.deploy_params, args[2], args[3] - unless r.nil? - @options_parser.invalid_deploy_command - abort(r) - end - q = {} - q[:servers] = options[:servers] unless options[:servers].nil? - q[:deploy_env] = args[3] unless args[3].nil? - job_ids = post "/project/#{args[2]}/deploy", q - reports_urls(job_ids) + post "/project/#{@project_id}/run_list", run_list end def test_handler args @@ -292,196 +135,36 @@ class Project < Handler reports_urls(job_ids) end -protected - def get_project_info_obj project_id - get("/project/#{project_id}") - end + protected + def create_project - def create_project args, env_method_name, type=nil - project_name = args[2] - providers = {} - providers[:obj], providers[:table] = fetcher.fetch_with_table('provider') - begin - project = get_project_info_obj(project_name) - puts_warn I18n.t("handler.project.exist", :project => project_name) - names = project["deploy_envs"].map{|de| de["identifier"]} - new_envs = [] - while question(I18n.t("handler.project.question.add_env")) - new_envs << method(env_method_name).call(project_name, providers, names) - break if self.options[:no_ask] - end - puts JSON.pretty_generate(new_envs) - if question(I18n.t("handler.project.question.update_with_new_envs")) - new_envs.each do |env| - post "/project/#{project_name}/deploy_env", env - end - end - rescue NotFound => e - project = create_project_cmd(project_name, providers, env_method_name) - project[:name] = args[2] - puts json = JSON.pretty_generate(project) - post_body("/project", json) if question(I18n.t("handler.project.question.create")) - end - end - - def create_project_cmd project_name, providers, env_method - project = {:deploy_envs => []} - names = [] - begin - d = method(env_method).call(project_name, providers, names) - project[:deploy_envs].push d - break if self.options[:no_ask] - end while question(I18n.t("handler.project.question.add_env")) - project - end - - def create_project_deploy_env_cmd project, providers, names - d = {} - set_identifier(d, names) - - set_provider(d, providers) - - de = DeployEnvFactory.create(d[:provider], @host, self.options, self.auth) - de.fill d - -=begin - unless d[:provider] == "static" - set_flavor(d, buf) - set_image(d, buf) - vpc_id = set_subnets(d, buf) - set_groups(d, buf, vpc_id) - end - set_users(d, buf) - - unless self.options[:run_list].nil? - self.options[:run_list] = self.options[:run_list].split(",").map{|e| e.strip} - abort("Invalid run list: '#{self.options[:run_list].join(",")}'") unless Project.validate_run_list(self.options[:run_list]) - end - set_parameter d, :run_list do - set_run_list_cmd project, d[:identifier] - end - - unless self.options[:no_expires] - set_parameter d, :expires do - s = enter_parameter_or_empty(I18n.t("options.project.create.expires") + ": ").strip - s.empty? ? nil : s - end - end -=end - d - end - - def create_project_multi_deploy_env_cmd project, providers, names - d = {} - set_identifier(d, names) - - set_provider(d, providers) - buf = providers[d[:provider]] - - set_flavor(d, buf) - set_image(d, buf) - vpc_id = set_subnets(d, buf) - set_groups(d, buf, vpc_id) - set_users(d, buf) - - unless self.options[:run_list].nil? - self.options[:run_list] = self.options[:run_list].split(",").map{|e| e.strip} - abort("Invalid run list: '#{self.options[:run_list].join(",")}'") unless DeployEnv.validate_run_list(self.options[:run_list]) - end - set_parameter d, :run_list do - set_run_list_cmd project, d[:identifier] - end - - unless self.options[:no_expires] - set_parameter d, :expires do - s = enter_parameter_or_empty(I18n.t("options.project.create.expires") + ": ").strip - s.empty? ? nil : s - end - end - d - end - - def set_identifier d, names - set_parameter d, :identifier do - begin - n = enter_parameter I18n.t("handler.project.create.env") + ": " - if names.include?(n) - puts I18n.t("handler.project.create.env_exist", :env => n) - raise ArgumentError - else - names.push n - n - end - rescue ArgumentError - retry - end - end - end - - def set_provider d, providers - set_parameter d, :provider do - providers[:obj][ choose_number_from_list(I18n.t("headers.provider"), providers[:obj], providers[:table]) ] - end - end - - def set_parameter obj, key - if self.options[key].nil? - obj[key] = yield + project = {:environments => [], :id => @project_id} + project[:description] = options[:description] || enter_parameter_or_empty(I18n.t("handler.project.create.description") + ": ") + project[:project_users] = if options[:project_users] + options[:project_users] else - obj[key] = self.options[key] + if question(I18n.t("handler.project.create.question.users_choose")) + #choose + resources_selector.select_available_users(label: I18n.t("handler.project.create.users")) + else + #enter + get_comma_separated_list(I18n.t("input.message.input_list", cmd: I18n.t("input.user.list"))) + end + end - end - # returns project id - def choose_project projects, table=nil - abort(I18n.t("handler.project.list.empty")) if projects.empty? - projects[ choose_number_from_list(I18n.t("headers.project"), projects, table) ] - end + project[:run_list] = if self.options[:run_list] + abort("Invalid run list: '#{self.options[:run_list].join(",")}'") unless Validators.validate_run_list(self.options[:run_list]) + self.options[:run_list] + else + input_run_list + end - # returns project env - def choose_project_env project_envs, table=nil - abort(I18n.t("handler.project.env.list.empty")) if project_envs.empty? - project_envs[ choose_number_from_list(I18n.t("headers.project_env"), project_envs, table) ] + json = JSON.pretty_generate(project) + post_body("/project", json) if question(I18n.t("handler.project.question.create")){puts json} end def data_to_output - @list || @show || @servers || @test + @list || @show || @test end - - def delete_servers_handler(args) - project, env = args[2], args[3] - if error = inspect_parameters(@options_parser.delete_servers_params, project, env) - @options_parser.invalid_delete_servers_command - abort(error) - end - - ask_for_delete_servers(project, env) - body = { - deploy_env: env, - dry_run: false - } - response = delete("/project/#{project}/servers", body) - reports_urls(response['reports']) - end - - private - - def ask_for_delete_servers(project, env) - body = { - deploy_env: env, - dry_run: true - } - to_delete = delete("/project/#{project}/servers", body)['to_delete'] - if to_delete.empty? - abort "There are no servers to delete." - else - puts "Servers to delete:\n----\n" - puts to_delete.join("\n") - puts '----' - end - if @options[:dry_run] || !question('Are you sure to delete them? ') - abort - end - end - end diff --git a/devops-client/lib/devops-client/handler/provider.rb b/devops-client/lib/devops-client/handler/provider.rb index f3389af..b830da0 100644 --- a/devops-client/lib/devops-client/handler/provider.rb +++ b/devops-client/lib/devops-client/handler/provider.rb @@ -8,33 +8,97 @@ class Provider < Handler def initialize(host, def_options={}) @host, @options = host, def_options - @options_parser = ProviderOptions.new(ARGV, def_options) end def handle - @options, @args = @options_parser.parse_options_for!(current_command) - case current_command - when :list - list_handler - output(output_type: :list) - when :accounts - @provider = @args[2] - accounts_handler - output(output_type: :accounts, provider: @provider) + @options_parser = ProviderOptions.new(ARGV, @options) + @command, @options, @args = @options_parser.parse_options_for! + extract_parameters + case @command + when :account_create + return account_create_handler + when :account_delete + return account_delete_handler end + send("#{@command}_handler") + output_data = { + provider: @provider, + account: @account + } + output(output_data) end def list_handler @list = get("/providers").sort!{|x,y| x["id"] <=> y["id"]} end - def accounts_handler - r = inspect_parameters @options_parser.accounts_params, @provider - unless r.nil? - @options_parser.invalid_accounts_command - abort(r) + def account_create_handler + file = @options[:file] + unless file.nil? + json = File.read(file) + begin + JSON.parse(json) + rescue JSON::ParserError => e + abort(I18n.t("handler.provider.account.create.invalid_json", :file => file)) + end + post_body("/provider/#{@provider}/account", json) + else + create_account end + end + + def account_delete_handler + delete "/provider/#{@provider}/account/#{@account}" if question(I18n.t("handler.provider.account.question.delete", :account => @account)) + end + + def create_account + q = { + "account_name" => @account + } + q["description"] = options[:description] || enter_parameter_or_empty(I18n.t("handler.provider.account.create.description") + ": ") + q["ssh_key"] = options[:ssh_key] || resources_selector.select_available_ssh_keys + + case @provider + when Providers::Aws + q["use_iam_profile"] = options[:use_iam_profile] || question(I18n.t("handler.provider.account.create.aws.use_iam_profile")) + unless q["use_iam_profile"] + q["access_key_id"] = options[:access_key_id] || enter_parameter(I18n.t("handler.provider.account.create.aws.access_key_id") + ": ") + q["secret_access_key"] = options[:secret_access_key] || enter_parameter(I18n.t("handler.provider.account.create.aws.secret_access_key") + ": ") + end + when Providers::Openstack + when Providers::Static + # nothing to do + end + json = JSON.pretty_generate(q) + post_body "/provider/#{@provider}/account", json if question(I18n.t("handler.provider.account.question.create")){puts json} + end + + def accounts_handler @list = get("/provider/#{@provider}/accounts") end + def flavors_handler + @list = get("/provider/#{@provider}/account/#{@account}/flavors").sort!{|x,y| x["id"] <=> y["id"]} + end + + def images_handler + @list = get("/provider/#{@provider}/account/#{@account}/images") + end + + def networks_handler + path = "/provider/#{@provider}/account/#{@account}/networks" + path += "?vpc-id=#{@vpc_id}" if @vpc_id + @list = get(path) + end + + def vpc_handler + abort(I18n.t("handler.provider.vpc.invalid_provider")) unless @provider == Providers::Aws + @list = get("/provider/#{@provider}/account/#{@account}/vpcs") + end + + def security_groups_handler + path = "/provider/#{@provider}/account/#{@account}/security_groups" + path += "?vpc-id=#{@vpc_id}" if @vpc_id + @list = get(path) + end end diff --git a/devops-client/lib/devops-client/handler/role.rb b/devops-client/lib/devops-client/handler/role.rb new file mode 100644 index 0000000..039a974 --- /dev/null +++ b/devops-client/lib/devops-client/handler/role.rb @@ -0,0 +1,75 @@ +require "devops-client/handler/handler" +require "devops-client/options/role_options" +require "devops-client/output/role" + +class Role < Handler + + output_with Output::Role + include InputUtils + + def initialize(host, def_options={}) + @host, @options = host, def_options + @options_parser = RoleOptions.new(ARGV, def_options) + end + + def handle + @command, @options, @args = @options_parser.parse_options_for! + extract_parameters + case @command + when :list + list_handler + output + when :show + show_handler + output + when :create + create_handler + when :delete + delete_handler + when :policies + policies_handler + output + end + end + + def list_handler + @list = get("/security/roles") + end + + def show_handler + @show = get("/security/role/#{@role_name}") + end + + def policies_handler + @list = get("/security/policies") + end + + def create_handler + q = { + "name" => @role_name + } + q["description"] = options[:description] || enter_parameter(I18n.t("handler.role.create.description") + ": ") + all = question(I18n.t("handler.role.question.all_policies")) + if all + q["policies"] = ["all"] + else + policies_handler + + q["policies"] = if options[:policies] + #TODO: validation + options[:policies] + else + @command = :policies + select_items_from_table(I18n.t("handler.role.create.policies"), @list, outputter.table).map{|p| p["id"]} + end + end + + json = JSON.pretty_generate(q) + post_body "/security/role", json if question(I18n.t("handler.role.question.create")){puts json} + end + + def delete_handler + delete("/security/role/#{@role_name}") if question(I18n.t("handler.role.question.delete", role: @role_name)) + end + +end diff --git a/devops-client/lib/devops-client/handler/server.rb b/devops-client/lib/devops-client/handler/server.rb index 07027b6..e9eec04 100644 --- a/devops-client/lib/devops-client/handler/server.rb +++ b/devops-client/lib/devops-client/handler/server.rb @@ -9,18 +9,19 @@ class Server < Handler def initialize(host, def_options={}) @host, @options = host, def_options - @options_parser = ServerOptions.new(ARGV, def_options) end def handle - @options, @args = @options_parser.parse_options_for!(current_command) - case current_command + @options_parser = ServerOptions.new(ARGV, @options) + @command, @options, @args = @options_parser.parse_options_for! + extract_parameters + case @command when :list list_handler output when :show show_handler - output + output(server: @server_id) when :create create_handler when :delete @@ -29,6 +30,8 @@ class Server < Handler delete_list_handler when :bootstrap bootstrap_handler + when :unbootstrap + unbootstrap_handler when :sync sync_handler when :pause @@ -47,35 +50,20 @@ class Server < Handler end def list_handler - if @args[2].nil? - @list = get("/servers") - return @list - end - self.options[:type] = @args[2] - @list = case @args[2] - when "chef" - get("/servers/chef").map {|l| {"chef_node_name" => l}} - when "ec2", "openstack", "static" - get("/servers/#{@args[2]}") - else - @options_parser.invalid_list_command - abort("Invlid argument '#{@args[2]}'") - end + params = {} + params["provider"] = @provider if @provider + @list = get("/servers", params) end def create_handler - r = inspect_parameters @options_parser.create_params, @args[2], @args[3] - unless r.nil? - @options_parser.invalid_create_command - abort(r) - end q = { - :project => @args[2], - :deploy_env => @args[3] + project: @project, + environment: @environment, + category: @category } - [:key, :without_bootstrap, :name, :groups, :force, :private_ip].each do |k| + [:ssh_key, :without_bootstrap, :name, :groups, :skip_rollback, :private_ip].each do |k| q[k] = self.options[k] unless self.options[k].nil? end @@ -84,18 +72,10 @@ class Server < Handler end def delete_handler - @args[2..-1].each do |name| - r = inspect_parameters @options_parser.delete_params, name - unless r.nil? - @options_parser.invalid_delete_command - abort(r) - end - if question(I18n.t("handler.server.question.delete", :name => name)) - jobs_ids = delete("/server/#{name}", options) # returns array with one job id, actually - puts reports_urls(jobs_ids) - end + if question(I18n.t("handler.server.question.delete", :id => @server_id)) + jobs_ids = delete("/server/#{@server_id}", options) # returns array with one job id, actually + reports_urls(jobs_ids) end - nil end # this method differs from #delete_handler in this: @@ -103,10 +83,8 @@ class Server < Handler # Timur said we planned to transfer all server requests to using ids by default, that's why # later we could get rid of #delete_list method. def delete_list_handler - abort "Please specify at least one server id" if @args.length < 3 - server_ids = @args[2..-1] - if question(I18n.t("handler.server.question.delete_list", ids: server_ids.join(', '))) - servers_jobs = post("/server/delete_list", {servers_ids: server_ids}) + if question(I18n.t("handler.server.question.delete_list", ids: @server_id.join(', '))) + servers_jobs = post("/servers/delete", {servers_ids: @server_id}) servers_jobs.each do |server_id, job_id| puts "Report for deleting #{server_id}: #{report_url(job_id)}" end @@ -115,47 +93,39 @@ class Server < Handler end def show_handler - r = inspect_parameters @options_parser.show_params, @args[2] - unless r.nil? - @options_parser.invalid_show_command - abort r - end - @show = get("/server/#{@args[2]}") + @show = get("/server/#{@server_id}") end def bootstrap_handler - r = inspect_parameters @options_parser.bootstrap_params, @args[2] - unless r.nil? - @options_parser.invalid_bootstrap_command - abort(r) - end - q = { - :instance_id => @args[2] - } - [:name, :bootstrap_template, :run_list].each do |k| + q = {} + [:cm_name, :bootstrap_template, :run_list].each do |k| q[k] = self.options[k] unless self.options[k].nil? end if q.has_key?(:run_list) abort unless Project.validate_run_list(q[:run_list]) end - job_ids = post "/server/bootstrap", q + job_ids = post "/server/#{@server_id}/bootstrap", q reports_urls(job_ids) end - def add_static_handler # add --public-ip - r = inspect_parameters @options_parser.add_params, @args[2], @args[3], @args[4], @args[5], @args[6] - unless r.nil? - @options_parser.invalid_add_command - abort(r) + def unbootstrap_handler + if question(I18n.t("handler.server.question.unbootstrap", :id => @server_id)) + job_ids = post("/server/#{@server_id}/unbootstrap") + reports_urls(job_ids) end + end + + def add_static_handler # add --public-ip q = { - :project => @args[2], - :deploy_env => @args[3], - :private_ip => @args[4], - :remote_user => @args[5], - :key => @args[6] + project: @project, + environment: @environment, + category: @category, + private_ip: @ip, + remote_user: @ssh_user, + key: @key_id, + name: @name } - q[:public_ip] = self.options[:public_ip] unless self.options[:public_ip].nil? + q[:public_ip] = self.options[:public_ip] if self.options[:public_ip] post "/server/add", q end @@ -179,39 +149,19 @@ class Server < Handler end def pause_handler - r = inspect_parameters @options_parser.pause_params, @args[2] - unless r.nil? - @options_parser.invalid_pause_command - abort(r) - end - post "/server/#{@args[2]}/pause", options + post "/server/#{@server_id}/pause" end def unpause_handler - r = inspect_parameters @options_parser.unpause_params, @args[2] - unless r.nil? - @options_parser.invalid_unpause_command - abort(r) - end - post "/server/#{@args[2]}/unpause", options + post "/server/#{@server_id}/unpause" end def reserve_handler - r = inspect_parameters @options_parser.reserve_params, @args[2] - unless r.nil? - @options_parser.invalid_reserve_command - abort(r) - end - post "/server/#{@args[2]}/reserve", options + post "/server/#{@server_id}/reserve" end def unreserve_handler - r = inspect_parameters @options_parser.unreserve_params, @args[2] - unless r.nil? - @options_parser.invalid_unreserve_command - abort(r) - end - post "/server/#{@args[2]}/unreserve", options + post "/server/#{@server_id}/unreserve" end end diff --git a/devops-client/lib/devops-client/handler/stack.rb b/devops-client/lib/devops-client/handler/stack.rb index c1f4f58..7656ec3 100644 --- a/devops-client/lib/devops-client/handler/stack.rb +++ b/devops-client/lib/devops-client/handler/stack.rb @@ -13,8 +13,9 @@ class Stack < Handler end def handle - @options, @args = @options_parser.parse_options_for!(current_command) - case current_command + @command, @options, @args = @options_parser.parse_options_for! + extract_parameters + case @command when :list list_handler output @@ -41,11 +42,14 @@ class Stack < Handler end def create_handler - attrs = {} - attrs[:project] = options[:project] || resources_selector.select_available_project - attrs[:deploy_env] = options[:deploy_env] || resources_selector.select_available_env(attrs[:project]) - env = fetcher.fetch_project(attrs[:project])['deploy_envs'].detect {|env| env['identifier'] == attrs[:deploy_env]} - attrs[:provider] = env['provider'] + attrs = { + project: @project, + environment: @environment, + category: @category + } + category = fetcher.fetch_category(@project, @environment, @category) + attrs[:provider] = category['provider']['name'] + attrs[:provider_account] = category['provider']['account'] params_filepath = options[:parameters_file] || enter_parameter_or_empty(I18n.t('handler.stack.create.parameters_file')) if params_filepath.empty? @@ -61,14 +65,11 @@ class Stack < Handler attrs[:tags] = JSON.parse(File.read(tags_filepath)) end - attrs.merge!( - launch_options: { - without_bootstrap: options[:without_bootstrap] || false, - skip_rollback: options[:skip_rollback] || false, - } + json = JSON.pretty_generate( + without_bootstrap: options[:without_bootstrap] || false, + skip_rollback: options[:skip_rollback] || false, + stack_attributes: attrs ) - - json = JSON.pretty_generate(attrs) if question(I18n.t("handler.stack.question.create")) {puts json} job_ids = post_body "/stack", json reports_urls(job_ids) @@ -104,14 +105,8 @@ class Stack < Handler end def delete_handler - stack_id = @args[2] - r = inspect_parameters(@options_parser.delete_params, stack_id) - unless r.nil? - @options_parser.invalid_delete_command - abort(r) - end - if question(I18n.t("handler.stack.question.delete", name: stack_id)) - delete "/stack/#{stack_id}" + if question(I18n.t("handler.stack.question.delete", name: @stack)) + delete "/stack/#{@stack}" end end diff --git a/devops-client/lib/devops-client/handler/stack_template.rb b/devops-client/lib/devops-client/handler/stack_template.rb index 949afe6..292a9e2 100644 --- a/devops-client/lib/devops-client/handler/stack_template.rb +++ b/devops-client/lib/devops-client/handler/stack_template.rb @@ -14,10 +14,11 @@ class StackTemplate < Handler end def handle - @options, @args = @options_parser.parse_options_for!(current_command) - case current_command + @command, @options, @args = @options_parser.parse_options_for! + extract_parameters + case @command when :list - list_handler + list_handler(@provider) output when :show show_handler @@ -34,74 +35,45 @@ class StackTemplate < Handler end def create_handler - q = {} - q[:provider] = options[:provider] || resources_selector.select_available_provider - q[:id] = options[:id] || enter_parameter(I18n.t('handler.stack_template.create.id')) + q = { + id: options[:id], + provider: options[:provider], + provider_account: options[:provider_account] + } + q[:provider] ||= resources_selector.select_available_provider(except: ['static']) + q[:provider_account] ||= resources_selector.select_available_provider_account(q[:provider])['account_name'] + q[:id] ||= enter_parameter(I18n.t('handler.stack_template.create.id')) filepath = options[:template_file] || enter_parameter(I18n.t('handler.stack_template.create.template_file')) q[:template_body] = get_file_contents(filepath) - json = JSON.pretty_generate(q) - post_body("/stack_template/#{q[:provider]}", json) if question(I18n.t('handler.stack_template.question.create')){puts json} + if question(I18n.t('handler.stack_template.question.create')) { puts confirming_json(q) } + post_body("/stack_template/#{q[:provider]}", JSON.pretty_generate(q)) + end end def list_handler(provider=nil) - provider ||= @options[:given_provider] - @list = get_stack_templates(provider) - end - - def get_stack_templates(provider=nil) - if provider + @list = if provider provider_stack_templates(provider) else get("/stack_templates") end end - def show_handler - r = inspect_parameters @options_parser.show_params, @args[2] - unless r.nil? - @options_parser.invalid_show_command - abort(r) - end - @show = get "/stack_template/#{@args[2]}" + @show = get "/stack_template/#{@stack_template}" end def delete_handler - r = inspect_parameters(@options_parser.delete_params, @args[2]) - unless r.nil? - @options_parser.invalid_delete_command - abort(r) - end - if question(I18n.t("handler.stack_template.question.delete", name: @args[2])) - delete "/stack_template/#{@args[2]}" + if question(I18n.t("handler.stack_template.question.delete", name: @stack_template)) + delete "/stack_template/#{@stack_template}" end end - def update_url_handler - r = inspect_parameters @options_parser.update_url_params, @args[2] - unless r.nil? - @options_parser.invalid_update_url_command - abort(r) - end - stack_template = post "/stack_template/#{@args[2]}/update_template_url" - puts stack_template['template_url'] - end - - def update_available_parameters_handler - r = inspect_parameters @options_parser.update_url_params, @args[2] - unless r.nil? - @options_parser.invalid_update_url_command - abort(r) - end - stack_template = post "/stack_template/#{@args[2]}/update_available_parameters" - puts JSON.pretty_generate(stack_template['available_parameters']) - end + private def provider_stack_templates(provider) if Providers.has_functionality?(provider, :stack_templates) - @provider = true @list = get("/stack_templates/provider/#{provider}") else @options_parser.invalid_list_command @@ -109,4 +81,10 @@ class StackTemplate < Handler end end + def confirming_json(hash) + to_output = hash.dup + to_output[:template_body] = to_output[:template_body][0..40] + '…' + JSON.pretty_generate(to_output) + end + end diff --git a/devops-client/lib/devops-client/handler/tag.rb b/devops-client/lib/devops-client/handler/tag.rb deleted file mode 100644 index 92bfcec..0000000 --- a/devops-client/lib/devops-client/handler/tag.rb +++ /dev/null @@ -1,61 +0,0 @@ -require "devops-client/handler/handler" -require "devops-client/options/tag_options" -require "json" -require "devops-client/output/tag" - -class Tag < Handler - - output_with Output::Tag - - def initialize(host, def_options={}) - @host, @options = host, def_options - @options_parser = TagOptions.new(ARGV, def_options) - end - - def handle - current_command = ARGV[1].to_sym - @options, @args = @options_parser.parse_options_for!(current_command) - case current_command - when :list - list_handler - output - when :create - create_handler - when :delete - delete_handler - end - end - - def list_handler - r = inspect_parameters @options_parser.list_params, @args[2] - unless r.nil? - @options_parser.invalid_list_command - abort(r) - end - @list = get("/tags/#{@args[2]}") - end - - def create_handler - if @args.length == 3 - @options_parser.invalid_create_command - abort() - end - node = @args[2] - tags = @args[3..-1] - - post "/tags/#{node}", tags - end - - def delete_handler - if @args.length == 3 - @options_parser.invalid_delete_command - abort() - end - node = @args[2] - tags = @args[3..-1] - - if question(I18n.t("handler.user.question.delete", :name => tags.join("', '"), :node => node)) - delete "/tags/#{node}", tags - end - end -end diff --git a/devops-client/lib/devops-client/handler/user.rb b/devops-client/lib/devops-client/handler/user.rb index a2e994e..f73c02e 100644 --- a/devops-client/lib/devops-client/handler/user.rb +++ b/devops-client/lib/devops-client/handler/user.rb @@ -7,14 +7,15 @@ class User < Handler output_with Output::User def initialize(host, def_options={}) - @host, @options = host, def_options + @host = host + @options = def_options @options_parser = UserOptions.new(ARGV, def_options) end def handle - current_command = ARGV[1].to_sym - @options, @args = @options_parser.parse_options_for!(current_command) - case current_command + @command, @options, @args = @options_parser.parse_options_for! + extract_parameters + case @command when :list list_handler output @@ -22,12 +23,14 @@ class User < Handler create_handler when :delete delete_handler - when :grant - grant_handler when :password password_handler when :email email_handler + when :role_add + role_add_handler + when :role_delete + role_delete_handler end end @@ -36,75 +39,46 @@ class User < Handler end def create_handler - r = inspect_parameters @options_parser.create_params, @args[2], @args[3] - unless r.nil? - @options_parser.invalid_create_command - abort(r) - end - - password = self.options[:new_password] || enter_password(@args[2]) - q = { - "username" => @args[2], - "password" => password, - "email" => @args[3] + "id" => @user_name, + "email" => @email } - post "/user", q + q["password"] = self.options[:new_password] || enter_password(@user_name) + q["roles"] = resources_selector.select_available_roles + + json = JSON.pretty_generate(q) + post_body "/user", json if question(I18n.t("handler.user.question.create")){puts json} end def delete_handler - r = inspect_parameters @options_parser.delete_params, @args[2] - unless r.nil? - @options_parser.invalid_delete_command - abort(r) - end - - if question(I18n.t("handler.user.question.delete", :name => @args[2])) - delete "/user/#{@args[2]}" - end + delete "/user/#{@user_name}" if question(I18n.t("handler.user.question.delete", :name => @user_name)) end def password_handler - r = inspect_parameters @options_parser.password_params, @args[2] - unless r.nil? - @options_parser.invalid_password_command - abort(r) - end - - password = enter_password(@args[2]) q = { - "password" => password + "password" => enter_password(@user_name) } - put "/user/#{@args[2]}/password", q + put "/user/#{@user_name}/password", q end def email_handler - r = inspect_parameters @options_parser.email_params, @args[2], @args[3] - unless r.nil? - @options_parser.invalid_email_command - abort(r) - end q = { - "email" => @args[3] + "email" => @email } - put "/user/#{@args[2]}/email", q + put "/user/#{@user_name}/email", q end - def grant_handler - r = inspect_parameters @options_parser.grant_params, @args[2], @args[3], @args[4] - unless r.nil? - @options_parser.invalid_grant_command - abort(r) - end + def role_add_handler + user = get("/user/#{@user_name}") + q = resources_selector.select_available_roles(user["roles"]) + post "/user/#{@user_name}/roles/add", q + end - @args[3] = '' if @args[3].nil? - q = { - 'cmd' => @args[3], - 'privileges' => @args[4] - } - - put "/user/#{@args[2]}", q + def role_delete_handler + user = get("/user/#{@user_name}") + q = resources_selector.select_user_roles(user["roles"]) + post "/user/#{@user_name}/roles/delete", q end def enter_password user diff --git a/devops-client/lib/devops-client/options/bootstrap_templates_options.rb b/devops-client/lib/devops-client/options/bootstrap_templates_options.rb deleted file mode 100644 index 6e76fd8..0000000 --- a/devops-client/lib/devops-client/options/bootstrap_templates_options.rb +++ /dev/null @@ -1,13 +0,0 @@ -require "devops-client/options/common_options" - -class BootstrapTemplatesOptions < CommonOptions - - commands :list - - def initialize args, def_options - super(args, def_options) - self.header = I18n.t("headers.template") - self.banner_header = "templates" - end - -end diff --git a/devops-client/lib/devops-client/options/category_options.rb b/devops-client/lib/devops-client/options/category_options.rb new file mode 100644 index 0000000..41d5801 --- /dev/null +++ b/devops-client/lib/devops-client/options/category_options.rb @@ -0,0 +1,91 @@ +require "devops-client/options/common_options" +require "set" + +class CategoryOptions < CommonOptions + + commands :create, :delete, :deploy, :list, {:servers => [:list, :delete]}, :stacks, {:set => [:run_list]}, :show, :update + + COMMAND_NAME = "cat" + + def initialize args, def_options + super(args, def_options) + self.header = I18n.t("headers.category") + id = "PROJECT_ID" + env = "ENVIRONMENT" + cat = "CATEGORY" + self.list_params = [id, env] + self.show_params = [id, env, cat] + self.create_params = [id, env, cat] + self.delete_params = [id, env, cat] + self.deploy_params = [id, env, cat] + self.set_run_list_params = [id, env, cat, "[RUN_LIST...]"] + self.servers_list_params = [id, env, cat] + #self.stacks_params = [id, "[#{env}]", "[#{cat}]"] + self.update_params = [id, env, cat, "FILE"] + #self.delete_servers_params = [id, "[#{env}]"] + end + + def create_options + self.options do |parser, options| + parser.banner << self.create_banner + parser.resource_name = :project + + parser.recognize_option_value(:groups, variable: 'GROUP_1,GROUP_2...') do |groups| + options[:groups] = groups.split(",") + end + + parser.recognize_option_value(:file) do |file| + abort("File '#{file}' does not exist") unless File.exist?(file) + options[:file] = file + end + + parser.recognize_option_value(:subnets, variable: 'SUBNET_1,SUBNET_2...') do |subnets| + options[:subnets] = subnets.split(",") + end + + parser.recognize_option_value(:users, variable: 'USER_1,USER_2...') do |users| + options[:users] = Set.new(users.split(",")) + end + + parser.recognize_option_value(:run_list, variable: 'ROLE_1,ROLE_2...') do |run_list| + options[:run_list] = Set.new(run_list.split(",")).to_a + end + + parser.recognize_option_value(:deploy_env, option_key: :identifier) + parser.recognize_option_value(:flavor) + parser.recognize_option_value(:image) + parser.recognize_option_value(:run_list) + parser.recognize_option_value(:provider) + parser.recognize_option_value(:no_expires, type: :switch, switch_value: true, default: false) + parser.recognize_option_value(:expires) + + + # TODO: + # support short options names + # + # options[:file] = nil + # parser.on("-f", "--file FILE", I18n.t("options.project.create.file")) do |file| + # abort("File '#{file}' does not exist") unless File.exist?(file) + # options[:file] = file + # end + + end + end + + def deploy_options + options do |parser, options| + parser.banner << self.deploy_banner + + parser.recognize_option_value(:servers, resource_name: :project, command_name: 'deploy') do |servers| + options[:servers] = servers.split(",") + end + end + end + + def delete_servers_options + self.options do |parser, options| + parser.recognize_option_value(:dry_run, resource_name: :project, type: :switch, default: false, switch_value: true, command_name: 'delete_servers') + end + end + +end diff --git a/devops-client/lib/devops-client/options/chef_options.rb b/devops-client/lib/devops-client/options/chef_options.rb new file mode 100644 index 0000000..2d85e6c --- /dev/null +++ b/devops-client/lib/devops-client/options/chef_options.rb @@ -0,0 +1,19 @@ +require "devops-client/options/common_options" + +class ChefOptions < CommonOptions + + commands :bootstrap_templates, tags: [:list, :set, :unset] + + COMMAND_NAME = "chef" + + def initialize args, def_options + super(args, def_options) + self.header = I18n.t("headers.chef") + self.banner_header = COMMAND_NAME + self.bootstrap_templates_params = [] + self.tags_list_params = ["CM_NAME"] + self.tags_set_params = ["CM_NAME", "TAGS..."] + self.tags_unset_params = ["CM_NAME", "TAGS..."] + end + +end diff --git a/devops-client/lib/devops-client/options/common_options.rb b/devops-client/lib/devops-client/options/common_options.rb index 95bfc1f..748cea2 100644 --- a/devops-client/lib/devops-client/options/common_options.rb +++ b/devops-client/lib/devops-client/options/common_options.rb @@ -13,22 +13,27 @@ class CommonOptions CSV_FORMAT = "csv" OUTPUT_FROMATS = [TABLE_FORMAT, JSON_FORMAT, CSV_FORMAT] + # skip command name and subcommand def initialize args, def_options self.args = args self.default_options = def_options + self.banner_header = self.class::COMMAND_NAME end def self.commands *cmds - define_method :available_commands do - cmds - end - + acommands = [] cmds.each do |cmd| if cmd.is_a?(Hash) key = cmd.keys[0] + acommands.push key.to_sym cmd[key].each do |subcmd| create_command key.to_s, subcmd.to_s end + + define_method "#{key}_subcommands" do + cmd[key] + end + invalid_command_method = "invalid_#{key}_command" banner_method = "#{key}_banner" @@ -40,10 +45,19 @@ class CommonOptions cmd[key].map{|sc| self.send("#{key}_#{sc}_banner")}.join("") + "\n" end else + acommands.push cmd.to_sym create_command cmd.to_s + + define_method "#{cmd}_subcommands" do + [] + end end end + define_method :available_commands do + acommands + end + define_method "banners" do r = [] cmds.each do |cmd| @@ -107,13 +121,25 @@ class CommonOptions end end - # returns [options, args] because they are always needed together + # returns [command, options, args] because they are always needed together # will exit if operation is unsupported - def parse_options_for!(command) + def parse_options_for! + if !ARGV[1] || ARGV[1].start_with?("-") + invalid_command + end + command = ARGV[1].to_sym # available_commands method is defined dinamically in .commands method if available_commands.include?(command) + subcommands = send("#{command}_subcommands") + n = 2 + unless subcommands.empty? + n = 3 + return invalid_command if !ARGV[2] || !subcommands.include?(ARGV[2].to_sym) + command = "#{command}_#{ARGV[2]}".to_sym + end + options = send("#{command}_options") - [options, args] + [command, options, args[n..-1]] else invalid_command end diff --git a/devops-client/lib/devops-client/options/deploy_options.rb b/devops-client/lib/devops-client/options/deploy_options.rb index 27faff1..49c7c14 100644 --- a/devops-client/lib/devops-client/options/deploy_options.rb +++ b/devops-client/lib/devops-client/options/deploy_options.rb @@ -4,6 +4,8 @@ class DeployOptions < CommonOptions attr_accessor :deploy_params + COMMAND_NAME = "deploy" + def initialize args, def_options super(args, def_options) self.header = I18n.t("headers.deploy") diff --git a/devops-client/lib/devops-client/options/environment_options.rb b/devops-client/lib/devops-client/options/environment_options.rb new file mode 100644 index 0000000..6e4d256 --- /dev/null +++ b/devops-client/lib/devops-client/options/environment_options.rb @@ -0,0 +1,108 @@ +require "devops-client/options/common_options" +require "set" + +class EnvironmentOptions < CommonOptions + + commands :create, :delete, :deploy, :list, {:servers => [:list, :delete]}, :stacks, {:set => [:run_list]}, :show, :update, {:user => [:add, :delete]} + + COMMAND_NAME = "env" + + def initialize args, def_options + super(args, def_options) + self.header = I18n.t("headers.environment") + id = "PROJECT_ID" + env = "ENVIRONMENT" + self.list_params = [id] + self.show_params = [id, env] + self.create_params = [id, env] + self.delete_params = [id, env] + self.deploy_params = [id, env] + self.set_run_list_params = [id, env, "[RUN_LIST...]"] + self.servers_list_params = [id, env] + #self.stacks_params = [id, "[#{env}]", "[#{cat}]"] + self.update_params = [id, env, "FILE"] + self.user_add_params = [id, env] + self.user_delete_params = [id, env, "USER..."] + #self.delete_servers_params = [id, "[#{env}]"] + end + + def create_options + self.options do |parser, options| + parser.banner << self.create_banner + parser.resource_name = :project + + parser.recognize_option_value(:groups, variable: 'GROUP_1,GROUP_2...') do |groups| + options[:groups] = groups.split(",") + end + + parser.recognize_option_value(:file) do |file| + abort("File '#{file}' does not exist") unless File.exist?(file) + options[:file] = file + end + + parser.recognize_option_value(:subnets, variable: 'SUBNET_1,SUBNET_2...') do |subnets| + options[:subnets] = subnets.split(",") + end + + parser.recognize_option_value(:users, variable: 'USER_1,USER_2...') do |users| + options[:users] = Set.new(users.split(",")) + end + + parser.recognize_option_value(:run_list, variable: 'ROLE_1,ROLE_2...') do |run_list| + options[:run_list] = Set.new(run_list.split(",")).to_a + end + + parser.recognize_option_value(:deploy_env, option_key: :identifier) + parser.recognize_option_value(:flavor) + parser.recognize_option_value(:image) + parser.recognize_option_value(:run_list) + parser.recognize_option_value(:provider) + parser.recognize_option_value(:no_expires, type: :switch, switch_value: true, default: false) + parser.recognize_option_value(:expires) + + + # TODO: + # support short options names + # + # options[:file] = nil + # parser.on("-f", "--file FILE", I18n.t("options.project.create.file")) do |file| + # abort("File '#{file}' does not exist") unless File.exist?(file) + # options[:file] = file + # end + + end + end + + def user_add_options + self.options do |parser, options| + parser.banner << self.user_add_banner + + parser.recognize_option_value(:deploy_env, resource_name: :project, command_name: 'user_add') + end + end + + def user_delete_options + self.options do |parser, options| + parser.banner << self.user_delete_banner + + parser.recognize_option_value(:deploy_env, resource_name: :project, command_name: 'user_delete') + end + end + + def deploy_options + options do |parser, options| + parser.banner << self.deploy_banner + + parser.recognize_option_value(:servers, resource_name: :project, command_name: 'deploy') do |servers| + options[:servers] = servers.split(",") + end + end + end + + def delete_servers_options + self.options do |parser, options| + parser.recognize_option_value(:dry_run, resource_name: :project, type: :switch, default: false, switch_value: true, command_name: 'delete_servers') + end + end + +end diff --git a/devops-client/lib/devops-client/options/filter_options.rb b/devops-client/lib/devops-client/options/filter_options.rb index 0992eb8..88800c4 100644 --- a/devops-client/lib/devops-client/options/filter_options.rb +++ b/devops-client/lib/devops-client/options/filter_options.rb @@ -5,13 +5,14 @@ class FilterOptions < CommonOptions commands :image => [:add, :delete, :list] + COMMAND_NAME = "filter" + def initialize args, def_options super(args, def_options) self.header = I18n.t("headers.filters") - self.banner_header = "filter" p = "PROVIDER" self.image_list_params = [p] - i = "IMAGE [IMAGE ...]" + i = "IMAGE..." self.image_add_params = [p, i] self.image_delete_params = [p, i] end diff --git a/devops-client/lib/devops-client/options/flavor_options.rb b/devops-client/lib/devops-client/options/flavor_options.rb deleted file mode 100644 index e298cd4..0000000 --- a/devops-client/lib/devops-client/options/flavor_options.rb +++ /dev/null @@ -1,19 +0,0 @@ -require "optparse" -require "devops-client/options/common_options" - -class FlavorOptions < CommonOptions - - commands :list - - def initialize args, def_options - super(args, def_options) - self.header = I18n.t("headers.flavor") - self.banner_header = "flavor" - self.list_params = ["PROVIDER"] - end - - extend_options_method :list_options do |options| - options[:given_provider] = args[2] if args[2] - end - -end diff --git a/devops-client/lib/devops-client/options/group_options.rb b/devops-client/lib/devops-client/options/group_options.rb deleted file mode 100644 index fa23881..0000000 --- a/devops-client/lib/devops-client/options/group_options.rb +++ /dev/null @@ -1,19 +0,0 @@ -require "optparse" -require "devops-client/options/common_options" - -class GroupOptions < CommonOptions - - commands :list - - def initialize args, def_options - super(args, def_options) - self.header = I18n.t("headers.group") - self.banner_header = "group" - self.list_params = ["PROVIDER", "[VPC-ID]"] - end - - extend_options_method :list_options do |options| - options[:given_provider] = args[2] if args[2] - end - -end diff --git a/devops-client/lib/devops-client/options/image_options.rb b/devops-client/lib/devops-client/options/image_options.rb index d217b78..4b12086 100644 --- a/devops-client/lib/devops-client/options/image_options.rb +++ b/devops-client/lib/devops-client/options/image_options.rb @@ -4,13 +4,15 @@ class ImageOptions < CommonOptions commands :create, :delete, :list, :show, :update + COMMAND_NAME = "image" + def initialize args, def_options super(args, def_options) self.header = I18n.t("headers.image") - self.banner_header = "image" - self.list_params = ["[provider]", "[ec2|openstack]"] + self.list_params = ["[PROVIDER]"] self.show_params = ["IMAGE"] - self.delete_params = ["IMAGE"] + self.create_params = [] + self.delete_params = ["IMAGE" ] self.update_params = ["IMAGE", "FILE"] end @@ -20,10 +22,9 @@ class ImageOptions < CommonOptions parser.resource_name = :image parser.recognize_option_value(:provider) + parser.recognize_option_value(:provider_account) parser.recognize_option_value(:image_id) parser.recognize_option_value(:ssh_username) - parser.recognize_option_value(:bootstrap_template) - parser.recognize_option_value(:no_bootstrap_template, type: :switch, switch_value: true, default: false) end end diff --git a/devops-client/lib/devops-client/options/key_options.rb b/devops-client/lib/devops-client/options/key_options.rb index f1cf490..a93331d 100644 --- a/devops-client/lib/devops-client/options/key_options.rb +++ b/devops-client/lib/devops-client/options/key_options.rb @@ -3,10 +3,12 @@ require "devops-client/options/common_options" class KeyOptions < CommonOptions commands :add, :delete, :list + COMMAND_NAME = "key" + def initialize args, def_options super(args, def_options) self.header = I18n.t("headers.key") - self.banner_header = "key" + self.list_params = [] self.add_params = ["KEY_NAME", "FILE"] self.delete_params = ["KEY_NAME"] end diff --git a/devops-client/lib/devops-client/options/main.rb b/devops-client/lib/devops-client/options/main.rb index 04811b8..d8986cc 100644 --- a/devops-client/lib/devops-client/options/main.rb +++ b/devops-client/lib/devops-client/options/main.rb @@ -2,42 +2,49 @@ require "optparse" require "devops-client/options/server_options" require "devops-client/options/image_options" require "devops-client/options/project_options" +require "devops-client/options/environment_options" +require "devops-client/options/category_options" require "devops-client/options/provider_options" -require "devops-client/options/flavor_options" require "devops-client/options/common_options" -require "devops-client/options/group_options" require "devops-client/options/deploy_options" require "devops-client/options/key_options" require "devops-client/options/user_options" -require "devops-client/options/tag_options" require "devops-client/options/script_options" require "devops-client/options/filter_options" -require "devops-client/options/network_options" -require "devops-client/options/bootstrap_templates_options" +require "devops-client/options/chef_options" +require "devops-client/options/role_options" +require "devops-client/options/stack_template_options" +require "devops-client/options/stack_options" class Main < CommonOptions + COMMAND_NAME = "" + def initialize args, def_options super(args, def_options) end def info o = nil + classes = [ + ChefOptions, + DeployOptions, + FilterOptions, + ImageOptions, + KeyOptions, + ProjectOptions, + EnvironmentOptions, + CategoryOptions, + ProviderOptions, + ScriptOptions, + ServerOptions, + UserOptions, + RoleOptions, + StackTemplateOptions, + StackOptions + ] options do |opts, options| - opts.banner << BootstrapTemplatesOptions.new(ARGV, default_options).error_banner - opts.banner << DeployOptions.new(ARGV, default_options).error_banner - opts.banner << FilterOptions.new(ARGV, default_options).error_banner - opts.banner << FlavorOptions.new(ARGV, default_options).error_banner - opts.banner << GroupOptions.new(ARGV, default_options).error_banner - opts.banner << ImageOptions.new(ARGV, default_options).error_banner - opts.banner << KeyOptions.new(ARGV, default_options).error_banner - opts.banner << NetworkOptions.new(ARGV, default_options).error_banner - opts.banner << ProjectOptions.new(ARGV, default_options).error_banner - opts.banner << ProviderOptions.new(ARGV, default_options).error_banner - opts.banner << ScriptOptions.new(ARGV, default_options).error_banner - opts.banner << ServerOptions.new(ARGV, default_options).error_banner - opts.banner << TagOptions.new(ARGV, default_options).error_banner - opts.banner << UserOptions.new(ARGV, default_options).error_banner + classes.each {|cl| opts.banner << cl.new(ARGV, default_options).error_banner} o = opts end puts(o.banner + "\n") diff --git a/devops-client/lib/devops-client/options/network_options.rb b/devops-client/lib/devops-client/options/network_options.rb deleted file mode 100644 index 8e527b9..0000000 --- a/devops-client/lib/devops-client/options/network_options.rb +++ /dev/null @@ -1,20 +0,0 @@ -require "optparse" -require "devops-client/options/common_options" - -class NetworkOptions < CommonOptions - - commands :list - - def initialize args, def_options - super(args, def_options) - self.header = I18n.t("headers.network") - self.banner_header = "network" - self.list_params = ["PROVIDER"] - end - - extend_options_method :list_options do |options| - options[:given_provider] = args[2] if args[2] - end - -end - diff --git a/devops-client/lib/devops-client/options/project_options.rb b/devops-client/lib/devops-client/options/project_options.rb index 64727e0..eeedc29 100644 --- a/devops-client/lib/devops-client/options/project_options.rb +++ b/devops-client/lib/devops-client/options/project_options.rb @@ -3,27 +3,26 @@ require "set" class ProjectOptions < CommonOptions - commands :create, :delete, :deploy, :list, {:multi => [:create]}, :servers, :stacks, {:set => [:run_list]}, :show, :test, :update, {:user => [:add, :delete]}, :delete_servers + commands :create, :delete, :list, {:set => [:run_list]}, :show, :update, {:user => [:add, :delete]}, :archive, :unarchive + + COMMAND_NAME = "project" def initialize args, def_options super(args, def_options) self.header = I18n.t("headers.project") - self.banner_header = "project" id = "PROJECT_ID" - env = "DEPLOY_ENV" + env = "ENVIRONMENT" + cat = "CATEGORY" + self.list_params = [] self.show_params = [id] + self.archive_params = [id] + self.unarchive_params = [id] self.create_params = [id] - self.delete_params = [id, "[#{env}]"] - self.deploy_params = [id, "[#{env}]"] - self.set_run_list_params = [id, env, "[(recipe[mycookbook::myrecipe])|(role[myrole]) ...]"] - self.servers_params = [id, "[#{env}]"] - self.stacks_params = [id, "[#{env}]"] - self.multi_create_params = [id] + self.delete_params = [id] + self.set_run_list_params = [id, "[RUN_LIST...]"] self.update_params = [id, "FILE"] - self.user_add_params = [id, "USER_NAME", "[USER_NAME ...]"] - self.user_delete_params = [id, "USER_NAME", "[USER_NAME ...]"] - self.test_params = [id, env] - self.delete_servers_params = [id, "[#{env}]"] + self.user_add_params = [id, "USER_NAME..."] + self.user_delete_params = [id, "USER_NAME..."] end def create_options @@ -31,31 +30,22 @@ class ProjectOptions < CommonOptions parser.banner << self.create_banner parser.resource_name = :project - parser.recognize_option_value(:groups, variable: 'GROUP_1,GROUP_2...') do |groups| - options[:groups] = groups.split(",") - end - parser.recognize_option_value(:file) do |file| abort("File '#{file}' does not exist") unless File.exist?(file) options[:file] = file end - parser.recognize_option_value(:subnets, variable: 'SUBNET_1,SUBNET_2...') do |subnets| - options[:subnets] = subnets.split(",") + parser.recognize_option_value(:description) do |description| + options[:description] = description end - parser.recognize_option_value(:users, variable: 'USER_1,USER_2...') do |users| - options[:users] = Set.new(users.split(",")) + parser.recognize_option_value(:project_users, variable: 'USER_1,USER_2...') do |users| + options[:users] = Set.new(users.split(",")).to_a end - parser.recognize_option_value(:deploy_env, option_key: :identifier) - parser.recognize_option_value(:flavor) - parser.recognize_option_value(:image) - parser.recognize_option_value(:run_list) - parser.recognize_option_value(:provider) - parser.recognize_option_value(:no_expires, type: :switch, switch_value: true, default: false) - parser.recognize_option_value(:expires) - + parser.recognize_option_value(:run_list, variable: 'ROLE_1,ROLE_2...') do |run_list| + options[:run_list] = Set.new(run_list.split(",")).to_a + end # TODO: # support short options names @@ -69,36 +59,4 @@ class ProjectOptions < CommonOptions end end - def user_add_options - self.options do |parser, options| - parser.banner << self.user_add_banner - - parser.recognize_option_value(:deploy_env, resource_name: :project, command_name: 'user_add') - end - end - - def user_delete_options - self.options do |parser, options| - parser.banner << self.user_delete_banner - - parser.recognize_option_value(:deploy_env, resource_name: :project, command_name: 'user_delete') - end - end - - def deploy_options - options do |parser, options| - parser.banner << self.deploy_banner - - parser.recognize_option_value(:servers, resource_name: :project, command_name: 'deploy') do |servers| - options[:servers] = servers.split(",") - end - end - end - - def delete_servers_options - self.options do |parser, options| - parser.recognize_option_value(:dry_run, resource_name: :project, type: :switch, default: false, switch_value: true, command_name: 'delete_servers') - end - end - end diff --git a/devops-client/lib/devops-client/options/provider_options.rb b/devops-client/lib/devops-client/options/provider_options.rb index adbf7c1..2b645de 100644 --- a/devops-client/lib/devops-client/options/provider_options.rb +++ b/devops-client/lib/devops-client/options/provider_options.rb @@ -3,14 +3,35 @@ require "devops-client/options/common_options" class ProviderOptions < CommonOptions - commands :list, :accounts + commands :list, :accounts, {:account => [:create, :delete]}, :flavors, :images, :networks, :security_groups, :vpc + + COMMAND_NAME = "provider" def initialize args, def_options super(args, def_options) self.header = I18n.t("headers.provider") - self.banner_header = "provider" self.list_params = [] self.accounts_params = %w(PROVIDER) + self.account_create_params = %w(PROVIDER ACCOUNT) + self.account_delete_params = %w(PROVIDER ACCOUNT) + self.flavors_params = %w(PROVIDER ACCOUNT) + self.images_params = %w(PROVIDER ACCOUNT) + self.networks_params = %w(PROVIDER ACCOUNT) + self.security_groups_params = %w(PROVIDER ACCOUNT [VPC_ID]) + self.vpc_params = %w(PROVIDER ACCOUNT) + end + + def account_create_options + self.options do |parser, options| + parser.banner << self.account_create_banner + parser.resource_name = "provider.account" + + parser.recognize_option_value(:description) + parser.recognize_option_value(:ssh_key) + parser.recognize_option_value(:use_iam_profile, type: :switch, switch_value: true, default: false) + parser.recognize_option_value(:access_key_id) + parser.recognize_option_value(:secret_access_key) + end end end diff --git a/devops-client/lib/devops-client/options/role_options.rb b/devops-client/lib/devops-client/options/role_options.rb new file mode 100644 index 0000000..da96262 --- /dev/null +++ b/devops-client/lib/devops-client/options/role_options.rb @@ -0,0 +1,28 @@ +require "devops-client/options/common_options" + +class RoleOptions < CommonOptions + commands :list, :policies, :create, :delete, :show + + COMMAND_NAME = "role" + + def initialize args, def_options + super(args, def_options) + self.header = I18n.t("headers.role") + self.policies_params = [] + self.create_params = ["ROLE_NAME"] + self.delete_params = ["ROLE_NAME"] + self.show_params = ["ROLE_NAME"] + self.list_params = [] + end + +=begin + def create_options + self.options do |parser, options| + parser.banner << self.create_banner + + parser.recognize_option_value(:new_password, resource_name: :user) + end + end +=end + +end diff --git a/devops-client/lib/devops-client/options/script_options.rb b/devops-client/lib/devops-client/options/script_options.rb index 42ffe54..f4394e8 100644 --- a/devops-client/lib/devops-client/options/script_options.rb +++ b/devops-client/lib/devops-client/options/script_options.rb @@ -4,10 +4,11 @@ class ScriptOptions < CommonOptions commands :list, :add, :delete, :run, :command + COMMAND_NAME = "script" + def initialize args, def_options super(args, def_options) self.header = I18n.t("headers.script") - self.banner_header = "script" sname = "SCRIPT_NAME" self.add_params = [sname, "FILE"] self.delete_params = [sname] diff --git a/devops-client/lib/devops-client/options/server_options.rb b/devops-client/lib/devops-client/options/server_options.rb index 0bb0f87..f1bb7b0 100644 --- a/devops-client/lib/devops-client/options/server_options.rb +++ b/devops-client/lib/devops-client/options/server_options.rb @@ -2,23 +2,26 @@ require "devops-client/options/common_options" class ServerOptions < CommonOptions - commands :add, :bootstrap, :create, :delete, :list, :pause, :reserve, :show, :unpause, :unreserve, :delete_list, :add_and_bootstrap_list + commands :add, :bootstrap, :create, :delete, :list, :pause, :reserve, :show, :unpause, :unreserve, :unbootstrap, :delete_list, :add_and_bootstrap_list + + COMMAND_NAME = "server" def initialize args, def_options super(args, def_options) self.header = I18n.t("headers.server") - self.banner_header = "server" - self.list_params = ["[chef|ec2|openstack|static]"] - self.create_params = ["PROJECT_ID", "DEPLOY_ENV"] - node_params = ["NODE_NAME"] - self.delete_params = node_params - self.show_params = node_params - self.pause_params = node_params - self.unpause_params = node_params - self.reserve_params = node_params - self.unreserve_params = node_params - self.bootstrap_params = ["INSTANCE_ID"] - self.add_params = ["PROJECT_ID", "DEPLOY_ENV", "IP", "SSH_USER", "KEY_ID"] + self.list_params = ["[PROVIDER]"] + self.create_params = ["PROJECT", "ENVIRONMENT", "CATEGORY"] + server_id = ["SERVER_ID"] + self.delete_list_params = ["SERVER_ID..."] + self.delete_params = server_id + self.show_params = server_id + self.pause_params = server_id + self.unpause_params = server_id + self.reserve_params = server_id + self.unreserve_params = server_id + self.bootstrap_params = server_id + self.unbootstrap_params = server_id + self.add_params = ["PROJECT", "ENVIRONMENT", "CATEGORY", "IP", "SSH_USER", "KEY_ID", "NAME"] self.add_and_bootstrap_list_params = ["PROJECT_ID", "DEPLOY_ENV", "SSH_USER", "KEY_ID", "IPS_FILE"] end @@ -28,13 +31,6 @@ class ServerOptions < CommonOptions parser.resource_name = :server parser.command_name = :delete - parser.recognize_option_value(:instance, - type: :switch, - default: 'node', - switch_value: 'instance', - option_key: :key - ) - parser.recognize_option_value(:no_ask, type: :switch, default: false, @@ -43,66 +39,6 @@ class ServerOptions < CommonOptions end end - def pause_options - options do |parser, options| - parser.banner << self.delete_banner - - parser.recognize_option_value(:instance, - resource_name: :server, - command_name: :pause, - type: :switch, - default: 'node', - switch_value: 'instance', - option_key: :key - ) - end - end - - def unpause_options - options do |parser, options| - parser.banner << self.delete_banner - - parser.recognize_option_value(:instance, - resource_name: :server, - command_name: :unpause, - type: :switch, - default: 'node', - switch_value: 'instance', - option_key: :key - ) - end - end - - def reserve_options - options do |parser, options| - parser.banner << self.delete_banner - - parser.recognize_option_value(:instance, - resource_name: :server, - command_name: :reserve, - type: :switch, - default: 'node', - switch_value: 'instance', - option_key: :key - ) - end - end - - def unreserve_options - options do |parser, options| - parser.banner << self.delete_banner - - parser.recognize_option_value(:instance, - resource_name: :server, - command_name: :unreserve, - type: :switch, - default: 'node', - switch_value: 'instance', - option_key: :key - ) - end - end - def create_options options do |parser, options| parser.banner << self.create_banner @@ -117,15 +53,22 @@ class ServerOptions < CommonOptions ) parser.recognize_option_value(:name, short: '-N') - parser.recognize_option_value(:force, short: '-f') - parser.recognize_option_value(:key) + parser.recognize_option_value('skip_rollback', + type: :switch, + switch_value: true, + option_key: :skip_rollback, + i18n_scope: 'create' + ) + parser.recognize_option_value(:ssh_key) +=begin parser.recognize_option_value(:groups, short: '-G', variable: 'GROUP_1,GROUP_2...' ) do |groups| options[:groups] = groups.split(",") end +=end parser.recognize_option_value(:private_ip, i18n_scope: 'create') @@ -142,7 +85,7 @@ class ServerOptions < CommonOptions parser.resource_name = :server parser.command_name = :bootstrap - parser.recognize_option_value(:name, short: '-N') + parser.recognize_option_value(:cm_name, short: '-N') parser.recognize_option_value(:bootstrap_template) parser.recognize_option_value(:run_list) do |list| options[:run_list] = list.split(",") @@ -168,12 +111,4 @@ class ServerOptions < CommonOptions end end - def delete_banner - self.banner_header + " delete NODE_NAME [NODE_NAME ...]\n" - end - - def delete_list_banner - self.banner_header + " delete_list INSTANCE_ID [INSTANCE_ID ...]\n" - end - end diff --git a/devops-client/lib/devops-client/options/stack_options.rb b/devops-client/lib/devops-client/options/stack_options.rb index a33a33a..5092a5c 100644 --- a/devops-client/lib/devops-client/options/stack_options.rb +++ b/devops-client/lib/devops-client/options/stack_options.rb @@ -4,12 +4,14 @@ class StackOptions < CommonOptions commands :create, :delete, :list, :show, :sync, :deploy, :reserve, :unreserve, :change_stack_template + COMMAND_NAME = "stack" + def initialize args, def_options super(args, def_options) self.header = I18n.t("headers.stack") - self.banner_header = "stack" - self.list_params = ["[provider]", "[ec2|openstack]"] + self.list_params = ["[provider]"] self.show_params = ["STACK"] + self.create_params = %w(PROJECT ENVIRONMENT CATEGORY) self.delete_params = ["STACK"] self.sync_params = ["STACK"] self.deploy_params = ["STACK"] @@ -22,11 +24,7 @@ class StackOptions < CommonOptions parser.banner << self.create_banner parser.resource_name = :stack - parser.recognize_option_value(:provider) parser.recognize_option_value(:id) - parser.recognize_option_value(:project) - parser.recognize_option_value(:deploy_env) - parser.recognize_option_value(:stack_template) parser.recognize_option_value(:parameters_file) parser.recognize_option_value(:tags_file) parser.recognize_option_value(:run_list) diff --git a/devops-client/lib/devops-client/options/stack_template_options.rb b/devops-client/lib/devops-client/options/stack_template_options.rb index 6f2fb08..be32c95 100644 --- a/devops-client/lib/devops-client/options/stack_template_options.rb +++ b/devops-client/lib/devops-client/options/stack_template_options.rb @@ -2,17 +2,17 @@ require "devops-client/options/common_options" class StackTemplateOptions < CommonOptions - commands :create, :delete, :list, :show, :update_url, :update_available_parameters + commands :create, :delete, :list, :show + + COMMAND_NAME = "stack_template" def initialize args, def_options super(args, def_options) self.header = I18n.t("headers.stack_template") self.banner_header = "stack_template" - self.list_params = ["[provider]", "[ec2|openstack]"] + self.list_params = ["[provider]"] self.show_params = ["STACK_TEMPLATE"] self.delete_params = ["STACK_TEMPLATE"] - self.update_url_params = ["STACK_TEMPLATE"] - self.update_available_parameters_params = ["STACK_TEMPLATE"] end def create_options @@ -21,17 +21,9 @@ class StackTemplateOptions < CommonOptions parser.resource_name = :stack_template parser.recognize_option_value(:provider, default: nil) + parser.recognize_option_value(:provider_account, default: nil) parser.recognize_option_value(:id) parser.recognize_option_value(:template_file) end end - - extend_options_method :list_options do |options| - if args[2] == "provider" and args[3] - options[:given_provider] = args[3] - elsif args[2] - options[:given_provider] = args[2] - end - end - end diff --git a/devops-client/lib/devops-client/options/tag_options.rb b/devops-client/lib/devops-client/options/tag_options.rb deleted file mode 100644 index 5494071..0000000 --- a/devops-client/lib/devops-client/options/tag_options.rb +++ /dev/null @@ -1,14 +0,0 @@ -require "devops-client/options/common_options" - -class TagOptions < CommonOptions - commands :create, :delete, :list - - def initialize args, def_options - super(args, def_options) - self.header = I18n.t("headers.tag") - self.banner_header = "tag" - self.create_params = ["NODE_NAME", "TAG_NAME", "[TAG_NAME ...]"] - self.delete_params = ["NODE_NAME", "TAG_NAME", "[TAG_NAME ...]"] - self.list_params = ["NODE_NAME"] - end -end diff --git a/devops-client/lib/devops-client/options/user_options.rb b/devops-client/lib/devops-client/options/user_options.rb index f6da6e0..9017f19 100644 --- a/devops-client/lib/devops-client/options/user_options.rb +++ b/devops-client/lib/devops-client/options/user_options.rb @@ -1,17 +1,20 @@ require "devops-client/options/common_options" class UserOptions < CommonOptions - commands :create, :delete, :grant, :list, :password, :email + commands :create, :delete, :list, :password, :email, role: [:add, :delete] + + COMMAND_NAME = "user" def initialize args, def_options super(args, def_options) self.header = I18n.t("headers.user") - self.banner_header = "user" + self.list_params = [] self.create_params = ["USER_NAME", "EMAIL"] self.delete_params = ["USER_NAME"] self.password_params = ["USER_NAME"] self.email_params = ["USER_NAME", "EMAIL"] - self.grant_params = ["USER_NAME", "[COMMAND]", "[PRIVILEGES]"] + self.role_add_params = ["USER_NAME"] + self.role_delete_params = ["USER_NAME"] end def create_options diff --git a/devops-client/lib/devops-client/output/base.rb b/devops-client/lib/devops-client/output/base.rb index 8a9d7ec..2aee7dc 100644 --- a/devops-client/lib/devops-client/output/base.rb +++ b/devops-client/lib/devops-client/output/base.rb @@ -50,19 +50,18 @@ module Output headers.unshift(I18n.t("output.table_header.number")) rows.each_with_index {|row, i| row.unshift(i + 1)} end - table = Terminal::Table.new do |t| + Terminal::Table.new do |t| titles = ["#{I18n.t("output.table_header.api_version")}: #{self.options[:api]}", "#{title}" ] t.title = titles.join( "\n" ) t.headings = headers - t.add_row rows[0] - rows[1..-1].each do |r| + t.add_row rows[0] if rows[0] + (rows[1..-1] || []).each do |r| t.add_separator if separator t.add_row r end end - table end def create_csv headers, rows, with_num=true, separator=":" @@ -72,7 +71,16 @@ module Output end c = CSV.new("", {col_sep: separator, headers: true}) c << headers - rows.each{|r| c << r} + rows.each do |r| + row = r.map do |cell| + if cell.is_a?(Array) + cell.join(',') + else + cell.to_s + end + end + c << row + end c.string end @@ -85,12 +93,27 @@ module Output [headers, rows] end + def headers_and_rows_for_array(records, field) + headers = [ I18n.t("output.table_header.#{field}") ] + rows = records.map{|record| [ record ] } + [headers, rows] + end + + def time_to_s value + return "null" if value.nil? + Time.at(value).to_s + end + private def shrink_cells_if_width_exceeded(rows) rows.each do |row| row.each_with_index do |cell, i| - row[i] = split_to_parts_of_size(cell, MAX_CELL_WIDTH) + if cell.is_a?(String) + row[i] = split_to_parts_of_size(cell, MAX_CELL_WIDTH) + elsif cell.is_a?(Array) + row[i] = cell.join("\n") + end end end end diff --git a/devops-client/lib/devops-client/output/bootstrap_templates.rb b/devops-client/lib/devops-client/output/bootstrap_templates.rb deleted file mode 100644 index b1ffeef..0000000 --- a/devops-client/lib/devops-client/output/bootstrap_templates.rb +++ /dev/null @@ -1,29 +0,0 @@ -require "devops-client/output/base" - -module Output - class BootstrapTemplates < Base - - def table - headers, rows = create(@data) - create_table(headers, rows, I18n.t("output.title.bootstrap_template.list")) - end - - def csv - headers, rows = create(@data) - create_csv(headers, rows) - end - - private - def create list - abort I18n.t("output.not_found.bootstrap_template.list") if list.nil? or list.empty? - headers = [ I18n.t("output.table_header.name") ] - rows = [] - list.each do |l| - rows.push [ l ] - end - return headers, rows - end - - end -end - diff --git a/devops-client/lib/devops-client/output/category.rb b/devops-client/lib/devops-client/output/category.rb new file mode 100644 index 0000000..3adcdd6 --- /dev/null +++ b/devops-client/lib/devops-client/output/category.rb @@ -0,0 +1,96 @@ +require "devops-client/output/base" + +module Output + class Category < Base + + def table + title = nil + with_separator = false + headers, rows = case options[:current_command] + when :show + title = I18n.t("output.title.category.show", env: options[:env], project: options[:project], cat: options[:cat]) + with_separator = true + create_show(@data) + when :servers_list + title = I18n.t("output.title.environment.servers", env: options[:env], project: options[:project]) + create_servers(@data) + when :stacks + title = I18n.t("output.title.environment.stacks", env: options[:env], project: options[:project]) + create_stacks(@data) + else + title = I18n.t("output.title.category.list", project: options[:project]) + create_list(@data) + end + create_table(headers, rows, title, with_num?, with_separator) + end + + def csv + with_num = true + headers, rows = case @additional_options[:current_command] + when :list + create_list(@data) + when :show + with_num = false + create_show(@data) + when :servers + create_servers(@data) + when :test + create_test(@data) + end + create_csv(headers, rows, with_num?) + end + + private + def create_list list + abort(I18n.t("output.not_found.category.list")) if list.empty? + rows = list.map {|l| [l["id"]]} + headers = [ I18n.t("output.table_header.id") ] + return headers, rows + end + + def create_show show + provider = show["provider"] + cm_tool = show["cm_tool"] + row = [ + show["id"], + provider["name"], + provider["account"], + provider["flavor"], + provider["image"], + provider["security_groups"], + provider["vpc_id"], + provider["subnet"], + cm_tool["name"], + cm_tool["bootstrap_template"] + ] + headers = [ + I18n.t("output.table_header.id"), + I18n.t("output.table_header.provider"), + I18n.t("output.table_header.provider_account"), + I18n.t("output.table_header.flavor"), + I18n.t("output.table_header.image"), + I18n.t("output.table_header.security_groups"), + I18n.t("output.table_header.vpc_id"), + I18n.t("output.table_header.subnet"), + I18n.t("output.table_header.cm_tool"), + I18n.t("output.table_header.bootstrap_template") + ] + return headers, [row] + end + + def create_servers servers + abort(I18n.t("output.not_found.category.servers", env: options[:env], project: options[:project])) if servers.empty? + fields_to_output = %w(id name project environment category cm_name remote_user provider) + headers_and_rows(servers, fields_to_output) + end + + def create_stacks(stacks) + abort(I18n.t("output.not_found.environment.stacks", env: options[:env], project: options[:project])) if stacks.empty? + + fields_to_output = %w(id deploy_env stack_template cloud_stack_id stack_status provider) + + headers_and_rows(stacks, fields_to_output) + end + + end +end diff --git a/devops-client/lib/devops-client/output/chef.rb b/devops-client/lib/devops-client/output/chef.rb new file mode 100644 index 0000000..85148e7 --- /dev/null +++ b/devops-client/lib/devops-client/output/chef.rb @@ -0,0 +1,44 @@ +require "devops-client/output/base" + +module Output + class Chef < Base + + def table + headers, rows, title = nil, nil, nil + case options[:current_command] + when :bootstrap_templates + headers, rows = create_bootstrap_templates + title = "output.title.chef.bootstrap_templates" + when :tags_list + headers, rows = create_tags_list + title = "output.title.chef.tags_list" + end + create_table(headers, rows, I18n.t(title)) + end + + def csv + headers, rows = nil, nil + case options[:current_command] + when :bootstrap_templates + headers, rows = create_bootstrap_templates + when :tags_list + headers, rows = create_tags_list + end + + create_csv(headers, rows) + end + + private + def create_bootstrap_templates + abort I18n.t("output.not_found.chef.bootstrap_template") if @data.empty? + headers_and_rows_for_array(@data, "name") + end + + def create_tags_list + abort I18n.t("output.not_found.chef.tags_list") if @data.empty? + headers_and_rows_for_array(@data, "name") + end + + end +end + diff --git a/devops-client/lib/devops-client/output/environment.rb b/devops-client/lib/devops-client/output/environment.rb new file mode 100644 index 0000000..862fb95 --- /dev/null +++ b/devops-client/lib/devops-client/output/environment.rb @@ -0,0 +1,106 @@ +require "devops-client/output/base" + +module Output + class Environment < Base + + def table + title = nil + with_separator = false + headers, rows = case options[:current_command] + when :show + title = I18n.t("output.title.environment.show", id: options[:env], project: options[:project]) + with_separator = true + create_show(@data) + when :servers + title = I18n.t("output.title.environment.servers", env: options[:env], project: options[:project]) + create_servers(@data) + when :stacks + title = I18n.t("output.title.environment.stacks", env: options[:env], project: options[:project]) + create_stacks(@data) + when :test + title = I18n.t("output.title.project.test", :project => ARGV[2], :env => ARGV[3]) + create_test(@data) + else + title = I18n.t("output.title.environment.list", project: options[:project]) + create_list(@data) + end + create_table(headers, rows, title, with_num?, with_separator) + end + + def csv + with_num = true + headers, rows = case @additional_options[:current_command] + when :list + create_list(@data) + when :show + with_num = false + create_show(@data) + when :servers + create_servers(@data) + when :test + create_test(@data) + end + create_csv(headers, rows, with_num?) + end + + private + def create_list list + abort(I18n.t("output.not_found.environment.list")) if list.empty? + rows = list.map {|l| [l["id"]]} + headers = [ I18n.t("output.table_header.id") ] + return headers, rows + end + + def create_show show + row = [ + show["id"], + show["categories"].map{|cat| cat["id"]}, + show["users"], + show["run_list"], + show["expires"] + ] + headers = [ + I18n.t("output.table_header.id"), + I18n.t("output.table_header.categories"), + I18n.t("output.table_header.users"), + I18n.t("output.table_header.run_list"), + I18n.t("output.table_header.expires") + ] + return headers, [row] + end + + def create_servers servers + abort(I18n.t("output.not_found.servers.servers", env: options[:env], project: options[:project])) if servers.empty? + fields_to_output = %w(id name project environment category cm_name remote_user provider) + headers_and_rows(servers, fields_to_output) + end + + def create_test test + rows = [] + headers = [ + I18n.t("output.table_header.server"), + I18n.t("output.table_header.node_name"), + I18n.t("output.table_header.creation"), + I18n.t("output.table_header.bootstrap"), + I18n.t("output.table_header.deletion") + ] + test["servers"].each do |s| + rows.push [ s["id"], + s["chef_node_name"], + "#{s["create"]["status"]}\n#{s["create"]["time"]}", + "#{s["bootstrap"]["status"]}\n#{s["bootstrap"]["time"]}", + "#{s["delete"]["status"]}\n#{s["delete"]["time"]}" ] + end + return headers, rows + end + + def create_stacks(stacks) + abort(I18n.t("output.not_found.environment.stacks", env: options[:env], project: options[:project])) if stacks.empty? + + fields_to_output = %w(id deploy_env stack_template cloud_stack_id stack_status provider) + + headers_and_rows(stacks, fields_to_output) + end + + end +end diff --git a/devops-client/lib/devops-client/output/filters.rb b/devops-client/lib/devops-client/output/filters.rb index 7f6c9a9..668cad2 100644 --- a/devops-client/lib/devops-client/output/filters.rb +++ b/devops-client/lib/devops-client/output/filters.rb @@ -15,13 +15,8 @@ module Output private def create list - abort(I18n.t("output.not_found.filter.list")) if list.nil? or list.empty? - headers = [ I18n.t("output.table_header.image_id") ] - rows = [] - list.each do |l| - rows.push [ l ] - end - return headers, rows + abort(I18n.t("output.not_found.filter.list")) if @data.empty? + headers_and_rows_for_array(@data, "image_id") end end end diff --git a/devops-client/lib/devops-client/output/flavors.rb b/devops-client/lib/devops-client/output/flavors.rb deleted file mode 100644 index ffb56a9..0000000 --- a/devops-client/lib/devops-client/output/flavors.rb +++ /dev/null @@ -1,48 +0,0 @@ -require "devops-client/output/base" -require "devops-client/output/concerns/has_provider" - -module Output - class Flavors < Base - include Concerns::HasProvider - - def table - headers, rows = create(@data, @options[:given_provider]) - create_table(headers, rows, I18n.t("output.title.flavor.list")) - end - - def csv - headers, rows = create(@data, @options[:given_provider]) - create_csv(headers, rows) - end - - private - def create list, provider - abort(I18n.t("output.not_found.flavor.list")) if list.nil? or list.empty? - headers = nil - rows = [] - if provider == "openstack" - headers = [ - I18n.t("output.table_header.id"), - I18n.t("output.table_header.virtual_cpus"), - I18n.t("output.table_header.disk"), - I18n.t("output.table_header.ram") - ] - list.each do |l| - rows << [ l["id"], l["v_cpus"], l["disk"], l["ram"] ] - end - elsif provider == "ec2" - headers = [ - I18n.t("output.table_header.name"), - I18n.t("output.table_header.id"), - I18n.t("output.table_header.virtual_cpus"), - I18n.t("output.table_header.disk"), - I18n.t("output.table_header.ram") - ] - list.each do |l| - rows << [ l["name"], l["id"], l["cores"], l["disk"], l["ram"] ] - end - end - return headers, rows - end - end -end diff --git a/devops-client/lib/devops-client/output/groups.rb b/devops-client/lib/devops-client/output/groups.rb deleted file mode 100644 index 3f1e447..0000000 --- a/devops-client/lib/devops-client/output/groups.rb +++ /dev/null @@ -1,43 +0,0 @@ -require "devops-client/output/base" - -module Output - class Groups < Base - - def table - headers, rows = create(@data) - create_table(headers, rows, I18n.t("output.title.group.list"), true, true) - end - - def csv - headers, rows = create(@data) - create_csv(headers, rows) - end - - private - def create list - abort(I18n.t("output.not_found.group.list")) if list.nil? or list.empty? - headers = [ - I18n.t("output.table_header.name"), - I18n.t("output.table_header.protocol"), - I18n.t("output.table_header.from"), - I18n.t("output.table_header.to"), - I18n.t("output.table_header.cidr"), - I18n.t("output.table_header.description") - ] - rows = [] - list.each do |name, v| - next if v.nil? or v.empty? - p, f, t, c = [], [], [], [] - v["rules"].map do |l| - p.push l["protocol"] - f.push l["from"] - t.push l["to"] - c.push l["cidr"] - end - rows.push [ name, p.join("\n"), f.join("\n"), t.join("\n"), c.join("\n"), v["description"] ] - end - return headers, rows - end - - end -end diff --git a/devops-client/lib/devops-client/output/image.rb b/devops-client/lib/devops-client/output/image.rb index 8c16081..b265b32 100644 --- a/devops-client/lib/devops-client/output/image.rb +++ b/devops-client/lib/devops-client/output/image.rb @@ -39,26 +39,26 @@ module Output I18n.t("output.table_header.status") ] else - list.each {|l| rows.push [ l["id"], l["name"], l["bootstrap_template"], l["remote_user"], l["provider"] ] } + list.each {|l| rows.push [ l["id"], l["name"], l["remote_user"], l["provider"], time_to_s(l["created_at"]) ] } [ I18n.t("output.table_header.id"), I18n.t("output.table_header.name"), - I18n.t("output.table_header.template"), I18n.t("output.table_header.remote_user"), - I18n.t("output.table_header.provider") + I18n.t("output.table_header.provider"), + I18n.t("output.table_header.created_at") ] end return headers, rows end def create_show - rows = [ [ @data["id"], @data["name"], @data["bootstrap_template"], @data["remote_user"], @data["provider"] ] ] + rows = [ [ @data["id"], @data["name"], @data["remote_user"], @data["provider"], time_to_s(@data["created_at"]) ] ] headers = [ I18n.t("output.table_header.id"), I18n.t("output.table_header.name"), - I18n.t("output.table_header.template"), I18n.t("output.table_header.remote_user"), - I18n.t("output.table_header.provider") + I18n.t("output.table_header.provider"), + I18n.t("output.table_header.created_at") ] return headers, rows end diff --git a/devops-client/lib/devops-client/output/key.rb b/devops-client/lib/devops-client/output/key.rb index cf9c853..7d89c83 100644 --- a/devops-client/lib/devops-client/output/key.rb +++ b/devops-client/lib/devops-client/output/key.rb @@ -18,8 +18,8 @@ module Output def create list abort(I18n.t("output.not_found.key.list")) if list.nil? or list.empty? rows = [] - list.each {|l| rows.push [ l["id"], l["scope"] ] } - return [ I18n.t("output.table_header.id"), I18n.t("output.table_header.scope") ], rows + list.each {|l| rows.push [ l["id"], l["filename"], time_to_s(l["created_at"]) ] } + return [ I18n.t("output.table_header.id"), I18n.t("output.table_header.filename"), I18n.t("output.table_header.created_at") ], rows end end end diff --git a/devops-client/lib/devops-client/output/network.rb b/devops-client/lib/devops-client/output/network.rb deleted file mode 100644 index da39491..0000000 --- a/devops-client/lib/devops-client/output/network.rb +++ /dev/null @@ -1,48 +0,0 @@ -require "devops-client/output/base" -require "devops-client/output/concerns/has_provider" - -module Output - class Network < Base - include Concerns::HasProvider - - - def table - headers, rows = create(@data, @options[:given_provider]) - create_table(headers, rows, I18n.t("output.title.network.list")) - end - - def csv - headers, rows = create(@data, @options[:given_provider]) - create_csv(headers, rows) - end - - private - def create list, provider - headers = nil - rows = [] - if provider == "openstack" - abort(I18n.t("output.not_found.network.list")) if list.nil? or list.empty? - headers = [ I18n.t("output.table_header.name"), I18n.t("output.table_header.cidr") ] - list.each do |l| - rows.push [ l["name"], l["cidr"] ] - end - elsif provider == "ec2" - if list.nil? or list.empty? - puts(I18n.t("output.not_found.network.list")) - return nil, nil - end - headers = [ - I18n.t("output.table_header.subnet"), - I18n.t("output.table_header.vpc_id"), - I18n.t("output.table_header.cidr"), - I18n.t("output.table_header.zone") - ] - list.each do |l| - rows.push [ l["subnetId"], l["vpcId"], l["cidr"], l["zone"] ] - end - end - return headers, rows - end - end -end - diff --git a/devops-client/lib/devops-client/output/project.rb b/devops-client/lib/devops-client/output/project.rb index 1123c51..0b80270 100644 --- a/devops-client/lib/devops-client/output/project.rb +++ b/devops-client/lib/devops-client/output/project.rb @@ -9,11 +9,11 @@ module Output def table title = nil with_separator = false - headers, rows = case options[:output_type] + headers, rows = case options[:current_command] when :show - title = I18n.t("output.title.project.show", :name => @data["name"]) + title = I18n.t("output.title.project.show", :name => @data["id"]) with_separator = true - create_show(@data) + create_show when :servers title = ARGV[2] title += " " + ARGV[3] unless ARGV[3].nil? @@ -29,7 +29,7 @@ module Output create_test(@data) else title = I18n.t("output.title.project.list") - create_list(@data) + create_list end create_table(headers, rows, title, with_num?, with_separator) end @@ -38,10 +38,10 @@ module Output with_num = true headers, rows = case @additional_options[:output_type] when :list - create_list(@data) + create_list when :show with_num = false - create_show(@data) + create_show when :servers create_servers(@data) when :test @@ -51,57 +51,25 @@ module Output end private - def create_list list - abort(I18n.t("output.not_found.project.list")) if list.empty? - rows = list.map {|l| [l["name"]]} + def create_list + abort(I18n.t("output.not_found.project.list")) if @data.empty? + rows = @data.map {|l| [l["id"]]} headers = [ I18n.t("output.table_header.id") ] return headers, rows end - def create_show show + def create_show rows = [] - if show["type"] == "multi" - show["deploy_envs"].each do |de| - subprojects = [] - nodes = [] - de["servers"].each do |s| - s["subprojects"].each do |sp| - subprojects.push "#{sp["name"]} - #{sp["env"]}" - nodes.push sp["node"] - end - end - rows.push [ de["identifier"], subprojects.join("\n"), nodes.join("\n"), de["users"].join("\n") ] - end - headers = [ - I18n.t("output.table_header.deploy_env"), - I18n.t("output.table_header.subproject") + " - " + I18n.t("output.table_header.deploy_env"), - I18n.t("output.table_header.node_number"), - I18n.t("output.table_header.users") - ] - else - show["deploy_envs"].each_with_index do |de, i| - rows.push [ - show["name"], - de["identifier"], - de["image"], - de["flavor"], - (de["run_list"] || []).join("\n"), - (de["groups"] || []).join("\n"), - (de["subnets"] || []).join("\n"), - (de["users"] || []).join("\n") - ] - end - headers = [ - I18n.t("output.table_header.id"), - I18n.t("output.table_header.deploy_env"), - I18n.t("output.table_header.image_id"), - I18n.t("output.table_header.flavor"), - I18n.t("output.table_header.run_list"), - I18n.t("output.table_header.groups"), - I18n.t("output.table_header.subnets"), - I18n.t("output.table_header.users") - ] - end + rows = [ [@data["id"], @data["description"], @data["environments"].map{|e| e["id"]}, @data["owner"], @data["project_users"], @data["run_list"], time_to_s(@data["created_at"])] ] + headers = [ + I18n.t("output.table_header.id"), + I18n.t("output.table_header.description"), + I18n.t("output.table_header.environments"), + I18n.t("output.table_header.owner"), + I18n.t("output.table_header.users"), + I18n.t("output.table_header.run_list"), + I18n.t("output.table_header.created_at") + ] return headers, rows end diff --git a/devops-client/lib/devops-client/output/provider.rb b/devops-client/lib/devops-client/output/provider.rb index fde48cf..40eda5d 100644 --- a/devops-client/lib/devops-client/output/provider.rb +++ b/devops-client/lib/devops-client/output/provider.rb @@ -4,23 +4,48 @@ module Output class Provider < Base def table - case options[:output_type] + case options[:current_command] when :list headers, rows = create_list title = I18n.t("output.title.provider.list") when :accounts - headers, rows = create_accounts + headers, rows = create_accounts(options[:provider]) title = I18n.t("output.title.provider.accounts", provider: options[:provider]) + when :flavors + headers, rows = create_flavors(options[:provider]) + title = I18n.t("output.title.provider.flavors", provider: options[:provider], account: options[:account]) + when :images + headers, rows = create_images(options[:provider]) + title = I18n.t("output.title.provider.images", provider: options[:provider], account: options[:account]) + when :security_groups + headers, rows = create_security_groups(options[:provider]) + title = I18n.t("output.title.provider.security_groups", provider: options[:provider], account: options[:account]) + when :vpc + headers, rows = create_vpc + title = I18n.t("output.title.provider.vpcs", provider: options[:provider], account: options[:account]) + when :networks + headers, rows = create_networks(options[:provider]) + title = I18n.t("output.title.provider.networks", provider: options[:provider], account: options[:account]) end create_table(headers, rows, title) end def csv - case options[:output_type] + case options[:current_command] when :list headers, rows = create_list when :accounts headers, rows = create_accounts + when :flavors + headers, rows = create_flavors(options[:provider]) + when :images + headers, rows = create_images(options[:provider]) + when :security_groups + headers, rows = create_security_groups(options[:provider]) + when :vpc + headers, rows = create_vpc + when :networks + headers, rows = create_networks(options[:provider]) end create_csv(headers, rows, with_num?) end @@ -30,28 +55,131 @@ module Output def create_list abort(I18n.t("output.not_found.provider.list")) if @data.empty? headers = [ I18n.t("output.table_header.provider") ] - rows = [] - @data.each do |l| - rows.push [ l ] - end + rows = @data.map {|l| [ l ]} return headers, rows end - def create_accounts + def create_accounts provider headers = [ I18n.t("output.table_header.id"), I18n.t("output.table_header.description"), I18n.t("output.table_header.ssh_key") ] + keys = %w(account_name description ssh_key) + case provider + when Providers::Aws + headers.push I18n.t("output.table_header.use_iam_profile") + keys.push "use_iam_profile" + when Providers::Openstack + when Providers::Static + end + headers.push I18n.t("output.table_header.created_at") rows = @data.map do |account| - [ - account['account_name'], - account['description'], - account['ssh_key'] - ] + keys.map{|key| account[key]}.push(time_to_s(account["created_at"])) end [headers, rows] end + def create_flavors provider + abort(I18n.t("output.not_found.flavor.list")) if @data.nil? or @data.empty? + headers = nil + rows = [] + case provider + when Providers::Aws + headers = [ + I18n.t("output.table_header.name"), + I18n.t("output.table_header.id"), + I18n.t("output.table_header.virtual_cpus"), + I18n.t("output.table_header.disk"), + I18n.t("output.table_header.ram") + ] + @data.each do |l| + rows << [ l["name"], l["id"], l["cores"], l["disk"], l["ram"] ] + end + when Providers::Openstack + headers = [ + I18n.t("output.table_header.id"), + I18n.t("output.table_header.virtual_cpus"), + I18n.t("output.table_header.disk"), + I18n.t("output.table_header.ram") + ] + @data.each do |l| + rows << [ l["id"], l["v_cpus"], l["disk"], l["ram"] ] + end + end + return headers, rows + end + + def create_networks provider + headers = nil + rows = [] + case provider + when Providers::Openstack + abort(I18n.t("output.not_found.network.list")) if @data.empty? + headers = [ I18n.t("output.table_header.name"), I18n.t("output.table_header.cidr") ] + @data.each do |l| + rows.push [ l["name"], l["cidr"] ] + end + when Providers::Aws + if @data.empty? + puts(I18n.t("output.not_found.network.list")) + return nil, nil + end + headers = [ + I18n.t("output.table_header.subnet"), + I18n.t("output.table_header.vpc_id"), + I18n.t("output.table_header.cidr"), + I18n.t("output.table_header.zone") + ] + @data.each do |l| + rows.push [ l["subnetId"], l["vpcId"], l["cidr"], l["zone"] ] + end + end + return headers, rows + + end + + def create_images provider + abort(I18n.t("output.not_found.image.list")) if @data.empty? + rows = [] + @data.each {|l| rows.push [ l["name"], l["id"], l["status"] ]} + headers = [ + I18n.t("output.table_header.name"), + I18n.t("output.table_header.id"), + I18n.t("output.table_header.status") + ] + return headers, rows + end + + def create_security_groups provider + abort(I18n.t("output.not_found.security_groups.list")) if @data.empty? + headers = [ + I18n.t("output.table_header.name"), + I18n.t("output.table_header.protocol"), + I18n.t("output.table_header.from"), + I18n.t("output.table_header.to"), + I18n.t("output.table_header.cidr"), + I18n.t("output.table_header.description") + ] + rows = [] + @data.each do |name, v| + next if v.nil? or v.empty? + p, f, t, c = [], [], [], [] + v["rules"].map do |l| + p.push l["protocol"] + f.push l["from"] + t.push l["to"] + c.push l["cidr"] + end + rows.push [ name, p.join("\n"), f.join("\n"), t.join("\n"), c.join("\n"), v["description"] ] + end + return headers, rows + end + + def create_vpc + abort(I18n.t("output.not_found.vpc.list")) if @data.empty? + headers_and_rows(@data, %w(vpc_id cidr)) + end + end end diff --git a/devops-client/lib/devops-client/output/role.rb b/devops-client/lib/devops-client/output/role.rb new file mode 100644 index 0000000..358ec7a --- /dev/null +++ b/devops-client/lib/devops-client/output/role.rb @@ -0,0 +1,75 @@ +require "devops-client/output/base" + +module Output + class Role < Base + + def table + title, headers, rows = nil, nil, nil + case options[:current_command] + when :list + headers, rows = prepare_list + title = "output.title.role.list" + when :show + headers, rows = prepare_show + title = "output.title.role.show" + when :policies + headers, rows = prepare_policies + title = "output.title.role.policies" + end + + create_table headers, rows, I18n.t(title) + end + + def csv + headers, rows = nil, nil + case options[:current_command] + when :list + headers, rows = prepare_list + when :show + headers, rows = prepare_show + when :policies + headers, rows = prepare_policies + end + create_csv headers, rows + end + + private + def prepare_list + headers = [ + I18n.t("output.table_header.id"), + I18n.t("output.table_header.name"), + I18n.t("output.table_header.description"), + I18n.t("output.table_header.policies"), + I18n.t("output.table_header.created_at") + ] + rows = @data.map do |role| + [ role["id"], role["name"], role["description"], role["policies"], time_to_s(role["created_at"]) ] + end + return headers, rows + end + + def prepare_show + headers = [ + I18n.t("output.table_header.id"), + I18n.t("output.table_header.name"), + I18n.t("output.table_header.description"), + I18n.t("output.table_header.policies"), + I18n.t("output.table_header.created_at") + ] + rows = [[ @data["id"], @data["name"], @data["description"], @data["policies"], time_to_s(@data["created_at"]) ]] + return headers, rows + end + + def prepare_policies + headers = [ + I18n.t("output.table_header.id"), + I18n.t("output.table_header.description"), + I18n.t("output.table_header.dependencies") + ] + rows = @data.map do |policy| + [ policy["id"], policy["description"], policy["dependencies"] ] + end + return headers, rows + end + end +end diff --git a/devops-client/lib/devops-client/output/server.rb b/devops-client/lib/devops-client/output/server.rb index 940679c..2770116 100644 --- a/devops-client/lib/devops-client/output/server.rb +++ b/devops-client/lib/devops-client/output/server.rb @@ -18,7 +18,7 @@ module Output end create_list else - title = I18n.t("output.title.server.show", :name => @data["chef_node_name"]) + title = I18n.t("output.title.server.show", :name => options[:server]) create_show end create_table headers, rows, title @@ -73,11 +73,11 @@ module Output I18n.t("output.table_header.created_at") ] else - keys = ["id", "chef_node_name"] + keys = ["id", "name"] title = "Servers" [ I18n.t("output.table_header.instance_id"), - I18n.t("output.table_header.node_name") + I18n.t("output.table_header.name") ] end list.each do |l| @@ -92,18 +92,20 @@ module Output rows = [] headers = [ I18n.t("output.table_header.instance_id"), - I18n.t("output.table_header.node_name"), + I18n.t("output.table_header.name"), I18n.t("output.table_header.project"), - I18n.t("output.table_header.deploy_env"), + I18n.t("output.table_header.environment"), + I18n.t("output.table_header.category"), I18n.t("output.table_header.provider"), I18n.t("output.table_header.remote_user"), I18n.t("output.table_header.private_ip"), - I18n.t("output.table_header.created_at"), - I18n.t("output.table_header.created_by") + I18n.t("output.table_header.created_by"), + I18n.t("output.table_header.created_at") ] - keys = ["id", "chef_node_name", "project", "deploy_env", "provider", "remote_user", "private_ip", "created_at", "created_by"] + keys = ["id", "name", "project", "environment", "category", "provider", "remote_user", "private_ip", "created_by"] row = [] keys.each{|k| row.push @data[k]} + row.push time_to_s(@data["created_at"]) rows.push row return headers, rows end diff --git a/devops-client/lib/devops-client/output/tag.rb b/devops-client/lib/devops-client/output/tag.rb deleted file mode 100644 index 24ef4f9..0000000 --- a/devops-client/lib/devops-client/output/tag.rb +++ /dev/null @@ -1,28 +0,0 @@ -require "devops-client/output/base" - -module Output - class Tag < Base - - def table - headers, rows = create(@data) - create_table(headers, rows, I18n.t("output.title.tag.list")) - end - - def csv - headers, rows = create(@data) - create_csv(headers, rows) - end - - def json - JSON.pretty_generate @data - end - - private - def create list - abort(I18n.t("output.not_found.tag.list")) if list.empty? - headers = [I18n.t("output.table_header.tag")] - rows = list.map {|l| [ l ]} - return headers, rows - end - end -end diff --git a/devops-client/lib/devops-client/output/user.rb b/devops-client/lib/devops-client/output/user.rb index 038a070..6928f22 100644 --- a/devops-client/lib/devops-client/output/user.rb +++ b/devops-client/lib/devops-client/output/user.rb @@ -4,24 +4,39 @@ module Output class User < Base def table - title, headers = nil, nil - rows, with_num = create_subheader, false - rows += create_rows - headers = [ - "", - "", - "", - {:value => I18n.t("output.table_header.privileges"), :colspan => 12, :alignment => :center } - ] + title, headers, rows = nil, nil, nil + with_num = options[:with_num] || true - create_table headers, rows, I18n.t("output.title.users.list"), with_num, true + case options[:current_command] + when :list + headers, rows = prepare_list + title = "output.title.users.list" + when :show + end + + create_table headers, rows, I18n.t(title), with_num, true + end + + def csv + headers, rows = nil, nil + case options[:current_command] + when :list + headers, rows = prepare_list + when :show + end + create_csv headers, rows end private - def csv - rows = create_rows(@data) - headers = create_subheader - create_csv headers, rows + def prepare_list + headers = [ + I18n.t("output.table_header.id"), + I18n.t("output.table_header.email"), + I18n.t("output.table_header.roles"), + I18n.t("output.table_header.created_at") + ] + rows = @data.map{|u| [ u["id"], u["email"], u["roles"], time_to_s(u["created_at"]) ] } + [headers, rows] end def create_subheader diff --git a/devops-client/lib/devops-client/providers/providers.rb b/devops-client/lib/devops-client/providers/providers.rb index 4c7b3c2..141d0b3 100644 --- a/devops-client/lib/devops-client/providers/providers.rb +++ b/devops-client/lib/devops-client/providers/providers.rb @@ -1,21 +1,21 @@ module Providers - Ec2 = 'ec2' + Aws = 'aws' Openstack = 'openstack' Static = 'static' def self.available - [Ec2, Openstack, Static] + [Aws, Openstack, Static] end def self.functionalities { - images: [Ec2, Openstack], - stack_templates: [Ec2, Openstack], - stacks: [Ec2, Openstack] + images: [Aws, Openstack], + stack_templates: [Aws, Openstack], + stacks: [Aws, Openstack] } end def self.has_functionality?(provider, functionality) functionalities.fetch(functionality).include?(provider.to_s) end -end \ No newline at end of file +end diff --git a/devops-client/lib/devops-client/version.rb b/devops-client/lib/devops-client/version.rb index 2759c4b..9bbd342 100644 --- a/devops-client/lib/devops-client/version.rb +++ b/devops-client/lib/devops-client/version.rb @@ -1,3 +1,3 @@ module DevopsClient - VERSION = "2.1.34" + VERSION = "3.0.1" end diff --git a/devops-client/locales/en.yml b/devops-client/locales/en.yml index 0620a69..6c5d27e 100644 --- a/devops-client/locales/en.yml +++ b/devops-client/locales/en.yml @@ -24,95 +24,127 @@ en: warn: "WARN: %{msg}" error: "ERROR: %{msg}" headers: - flavor: "Flavor" - template: "Bootstrap template" - bootstrap_template: "Bootstrap template" + chef: "Chef options" + bootstrap_templates: Bootstrap templates deploy: "Deploy" filters: "Filters" - group: "Security groups" image: "Image" key: "Key" - network: "Network" project: "Project" - project_env: "Project environment" - deploy_env: "Deploy environment" + environment: "Project environment" + category: "Environment category" provider: "Provider" + provider_account: "Provider account" server: "Server" script: "Script" - tag: "Tag" user: "User" stack: "Stack" stack_template: "Stack template" - env: "Deploy environment" + env: "Environment" + role: "Role" + category_type: Category type handler: - flavor: - list: - empty: "Flavors list is empty" - env: + role: + create: + description: "Role description" + policies: "Role policies" + question: + create: "Create role" + delete: "Delete role '%{role}'" + all_policies: "Set all policies for a role" + provider: + vpc: + invalid_provider: "Operation available for 'aws' provider only" list: - empty: "Project environment list is empty" + empty: "VPCs list is empty" + account: + create: + description: "Description" + ssh_key: "SSH key" + aws: + use_iam_profile: "Use IAM profile" + secret_access_key: "Secret access key" + access_key_id: "Access key id" + question: + delete: "Are you sure to delete account '%{account}'" + create: "Create provider account" + tags: + question: + delete: "Are you sure to delete tag(s) '%{name}' from node '%{node}'?" + flavor: + list: + empty: "Flavors list is empty" image: question: delete: "Are you sure to delete image '%{name}'?" - create: "Create image?" + create: "Create image" create: ssh_user: "The ssh username" template: "Bootstrap template or empty value" template_empty: "No bootatrap template found, it will be used default template" filter: question: - delete: "Are you sure to delete image filter(s) '%{name}'?" + delete: "Are you sure to delete image filter(s) '%{name}'" key: question: - delete: "Are you sure to delete key '%{name}'?" + delete: "Are you sure to delete key '%{name}'" + create: "Create key" project: list: empty: "Project list is empty" question: - delete: "Are you sure to delete project '%{name}'?" - create: "Create project?" - update: "Update project?" - add_env: "Add environment?" - update_with_new_envs: "Add these envs to project?" - set_stack_template: "Set stack template?" + delete: "Are you sure to delete project '%{name}'" + create: "Create project" + update: "Update project" + add_env: "Add environment" + update_with_new_envs: "Add these envs to project" + set_stack_template: "Set stack template" + run_list: + empty: "Set empty run_list" parameter: run_list: empty: "WARN: run list is empty, continue?" exist: "Project '%{project}' already exist" create: + description: "Project description" invalid_json: "Invalid JSON in file '%{file}'" - env: "Deploy environment identifier" - env_exist: "Deploy environment '%{env}' already exist" - flavor: - not_found: "No such flavor" - subnet: - ec2: "Subnet (or Enter)" - openstack: "Subnets" - user: "Users, you will be added automatically" + users: "project users" + question: + users_choose: "Would you like to choose users (y) or type manually (n)" run_list: invalid: "ERROR: invalid run list elements: %{list}" - invalid_subcommand: "Invalid subcommand for '%{cmd}': '%{scmd}'" + environment: + create: + id_exists: "Environment with identifier '%{env}' already exists" + question: + delete: "Are you sure to delete environment '%{env}' from project '%{name}'" + create: "Create environment" + category: + question: + delete: "Are you sure to delete category '%{cat}' from environment '%{env}' from project '%{project}'" + create: "Create category" + create: + chef_env: "Chef env: " script: question: - delete: "Are you sure to delete script '%{name}'?" - tag: - question: - delete: "Are you sure to delete tag(s) '%{name}' from node '%{node}'?" + delete: "Are you sure to delete script '%{name}'" user: question: - delete: "Are you sure to delete user '%{name}'?" + create: "Create user" + delete: "Are you sure to delete user '%{name}'" password_for: "Password for %{user}:" server: question: - delete: "Are you sure to delete server '%{name}'?" - delete_list: "Are you sure to delete these servers: %{ids}?" + unbootstrap: "Are you sure to unbootstrap server '%{id}'" + delete: "Are you sure to delete server '%{id}'" + delete_list: "Are you sure to delete these servers: %{ids}" stack_template: create: id: "Id: " template_file: "Path to file with template body: " question: - create: "Are you sure to create stack template?" - delete: "Are you sure to delete stack template '%{name}'?" + create: "Are you sure to create stack template" + delete: "Are you sure to delete stack template '%{name}'" stack: create: id: "Id: " @@ -121,12 +153,12 @@ en: run_list: "Run list: " tags_file: "Path to file with tags in JSON (or Enter): " question: - create: "Are you sure to create stack?" - delete: "Are you sure to delete stack '%{name}'?" + create: "Are you sure to create stack" + delete: "Are you sure to delete stack '%{name}'" message: - choose_list_default: "Choose %{name} (comma separated), like 1,2,3 or empty for default value '%{default}': " - choose_list: "Choose %{name} (comma separated), like 1,2,3: " - choose: "Choose '%{name}': " + choose_list_default: "Choose %{name} (comma separated), like 1,2,3 or empty for default value '%{default}'" + choose_list: "Choose %{name} (comma separated), like 1,2,3" + choose: "Choose %{name}" error: parameter: undefined: "ERROR: parameter '%{name}' is undefined" @@ -137,6 +169,26 @@ en: invalid: "Invalid number" list: empty: "%{name} list is empty" + choose: + flavor: flavor + image: image + vpc: VPC + network: network + networks: networks + security_groups: "security groups" + ssh_key: "SSH key" + input: + run_list: + label: "Run list, like recipe[mycookbook::myrecipe],role[myrole]" + invalid: "Invalid run list '%{list}'" + user: + label: "Users" + list: "users list" + question: + choose: "Choose" + message: + input_list_default: "Input %{cmd} (comma separated) or empty for default value '%{default}': " + input_list: "Input %{cmd} (comma separated): " output: table_header: api_version: "API version" @@ -144,6 +196,8 @@ en: id: "Id" name: "Name" provider: "Provider" + provider_account: "Provider account" + use_iam_profile: "IAM profile" remote_user: "Remote user" disk: "Disk" virtual_cpus: "Virtual CPUs" @@ -155,20 +209,22 @@ en: cidr: "CIDR" description: "Description" status: "Status" - template: "Bootstrap template" - scope: "Scope" + filename: "Filename" subnet: "Subnet" vpc_id: "VPC Id" zone: "Zone" - deploy_env: "Environment" + environments: "Environments" + environment: "Environment" + categories: "Categories" + category: "Category" + expires: "Expires in" node_name: "Node name" image: "Image" flavor: "Flavor" - group: "Group" + security_groups: "Security groups" key: "Keys" templates: "Templates" run_list: "Run list" - groups: "Security groups" subnets: "Subnets" users: "Users" server: "Server" @@ -199,31 +255,44 @@ en: cloud_stack_id: "Cloud Stack id" stack_status: Stack status ssh_key: SSH key + policies: Policies + dependencies: Dependencies + roles: Roles + owner: Owner + cm_tool: CM + bootstrap_template: Bootstrap template title: - flavor: - list: "Flavors" - bootstrap_template: - list: "Bootstrap templates" + chef: + bootstrap_templates: "Bootstrap templates" + tags: "Tags" filter: list: "Filters" - group: - list: "Security groups" image: list: "Images" show: "Image '%{id}' information" key: list: "Keys" - network: - list: "Networks" project: list: "Projects" show: "Project '%{name}' information" servers: "Project '%{title}' servers" test: "Project test: %{project} - %{env}" envs: "Project '%{name}' deploy envs" + environment: + list: "Project '%{project}' environments" + show: "Project '%{project}' environment '%{id}' information" + servers: "Servers for project '%{project}' and environment '%{env}'" + stacks: "Stacks for project '%{project}' and environment '%{env}'" + category: + list: Categories + show: "Information about category '%{cat}' of project '%{project}' and environment '%{env}'" provider: list: "Providers" accounts: "Provider %{provider} accounts" + flavors: "Flavors" + networks: "Networks" + security_groups: "Security groups" + vpcs: "VPCs" script: list: "Scripts" server: @@ -232,8 +301,6 @@ en: ec2: "Ec2 servers" openstack: "Openstack servers" show: "Server '%{name}'" - tag: - list: "Tags" users: list: "Users" stack_template: @@ -242,33 +309,38 @@ en: stack: list: "Stacks" show: "Stack" + role: + list: "Roles" + policies: "Roles policies" not_found: - flavor: - list: "No flavor found" - bootstrap_template: - list: "No bootstrap templates found" + chef: + bootstrap_template: "No bootstrap templates found" + tags: "No tags found" filter: list: "No filters found" - group: - list: "No security groups found" image: list: "No images found" key: list: "No keys found" - network: - list: "No networks found" project: list: "No project found" servers: "No servers for project '%{name}' found" stacks: "No stacks for project '%{name}' found" + environment: + list: "No environments found" + category: + list: "No categories found" + servers: "No servers found" provider: list: "Empty providers list" + flavors: "No flavor found" + network: "No networks found" + security_group: "No security groups found" + image: "No images found" script: list: "No scripts uploaded" server: list: "No servers found" - tag: - list: "No tags found" user: list: "No users found" stack_template: @@ -360,9 +432,9 @@ en: instance: Unreserve server by instance id create: without_bootstrap: 'Run server without bootsraping phase' - name: Set node name + name: Set server name groups: The security groups for this server - force: Cancel rollback operation on error + skip_rollback: Cancel rollback operation on error key: User another key for server private_ip: Private ip for this server bootstrap: @@ -383,7 +455,16 @@ en: without_bootstrap: Skip bootsraping phase on created instances stack_template: provider: Stack template provider + provider_account: Provider account id: Stack template id template_file: Stack template file user: new_password: New user password + provider: + account: + description: "Account description" + ssh_key: "Key id" + use_iam_profile: "Use IAM profile (aws only)" + access_key_id: "Access key id (aws only)" + secret_access_key: "Secret access key (aws only)" + diff --git a/devops-client/locales/ru.yml b/devops-client/locales/ru.yml index 0d25af7..682fb6e 100644 --- a/devops-client/locales/ru.yml +++ b/devops-client/locales/ru.yml @@ -25,84 +25,113 @@ ru: warn: "Предупреждение: %{msg}" error: "Ошибка: %{msg}" headers: - flavor: "Конфигурация" + chef: "Опции Chef" + bootstrap_templates: "Шаблоны" deploy: "Деплой" - template: "Шаблон загрузки" filters: "Фильтры" - group: "Группы безопасности" image: "Образ" - key: "Ключ" - network: "Сеть" + key: "SSH ключ" project: "Проект" - project_env: "Окружение проект" + environment: "Окружение проект" + category: "Категория Окружения" provider: "Провайдер" + provider_account: "Аккаунт провайдера" server: "Сервер" script: "Скрипт" - tag: "Тег" user: "Пользователь" + role: "Роль" handler: - flavor: - list: - empty: "Список конфигураций пуст" + role: + create: + description: "Описание роли" + policies: "Политики роли" + question: + create: "Создать роль" + delete: "Удалить роль '%{role}'" + all_policies: "Установить все политики для роли" + provider: + vpc: + invalid_provider: "Операция доступна только для провайдера 'aws'" + list: + empty: "Список VPC пуст" + account: + create: + description: "Описание" + ssh_key: "SSH ключ" + aws: + use_iam_profile: "Использовать профайл IAM" + secret_access_key: "Ключ доступа" + access_key_id: "Идентификатор ключа доступа" + question: + delete: "Вы уверен, что хотите удалить аккаунт '%{account}'" + create: "Создать аккаунт для провайдера" + tags: + question: + delete: "Вы уверены, что хотите удалить тэг(и) '%{name}' из ноды '%{node}'?" + flavor: + list: + empty: "Список конфигураций пуст" image: question: - delete: "Вы уверены, что хотите удалить образ '%{name}'?" - create: "Создать образ?" + delete: "Вы уверены, что хотите удалить образ '%{name}'" + create: "Создать образ" create: ssh_user: "Имя пользоватлея ssh" - template: "Шаблон загрузки или пустое значение" - template_empty: "Нет ни одного шаблона загрузки, будет использован шаблон по умолчанию" filter: question: - delete: "Вы уверены, что хотите удалить фильтр(ы) образа '%{name}'?" + delete: "Вы уверены, что хотите удалить фильтр(ы) образа '%{name}'" key: question: - delete: "Вы уверены, что хотите удалить ключ '%{name}'?" + delete: "Вы уверены, что хотите удалить ключ '%{name}'" + create: "Создать ключ" project: list: empty: "Список проектов пуст" - env: - list: - empty: "Список окружений проекта пуст" question: - delete: "Вы уверены, что хотите удалить проект '%{name}'?" - create: "Создать проект?" - update: "Обновить проект?" - add_env: "Добавить окружение?" + delete: "Вы уверены, что хотите удалить проект '%{name}'" + create: "Создать проект" + update: "Обновить проект" + add_env: "Добавить окружение" + run_list: + empty: "Сделать run_list пустым" parameter: run_list: - empty: "Предупреждение: список запуска пуст, продолжить?" + empty: "Предупреждение: список запуска пуст, продолжить" exist: "Проект '%{project}' уже существует" create: + question: + users_choose: "Вы хотите выбрать пользователей" + description: "Описание проекта" invalid_json: "Неверный JSON в файле '%{file}'" - env: "Идентификатор окружения" - env_exist: "Окружение '%{env}' уже существует" - flavor: - not_found: "Конфигурация не надена" - subnet: - ec2: "Подсеть (или Enter)" - openstack: "Подсети" - user: "Пользователи, Вы будете добалены автоматически" + users: "пользователи проекта" run_list: invalid: "ОШИБКА: неверные элементы run_list: %{list}" - invalid_subcommand: "Неверная подкомманда для '%{cmd}': '%{scmd}'" + environment: + create: + id_exists: "Окружение с идентификатором '%{env}' уже существует" + question: + delete: "Вы уверены, что хотите удалить окружение '%{env}' из проекта '%{name}'" + create: "Создать окружение" + category: + question: + delete: "Вы уверены, что хотите удалить категорию '%{cat}' из окружения '%{env}' проекта '%{name}'" + create: "Создать категорию" script: question: - delete: "Вы уверены, что хотите удалить скрипт '%{name}'?" - tag: - question: - delete: "Вы уверены, что хотите удалить тэг(и) '%{name}' из ноды '%{node}'?" + delete: "Вы уверены, что хотите удалить скрипт '%{name}'" user: question: - delete: "Вы уверены, что хотите удалить пользователя '%{name}'?" + create: "Создать пользователя" + delete: "Вы уверены, что хотите удалить пользователя '%{name}'" password_for: "Пароль для %{user}:" server: question: - delete: "Вы уверены, что хотите удалить сервер '%{name}'?" + delete: "Вы уверены, что хотите удалить сервер '%{id}'" + unbootstrap: "Вы уверены, что хотите удалить конфигурацию сервера '%{id}'" message: - choose_list_default: "Выберите значения из списка (разделенные запятой), например 1,2,3 или оставте пустым для значеия по умолчанию '%{default}': " - choose_list: "Выберите значения из списка (разделенные запятой), например 1,2,3: " - choose: "Выберите '%{name}': " + choose_list_default: "Выберите значения из списка (разделенные запятой), например 1,2,3 или оставте пустым для значеия по умолчанию '%{default}'" + choose_list: "Выберите значения из списка (разделенные запятой), например 1,2,3" + choose: "Выберите %{name}" error: parameter: undefined: "Ошибка: параметр '%{name}' не указан" @@ -113,6 +142,26 @@ ru: invalid: "Неверный номер" list: empty: "%{name} список пуст" + choose: + flavor: конфигурацию + image: образ + vpc: VPC + network: подсеть + networks: подсети + security_groups: "группы безопасности" + ssh_key: "SSH ключ" + input: + run_list: + label: "Список запуска, например, recipe[mycookbook::myrecipe],role[myrole]" + invalid: "Неверный список запуска" + user: + label: "Пользователи" + list: "список пользователей" + question: + choose: "Выбрать" + message: + input_list_default: "Введите %{cmd} (разделенные запятой) или оставьте пустым для значения по умолчанию '%{default}': " + input_list: "Введите %{cmd} (разделенные запятой): " output: table_header: api_version: "Версия API" @@ -120,6 +169,8 @@ ru: id: "Id" name: "Имя" provider: "Провайдер" + provider_account: "Аккаунт провайдера" + use_iam_profile: "IAM профиль" remote_user: "Пользователь" disk: "Диск" virtual_cpus: "Виртуальные ЦПУ" @@ -131,12 +182,14 @@ ru: cidr: "CIDR" description: "Описание" status: "Статус" - template: "Шаблон" - scope: "Область" + filename: "Имя файла" subnet: "Подсеть" vpc_id: "VPC Id" zone: "Зона" - deploy_env: "Окружение" + environments: "Окружения" + environment: "Окружение" + category: "Категория" + expires: "Время жизни" node_name: "Имя ноды" image: "Образ" flavor: "Конфигурация" @@ -144,7 +197,7 @@ ru: key: "Ключи" templates: "Шаблоны" run_list: "Список запуска" - groups: "Группы безоп." + security_groups: "Группы безоп." subnets: "Подсети" users: "Пользователи" server: "Сервер" @@ -168,29 +221,43 @@ ru: keypair: "Ключ" created_at: "Создан" created_by: "Создал" + policies: Политики + dependencies: Зависимости + roles: Роли + owner: Владелец + cm_tool: УК + bootstrap_template: Шаблон конфигурации title: - flavor: - list: "Конфигурации" - bootstrap_template: - list: "Шаблоны" + chef: + bootstrap_templates: "Шаблоны" + tags: "Теги" filter: list: "Фильтры" - group: - list: "Группы безопасности" image: list: "Образы" show: "Информация об образе '%{id}'" key: list: "Ключи" - network: - list: "Сети" project: list: "Проекты" show: "Информация о проекте '%{name}'" servers: "Сервера проекта '%{title}'" test: "Тестирование проекта: %{project} - %{env}" + environment: + list: "Окружения проекта '%{project}'" + show: "Информация об окружении '%{id}' проекта '%{project}'" + servers: "Сервера для проекта '%{project}' и окружения '%{env}'" + stacks: "Стеки для проекта '%{project}' и окружения '%{env}'" + category: + list: Категории + show: "Информация о категории '%{cat}' проекта '%{project}' и окружения '%{env}'" provider: list: "Провайдеры" + flavors: "Конфигурации" + security_groups: "Группы безопасности" + network: "Сети" + images: "Образы" + vpcs: "VPCs" script: list: "Скрипты" server: @@ -199,36 +266,36 @@ ru: ec2: "Сервера Ec2" openstack: "Сервера Openstack" show: "Сервер '%{name}'" - tag: - list: "Теги" users: list: "Пользователи" + role: + list: "Роли" + policies: "Политики ролей" not_found: - flavor: - list: "Ни одной конфигурации не найдено" - bootstrap_template: - list: "Ни одного шаблона не найдено" + chef: + bootstrap_template: "Ни одного шаблона не найдено" + tags: "Ни одного тега не найдено" filter: list: "Ни одного фильтра не найдено" - group: - list: "Ни одной группы безопасности не найдено" image: list: "Ни одного образа не найдено" key: list: "Ни одного ключа не найдено" - network: - list: "Ни одной сети не найдено" project: list: "Ни одного проекта не найдено" servers: "Ни одного сервера для проекта '%{name}' не найдено" + environment: + list: "Ни одного окружения не найдено" provider: list: "Ни одного провайдера не найдено" + flavors: "Ни одной конфигурации не найдено" + security_groups: "Ни одной группы безопасности не найдено" + network: "Ни одной сети не найдено" + images: "Ни одного образа не найдено" script: list: "Не загружено ни одного скрипта" server: list: "Ни одного сервера не найдено" - tag: - list: "Ни одного тега не найдено" user: list: "Ни одного пользователя не найдено" options: @@ -270,3 +337,7 @@ ru: script: run: params: "Аргументы скрипта (список разделенный запятой)" + description: + provider: + images: + all: "Показать все образы без фильтра" diff --git a/devops-service/Gemfile b/devops-service/Gemfile index 434263d..0944002 100644 --- a/devops-service/Gemfile +++ b/devops-service/Gemfile @@ -4,20 +4,24 @@ source 'https://rubygems.org' gem "thin", "~>1.5.1" gem "mime-types", "~>1.25.1" -gem "sinatra", "1.4.5" +gem "sinatra", '~> 1.4.5' gem "sinatra-contrib"#, "1.4.1" gem "sinatra-websocket"#, "~>0.3.0" -gem "fog", "~>1.20" +gem "fog", "~>1.30" gem "mixlib-shellout" gem "chef", ">=12" -gem "mongo", '1.12.3' +gem "mongo", '~> 2.1' gem "bson_ext" gem "multi_json", "1.7.8" -gem "sidekiq", "3.2.6" +gem "sidekiq", "4.1.0" gem 'rake', '10.2.0' gem 'rack-accept-media-types' gem 'rack', '1.5.2' gem 'hooks' +gem 'mongoid', '~> 5.0.0' +gem 'net-scp', '1.2.1' +gem 'net-ssh', '3.0.2' # with version 3.1.1 scp.upload method does not work +gem 'swagger-blocks', '1.3.3' #gem "devops-nibr", :path => "../../devops-nibr" @@ -30,6 +34,7 @@ group :test do gem 'factory_girl', '~>4.5' gem 'activesupport' gem 'rspec_junit_formatter' + gem 'database_cleaner', '~> 1.5' end group :devepoment do diff --git a/devops-service/Gemfile.lock b/devops-service/Gemfile.lock index 023b96c..2c68783 100644 --- a/devops-service/Gemfile.lock +++ b/devops-service/Gemfile.lock @@ -1,91 +1,105 @@ GEM remote: https://rubygems.org/ specs: - CFPropertyList (2.3.1) - activesupport (4.2.4) + CFPropertyList (2.3.2) + activemodel (4.2.6) + activesupport (= 4.2.6) + builder (~> 3.1) + activesupport (4.2.6) i18n (~> 0.7) json (~> 1.7, >= 1.7.7) minitest (~> 5.1) thread_safe (~> 0.3, >= 0.3.4) tzinfo (~> 1.1) - addressable (2.3.8) - backports (3.6.4) - bson (1.12.3) - bson_ext (1.12.3) - bson (~> 1.12.3) + addressable (2.4.0) + backports (3.6.8) + bson (4.1.0) + bson_ext (1.5.1) builder (3.2.2) - byebug (5.0.0) - columnize (= 0.9.0) - celluloid (0.15.2) - timers (~> 1.1.0) - chef (12.1.2) - chef-zero (~> 4.0) + byebug (8.2.4) + chef (12.9.38) + bundler (>= 1.10) + chef-config (= 12.9.38) + chef-zero (~> 4.5) diff-lcs (~> 1.2, >= 1.2.4) erubis (~> 2.7) - ffi-yajl (~> 1.2) + ffi-yajl (~> 2.2) highline (~> 1.6, >= 1.6.9) - mixlib-authentication (~> 1.3) + mixlib-authentication (~> 1.4) mixlib-cli (~> 1.4) - mixlib-config (~> 2.0) mixlib-log (~> 1.3) - mixlib-shellout (>= 2.0.0.rc.0, < 3.0) - net-ssh (~> 2.6) + mixlib-shellout (~> 2.0) + net-sftp (~> 2.1, >= 2.1.2) + net-ssh (>= 2.9, < 4.0) net-ssh-multi (~> 1.1) - ohai (~> 8.0) - plist (~> 3.1.0) - pry (~> 0.9) - rspec-core (~> 3.2) - rspec-expectations (~> 3.2) - rspec-mocks (~> 3.2) + ohai (>= 8.6.0.alpha.1, < 9) + plist (~> 3.2) + proxifier (~> 1.0) + rspec-core (~> 3.4) + rspec-expectations (~> 3.4) + rspec-mocks (~> 3.4) rspec_junit_formatter (~> 0.2.0) serverspec (~> 2.7) specinfra (~> 2.10) - chef-zero (4.2.3) - ffi-yajl (>= 1.1, < 3.0) - hashie (~> 2.0) + syslog-logger (~> 1.6) + uuidtools (~> 2.1.5) + chef-config (12.9.38) + fuzzyurl (~> 0.8.0) + mixlib-config (~> 2.0) + mixlib-shellout (~> 2.0) + chef-zero (4.6.1) + ffi-yajl (~> 2.2) + hashie (>= 2.0, < 4.0) mixlib-log (~> 1.3) rack uuidtools (~> 2.1) - coderay (1.1.0) - columnize (0.9.0) + coderay (1.1.1) + concurrent-ruby (1.0.1) connection_pool (2.2.0) - cucumber (2.0.0) + cucumber (2.3.3) builder (>= 2.1.2) - cucumber-core (~> 1.1.3) + cucumber-core (~> 1.4.0) + cucumber-wire (~> 0.0.1) diff-lcs (>= 1.1.3) - gherkin (~> 2.12) + gherkin (~> 3.2.0) multi_json (>= 1.7.5, < 2.0) multi_test (>= 0.1.2) - cucumber-core (1.1.3) - gherkin (~> 2.12.0) + cucumber-core (1.4.0) + gherkin (~> 3.2.0) + cucumber-wire (0.0.1) daemons (1.2.3) + database_cleaner (1.5.1) diff-lcs (1.2.5) docile (1.1.5) em-websocket (0.3.8) addressable (>= 2.1.1) eventmachine (>= 0.12.9) erubis (2.7.0) - eventmachine (1.0.7) - excon (0.45.3) - factory_girl (4.5.0) + eventmachine (1.2.0.1) + excon (0.49.0) + factory_girl (4.7.0) activesupport (>= 3.0.0) - ffi (1.9.9) - ffi-yajl (1.4.0) - ffi (~> 1.5) + ffi (1.9.10) + ffi-yajl (2.2.3) libyajl2 (~> 1.2) fission (0.5.0) CFPropertyList (~> 2.2) - fog (1.31.0) + fog (1.38.0) + fog-aliyun (>= 0.1.0) fog-atmos - fog-aws (~> 0.0) + fog-aws (>= 0.6.0) fog-brightbox (~> 0.4) - fog-core (~> 1.30) - fog-ecloud - fog-google (>= 0.0.2) + fog-cloudatcost (~> 0.1.0) + fog-core (~> 1.32) + fog-dynect (~> 0.0.2) + fog-ecloud (~> 0.1) + fog-google (<= 0.1.0) fog-json fog-local + fog-openstack fog-powerdns (>= 0.1.1) fog-profitbricks + fog-rackspace fog-radosgw (>= 0.0.2) fog-riakcs fog-sakuracloud (>= 0.0.4) @@ -95,49 +109,71 @@ GEM fog-terremark fog-vmfusion fog-voxel + fog-vsphere (>= 0.4.0) + fog-xenserver fog-xml (~> 0.1.1) ipaddress (~> 0.5) - nokogiri (~> 1.5, >= 1.5.11) + fog-aliyun (0.1.0) + fog-core (~> 1.27) + fog-json (~> 1.0) + ipaddress (~> 0.8) + xml-simple (~> 1.1) fog-atmos (0.1.0) fog-core fog-xml - fog-aws (0.6.0) + fog-aws (0.9.2) fog-core (~> 1.27) fog-json (~> 1.0) fog-xml (~> 0.1) ipaddress (~> 0.8) - fog-brightbox (0.7.2) + fog-brightbox (0.10.1) fog-core (~> 1.22) fog-json inflecto (~> 0.0.2) - fog-core (1.31.1) + fog-cloudatcost (0.1.2) + fog-core (~> 1.36) + fog-json (~> 1.0) + fog-xml (~> 0.1) + ipaddress (~> 0.8) + fog-core (1.37.0) builder excon (~> 0.45) formatador (~> 0.2) - mime-types - net-scp (~> 1.1) - net-ssh (>= 2.1.3) + fog-dynect (0.0.3) + fog-core + fog-json + fog-xml fog-ecloud (0.3.0) fog-core fog-xml - fog-google (0.0.6) + fog-google (0.1.0) fog-core fog-json fog-xml fog-json (1.0.1) fog-core (~> 1.0) multi_json (~> 1.0) - fog-local (0.2.1) + fog-local (0.3.0) fog-core (~> 1.27) + fog-openstack (0.1.2) + fog-core (>= 1.35) + fog-json (>= 1.0) + fog-xml (>= 0.1) + ipaddress (>= 0.8) fog-powerdns (0.1.1) fog-core (~> 1.27) fog-json (~> 1.0) fog-xml (~> 0.1) - fog-profitbricks (0.0.3) + fog-profitbricks (0.0.5) fog-core fog-xml nokogiri - fog-radosgw (0.0.4) + fog-rackspace (0.1.1) + fog-core (>= 1.35) + fog-json (>= 1.0) + fog-xml (>= 0.1) + ipaddress (>= 0.8) + fog-radosgw (0.0.5) fog-core (>= 1.21.0) fog-json fog-xml (>= 0.0.1) @@ -145,13 +181,13 @@ GEM fog-core fog-json fog-xml - fog-sakuracloud (1.0.1) + fog-sakuracloud (1.7.5) fog-core fog-json fog-serverlove (0.1.2) fog-core fog-json - fog-softlayer (0.4.7) + fog-softlayer (1.1.0) fog-core fog-json fog-storm_on_demand (0.1.1) @@ -166,12 +202,18 @@ GEM fog-voxel (0.1.0) fog-core fog-xml + fog-vsphere (0.6.3) + fog-core + rbvmomi (~> 1.8) + fog-xenserver (0.2.3) + fog-core + fog-xml fog-xml (0.1.2) fog-core nokogiri (~> 1.5, >= 1.5.11) formatador (0.2.5) - gherkin (2.12.2) - multi_json (~> 1.3) + fuzzyurl (0.8.0) + gherkin (3.2.0) guard (2.13.0) formatador (>= 0.2.4) listen (>= 2.7, <= 4.0) @@ -182,69 +224,80 @@ GEM shellany (~> 0.0) thor (>= 0.18.1) guard-compat (1.2.1) - guard-rspec (4.6.4) + guard-rspec (4.6.5) guard (~> 2.1) guard-compat (~> 1.1) rspec (>= 2.99.0, < 4.0) - hashie (2.1.2) - highline (1.7.2) - hooks (0.4.0) - uber (~> 0.0.4) - httpclient (2.6.0.1) + hashie (3.4.3) + highline (1.7.8) + hooks (0.4.1) + uber (~> 0.0.14) + httpclient (2.7.1) i18n (0.7.0) inflecto (0.0.2) - ipaddress (0.8.0) + ipaddress (0.8.3) json (1.8.3) libyajl2 (1.2.0) - listen (3.0.4) + listen (3.0.6) rb-fsevent (>= 0.9.3) - rb-inotify (>= 0.9) - lumberjack (1.0.9) + rb-inotify (>= 0.9.7) + lumberjack (1.0.10) method_source (0.8.2) mime-types (1.25.1) - mini_portile (0.6.2) - minitest (5.8.2) - mixlib-authentication (1.3.0) + mini_portile2 (2.0.0) + minitest (5.8.4) + mixlib-authentication (1.4.0) mixlib-log + rspec-core (~> 3.2) + rspec-expectations (~> 3.2) + rspec-mocks (~> 3.2) mixlib-cli (1.5.0) mixlib-config (2.2.1) mixlib-log (1.6.0) - mixlib-shellout (2.1.0) - mongo (1.12.3) - bson (= 1.12.3) + mixlib-shellout (2.2.6) + mongo (2.2.4) + bson (~> 4.0) + mongoid (5.0.2) + activemodel (~> 4.0) + mongo (~> 2.1) + origin (~> 2.1) + tzinfo (>= 0.3.37) multi_json (1.7.8) multi_test (0.1.2) - nenv (0.2.0) - net-dhcp (1.3.2) + nenv (0.3.0) net-scp (1.2.1) net-ssh (>= 2.6.5) - net-ssh (2.9.2) + net-sftp (2.1.2) + net-ssh (>= 2.6.5) + net-ssh (3.0.2) net-ssh-gateway (1.2.0) net-ssh (>= 2.6.5) net-ssh-multi (1.2.1) net-ssh (>= 2.6.5) net-ssh-gateway (>= 1.2.0) - nokogiri (1.6.6.2) - mini_portile (~> 0.6.0) + net-telnet (0.1.1) + nokogiri (1.6.7.2) + mini_portile2 (~> 2.0.0.rc2) notiffany (0.0.8) nenv (~> 0.1) shellany (~> 0.0) - ohai (8.0.1) + ohai (8.14.0) + chef-config (>= 12.5.0.alpha.1, < 13) ffi (~> 1.9) - ffi-yajl (~> 1.1) + ffi-yajl (~> 2.2) ipaddress - mime-types (~> 1.16) mixlib-cli mixlib-config (~> 2.0) mixlib-log mixlib-shellout (~> 2.0) - net-dhcp - rake (~> 10.1) + plist (~> 3.1) systemu (~> 2.6.4) wmi-lite (~> 1.0) - plist (3.1.0) - power_assert (0.2.3) - pry (0.10.1) + origin (2.2.0) + plist (3.2.0) + power_assert (0.2.7) + proxifier (1.0.3) + pry (0.10.3) coderay (~> 1.1.0) method_source (~> 0.8.1) slop (~> 3.4) @@ -255,55 +308,56 @@ GEM rack-test (0.6.3) rack (>= 1.0) rake (10.2.0) - rb-fsevent (0.9.6) - rb-inotify (0.9.5) + rb-fsevent (0.9.7) + rb-inotify (0.9.7) ffi (>= 0.5.0) - redis (3.2.1) - redis-namespace (1.5.2) - redis (~> 3.0, >= 3.0.4) - rspec (3.3.0) - rspec-core (~> 3.3.0) - rspec-expectations (~> 3.3.0) - rspec-mocks (~> 3.3.0) - rspec-core (3.3.1) - rspec-support (~> 3.3.0) - rspec-expectations (3.3.0) + rbvmomi (1.8.2) + builder + nokogiri (>= 1.4.1) + trollop + redis (3.2.2) + rspec (3.4.0) + rspec-core (~> 3.4.0) + rspec-expectations (~> 3.4.0) + rspec-mocks (~> 3.4.0) + rspec-core (3.4.4) + rspec-support (~> 3.4.0) + rspec-expectations (3.4.0) diff-lcs (>= 1.2.0, < 2.0) - rspec-support (~> 3.3.0) + rspec-support (~> 3.4.0) rspec-its (1.2.0) rspec-core (>= 3.0.0) rspec-expectations (>= 3.0.0) - rspec-mocks (3.3.1) + rspec-mocks (3.4.1) diff-lcs (>= 1.2.0, < 2.0) - rspec-support (~> 3.3.0) - rspec-support (3.3.0) + rspec-support (~> 3.4.0) + rspec-support (3.4.1) rspec_junit_formatter (0.2.3) builder (< 4) rspec-core (>= 2, < 4, != 2.12.0) - serverspec (2.19.0) + serverspec (2.31.1) multi_json rspec (~> 3.0) rspec-its - specinfra (~> 2.35) + specinfra (~> 2.53) + sfl (2.2) shellany (0.0.1) - sidekiq (3.2.6) - celluloid (= 0.15.2) - connection_pool (>= 2.0.0) - json - redis (>= 3.0.6) - redis-namespace (>= 1.3.1) - simplecov (0.11.1) + sidekiq (4.1.0) + concurrent-ruby (~> 1.0) + connection_pool (~> 2.2, >= 2.2.0) + redis (~> 3.2, >= 3.2.1) + simplecov (0.11.2) docile (~> 1.1.0) json (~> 1.8) simplecov-html (~> 0.10.0) simplecov-html (0.10.0) simplecov-rcov (0.2.3) simplecov (>= 0.4.1) - sinatra (1.4.5) - rack (~> 1.4) + sinatra (1.4.7) + rack (~> 1.5) rack-protection (~> 1.4) - tilt (~> 1.3, >= 1.3.4) - sinatra-contrib (1.4.4) + tilt (>= 1.3, < 3) + sinatra-contrib (1.4.7) backports (>= 2.0) multi_json rack-protection @@ -315,11 +369,15 @@ GEM eventmachine thin (>= 1.3.1, < 2.0.0) slop (3.6.0) - specinfra (2.36.6) + specinfra (2.56.1) net-scp - net-ssh + net-ssh (>= 2.7, < 4.0) + net-telnet + sfl + swagger-blocks (1.3.3) + syslog-logger (1.6.8) systemu (2.6.5) - test-unit (3.1.2) + test-unit (3.1.8) power_assert thin (1.5.1) daemons (>= 1.0.9) @@ -327,13 +385,14 @@ GEM rack (>= 1.0.0) thor (0.19.1) thread_safe (0.3.5) - tilt (1.4.1) - timers (1.1.0) + tilt (2.0.2) + trollop (2.1.2) tzinfo (1.2.2) thread_safe (~> 0.1) - uber (0.0.13) + uber (0.0.15) uuidtools (2.1.5) wmi-lite (1.0.0) + xml-simple (1.1.5) PLATFORMS ruby @@ -344,28 +403,30 @@ DEPENDENCIES byebug chef (>= 12) cucumber + database_cleaner (~> 1.5) factory_girl (~> 4.5) - fog (~> 1.20) + fog (~> 1.30) guard-rspec hooks httpclient mime-types (~> 1.25.1) mixlib-shellout - mongo (= 1.12.3) + mongo (~> 2.1) + mongoid (~> 5.0.0) multi_json (= 1.7.8) + net-scp (= 1.2.1) + net-ssh (= 3.0.2) rack (= 1.5.2) rack-accept-media-types rake (= 10.2.0) rspec (~> 3.3) rspec_junit_formatter - sidekiq (= 3.2.6) + sidekiq (= 4.1.0) simplecov simplecov-rcov - sinatra (= 1.4.5) + sinatra (~> 1.4.5) sinatra-contrib sinatra-websocket + swagger-blocks (= 1.3.3) test-unit thin (~> 1.5.1) - -BUNDLED WITH - 1.11.2 diff --git a/devops-service/Guardfile b/devops-service/Guardfile index dd95f5c..8e3499e 100644 --- a/devops-service/Guardfile +++ b/devops-service/Guardfile @@ -24,7 +24,7 @@ # * zeus: 'zeus rspec' (requires the server to be started separately) # * 'just' rspec: 'rspec' -guard :rspec, cmd: "rspec" do +guard :rspec, cmd: "rspec", cmd_additional_args: '--fail-fast --order defined' do require "guard/rspec/dsl" dsl = Guard::RSpec::Dsl.new(self) diff --git a/devops-service/app/api2/handlers/bootstrap_templates.rb b/devops-service/app/api2/handlers/bootstrap_templates.rb deleted file mode 100644 index 4c4e8f8..0000000 --- a/devops-service/app/api2/handlers/bootstrap_templates.rb +++ /dev/null @@ -1,18 +0,0 @@ -require "commands/bootstrap_templates" -require "app/api2/parsers/bootstrap_template" -require_relative "request_handler" - -module Devops - module API2_0 - module Handler - class BootstrapTemplates < RequestHandler - - set_parser Devops::API2_0::Parser::BootstrapTemplateParser - - include BootstrapTemplatesCommands - - end - end - end -end - diff --git a/devops-service/app/api2/handlers/filter.rb b/devops-service/app/api2/handlers/filter.rb deleted file mode 100644 index 8b8d73e..0000000 --- a/devops-service/app/api2/handlers/filter.rb +++ /dev/null @@ -1,27 +0,0 @@ -require "app/api2/parsers/filter" -require_relative "request_handler" - -module Devops - module API2_0 - module Handler - class Filter < RequestHandler - - set_parser Devops::API2_0::Parser::FilterParser - - def available_images provider - Devops::Db.connector.available_images(provider) - end - - def add_images provider - Devops::Db.connector.add_available_images(parser.images, provider) - end - - def delete_images provider - Devops::Db.connector.delete_available_images(parser.images, provider) - end - - end - end - end -end - diff --git a/devops-service/app/api2/handlers/flavor.rb b/devops-service/app/api2/handlers/flavor.rb deleted file mode 100644 index 34ddb12..0000000 --- a/devops-service/app/api2/handlers/flavor.rb +++ /dev/null @@ -1,20 +0,0 @@ -require_relative "request_handler" -require "providers/provider_factory" - -module Devops - module API2_0 - module Handler - class Flavor < RequestHandler - - def flavors provider - flavors_with_account(provider, nil) - end - - def flavors_with_account provider, account - ::Provider::ProviderFactory.get(provider, account).flavors - end - end - end - end -end - diff --git a/devops-service/app/api2/handlers/group.rb b/devops-service/app/api2/handlers/group.rb deleted file mode 100644 index 8b44aed..0000000 --- a/devops-service/app/api2/handlers/group.rb +++ /dev/null @@ -1,24 +0,0 @@ -require "app/api2/parsers/security_groups" -require "providers/provider_factory" -require_relative "request_handler" - -module Devops - module API2_0 - module Handler - class Group < RequestHandler - - set_parser Devops::API2_0::Parser::SecurityGroupsParser - - def groups provider - groups_with_account(provider, nil) - end - - def groups_with_account provider, account - available_keys = ["vpc-id"] - ::Provider::ProviderFactory.get(provider, account).groups(parser.security_groups.select{|k,v| available_keys.include?(k)}) - end - end - end - end -end - diff --git a/devops-service/app/api2/handlers/image.rb b/devops-service/app/api2/handlers/image.rb deleted file mode 100644 index f743081..0000000 --- a/devops-service/app/api2/handlers/image.rb +++ /dev/null @@ -1,58 +0,0 @@ -require "providers/provider_factory" -require "commands/image" -require "app/api2/parsers/image" -require_relative "request_handler" - -module Devops - module API2_0 - module Handler - class Image < RequestHandler - - set_parser Devops::API2_0::Parser::ImageParser - - extend ImageCommands - - def images - Devops::Db.connector.images(parser.images) - end - - def provider_images provider - Image.get_available_provider_images(Devops::Db.connector, provider) - end - - def provider_account_images provider, account - Image.get_available_provider_images(Devops::Db.connector, provider, account) - end - - def image id - Devops::Db.connector.image(id) - end - - def create_image - Devops::Db.connector.image_insert parser.image - end - - def update_image id - Devops::Db.connector.image id - obj = parser.image - obj.id = id - Devops::Db.connector.image_update obj - end - - def delete_image id - projects = Devops::Db.connector.projects_by_image id - unless projects.empty? - ar = [] - projects.each do |p| - ar += p.deploy_envs.select{|e| e.respond_to?(:image)}.select{|e| e.image == id}.map{|e| "#{p.id}.#{e.identifier}"} - end - raise DependencyError.new "Deleting is forbidden: Image is used in #{ar.join(", ")}" - end - - Devops::Db.connector.image_delete id - end - end - end - end -end - diff --git a/devops-service/app/api2/handlers/key.rb b/devops-service/app/api2/handlers/key.rb deleted file mode 100644 index 9bb3b09..0000000 --- a/devops-service/app/api2/handlers/key.rb +++ /dev/null @@ -1,53 +0,0 @@ -require "db/mongo/models/key" -require "fileutils" -require "app/api2/parsers/key" -require_relative "request_handler" - -module Devops - module API2_0 - module Handler - class Key < RequestHandler - - set_parser Devops::API2_0::Parser::KeyParser - - def keys - # Devops::Db.connector.keys({}, {path: false}) - Devops::Db.connector.keys({}) - end - - def create(keys_dir) - body = parser.create - fname = body["file_name"] - file_name = File.join(keys_dir, fname) - raise InvalidRecord.new("File '#{fname}' already exist") if File.exists?(file_name) - File.open(file_name, "w") do |f| - f.write(body["content"]) - f.chmod(0400) - end - - key = Devops::Model::Key.new({"path" => file_name, "id" => body["key_name"]}) - Devops::Db.connector.key_insert key - end - - def delete key_id - mongo = Devops::Db.connector - servers = mongo.servers_by_key key_id - unless servers.empty? - s_str = servers.map{|s| s.id}.join(", ") - raise DependencyError.new "Deleting is forbidden: Key is used in servers: #{s_str}" - end - - k = mongo.key key_id - begin - FileUtils.rm(k.path) - rescue - DevopsLogger.logger.error "Missing key file for #{key_id} - #{k.filename}" - end - mongo.key_delete key_id - end - - end - end - end -end - diff --git a/devops-service/app/api2/handlers/network.rb b/devops-service/app/api2/handlers/network.rb deleted file mode 100644 index 24403eb..0000000 --- a/devops-service/app/api2/handlers/network.rb +++ /dev/null @@ -1,25 +0,0 @@ -require "app/api2/parsers/network" -require "providers/provider_factory" -require_relative "request_handler" - -module Devops - module API2_0 - module Handler - class Network < RequestHandler - - set_parser Devops::API2_0::Parser::NetworkParser - - def networks provider - networks_with_account provider, nil - end - - def networks_with_account provider, account - p = ::Provider::ProviderFactory.get(provider, account) - available_keys = ["vpc-id"] - p.networks_detail(parser.networks.select{|k,v| available_keys.include?(k)}) - end - end - end - end -end - diff --git a/devops-service/app/api2/handlers/project.rb b/devops-service/app/api2/handlers/project.rb deleted file mode 100644 index 873b18d..0000000 --- a/devops-service/app/api2/handlers/project.rb +++ /dev/null @@ -1,332 +0,0 @@ -require "commands/status" -require "db/mongo/models/project" -require "workers/project_test_worker" -require "app/api2/parsers/project" -require "lib/project/type/types_factory" -require "lib/executors/server_executor" -require "workers/delete_server_worker" -require_relative "../helpers/version_2.rb" -require_relative "request_handler" - -module Devops - module API2_0 - module Handler - class Project < RequestHandler - - set_parser Devops::API2_0::Parser::ProjectParser - - include Devops::API2_0::Helpers - - extend StatusCommands - - def project_types - Devops::TypesFactory.types_names - end - - def projects - Devops::Db.connector.projects(nil, nil, parser.projects, parser.archived_projects) - end - - def project id - Devops::Db.connector.project(id) - end - - def project_deploy_envs(id) - project = Devops::Db.connector.project(id) - project.deploy_envs - end - - def project_deploy_env(project_id, env) - project = Devops::Db.connector.project(project_id) - project.deploy_env(env) - end - - def project_servers id - Devops::Db.connector.project(id) - Devops::Db.connector.servers(id, parser.project_servers) - end - - def project_stacks id - # check if project exists - Devops::Db.connector.project(id) - options = {project: id} - deploy_env = parser.project_stacks - options[:deploy_env] = deploy_env if deploy_env - Devops::Db.connector.stacks(options) - end - - def create_project - p = parser.create_project - raise InvalidRecord.new("Project '#{p.id}' already exist") if Devops::Db.connector.is_project_exists?(p) - - p.deploy_envs.each do |env| - env.add_users [parser.current_user] - end - res = p.create - info = if p.multi? - "Project '#{p.id}' with type 'multi' created" - else - "Project '#{p.id}' created." - end -# info << " " + res[:before] if res[:before] -# info << " " + res[:after] if res[:after] - info - end - - def set_project_components id - body = parser.set_project_components - project = Devops::Db.connector.project(id) - project.components = body["components"] - project.validate_components - Devops::Db.connector.project_update_field id, "components", body["components"] - "Updated project '#{project.id}' with components '#{body["components"].inspect}'" - end - - def add_deploy_env id - project = Devops::Db.connector.project(id) - env = parser.add_deploy_env - env.add_users [parser.current_user] - env.validate! - begin - db_env = project.deploy_env(env.identifier) - raise InvalidRecord.new("Can not add new environment for project '#{id}'. Environment '#{env.identifier}' already exist") - rescue RecordNotFound => e - res = project.add_deploy_env env - return "Deploy environment '#{env.identifier}' has been added to project '#{project.id}'." + res, env - end - end - - def update_deploy_env_field id, deploy_env, field - project = Devops::Db.connector.project(id) - db_env = project.deploy_env(deploy_env) - value = parser.update_deploy_env_field - if db_env.respond_to?(field + "=") - if field == "identifier" - Devops::Db.connector.change_servers_deploy_env(db_env.identifier, value) - Devops::Db.connector.change_stacks_deploy_env(db_env.identifier, value) - db_env.rename id, value - "Environment '#{deploy_env}' has been renamed to '#{value}'" - else - db_env.update_field(id, field, value) - "Environment's field '#{field}' has been updated" - end - else - raise RecordNotFound.new("Field '#{field}' does not exist") - end - end - - def update_deploy_env id, deploy_env - project = Devops::Db.connector.project(id) - db_env = project.deploy_env(deploy_env) - env = parser.update_deploy_env - env.identifier = deploy_env if env.identifier.nil? - begin - unless env.identifier == deploy_env - servers = Devops::Db.connector.servers_by_project_and_deploy_env(id, deploy_env) - raise InvalidRecord.new("Environment '#{deploy_env}' can't be updated: it has #{servers.size} running servers.") unless servers.empty? - end - begin - project.deploy_env(env.identifier) - raise InvalidRecord.new("Environment '#{deploy_env}' can't be renamed to '#{env.identifier}', environment '#{env.identifier}' already exists") unless deploy_env == env.identifier - rescue RecordNotFound => e - end - env.validate! - project.delete_deploy_env(deploy_env) - project.add_deploy_env(env) - "Deploy environment '#{deploy_env}' has been updated in project '#{project.id}'" - rescue RecordNotFound => e - env.identifier = deploy_env - res = project.add_deploy_env env - "Deploy environment '#{env.identifier}' has been added to project '#{project.id}'." + res - end - end - - def delete_deploy_env id, deploy_env - project = Devops::Db.connector.project(id) - servers = Devops::Db.connector.servers_by_project_and_deploy_env(id, deploy_env) - raise InvalidRecord.new("Can not delete environment '#{deploy_env}', there are #{servers.size} servers on it") unless servers.empty? - project.delete_deploy_env(deploy_env) - "Deploy environment '#{deploy_env}' has been deleted from project '#{project.id}'." - end - - # updates only run_list and description - def update_project id - body = parser.update - old_project = Devops::Db.connector.project id - Devops::Db.connector.project_update id, body - end - - # TODO: multi project - def update_project_users id - deploy_env, users = parser.project_users - project = Devops::Db.connector.project(id) - Validators::Helpers::Users.new(users).validate! - project.add_authorized_user users, deploy_env - info = "Users '#{users.join("', '")}' has been added to '#{id}' project's authorized users." - info - end - - # TODO: multi project - def delete_project_users id - deploy_env, users = parser.project_users - project = Devops::Db.connector.project(id) - project.remove_authorized_user users, deploy_env - "Users '#{users.join("', '")}' have been removed from '#{id}' project's authorized users" - end - - def set_project_run_list id - list = parser.run_list - project = Devops::Db.connector.project(id) - Devops::Db.connector.set_project_run_list id, list - "Updated project with run_list '#{list.inspect}'" - end - - def set_project_env_run_list id, deploy_env - list = parser.run_list - project = Devops::Db.connector.project(id) - env = project.deploy_env deploy_env - Devops::Db.connector.set_project_env_run_list id, deploy_env, list - "Updated environment '#{env.identifier}' with run_list '#{list.inspect}' in project '#{project.id}'" - end - - def delete_project id - deploy_env = parser.delete - project = Devops::Db.connector.project(id) - if deploy_env.nil? - servers = Devops::Db.connector.servers id - raise DependencyError.new "Deleting project #{id} is forbidden: Project has servers" unless servers.empty? - project.delete - "Project '#{id}' is deleted" - else - servers = Devops::Db.connector.servers id, deploy_env - raise DependencyError.new "Deleting deploy_env #{deploy_env} is forbidden: Project has servers" unless servers.empty? - project.delete_deploy_env(deploy_env) - "Project '#{id}'. Deploy environment '#{deploy_env}' has been deleted" - end - end - - def deploy_project_stream out, id - # check if project exist - project = Devops::Db.connector.project(id) - deploy_env, servers = parser.deploy - keys = {} - dbserver = Devops::Db.connector.servers(id, deploy_env, servers, true) - out << (dbservers.empty? ? "No reserved servers to deploy\n" : "Deploy servers: '#{dbservers.map{|s| s.chef_node_name}.join("', '")}'\n") - status = [] - deploy_info_buf = {} - dbservers.each do |s| - begin - Devops::Db.connector.check_project_auth s.project, s.deploy_env, parser.current_user - rescue InvalidPrivileges, RecordNotFound => e - out << e.message + "\n" - status.push 2 - next - end - deploy_env_model = project.deploy_env(s.deploy_env) - deploy_info = if deploy_info_buf[s.deploy_env] - deploy_info_buf[s.deploy_env] - else - # мы не можем указать один build_number для всех окружений, поэтому nil - deploy_info_buf[s.deploy_env] = project.deploy_info(deploy_env_model, nil) - end - status.push(Devops::Executor::ServerExecutor.new(s, out, current_user: parser.current_user).deploy_server(deploy_info)) - end - status - end - - def deploy_project id - # check if project exist - project_model = Devops::Db.connector.project(id) - deploy_env, servers = parser.deploy - files = [] - dbservers = Devops::Db.connector.servers(id, deploy_env, servers, true) - #out << (dbservers.empty? ? "No reserved servers to deploy\n" : "Deploy servers: '#{dbservers.map{|s| s.chef_node_name}.join("', '")}'\n") - deploy_info_buf = {} - dbservers.each do |s| - begin - Devops::Db.connector.check_project_auth s.project, s.deploy_env, parser.current_user - rescue InvalidPrivileges, RecordNotFound => e - next - end - - deploy_env_model = project_model.deploy_env(s.deploy_env) - deploy_info = if deploy_info_buf[s.deploy_env] - deploy_info_buf[s.deploy_env] - else - # мы не можем указать один build_number для всех окружений, поэтому nil - deploy_info_buf[s.deploy_env] = project_model.deploy_info(deploy_env_model, nil) - end - - jid = Worker.start_async(DeployWorker, - server_attrs: s.to_hash, - owner: parser.current_user, - tags: [], - deploy_info: deploy_info - ) - files.push jid - end - files - end - - def archive_project id - project = Devops::Db.connector.project(id) - Devops::Db.connector.archive_project(id) - msg = "Project '#{id}' has been archived" - DevopsLogger.logger.info msg - msg - end - - def unarchive_project id - project = Devops::Db.connector.project(id) - Devops::Db.connector.unarchive_project(id) - msg = "Project '#{id}' has been unarchived" - DevopsLogger.logger.info msg - msg - end - - def test_project id, deploy_env - project = Devops::Db.connector.project(id) - env = project.deploy_env deploy_env - DevopsLogger.logger.info "Test project '#{project.id}' and environment '#{env.identifier}'" - if env.provider == ::Provider::Static::PROVIDER - msg = "Can not test environment with provider '#{::Provider::Static::PROVIDER}'" - Logger.warn msg - raise InvalidRecord.new(msg) - end - - jid = Worker.start_async(ProjectTestWorker, - project: project.id, - deploy_env: env.identifier, - user: @request.env['REMOTE_USER'] - ) - - sleep 1 - return [jid] - end - - def delete_project_servers(project_id) - env_id, dry_run = parser.delete_project_servers - Devops::Db.connector.project(project_id) - servers = Devops::Db.connector.servers(project_id, env_id) - info = {to_delete: servers.map(&:id)} - if !dry_run - info.merge!(delete_chosen_servers!(servers)) - end - info - end - - private - - def delete_chosen_servers!(servers) - current_user = parser.current_user - reports = servers.map do |server| - Worker.start_async(DeleteServerWorker, 'server_id' => server.id, 'current_user' => current_user) - end - {reports: reports} - end - - end - end - end -end - diff --git a/devops-service/app/api2/handlers/provider.rb b/devops-service/app/api2/handlers/provider.rb deleted file mode 100644 index 7e74f27..0000000 --- a/devops-service/app/api2/handlers/provider.rb +++ /dev/null @@ -1,50 +0,0 @@ -require "app/api2/parsers/provider" -require "providers/provider_factory" -require_relative "request_handler" -require "db/mongo/models/provider_accounts/static_provider_account" -require "db/mongo/models/provider_accounts/openstack_provider_account" -require "db/mongo/models/provider_accounts/ec2_provider_account" - -module Devops - module API2_0 - module Handler - class Provider < RequestHandler - - set_parser Devops::API2_0::Parser::ProviderParser - - def providers - ::Provider::ProviderFactory.providers - end - - def accounts provider - ::Provider::ProviderFactory.get_accounts_factory(provider).accounts - end - - def account_fields provider - ::Provider::ProviderFactory.get_account_class(provider).account_fields - end - - def add_account provider - account = ::Provider::ProviderFactory.get_accounts_factory(provider).create_account(parser.account) - account.validate_fields! - Devops::Db.connector.provider_account_insert(account) - ::Provider::ProviderFactory.add_account(provider, account) - account.to_hash - end - - def delete_account name, provider - account = Devops::Db.connector.provider_account(provider, name) - Devops::Db.connector.provider_account_delete(name) - ::Provider::ProviderFactory.delete_account(provider, account) - account.to_hash - end - - def account_vpcs provider, name - Devops::Db.connector.provider_account(provider, name) - ::Provider::ProviderFactory.get(provider, name).describe_vpcs - end - - end - end - end -end diff --git a/devops-service/app/api2/handlers/report.rb b/devops-service/app/api2/handlers/report.rb deleted file mode 100644 index ec10eea..0000000 --- a/devops-service/app/api2/handlers/report.rb +++ /dev/null @@ -1,61 +0,0 @@ -require_relative "request_handler" - -module Devops - module API2_0 - module Handler - class Report < RequestHandler - - def options - params = @request.params - options = {} - ["project", "deploy_env", "type", "created_by", "date_from", "date_to", "sort", "status", "chef_node_name", "max_number"].each do |k| - options[k] = params[k] unless params[k].nil? - end - #attributes_keys = params.keys.select{|k| k =~ /attributes\.*/} - #attributes_keys.each do |ak| - # options[ak] = params[ak] - #end - options - end - - def all - Devops::Db.connector.reports(options) - end - - def all_latest - Devops::Db.connector.latest_reports(options()) - end - - def attributes name - Devops::Db.connector.reports_attributes_values(name) - end - - def report id - r = Devops::Db.connector.report(id) - file = r.file - raise RecordNotFound.new("Report '#{id}' does not exist") unless File.exists? file - return Rack::Utils.escape_html(File.read(file).encode('UTF-8', 'binary', invalid: :replace, undef: :replace, replace: '')), completed?(id) - rescue RecordNotFound => e - if status(id) == Worker::STATUS::IN_QUEUE - return "Task '#{id}' has been queued", false - else - raise e - end - end - - def status id - Sidekiq.redis do |connection| - connection.hget("devops", id) - end - end - - def completed? id - r = self.status(id) - r == "completed" or r == "failed" - end - - end - end - end -end - diff --git a/devops-service/app/api2/handlers/request_handler.rb b/devops-service/app/api2/handlers/request_handler.rb deleted file mode 100644 index cf50caa..0000000 --- a/devops-service/app/api2/handlers/request_handler.rb +++ /dev/null @@ -1,26 +0,0 @@ -module Devops - module API2_0 - module Handler - class RequestHandler - - class << self - def set_parser parser - define_method("parser") do - @request_parser ||= parser.new(@request) - end - end - end - - def initialize request - @request = request - end - - private - - def owner_from_request - @request.env['REMOTE_USER'] - end - end - end - end -end diff --git a/devops-service/app/api2/handlers/script.rb b/devops-service/app/api2/handlers/script.rb deleted file mode 100644 index 80ac4f4..0000000 --- a/devops-service/app/api2/handlers/script.rb +++ /dev/null @@ -1,103 +0,0 @@ -require "providers/provider_factory" -require "fileutils" -require "commands/status" -require "app/api2/parsers/script" -require_relative "request_handler" - -module Devops - module API2_0 - module Handler - class Script < RequestHandler - - set_parser Devops::API2_0::Parser::ScriptParser - - def scripts - res = [] - Dir.foreach(DevopsConfig.config[:scripts_dir]) {|f| res.push(f) unless f.start_with?(".")} - end - - def execute_command out, node_name - cmd = parse.execute_command - user = parser.current_user - s = ::Devops::Db.connector.server_by_chef_node_name node_name - ::Devops::Db.connector.check_project_auth s.project, s.deploy_env, user - cert = ::Devops::Db.connector.key s.key - addr = "#{s.remote_user}@#{s.public_ip || s.private_ip}" - ssh_cmd = "ssh -i %s #{addr} '#{cmd}'" - out << ssh_cmd % File.basename(cert.path) - out << "\n" - IO.popen((ssh_cmd % cert.path) + " 2>&1") do |so| - while line = so.gets do - out << line - end - end - out << "\nDone" - end - - def run_script out, script_name - nodes, script_params = parser.run_script - file = File.join(DevopsConfig.config[:scripts_dir], script_name) - unless File.exists?(file) - out << "File '#{file_name}' does not exist\n" - return - end - servers = ::Devops::Db.connector.servers_by_names(nodes) - if servers.empty? - out << "No servers found for names '#{nodes.join("', '")}'\n" - return - end - user = @request.env['REMOTE_USER'] - servers.each do |s| - ::Devops::Db.connector.check_project_auth s.project, s.deploy_env, user - end - status = [] - servers.each do |s| - cert = begin - ::Devops::Db.connector.key s.key - rescue - out << "No key found for '#{s.chef_node_name}'" - status.push 2 - next - end - ssh_cmd = "ssh -i #{cert.path} #{s.remote_user}@#{s.public_ip || s.private_ip} 'bash -s' < %s" - out << "\nRun script on '#{s.chef_node_name}'\n" - unless script_params.nil? - ssh_cmd += " " + script_params.join(" ") - end - out << (ssh_cmd % [file_name]) - out << "\n" - - begin - IO.popen( (ssh_cmd % [file]) + " 2>&1") do |so| - while line = so.gets do - out << line - end - so.close - status.push $?.to_i - end - rescue IOError => e - logger.error e.message - out << e.message - status.push 3 - end - end - status - end - - def create_script file_name - file = File.join(Devops::Api2.settings.scripts_dir, file_name) - raise RecordNotFound.new("File '#{file_name}' already exist") if File.exists?(file) - File.open(file, "w") {|f| f.write(parser.create_script)} - end - - def delete_script file_name - file = File.join(Devops::Api2.settings.scripts_dir, file_name) - raise RecordNotFound.new("File '#{file_name}' does not exist") unless File.exists?(file) - FileUtils.rm(file) - end - - end - end - end -end - diff --git a/devops-service/app/api2/handlers/server.rb b/devops-service/app/api2/handlers/server.rb deleted file mode 100644 index 069c524..0000000 --- a/devops-service/app/api2/handlers/server.rb +++ /dev/null @@ -1,382 +0,0 @@ -require "uri" - -require "commands/status" -require "commands/bootstrap_templates" - -require "lib/executors/server_executor" -require "providers/provider_factory" - -require "db/mongo/models/server" - -require "workers/create_server_worker" -require "workers/bootstrap_worker" -require "workers/delete_server_worker" -require "app/api2/parsers/server" -require_relative "request_handler" - -module Devops - module API2_0 - module Handler - class Server < RequestHandler - - set_parser Devops::API2_0::Parser::ServerParser - - extend StatusCommands - extend BootstrapTemplatesCommands - - #scheduler = Rufus::Scheduler.new - - def servers - reserved = parser.servers - Devops::Db.connector.servers(nil, nil, nil, reserved).map {|s| s.to_hash} - end - - def chef_servers - KnifeFactory.instance.chef_node_list - end - - def provider_servers provider - provider_servers_with_account provider, nil - end - - def provider_servers_with_account provider, account - ::Provider::ProviderFactory.get(provider, account).servers - end - - def server id - get_server_by_key(id, parser.server) - end - - def delete id - server = get_server_by_key(id, parser.instance_key) - current_user = parser.current_user - Devops::Db.connector.check_project_auth server.project, server.deploy_env, current_user - jid = Worker.start_async(DeleteServerWorker, 'server_id' => server.id, 'current_user' => current_user) - [jid] - end - - def delete_list - server_ids = parser.delete_list.uniq - servers = server_ids.map { |id| Devops::Db.connector.server_by_instance_id(id) } - current_user = parser.current_user - check_servers_list_auth(servers, current_user) - server_ids.inject({}) do |hash, server_id| - hash[server_id] = Worker.start_async(DeleteServerWorker, 'server_id' => server_id, 'current_user' => current_user) - hash - end - end - - def create_server_stream out - status = [] - prepare_create_server do |project, env, user, body| - e = Devops::Executor::ServerExecutor.new(nil, out) - e.project = project - e.deploy_env = env - body["created_by"] = user - res = e.create_server(body) - status.push res - end - status - end - - def create_server - body = parser.create - user = parser.current_user - - check_if_server_attrs_are_valid(body, user) - jid = Worker.start_async(CreateServerWorker, - server_attrs: body, - owner: user - ) - [jid] - end - - def deploy node_name - call_deploy(node_name) do |options| - [ Worker.start_async(DeployWorker, @request, options) ] - end - end - - def deploy_stream node_name, out - call_deploy(node_name) do |options| - Worker.start_sync(DeployWorker, @request, options, out) - end - rescue RecordNotFound => e - out << e.message - -10 - end - - def call_deploy node_name - body = parser.deploy - names = body["names"] - tags = body["tags"] || [] - run_list = body["run_list"] - dir = DevopsConfig.config[:report_dir_v2] - owner = parser.current_user - s = Server.get_server_by_key(node_name, parser.instance_key) - project = Devops::Db.connector.check_project_auth s.project, s.deploy_env, owner - deploy_info = create_deploy_info(s, project, body["build_number"]) - deploy_info["run_list"] = run_list if run_list - - yield({ - server_attrs: s.to_hash, - owner: owner, - tags: tags, - deploy_info: deploy_info - }) - end - - def pause_server node_name - s = get_server_by_key(node_name, parser.instance_key) - ## Authorization - Devops::Db.connector.check_project_auth s.project, s.deploy_env, parser.current_user - provider = s.provider_instance - r = provider.pause_server s - if r.nil? - set_last_operation_and_save(s, Devops::Model::Server::OperationType::PAUSE) - - "Server with instance ID '#{s.id}' and node name '#{node_name}' is paused" - else - raise ConflictException.new("Server with instance ID '#{s.id}' and node name '#{node_name}' can not be paused, It in state '#{r}'", 409) - end - end - - def unpause_server node_name - s = get_server_by_key(node_name, parser.instance_key) - ## Authorization - Devops::Db.connector.check_project_auth s.project, s.deploy_env, parser.current_user - provider = s.provider_instance - r = provider.unpause_server s - if r.nil? - set_last_operation_and_save(s, Devops::Model::Server::OperationType::UNPAUSE) - - "Server with instance ID '#{s.id}' and node name '#{node_name}' is unpaused" - else - raise ConflictException.new("Server with instance ID '#{s.id}' and node name '#{node_name}' can not be unpaused, It in state '#{r}'") - end - end - - def reserve_server node_name - s = get_server_by_key(node_name, parser.instance_key) - user = parser.current_user - Devops::Db.connector.check_project_auth s.project, s.deploy_env, user - raise ConflictException.new("Server '#{node_name}' already reserved") unless s.reserved_by.nil? - s.reserved_by = user - set_last_operation_and_save(s, Devops::Model::Server::OperationType::RESERVE) - end - - def unreserve_server node_name - s = get_server_by_key(node_name, parser.instance_key) - Devops::Db.connector.check_project_auth s.project, s.deploy_env, parser.current_user - raise ConflictException.new("Server '#{node_name}' is not reserved") if s.reserved_by.nil? - s.reserved_by = nil - set_last_operation_and_save(s, Devops::Model::Server::OperationType::UNRESERVE) - end - - # TODO: check bootstrap template name - def bootstrap_server_stream out - options = prepare_bootstrap_server - s = options.delete(:server) - status = [] - cert = Devops::Db.connector.key s.key - DevopsLogger.logger.debug "Bootstrap certificate path: #{cert.path}" - #bootstrap s, out, cert.path, logger - options[:cert_path] = cert.path - executor = Devops::Executor::ServerExecutor.new(s, out, current_user: parser.current_user) - r = executor.two_phase_bootstrap(options) - str = nil - r = if check_server(s) - Devops::Db.connector.server_set_chef_node_name s - str = "Server with id '#{s.id}' is bootstraped" - DevopsLogger.logger.info str - 0 - else - str = "Server with id '#{s.id}' is not bootstraped" - DevopsLogger.logger.warn str - 1 - end - status.push r - out << str - out << "\n" - status - end - - def bootstrap_server - attrs = prepare_bootstrap_server - server = attrs[:server] - bootstrap_template = attrs[:bootstrap_template] - - jid = Worker.start_async(BootstrapWorker, - server_attrs: server.to_mongo_hash, - bootstrap_template: bootstrap_template, - owner: parser.current_user - ) - - [jid] - end - - def prepare_bootstrap_server - body = parser.bootstrap - id = body["instance_id"] - name = body["name"] - rl = body["run_list"] - t = body["bootstrap_template"] - s = Devops::Db.connector.server_by_instance_id(id) - res = {server: s} - - p = Devops::Db.connector.check_project_auth s.project, s.deploy_env, parser.current_user - d = p.deploy_env(s.deploy_env) - - provider = s.provider_instance - - check_chef_node_name(name, provider, KnifeFactory.instance) unless name.nil? - unless t.nil? - templates = get_templates - halt_response("Invalid bootstrap template '#{t}', available values: #{templates.join(", ")}", 400) unless templates.include?(t) - res[:bootstrap_template] = t - end - s.chef_node_name = name || provider.create_default_chef_node_name(s) - res[:run_list] = rl || d.run_list - return res - end - - def unbootstrap_server id - s = get_server_by_key(id, parser.instance_key) - ### Authorization - Devops::Db.connector.check_project_auth s.project, s.deploy_env, parser.current_user - Devops::Executor::ServerExecutor.new(s, "").unbootstrap - end - - def add_server - project, deploy_env, server_attrs = parser.add_server - Devops::Db.connector.check_project_auth project, deploy_env, parser.current_user - - server = add_static_server(server_attrs) - "Server '#{server.id}' has been added" - end - - # returns jobs ids - def add_and_bootstrap_servers - body, servers_attrs = parser.add_and_bootstrap_servers - Devops::Db.connector.check_project_auth body['project'], body['deploy_env'], parser.current_user - servers_attrs.map do |attrs| - server = add_static_server(attrs) - Worker.start_async(BootstrapWorker, - server_attrs: server.to_mongo_hash, - bootstrap_template: body['bootstrap_template'], - owner: parser.current_user - ) - end - end - - def set_tags node_name - tags = parser.tags - prepare_tags do |id, provider| - provider.set_tags id, tags - end - end - - def unset_tags node_name - tags = parser.tags - prepare_tags do |id, provider| - provider.unset_tags id, tags - end - end - - def prepare_tags node_name - s = get_server_by_key(node_name, parser.instance_key) - Devops::Db.connector.check_project_auth s.project, s.deploy_env, parser.current_user - provider = ::Provider::ProviderFactory.get(s.provider) - yield s.id, provider - end - - def set_run_list node_name - s = get_server_by_key(node_name, parser.instance_key) - Devops::Db.connector.check_project_auth s.project, s.deploy_env, parser.current_user - Devops::Db.connector.set_server_run_list(s.id, parser.run_list) - end - - def get_server_by_key id, key - mongo = Devops::Db.connector - key == "instance" ? mongo.server_by_instance_id(id) : mongo.server_by_chef_node_name(id) - end - - def check_chef_node_name name, provider, knife - Devops::Db.connector.server_by_chef_node_name(name) - raise InvalidRecord.new("Server with name '#{name}' already exist") - rescue RecordNotFound => e - # server not found - OK - s = provider.servers.detect {|s| s["name"] == name} - raise InvalidRecord.new("#{provider.name} node with name '#{name}' already exist") unless s.nil? - s = knife.chef_node_list.detect {|n| n == name} - raise InvalidRecord.new("Chef node with name '#{name}' already exist") unless s.nil? - s = knife.chef_client_list.detect {|c| c == name} - raise InvalidRecord.new("Chef client with name '#{name}' already exist") unless s.nil? - end - - private - - # Security checks should be already done here. - # @attrs should be a hash with: - # :project - # :deploy_env - # :key - # :remote_user - # :private_ip - # :public_ip - # :chef_node_name - # :run_list - def add_static_server(attrs) - server = Devops::Model::Server.new( - '_id' => "static_#{attrs[:key]}-#{attrs[:chef_node_name]}-#{Time.now.to_i}", - 'provider' => ::Provider::ProviderFactory.get('static').name, - 'project' => attrs[:project], - 'deploy_env' => attrs[:deploy_env], - 'remote_user' => attrs[:remote_user], - 'private_ip' => attrs[:private_ip], - 'public_ip' => attrs[:public_ip], - 'key' => attrs[:key], - 'chef_node_name' => attrs[:chef_node_name], - 'run_list' => attrs[:run_list] - ) - Devops::Db.connector.server_insert(server) - server - end - - def check_if_server_attrs_are_valid(body, user) - key_name = body["key"] - Devops::Db.connector.key(key_name) unless key_name.nil? - - project = Devops::Db.connector.check_project_auth(body["project"], body["deploy_env"], user) - env = project.deploy_env(body["deploy_env"]) - - provider = env.provider_instance - server_name = body["name"] - check_chef_node_name(server_name, provider, KnifeFactory.instance) unless server_name.nil? - groups = body["groups"] - unless groups.nil? - buf = groups - provider.groups.keys - halt_response("Invalid security groups '#{buf.join("', '")}' for provider '#{provider.name}'") if buf.empty? - end - end - - def set_last_operation_and_save(server, operation_type) - server.set_last_operation(operation_type, parser.current_user) - Devops::Db.connector.server_update(server) - end - - def check_servers_list_auth(servers, current_user) - project_with_env_pairs = servers.map do |server| - [server.project, server.deploy_env] - end - project_with_env_pairs.uniq.each do |pair| - project, env = *pair - Devops::Db.connector.check_project_auth project, env, current_user - end - end - - end - end - end -end - diff --git a/devops-service/app/api2/handlers/stack_template.rb b/devops-service/app/api2/handlers/stack_template.rb deleted file mode 100644 index fe134a8..0000000 --- a/devops-service/app/api2/handlers/stack_template.rb +++ /dev/null @@ -1,81 +0,0 @@ -require 'db/mongo/models/stack_template/stack_template_factory' -require "app/api2/parsers/stack_template" -require_relative "request_handler" - -module Devops - module API2_0 - module Handler - class StackTemplate < RequestHandler - - set_parser Devops::API2_0::Parser::StackTemplateParser - - def stack_templates - Devops::Db.connector.stack_templates - end - - def stack_templates_for_provider provider - Devops::Db.connector.stack_templates(provider) - end - - def create_stack_template provider - body = parser.create - template_model = Model::StackTemplateFactory.create(provider, body) - template_model.owner = parser.current_user - Devops::Db.connector.stack_template_insert(template_model) - template_model - end - - def get_stack_template id - Devops::Db.connector.stack_template(id) - end - - def delete_stack_template id - envs_with_this_template = envs_using_stack_template(id) - - if envs_with_this_template.empty? - Devops::Db.connector.stack_template_delete id - else - raise ConflictException.new("Stack template '#{id}' is already in use in #{envs_with_this_template.map{|project, envs| "#{project}: #{envs.join(', ')}"}.join('; ')}", {projects: envs_with_this_template}) - end - end - - # temp solution to update url on existing stacks - def update_template_url(id) - template = Devops::Db.connector.stack_template(id) - template.update_template_url - Devops::Db.connector.stack_template_update(template) - template - end - - def update_available_parameters(id) - template = Devops::Db.connector.stack_template(id) - template.available_parameters = template.parse_parameters - Devops::Db.connector.stack_template_update(template) - template - end - - private - - # returns: - # { - # "project" => ["deploy_env"] - # } - def envs_using_stack_template(id) - projects = Devops::Db.connector.projects_and_deploy_envs_by_field('stack_template', id) - envs_with_this_template = [] - res = {} - - projects.each do |project| - array = [] - res[project.id] = array - project.deploy_envs.each do |env| - array << env.identifier - end - end - res - end - - end - end - end -end diff --git a/devops-service/app/api2/handlers/user.rb b/devops-service/app/api2/handlers/user.rb deleted file mode 100644 index 5026cfd..0000000 --- a/devops-service/app/api2/handlers/user.rb +++ /dev/null @@ -1,62 +0,0 @@ -require "db/mongo/models/user" -require "app/api2/parsers/user" -require_relative "request_handler" - -module Devops - module API2_0 - module Handler - class User < RequestHandler - - set_parser Devops::API2_0::Parser::UserParser - - def users - Devops::Db.connector.users({}, fields: {password: false}) - end - - def create - Devops::Db.connector.user_insert parser.create - end - - def delete user_id - projects = Devops::Db.connector.projects_by_user user_id - if !projects.empty? - str = "" - projects.each do |p| - p.deploy_envs.each do |e| - str+="#{p.id}.#{e.identifier} " if e.users.include? user_id - end - end - raise DependencyError.new "Deleting is forbidden: User is included in #{str}" - end - Devops::Db.connector.user_delete user_id - end - - def change_user_privileges user_id - cmd, privileges = parser.user_privileges - change_user(user_id) do |user| - user.grant(cmd, privileges) - end - end - - def change_email user_id - change_user(user_id) do |user| - user.email = parser.change_email - end - end - - def change_password user_id - change_user(user_id) do |user| - user.password = parser.change_password - end - end - - def change_user user_id - user = Devops::Db.connector.user user_id - yield(user) - Devops::Db.connector.user_update user - end - end - end - end -end - diff --git a/devops-service/app/api2/helpers/request.rb b/devops-service/app/api2/helpers/request.rb deleted file mode 100644 index d704827..0000000 --- a/devops-service/app/api2/helpers/request.rb +++ /dev/null @@ -1,49 +0,0 @@ -require 'sinatra/base' -require "sinatra/json" - -require "providers/provider_factory" - -module Sinatra - module Version2_0 - module Request - module Helpers - -=begin - # 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 -=end - - end - end - end -end diff --git a/devops-service/app/api2/parsers/deploy.rb b/devops-service/app/api2/parsers/deploy.rb deleted file mode 100644 index 084070a..0000000 --- a/devops-service/app/api2/parsers/deploy.rb +++ /dev/null @@ -1,22 +0,0 @@ -require_relative "request_parser" - -module Devops - module API2_0 - module Parser - class DeployParser < RequestParser - - def deploy - r = create_object_from_json_body - names = check_array(r["names"], "Parameter 'names' should be a not empty array of strings") - tags = check_array(r["tags"], "Parameter 'tags' should be an array of strings", String, true) - build_number = check_string(r["build_number"], "Parameter 'build_number' should be a not empty string", true) - rl = check_array(r["run_list"], "Parameter 'run_list' should be an array of string", String, true) - Validators::Helpers::RunList.new(rl).validate! unless rl.nil? - check_string(r["named_task"], "Parameter 'named_task' should be a not empty string", true) - r - end - - end - end - end -end diff --git a/devops-service/app/api2/parsers/network.rb b/devops-service/app/api2/parsers/network.rb deleted file mode 100644 index e808cc3..0000000 --- a/devops-service/app/api2/parsers/network.rb +++ /dev/null @@ -1,15 +0,0 @@ -require_relative "request_parser" - -module Devops - module API2_0 - module Parser - class NetworkParser < RequestParser - - def networks - @params - end - end - end - end -end - diff --git a/devops-service/app/api2/parsers/user.rb b/devops-service/app/api2/parsers/user.rb deleted file mode 100644 index ac7858a..0000000 --- a/devops-service/app/api2/parsers/user.rb +++ /dev/null @@ -1,37 +0,0 @@ -require_relative "request_parser" - -module Devops - module API2_0 - module Parser - class UserParser < RequestParser - - def create - user = create_object_from_json_body - ["username", "password", "email"].each do |p| - check_string(user[p], "Parameter '#{p}' must be a not empty string") - end - Devops::Model::User.new(user) - end - - def user_privileges - data = create_object_from_json_body - cmd = check_string(data["cmd"], "Parameter 'cmd' should be a not empty string", true) - privileges = check_string(data["privileges"], "Parameter 'privileges' should be a string", true, true) - return cmd, privileges - end - - def change_password - body = create_object_from_json_body - check_string(body["password"], "Parameter 'password' must be a not empty string") - end - - def change_email - body = create_object_from_json_body - check_string(body["email"], "Parameter 'email' must be a not empty string") - end - - end - end - end -end - diff --git a/devops-service/app/api2/routes/bootstrap_templates.rb b/devops-service/app/api2/routes/bootstrap_templates.rb deleted file mode 100644 index 60d27a8..0000000 --- a/devops-service/app/api2/routes/bootstrap_templates.rb +++ /dev/null @@ -1,30 +0,0 @@ -module Devops - module API2_0 - module Routes - module BootstrapTemplatesRoutes - - def self.registered(app) - - # Get list of available bootstrap templates - # - # * *Request* - # - method : GET - # - headers : - # - Accept: application/json - # - # * *Returns* : array of strings - # [ - # "omnibus" - # ] - app.get_with_headers "/templates", :headers => [:accept] do - check_privileges("templates", "r") - json Devops::API2_0::Handler::BootstrapTemplates.new(request).get_templates - end - - puts "Bootstrap templates routes initialized" - end - - end - end - end -end diff --git a/devops-service/app/api2/routes/deploy.rb b/devops-service/app/api2/routes/deploy.rb deleted file mode 100644 index 7a2a208..0000000 --- a/devops-service/app/api2/routes/deploy.rb +++ /dev/null @@ -1,66 +0,0 @@ - -module Devops - module API2_0 - module Routes - module DeployRoutes - - def self.registered(app) - - # Run chef-client on reserved server - # - # * *Request* - # - method : POST - # - headers : - # - Content-Type: application/json - # - body : - # { - # "names": [], -> array of servers chef node 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 - # "run_list": [], -> array of strings to set run_list for chef-client - # } - # - # * *Returns* : text stream - app.post_with_headers "/deploy", :headers => [:content_type] do - check_privileges("server", "x") - - if request["X-Stream"] - stream() do |out| - status = [] - begin - status = Devops::API2_0::Handler::Deploy.new(request).deploy_stream(out) - out << create_status(status) - rescue IOError => e - logger.error e.message - break - end - end # stream - else - files = Devops::API2_0::Handler::Deploy.new(request).deploy() - sleep 1 - json files - end - end - - app.get "/deploy/data/:project/:env" do |project, env| - p = Devops::Db.connector.project project - data = p.deploy_info(env, params["build_number"]) - content_type "application/json" - (JSON.pretty_generate data) << "\n" - end - - app.get "/deploy/data/:file" do |file| - dir = DevopsConfig.config[:project_info_dir] - file_path = File.join(dir, file) - return [404, "Data for '#{file}' not found"] unless File.exists?(file_path) - content_type "application/json" - File.read(file_path) + "\n" - end - - puts "Deploy routes initialized" - end - - end - end - end -end diff --git a/devops-service/app/api2/routes/filter.rb b/devops-service/app/api2/routes/filter.rb deleted file mode 100644 index e3efe85..0000000 --- a/devops-service/app/api2/routes/filter.rb +++ /dev/null @@ -1,80 +0,0 @@ -module Devops - module API2_0 - module Routes - module FilterRoutes - - def self.registered(app) - - # Get list of images filters for :provider - # - # Devops can works with images from filters list only - # - # * *Request* - # - method : GET - # - headers : - # - Accept: application/json - # - # * *Returns* : array of strings - # - ec2: - # [ - # "ami-83e4bcea" - # ] - # - openstack: - # [ - # "36dc7618-4178-4e29-be43-286fbfe90f50" - # ] - app.get_with_headers "/filter/:provider/images", :headers => [:accept] do |provider| - check_privileges("filter", "r") - check_provider(provider) - json Devops::API2_0::Handler::Filter.new(request).available_images(provider) - end - - hash = {} - - # Add image ids to filter for :provider - # - # * *Request* - # - method : PUT - # - headers : - # - Accept: application/json - # - Content-Type: application/json - # - body : - # [ - # "image_id" - # ] -> array of image ids to add to filter - # - # * *Returns* : list of images filters for :provider - hash["PUT"] = lambda { |provider| - check_privileges("filter", "w") - check_provider(provider) - create_response("Updated", {:images => Devops::API2_0::Handler::Filter.new(request).add_images(provider)}) - } - - # Delete image ids from filter for :provider - # - # * *Request* - # - method : DELETE - # - headers : - # - Accept: application/json - # - Content-Type: application/json - # - body : - # [ - # "image_id" - # ] -> array of image ids to delete from filter - # - # * *Returns* : list of images filters for :provider - hash["DELETE"] = lambda { |provider| - check_privileges("filter", "w") - check_provider(provider) - create_response("Deleted", {:images => Devops::API2_0::Handler::Filter.new(request).delete_images(provider)}) - } - - app.multi_routes "/filter/:provider/image", {:headers => [:accept, :content_type]}, hash - - puts "Filter routes initialized" - end - - end - end - end -end diff --git a/devops-service/app/api2/routes/flavor.rb b/devops-service/app/api2/routes/flavor.rb deleted file mode 100644 index 67db888..0000000 --- a/devops-service/app/api2/routes/flavor.rb +++ /dev/null @@ -1,53 +0,0 @@ -module Devops - module API2_0 - module Routes - module FlavorRoutes - - def self.registered(app) - # Get list of flavors for :provider - # - # * *Request* - # - method : GET - # - headers : - # - Accept: application/json - # - # * *Returns* : array of objects - # - ec2: - # [ - # { - # "id": "t1.micro", - # "cores": 2, - # "disk": 0, - # "name": "Micro Instance", - # "ram": 613 - # } - # ] - # - openstack: - # [ - # { - # "id": "m1.small", - # "v_cpus": 1, - # "ram": 2048, - # "disk": 20 - # } - # ] - app.get_with_headers "/flavors/:provider", :headers => [:accept] do |provider| - check_privileges("flavor", "r") - check_provider(provider) - json Devops::API2_0::Handler::Flavor.new(request).flavors(provider) - end - - # TODO: check account - app.get_with_headers "/flavors/:provider/:account", :headers => [:accept] do |provider, account| - check_privileges("flavor", "r") - check_provider(provider) - json Devops::API2_0::Handler::Flavor.new(request).flavors_with_account(provider, account) - end - - puts "Flavor routes initialized" - end - - end - end - end -end diff --git a/devops-service/app/api2/routes/group.rb b/devops-service/app/api2/routes/group.rb deleted file mode 100644 index 182d82f..0000000 --- a/devops-service/app/api2/routes/group.rb +++ /dev/null @@ -1,67 +0,0 @@ -# encoding: UTF-8 -module Devops - module API2_0 - module Routes - module GroupRoutes - - def self.registered(app) - - # Get security groups for :provider - # - # * *Request* - # - method : GET - # - headers : - # - Accept: application/json - # - # * Params: - # vpc-id - string - # - # * *Returns* : - # - ec2: - # { - # "default": { - # "description": "default group", - # "id": "sg-565cf93f", - # "rules": [ - # { - # "protocol": "tcp", - # "from": 22, - # "to": 22, - # "cidr": "0.0.0.0/0" - # } - # ] - # } - # } - # - openstack: - # { - # "default": { - # "description": "default", - # "rules": [ - # { - # "protocol": null, - # "from": null, - # "to": null, - # "cidr": null - # } - # ] - # } - # } - app.get_with_headers "/groups/:provider", :headers => [:accept] do |provider| - check_privileges("group", "r") - check_provider(provider) - json Devops::API2_0::Handler::Group.new(request).groups(provider) - end - - app.get_with_headers "/groups/:provider/:account", :headers => [:accept] do |provider, account| - check_privileges("group", "r") - check_provider(provider) - json Devops::API2_0::Handler::Group.new(request).groups_with_account(provider, account) - end - - puts "Group routes initialized" - end - - end - end - end -end diff --git a/devops-service/app/api2/routes/image.rb b/devops-service/app/api2/routes/image.rb deleted file mode 100644 index c63ae60..0000000 --- a/devops-service/app/api2/routes/image.rb +++ /dev/null @@ -1,160 +0,0 @@ -module Devops - module API2_0 - module Routes - module ImageRoutes - - def self.registered(app) - - # Get devops images list - # - # * *Request* - # - method : GET - # - headers : - # - Accept: application/json - # - parameters: - # - provider=ec2|openstack -> return images for provider - # - # * *Returns* : - # [ - # { - # "provider": "openstack", - # "name": "centos-6.4-x86_64", - # "remote_user": "root", - # "bootstrap_template": null, - # "id": "36dc7618-4178-4e29-be43-286fbfe90f50" - # } - # ] - app.get_with_headers "/images", :headers => [:accept] do - check_privileges("image", "r") - json Devops::API2_0::Handler::Image.new(request).images.map(&:to_hash) - end - - # Get raw images for :provider - # - # * *Request* - # - method : GET - # - headers : - # - Accept: application/json - # - # * *Returns* : - # - ec2 - # [ - # { - # "id": "ami-83e4bcea", - # "name": "amzn-ami-pv-2013.09.1.x86_64-ebs", - # "status": "available" - # } - # ] - # - openstack - # [ - # { - # "id": "36dc7618-4178-4e29-be43-286fbfe90f50", - # "name": "centos-6.4-x86_64", - # "status": "ACTIVE" - # } - # ] - app.get_with_headers "/images/provider/:provider", :headers => [:accept] do |provider| - check_privileges("image", "r") - check_provider(provider) - json Devops::API2_0::Handler::Image.new(request).provider_images(provider) - end - - app.get_with_headers "/images/provider/:provider/:account", :headers => [:accept] do |provider, account| - check_privileges("image", "r") - check_provider(provider) - json Devops::API2_0::Handler::Image.new(request).provider_account_images(provider, account) - end - - # Create devops image - # - # * *Request* - # - method : POST - # - headers : - # - Accept: application/json - # - Content-Type: application/json - # - body : - # { - # "id": "image id", - # "provider": "image provider", - # "remote_user": "user", -> the ssh username - # "bootstrap_template": null, -> specific bootstrap template name or nil - # "name": "image name" - # } - # - # * *Returns* : - # 201 - Created - app.post_with_headers "/image", :headers => [:accept, :content_type] do - check_privileges("image", "w") - Devops::API2_0::Handler::Image.new(request).create_image() - create_response "Created", nil, 201 - end - - hash = {} - # Get devops image by id - # - # * *Request* - # - method : GET - # - headers : - # - Accept: application/json - # - # * *Returns* : - # { - # "provider": "openstack", - # "name": "centos-6.4-x86_64", - # "remote_user": "root", - # "bootstrap_template": null, - # "id": "36dc7618-4178-4e29-be43-286fbfe90f50" - # } - hash["GET"] = lambda { |image_id| - check_privileges("image", "r") - json Devops::API2_0::Handler::Image.new(request).image(image_id) - } - - # Update devops image - # - # * *Request* - # - method : PUT - # - headers : - # - Accept: application/json - # - Content-Type: application/json - # - body : - # { - # "id": "image id", - # "provider": "image provider", - # "remote_user": "user" -> the ssh username - # "bootstrap_template": null -> specific bootstrap template name or nil - # "name": "image name" - # } - # - # * *Returns* : - # 200 - Updated - hash["PUT"] = lambda {|image_id| - check_privileges("image", "w") - Devops::API2_0::Handler::Image.new(request).update_image(image_id) - create_response("Image '#{image_id}' has been updated") - } - - # Delete devops image - # - # * *Request* - # - method : DELETE - # - headers : - # - Accept: application/json - # - # * *Returns* : - # 200 - Deleted - hash["DELETE"] = lambda {|image_id| - check_privileges("image", "w") - Devops::API2_0::Handler::Image.new(request).delete_image(image_id) - create_response("Image '#{image_id}' has been removed") - } - - app.multi_routes "/image/:image_id", {}, hash - - puts "Image routes initialized" - end - - end - end - end -end diff --git a/devops-service/app/api2/routes/key.rb b/devops-service/app/api2/routes/key.rb deleted file mode 100644 index a10e816..0000000 --- a/devops-service/app/api2/routes/key.rb +++ /dev/null @@ -1,73 +0,0 @@ -require "json" - -module Devops - module API2_0 - module Routes - module KeyRoutes - - def self.registered(app) - # Get list of available ssh keys - # - # * *Request* - # - method : GET - # - headers : - # - Accept: application/json - # - # * *Returns* : array of strings - # [ - # { - # "scope": "system", -> 'system' - key was added by server, 'user' - key was added by user - # "id": "devops" - # } - # ] - app.get_with_headers "/keys", :headers => [:accept] do - check_privileges("key", "r") - json Devops::API2_0::Handler::Key.new(request).keys.map{|k| h = k.to_hash; h.delete("path"); h} - end - - # Create ssh key on devops server - # - # * *Request* - # - method : POST - # - headers : - # - Accept: application/json - # - Content-Type: application/json - # - body : - # { - # "file_name": "key file name", - # "key_name": "key name", - # "content": "key content" - # } - # - # * *Returns* : - # 201 - Created - app.post_with_headers "/key", :headers => [:accept, :content_type] do - check_privileges("key", "w") - Devops::API2_0::Handler::Key.new(request).create(settings.keys_dir) - create_response("Created", nil, 201) - end - - # Delete ssh key from devops server - # - # * *Request* - # - method : DELETE - # - headers : - # - Accept: application/json - # - # * *Returns* : - # 200 - Deleted - app.delete_with_headers "/key/:key", :headers => [:accept] do |key| - check_privileges("key", "w") - - r = Devops::API2_0::Handler::Key.new(request).delete key - return [500, r["err"].inspect] if r["err"] - create_response("Key '#{key}' removed") - end - - puts "Key routes initialized" - end - - end - end - end -end diff --git a/devops-service/app/api2/routes/network.rb b/devops-service/app/api2/routes/network.rb deleted file mode 100644 index f984438..0000000 --- a/devops-service/app/api2/routes/network.rb +++ /dev/null @@ -1,56 +0,0 @@ -# encoding: UTF-8 -module Devops - module API2_0 - module Routes - module NetworkRoutes - - def self.registered(app) - - # Get list of networks for :provider - # - # * *Request* - # - method : GET - # - headers : - # - Accept: application/json - # - # * Params: - # vpc-id - string - # - # * *Returns* : array of strings - # - ec2: - # [ - # { - # "cidr": "0.0.0.0/16", - # "vpcId": "vpc-1", - # "subnetId": "subnet-1", - # "name": "subnet-1", - # "zone": "us-east-1a" - # } - # ] - # - openstack: - # [ - # { - # "cidr": "0.0.0.0/16", - # "name": "private", - # "id": "b14f8df9-ac27-48e2-8d65-f7ef78dc2654" - # } - # ] - app.get_with_headers "/networks/:provider", :headers => [:accept] do |provider| - check_privileges("network", "r") - check_provider(provider) - json Devops::API2_0::Handler::Network.new(request).networks(provider) - end - - app.get_with_headers "/networks/:provider/:account", :headers => [:accept] do |provider, account| - check_privileges("network", "r") - check_provider(provider) - json Devops::API2_0::Handler::Network.new(request).networks_with_account(provider, account) - end - - puts "Network routes initialized" - end - - end - end - end -end diff --git a/devops-service/app/api2/routes/project.rb b/devops-service/app/api2/routes/project.rb deleted file mode 100644 index 6d195fb..0000000 --- a/devops-service/app/api2/routes/project.rb +++ /dev/null @@ -1,625 +0,0 @@ -module Devops - module API2_0 - module Routes - module ProjectRoutes - - def self.registered(app) - - # Get project types - # - # * *Request* - # - method : GET - # - headers : - # - Accept: application/json - # - # * *Returns* : - # [ - # "type" - # ] - app.get_with_headers "/project_types", :headers => [:accept] do - check_privileges("project", "r") - json Devops::API2_0::Handler::Project.new(request).project_types - end - - # Get projects list - # - # * *Request* - # - method : GET - # - headers : - # - Accept: application/json - # - params : - # - fields - show project fields, available values: deploy_envs, type - # - # * *Returns* : - # [ - # {"name" : "project_1"} - # ] - app.get_with_headers "/projects", :headers => [:accept] do - check_privileges("project", "r") - projects = Devops::API2_0::Handler::Project.new(request).projects - json projects.map(&:to_hash) - end - - # Get project by id - # - # * *Request* - # - method : GET - # - headers : - # - Accept: application/json - # - # * *Returns* : - # { - # "deploy_envs": [ - # { - # "flavor": "flavor", - # "identifier": "prod", - # "image": "image id", - # "run_list": [ - # "role[project_1-prod]" - # ], - # "subnets": [ - # "private" - # ], - # "expires": null, - # "provider": "openstack", - # "groups": [ - # "default" - # ], - # "users": [ - # "user" - # ] - # } - # ], - # "name": "project_1" - # } - hash = {} - hash["GET"] = lambda {|project| - check_privileges("project", "r") - json Devops::API2_0::Handler::Project.new(request).project(project) - } - - # Update project - # - # * *Request* - # - method : PUT - # - headers : - # - Accept: application/json - # - Content-Type: application/json - # - body : - # { - # "run_list": [], - # "description": "Description", - # "named_tasks": [{ - # "name": "restart", - # "run_list": ["role[restart_service]"] - # }] - # } - # - # * *Returns* : - # 200 - Updated - hash["PUT"] = lambda { |project| - check_privileges("project", "w") - r = Devops::API2_0::Handler::Project.new(request).update_project project - create_response("Project '#{project}' has been updated.") - } - - # Delete project - # - # * *Request* - # - method : DELETE - # - headers : - # - Accept: application/json - # - Content-Type: application/json - # - body : - # { - # "deploy_env": "env" -> if not null, will be deleted environment only - # } - # - # * *Returns* : - # 200 - Deleted - hash["DELETE"] = lambda {|project| - check_privileges("project", "w") - info = Devops::API2_0::Handler::Project.new(request).delete_project(project) - create_response(info) - } - app.multi_routes "/project/:project", {}, hash - - # Get project servers - # - # * *Request* - # - method : GET - # - headers : - # - Accept: application/json - # - parameters : - # - deploy_env=:env -> show servers with environment :env - # - # * *Returns* : - # [ - # { - # "provider": "openstack", - # "chef_node_name": "project_1_server", - # "remote_user": "root", - # "project": "project_1", - # "deploy_env": "prod", - # "private_ip": "10.8.8.8", - # "public_ip": null, - # "created_at": "2014-04-23 13:35:18 UTC", - # "created_by": "user", - # "static": false, - # "key": "ssh key", - # "id": "nstance id" - # } - # ] - servers_routes_hash = {} - servers_routes_hash["GET"] = lambda { |project| - check_privileges("project", "r") - json Devops::API2_0::Handler::Project.new(request).project_servers(project).map(&:to_hash) - } - - # Deletes project servers - # - # * *Request* - # - method : DELETE - # - headers : - # - Accept: application/json - # - Content-Type: application/json - # - body : - # { - # "dry_run": false # set to true if you'd like to just see list of servers to delete - # "deploy_env": null # set to env's identifier to delete that env's servers - # } - # - # * *Returns* : - # 200 - - # { - # "to_delete": ['server1', 'server2'], - # "deleted": ['server1'], - # "failed": ['server2'] - # } - servers_routes_hash["DELETE"] = lambda { |project_id| - check_privileges("project", "w") - json Devops::API2_0::Handler::Project.new(request).delete_project_servers(project_id) - } - app.multi_routes "/project/:project/servers", {}, servers_routes_hash - - # Get project stacks - # - # * *Request* - # - method : GET - # - headers : - # - Accept: application/json - # - parameters : - # - deploy_env=:env -> show stacks with environment :env - # - # * *Returns* : - # [ - # "provider": "openstack", - # "project": "test_openstack", - # "deploy_env": "test", - # "stack_template": "openstack_template", - # "cloud_stack_id": "4c712026-dcd5-4664-90b8-0915494c1332", - # "parameters": { - # "admin_pass": "Pass12", - # "key_name": "devops", - # "image": "CirrOS_0.3.1" - # }, - # "stack_status": null, - # "id": "openstack_stack" - # ] - app.get_with_headers "/project/:project/stacks", :headers => [:accept] do |project| - check_privileges("project", "r") - json Devops::API2_0::Handler::Project.new(request).project_stacks(project).map(&:to_hash) - end - - # Get project deploy environments - # - # * *Request* - # - method : GET - # - headers : - # - Accept: application/json - app.get_with_headers "/project/:project/deploy_envs", :headers => [:accept] do |project| - check_privileges("project", "r") - json Devops::API2_0::Handler::Project.new(request).project_deploy_envs(project) - end - - # Add project deploy environment - # - # * *Request* - # - method : POST - # - headers : - # - Accept: application/json - # - body : - # { - # "identifier": "prod", - # "provider": "openstack", - # "flavor": "m1.small", - # "image": "image id", - # "subnets": [ - # "private" - # ], - # "groups": [ - # "default" - # ], - # "users": [ - # "user" - # ], - # "run_list": [ ], - # "expires": null - # } - # - # * *Returns* : - # 200 - Added - app.post_with_headers "/project/:project/deploy_env", :headers => [:accept, :content_type] do |project| - check_privileges("project", "w") - res, env = Devops::API2_0::Handler::Project.new(request).add_deploy_env(project) - create_response(res, {environment: env.to_hash}, 200) - end - - deploy_env_hash = {} - # Get project deploy environment - # - # * *Request* - # - method : GET - # - headers : - # - Accept: application/json - deploy_env_hash["GET"] = lambda{|project, env| - check_privileges("project", "r") - json Devops::API2_0::Handler::Project.new(request).project_deploy_env(project, env) - } - - # Update deploy_env, you can send few fields in the body - # - # * *Request* - # - method : PUT - # - headers : - # - Accept: application/json - # - Content-Type: application/json - # - body : - # { - # "identifier": "prod", - # "provider": "openstack", - # "flavor": "m1.small", - # "image": "image id", - # "subnets": [ - # "private" - # ], - # "groups": [ - # "default" - # ], - # "users": [ - # "user" - # ], - # "run_list": [ ], - # "expires": null - # } - # - # * *Returns* : - # 200 - Updated - deploy_env_hash["PUT"] = lambda{|id, deploy_env| - check_privileges("project", "w") - begin - res = Devops::API2_0::Handler::Project.new(request).update_deploy_env(id, deploy_env) - create_response(res, nil, 200) - rescue InvalidRecord => e - halt_response(e.message) - end - } - - # Delete deploy_env - # - # * *Request* - # - method : DELETE - # - headers : - # - Accept: application/json - # - # * *Returns* : - # 200 - Deleted - deploy_env_hash["DELETE"] = lambda{|id, deploy_env| - check_privileges("project", "w") - begin - res = Devops::API2_0::Handler::Project.new(request).delete_deploy_env(id, deploy_env) - create_response(res, nil, 200) - rescue InvalidRecord => e - halt_response(e.message) - end - } - app.multi_routes "/project/:id/deploy_envs/:deploy_env", {}, deploy_env_hash - - app.put_with_headers "/project/:id/deploy_env/:deploy_env/:field", :headers => [:accept, :content_type] do |project_id, deploy_env, field| - check_privileges("project", "w") - res = Devops::API2_0::Handler::Project.new(request).update_deploy_env_field(project_id, deploy_env, field) - create_response(res, nil, 200) - end - - # Create project - # - # * *Request* - # - method : POST - # - headers : - # - Accept: application/json - # - Content-Type: application/json - # - body : - # { - # "deploy_envs": [ - # { - # "identifier": "prod", - # "provider": "openstack", - # "flavor": "m1.small", - # "image": "image id", - # "subnets": [ - # "private" - # ], - # "groups": [ - # "default" - # ], - # "users": [ - # "user" - # ], - # "run_list": [ - # - # ], - # "expires": null - # } - # ], - # "name": "project_1" - # } - # - # * *Returns* : - # 201 - Created - app.post_with_headers "/project", :headers => [:accept, :content_type] do - check_privileges("project", "w") - res = Devops::API2_0::Handler::Project.new(request).create_project - res = "Created. " + res - create_response(res, nil, 201) - end - -=begin - # Set components to project - # - # * *Request* - # - method : POST - # - headers : - # - Accept: application/json - # - Content-Type: application/json - # - body : - # components: { - # "some_id": { - # "filename" : "some.war" - # } - # } - # - # * *Returns* : - # 200 - Updated - app.post_with_headers "/project/:id/components", :headers => [:accept, :content_type] do |id| - check_privileges("project", "w") - res = Devops::API2_0::Handler::Project.new(request).set_project_components(id) - create_response(res) - end -=end - - users_hash = {} - # Add users to project environment - # - # * *Request* - # - method : PUT - # - headers : - # - Accept: application/json - # - Content-Type: application/json - # - body : - # { - # "users": [ - # "user1" - # ], - # "deploy_env": "env" -> if null, users will be added to all environments - # } - # - # * *Returns* : - # 200 - Updated - users_hash["PUT"] = lambda { |project| - check_privileges("project", "w") - info = Devops::API2_0::Handler::Project.new(request).update_project_users(project) - create_response(info) - } - - # Delete users from project environment - # - # * *Request* - # - method : DELETE - # - headers : - # - Accept: application/json - # - Content-Type: application/json - # - body : - # { - # "users": [ - # "user1" - # ], - # "deploy_env": "env" -> if null, users will be deleted from all environments - # } - # - # * *Returns* : - # 200 - Updated - users_hash["DELETE"] = lambda {|project| - check_privileges("project", "w") - info = Devops::API2_0::Handler::Project.new(request).delete_project_users(project) - create_response(info) - } - app.multi_routes "/project/:id/user", {}, users_hash - - # Set run_list to project - # - # * *Request* - # - method : PATCH - # - headers : - # - Accept: application/json - # - Content-Type: application/json - # - body : - # [ - # "role[role_1]", - # "recipe[recipe_1]" - # ] - # - # * *Returns* : - # 200 - Updated - app.patch_with_headers "/project/:id/run_list", :headers => [:accept, :content_type] do |project| - check_privileges("project", "w") - info = Devops::API2_0::Handler::Project.new(request).set_project_run_list(project) - create_response(info) - end - - # Set run_list to project environment - # - # * *Request* - # - method : PATCH - # - headers : - # - Accept: application/json - # - Content-Type: application/json - # - body : - # [ - # "role[role_1]", - # "recipe[recipe_1]" - # ] - # - # * *Returns* : - # 200 - Updated - app.patch_with_headers "/project/:id/:env/run_list", :headers => [:accept, :content_type] do |project, deploy_env| - check_privileges("project", "w") - info = Devops::API2_0::Handler::Project.new(request).set_project_env_run_list(project, deploy_env) - create_response(info) - end - - # Run chef-client on reserved project servers - # - # * *Request* - # - method : POST - # - headers : - # - X-Stream: true -> return output in text stream - # - Content-Type: application/json - # - body : - # { - # "servers": [ - # "server_1" - # ], -> deploy servers from list, all servers if null - # "deploy_env": "env" -> deploy servers with environment 'env' or all project servers if null - # } - # - # * *Returns* : text stream - 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 request["X-Stream"] - stream() do |out| - begin - status = handler.deploy_project_stream out, project - out << create_status(status) - rescue IOError => e - logger.error e.message - end - end - else - json handler.deploy_project project - end - end - - # Set project to archivated state - # - # * *Request* - # - method : POST - # - headers : - # - Content-Type: application/json - app.post_with_headers "/project/:project/archive", :headers => [:content_type] do |project| - check_privileges("project", "w") - info = Devops::API2_0::Handler::Project.new(request).archive_project(project) - create_response(info) - end - - # Set project to normal state - # - # * *Request* - # - method : POST - # - headers : - # - Content-Type: application/json - app.post_with_headers "/project/:project/unarchive", :headers => [:content_type] do |project| - check_privileges("project", "w") - info = Devops::API2_0::Handler::Project.new(request).unarchive_project(project) - create_response(info) - end - - # Test project environment - # - # Run tests: - # - run server - # - bootstrap server - # - delete server - # - # * *Request* - # - method : POST - # - headers : - # - Accept: application/json - # - Content-Type: application/json - # - # * *Returns* : - # 200 - - # { - # "servers": [ - # { - # "id": "132958f0-61c5-4665-8cc3-66e1bacd285b", - # "create": { - # "status": true, - # "time": "155s" - # }, - # "chef_node_name": "chef name", - # "bootstrap": { - # "status": true, - # "log": "\nWaiting for SSH...\n" - # "return_code": 0 - # }, - # "delete": { - # "status": true, - # "time": "2s" - # "log": { - # "chef_node": "Deleted node[chef name]", - # "chef_client": "Deleted client[chef name]", - # "server": "Server with id '132958f0-61c5-4665-8cc3-66e1bacd285b' terminated" - # } - # }, - # } - # ], - # "project": { - # "deploy_envs": [ - # { - # "flavor": "flavor", - # "identifier": "prod", - # "image": "image id", - # "run_list": [ - # "role[prod]" - # ], - # "subnets": [ - # "private" - # ], - # "expires": null, - # "provider": "openstack", - # "groups": [ - # "default" - # ], - # "users": [ - # "root" - # ] - # } - # ], - # "name": "prject_1" - # }, - # "message": "Test project 'project_1' and environment 'prod'" - # } - app.post_with_headers "/project/test/:id/:env", :headers => [:accept, :content_type] do |project, deploy_env| - check_privileges("project", "r") - json Devops::API2_0::Handler::Project.new(request).test_project(project, deploy_env) - end - - puts "Project routes initialized" - end - - end - end - end -end - diff --git a/devops-service/app/api2/routes/provider.rb b/devops-service/app/api2/routes/provider.rb deleted file mode 100644 index dd51af9..0000000 --- a/devops-service/app/api2/routes/provider.rb +++ /dev/null @@ -1,142 +0,0 @@ -# encoding: UTF-8 - -require "providers/provider_factory" - -module Devops - module API2_0 - module Routes - module ProviderRoutes - - def self.registered(app) - - # Get devops providers - # - # * *Request* - # - method : GET - # - headers : - # - Accept: application/json - # - # * *Returns* : - # [ - # "ec2", - # "openstack" - # ] - app.get_with_headers "/providers", :headers => [:accept] do#, &Devops::Version2_0::Handler::Provider.get_providers - check_privileges("provider", "r") - json Devops::API2_0::Handler::Provider.new(request).providers - end - - # Get list of provider account fields - # - # * *Request* - # - method : GET - # - headers : - # - Accept: application/json - # - # * *Returns* : hash - # key - field - # value - description - app.get_with_headers "/provider/:provider/account/fields", :headers => [:accept] do |provider| - check_privileges("provider", "r") - check_provider(provider) - json Devops::API2_0::Handler::Provider.new(request).account_fields(provider) - end - - # Get list of provider accounts - # - # * *Request* - # - method : GET - # - headers : - # - Accept: application/json - # - # * *Returns* : array of strings - # - ec2: - # { - # "account_name": "", - # "description": "", - # "access_key_id" : "", - # "ssh_key": "", - # "certificate" : "path to file", - # "availability_zone": "" - # - # } - # - openstack: - # { - # "account_name": "", - # "description": "", - # "username": "", - # "auth_url": "", - # "tenant": "", - # "ssh_key": "", - # "certificate" : "path to file" - # } - # - static: - # { - # "account_name": "", - # "description": "", - # "ssh_key": "", - # "certificate" : "path to file" - # } - app.get_with_headers "/provider/:provider/accounts", :headers => [:accept] do |provider| - check_privileges("provider", "r") - check_provider(provider) - json Devops::API2_0::Handler::Provider.new(request).accounts(provider) - end - - # Create provider account for :provider - # - # * *Request* - # - method : POST - # - headers : - # - Accept: application/json - # - Content-Type: application/json - # - body : - # { - # - # - # } - # - # * *Returns* : 201 - app.post_with_headers "/provider/:provider/account", :headers => [:accept, :content_type] do |provider| - check_privileges("provider", "w") - check_provider(provider) - create_response("Created", {:account => Devops::API2_0::Handler::Provider.new(request).add_account(provider)}, 201) - end - - # Delete account with name :account_name for :provider - # - # * *Request* - # - method : DELETE - # - headers : - # - Accept: application/json - # - Content-Type: application/json - # - # * *Returns* : 200 - app.delete_with_headers "/provider/:provider/account/:account_name", :headers => [:accept, :content_type] do |provider, account_name| - check_privileges("provider", "w") - check_provider(provider) - create_response("Deleted", {:account => Devops::API2_0::Handler::Provider.new(request).delete_account(account_name, provider)}) - end - - # Describe vpc for account with name :account_name for provider ec2 - # - # * *Request* - # - method : GET - # - headers : - # - Accept: application/json - # - Content-Type: application/json - # - # * *Returns* : 200 - app.get_with_headers "/provider/ec2/account/:account_name/vpcs", :headers => [:accept, :content_type] do |account_name| - provider = "ec2" - check_privileges("provider", "r") - check_provider(provider) - json Devops::API2_0::Handler::Provider.new(request).account_vpcs(provider, account_name) - end - - puts "Provider routes initialized" - end - end - end - end -end diff --git a/devops-service/app/api2/routes/report.rb b/devops-service/app/api2/routes/report.rb deleted file mode 100644 index bfd45c1..0000000 --- a/devops-service/app/api2/routes/report.rb +++ /dev/null @@ -1,38 +0,0 @@ -module Devops - module API2_0 - module Routes - module ReportRoutes - - def self.registered(app) - - app.get_with_headers "/report/all", headers: [:accept] do - json Devops::API2_0::Handler::Report.new(request).all.map{|r| r.to_hash} - end - - app.get_with_headers "/report/all/latest", headers: [:accept] do - json Devops::API2_0::Handler::Report.new(request).all_latest.map{|r| r.to_hash} - end - - app.get_with_headers "/report/all/attributes/:name", headers: [:accept] do |name| - json Devops::API2_0::Handler::Report.new(request).attributes(name) - end - - app.get "/report/:id" do |id| - @text, @done = Devops::API2_0::Handler::Report.new(request).report(id) - erb :report - end - - app.get "/status/:id" do |id| - r = Devops::API2_0::Handler::Report.new(request).status(id) - return [404, "Job with id '#{id}' not found"] if r.nil? - r - end - - puts "Report routes initialized" - end - - end - end - end -end - diff --git a/devops-service/app/api2/routes/server.rb b/devops-service/app/api2/routes/server.rb deleted file mode 100644 index 5d1f594..0000000 --- a/devops-service/app/api2/routes/server.rb +++ /dev/null @@ -1,504 +0,0 @@ -module Devops - module API2_0 - module Routes - module ServerRoutes - - def self.registered(app) - - # Get devops servers list - # - # * *Request* - # - method : GET - # - headers : - # - Accept: application/json - # - params : - # - fields - show server fields, available values: project, deploy_env, provider, remote_user, private_ip, public_ip, created_at, created_by, static, key, reserved_by - # - # * *Returns* : - # [ - # { - # "id": "instance id", - # "chef_node_name": "chef name" - # } - # ] - app.get_with_headers "/servers", :headers => [:accept] do - check_privileges("server", "r") - json Devops::API2_0::Handler::Server.new(request).servers - end - - # Get chef nodes list - # - # * *Request* - # - method : GET - # - headers : - # - Accept: application/json - # - # * *Returns* : - # [ - # { - # "chef_node_name": "chef name" - # } - # ] - app.get_with_headers "/servers/chef", :headers => [:accept] do - check_privileges("server", "r") - json Devops::API2_0::Handler::Server.new(request).chef_servers - end - - # Get provider servers list - # - # * *Request* - # - method : GET - # - headers : - # - Accept: application/json - # - # * *Returns* : - # -ec2 - # [ - # { - # "state": "running", - # "name": "name", - # "image": "ami-83e4bcea", - # "flavor": "m1.small", - # "keypair": "ssh key", - # "instance_id": "i-8441bfd4", - # "dns_name": "ec2-204-236-199-49.compute-1.amazonaws.com", - # "zone": "us-east-1d", - # "private_ip": "10.215.217.210", - # "public_ip": "204.236.199.49", - # "launched_at": "2014-04-25 07:56:33 UTC" - # } - # ] - # -openstack - # [ - # { - # "state": "ACTIVE", - # "name": "name", - # "image": "image id", - # "flavor": null, - # "keypair": "ssh key", - # "instance_id": "instance id", - # "private_ip": "172.17.0.1" - # } - # ] - app.get_with_headers "/servers/:provider", :headers => [:accept] do |provider| - check_privileges("server", "r") - json Devops::API2_0::Handler::Server.new(request).provider_servers(provider) - end - - app.get_with_headers "/servers/provider/:provider/:account", :headers => [:accept] do |provider, account| - check_privileges("server", "r") - json Devops::API2_0::Handler::Server.new(request).provider_servers_with_account(provider, account) - end - - # Get server info by :name - # - # * *Request* - # - method : GET - # - headers : - # - Accept: application/json - # - parameters: - # key=instance -> search server by instance_id rather then chef_node_name - # - # * *Returns* : - # [ - # { - # "chef_node_name": "chef name" - # } - # ] - hash = {} - hash["GET"] = lambda {|id| - check_privileges("server", "r") - json Devops::API2_0::Handler::Server.new(request).server(id).to_hash - } - - # Delete devops server - # - # * *Request* - # - method : DELETE - # - headers : - # - Accept: application/json - # - Content-Type: application/json - # - body : - # { - # "key": "instance", -> search server by instance_id rather then chef_node_name - # } - # - # * *Returns* : - # 200 - Deleted - hash["DELETE"] = lambda {|id| - check_privileges("server", "w") - json Devops::API2_0::Handler::Server.new(request).delete(id) - } - app.multi_routes "/server/:id", {:headers => [:accept, :content_type]}, hash - - # Run deploy command on reserved server - # - # * *Request* - # - method : POST - # - headers : - # - Content-Type: application/json - # - body : - # { - # "names": [], -> array of servers names to run chef-client - # "tags": [], -> array of tags to apply on each server before running chef-client - # "build_number": "", -> string, build number to deploy - # "run_list": [], -> array of strings to set run_list for chef-client - # } - # - # * *Returns* : text stream - app.post_with_headers "/server/:node_name/deploy", :headers => [:content_type, :accept] do |node_name| - check_privileges("server", "x") - - if request["HTTP_X_STREAM"] - stream() do |out| - status = [] - begin - status = Devops::API2_0::Handler::Server.new(request).deploy_stream(node_name, out) - out << create_status(status) - rescue DeployInfoError => e - msg = "Can not get deploy info: " + e.message - DevopsLogger.logger.error "msg:\n#{e.backtrace.join('\n')}" - out.puts msg - rescue IOError => e - logger.error e.message - break - end - end # stream - else - files = begin - Devops::API2_0::Handler::Server.new(request).deploy(node_name) - rescue DeployInfoError => e - msg = "Can not get deploy info: " + e.message - DevopsLogger.logger.error "#{msg}:\n#{e.backtrace.join("\n")}" - out << "\nError - " - out.puts msg - end - sleep 1 - json files - end - end - - # Create devops server - # - # * *Request* - # - method : POST - # - headers : - # - X-Stream: true -> return output in text stream - # - Accept: application/json - # - Content-Type: application/json - # - body : - # { - # "project": "project name", -> mandatory parameter - # "deploy_env": "env", -> mandatory parameter - # "name": "server_name", -> if null, name will be generated - # "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 - # "private_ip": null -> should be string like "172.31.31.203" if present - # "project_info": { - # "deployers": ['user1'] -> currently it's used only in sandbox projects - # } - # } - # - # * *Returns* : text stream - app.post_with_headers "/server", :headers => [:accept, :content_type] do - check_privileges("server", "w") - handler = Devops::API2_0::Handler::Server.new(request) - if request["X-Stream"] or request["HTTP_X_STREAM"] - stream() do |out| - begin - status = handler.create_server_stream out - out << create_status(status) - rescue IOError => e - logger.error e.message - end - end - else - json handler.create_server - end - end - - # Pause devops server by name - # - # * *Request* - # - method : POST - # - headers : - # - Accept: application/json - # - Content-Type: application/json - # - body : - # { - # "key": "instance", -> search server by instance_id rather then chef_node_name - # } - # - # * *Returns* : - # 200 - Paused - app.post_with_headers "/server/:node_name/pause", :headers => [:accept, :content_type] do |node_name| - check_privileges("server", "w") - info = Devops::API2_0::Handler::Server.new(request).pause_server(node_name) - create_response(info) - end - - # Unpause devops server by name - # - # * *Request* - # - method : POST - # - headers : - # - Accept: application/json - # - Content-Type: application/json - # - body : - # { - # "key": "instance", -> search server by instance_id rather then chef_node_name - # } - # - # * *Returns* : - # 200 - Unpaused - app.post_with_headers "/server/:node_name/unpause", :headers => [:accept, :content_type] do |node_name| - check_privileges("server", "w") - info = Devops::API2_0::Handler::Server.new(request).unpause_server(node_name) - create_response(info) - end - - # Reserve devops server - # - # * *Request* - # - method : POST - # - headers : - # - Accept: application/json - # - Content-Type: application/json - # - body : - # { - # "key": "instance", -> search server by instance_id rather then chef_node_name - # } - # - # * *Returns* : - # 200 - Reserved - app.post_with_headers "/server/:node_name/reserve", :headers => [:accept, :content_type] do |node_name| - check_privileges("server", "w") - Devops::API2_0::Handler::Server.new(request).reserve_server(node_name) - create_response("Server '#{node_name}' has been reserved") - end - - # Unreserve devops server - # - # * *Request* - # - method : POST - # - headers : - # - Accept: application/json - # - Content-Type: application/json - # - body : - # { - # "key": "instance", -> search server by instance_id rather then chef_node_name - # } - # - # * *Returns* : - # 200 - Unreserved - app.post_with_headers "/server/:node_name/unreserve", :headers => [:accept, :content_type] do |node_name| - check_privileges("server", "w") - Devops::API2_0::Handler::Server.new(request).unreserve_server(node_name) - create_response("Server '#{node_name}' has been unreserved") - end - - # Bootstrap devops server - # - # * *Request* - # - method : POST - # - headers : - # - X-Stream: true -> return output in text stream - # - Accept: application/json - # - Content-Type: application/json - # - body : - # { - # "instance_id": "instance id", -> mandatory parameter - # "name": "server_name", -> if null, name will be generated - # "run_list": [], -> specify list of roles and recipes - # "bootstrap_template": "template" -> specify ssh key for server, overrides value from project env - # } - # - # * *Returns* : text stream - app.post_with_headers "/server/bootstrap", :headers => [:accept, :content_type] do - check_privileges("server", "w") - - handler = Devops::API2_0::Handler::Server.new(request) - if request["X-Stream"] - stream() do |out| - begin - status = handler.bootstrap_server_stream out - out << create_status(status) - rescue IOError => e - logger.error e.message - end - end - else - json handler.bootstrap_server() - end - end - - # Unbootstrap devops server - # - # * *Request* - # - method : POST - # - headers : - # - Accept: application/json - # - Content-Type: application/json - # - body : - # { - # "key": "instance", -> search server by instance_id rather then chef_node_name - # } - # - # * *Returns* : 200 - app.post_with_headers "/server/:id/unbootstrap", :headers => [:accept, :content_type] do |id| - check_privileges("server", "w") - info = Devops::API2_0::Handler::Server.new(request).unbootstrap_server(id) - create_response("Unbootstrap", info) - end - - # Add external server to devops - # - # * *Request* - # - method : POST - # - headers : - # - Accept: application/json - # - Content-Type: application/json - # - body : - # { - # "project": "project name", -> mandatory parameter - # "deploy_env": "env", -> mandatory parameter - # "key": "ssh key", -> mandatory parameter - # "remote_user": "ssh user", -> mandatory parameter - # "private_ip": "ip", -> mandatory parameter - # "public_ip": "ip" - # } - # - # * *Returns* : - # 200 - Added - app.post_with_headers "/server/add", :headers => [:accept, :content_type] do - check_privileges("server", "w") - info = Devops::API2_0::Handler::Server.new(request).add_server() - create_response(info) - end - - - # Add list of external servers to devops and bootstrap them - # - # * *Request* - # - method : POST - # - headers : - # - Accept: application/json - # - Content-Type: application/json - # - body : - # { - # "project": "project name", -> required - # "deploy_env": "env", -> required - # "key": "ssh key", -> required - # "remote_user": "ssh user", -> required - # "ips_with_names": multiline string like, required - # 127.0.0.1:node1 - # 127.0.0.2:node2 - # "private_ip": "ip", -> required - # "public_ip": "ip" - # } - # - # * *Returns* : - # ["report1", "report2"] - app.post_with_headers "/server/add_and_bootstrap_servers", :headers => [:accept, :content_type] do - check_privileges("server", "w") - json Devops::API2_0::Handler::Server.new(request).add_and_bootstrap_servers() - end - - hash = {} - # Add instance tags - # - # * *Request* - # - method : PUT - # - headers : - # - Content-Type: application/json - # - body : - # { - # "tags": {"tag name": "tag value"} - # "key": "instance", -> search server by instance_id rather then chef_node_name - # } - # - # * *Returns* : - # 200 - Added - hash["PUT"] = lambda {|id| - check_privileges("server", "w") - Devops::API2_0::Handler::Server.new(request).set_tags(id) - create_response("Added") - } - - # Delete instance tags - # - # * *Request* - # - method : DELETE - # - headers : - # - Content-Type: application/json - # - body : - # { - # "tags": {"tag name": "tag value"} - # "key": "instance", -> search server by instance_id rather then chef_node_name - # } - # - # * *Returns* : - # 200 - Deleted - hash["DELETE"] = lambda {|id| - check_privileges("server", "w") - Devops::API2_0::Handler::Server.new(request).unset_tags(id) - create_response("Deleted") - } - app.multi_routes "/server/:id/tags", {:headers => [:content_type]}, hash - - # Set run_list to server - # - # * *Request* - # - method : PATCH - # - headers : - # - Accept: application/json - # - Content-Type: application/json - # - body : - # { - # "run_list": [ - # "role[role_1]", - # "recipe[recipe_1]" - # ], - # "key": "instance", -> search server by instance_id rather then chef_node_name - # } - # - # * *Returns* : - # 200 - Updated - app.put_with_headers "/server/:id/run_list", :headers => [:accept, :content_type] do |node_name| - check_privileges("server", "w") - Devops::API2_0::Handler::Server.new(request).set_run_list(node_name) - create_response("Run list has been changed") - end - - - # Delete list of servers - # - # * *Request* - # - method : POST - # - headers : - # - Accept: application/json - # - Content-Type: application/json - # - body : - # { - # "servers_ids": [ "server1", "server2"] - # } - # - # * *Returns* : - # { - # "server1": "report_1", - # "server2": "report_2" - # } - app.post_with_headers "/server/delete_list", :headers => [:accept, :content_type] do - check_privileges("server", "w") - json Devops::API2_0::Handler::Server.new(request).delete_list - end - - puts "Server routes initialized" - end - - end - end - end -end diff --git a/devops-service/app/api2/routes/stack_template.rb b/devops-service/app/api2/routes/stack_template.rb deleted file mode 100644 index 5a46f01..0000000 --- a/devops-service/app/api2/routes/stack_template.rb +++ /dev/null @@ -1,58 +0,0 @@ -module Devops - module API2_0 - module Routes - module StackTemplateRoutes - - def self.registered(app) - app.get_with_headers '/stack_templates', :headers => [:accept] do - check_privileges('stack_template', 'r') - json Devops::API2_0::Handler::StackTemplate.new(request).stack_templates.map(&:to_hash) - end - - app.get_with_headers '/stack_templates/provider/:provider', :headers => [:accept] do |provider| - check_privileges('stack_template', 'r') - check_provider(provider) - json Devops::API2_0::Handler::StackTemplate.new(request).stack_templates_for_provider(provider).map(&:to_hash) - end - - app.post_with_headers "/stack_template/:provider", :headers => [:accept] do |provider| - check_privileges('stack_template', 'w') - check_provider(provider) - model = Devops::API2_0::Handler::StackTemplate.new(request).create_stack_template(provider) - create_response 'Created', model.to_hash, 201 - end - - # Temp route just to process migration. Could be deleted safely - app.post_with_headers "/stack_template/:id/update_template_url", :headers => [:accept] do |template_id| - check_privileges('stack_template', 'w') - json Devops::API2_0::Handler::StackTemplate.new(request).update_template_url(template_id).to_hash - end - - # Temp route just to process migration - app.post_with_headers "/stack_template/:id/update_available_parameters", :headers => [:accept] do |template_id| - check_privileges('stack_template', 'w') - json Devops::API2_0::Handler::StackTemplate.new(request).update_available_parameters(template_id).to_hash - end - - hash = {} - - hash['GET'] = lambda {|stack_template_id| - check_privileges('stack_template', 'r') - json Devops::API2_0::Handler::StackTemplate.new(request).get_stack_template(stack_template_id).to_hash - } - - hash['DELETE'] = lambda {|stack_template_id| - check_privileges('stack_template', 'w') - Devops::API2_0::Handler::StackTemplate.new(request).delete_stack_template(stack_template_id) - create_response("Template '#{stack_template_id}' has been removed") - } - - app.multi_routes '/stack_template/:stack_template_id', {}, hash - - puts "Stack_template routes initialized" - end - - end - end - end -end diff --git a/devops-service/app/api2/routes/statistic.rb b/devops-service/app/api2/routes/statistic.rb deleted file mode 100644 index 099ebba..0000000 --- a/devops-service/app/api2/routes/statistic.rb +++ /dev/null @@ -1,18 +0,0 @@ -module Devops - module API2_0 - module Routes - module StatisticRoutes - - def self.registered(app) - app.get_with_headers '/statistic', :headers => [:accept] do - # check_privileges('statistic', 'r') - JSON.pretty_generate Devops::Db.connector.search_statistic(@params) - end - - puts "Statistic routes initialized" - end - - end - end - end -end diff --git a/devops-service/app/api2/routes/tag.rb b/devops-service/app/api2/routes/tag.rb deleted file mode 100644 index ff8ffe0..0000000 --- a/devops-service/app/api2/routes/tag.rb +++ /dev/null @@ -1,72 +0,0 @@ -module Devops - module API2_0 - module Routes - module TagRoutes - - def self.registered(app) - - hash = {} - # Get tags list for :node_name - # - # * *Request* - # - method : GET - # - headers : - # - Accept: application/json - # - # * *Returns* : - # [ - # "tag_1" - # ] - hash["GET"] = lambda {|node_name| - check_privileges("server", "r") - json Devops::API2_0::Handler::Tag.new(request).tags(node_name) - } - - # Set tags list to :node_name - # - # * *Request* - # - method : POST - # - headers : - # - Accept: application/json - # - Content-Type: application/json - # - body : - # [ - # "tag_1" - # ] - # - # * *Returns* : - # 200 - hash["POST"] = lambda {|node_name| - check_privileges("server", "w") - tags = Devops::API2_0::Handler::Tag.new(request).set_tags(node_name) - create_response("Set tags for #{node_name}", tags: tags) - } - - # Delete tags from :node_name - # - # * *Request* - # - method : DELETE - # - headers : - # - Accept: application/json - # - Content-Type: application/json - # - body : - # [ - # "tag_1" - # ] - # - # * *Returns* : - # 200 - hash["DELETE"] = lambda {|node_name| - check_privileges("server", "w") - tags = Devops::API2_0::Handler::Tag.new(request).unset_tags(node_name) - create_response("Deleted tags for #{node_name}", tags: tags) - } - app.multi_routes "/tags/:node_name", {:headers => [:accept, :content_type]}, hash - - puts "Tag routes initialized" - end - - end - end - end -end diff --git a/devops-service/app/api2/routes/user.rb b/devops-service/app/api2/routes/user.rb deleted file mode 100644 index 2ac0dbb..0000000 --- a/devops-service/app/api2/routes/user.rb +++ /dev/null @@ -1,151 +0,0 @@ -module Devops - module API2_0 - module Routes - module UserRoutes - - def self.registered(app) - - # Get users list - # - # * *Request* - # - method : GET - # - headers : - # - Accept: application/json - # - # * *Returns* : - # [ - # { - # "email": "test@test.test", - # "privileges": { - # "flavor": "r", - # "group": "r", - # "image": "r", - # "project": "r", - # "server": "r", - # "key": "r", - # "user": "", - # "filter": "r", - # "network": "r", - # "provider": "r", - # "script": "r", - # "templates": "r" - # }, - # "id": "test" - # } - # ] - app.get_with_headers "/users", :headers => [:accept] do - check_privileges("user", "r") - json Devops::API2_0::Handler::User.new(request).users.map(&:to_hash) - end - - # Create user - # - # * *Request* - # - method : POST - # - headers : - # - Accept: application/json - # - Content-Type: application/json - # - body : - # { - # "username": "user name", - # "email": "user email", - # "password": "user password" - # } - # - # * *Returns* : - # 201 - Created - app.post_with_headers "/user", :headers => [:accept, :content_type] do - check_privileges("user", "w") - Devops::API2_0::Handler::User.new(request).create - create_response("Created", nil, 201) - end - - hash = {} - # Delete user - # - # * *Request* - # - method : DELETE - # - headers : - # - Accept: application/json - # - # * *Returns* : - # 200 - Deleted - hash["DELETE"] = lambda {|user| - check_privileges("user", "w") - Devops::API2_0::Handler::User.new(request).delete(user) - create_response("User '#{user}' removed") - } - - # Change user privileges - # - # * *Request* - # - method : PUT - # - headers : - # - Accept: application/json - # - Content-Type: application/json - # - body : - # { - # "cmd": "command or all", -> if empty, set default privileges - # "privileges": "priv" -> 'rwx' or '' - # } - # - # * *Returns* : - # 200 - Updated - hash["PUT"] = lambda {|user| - check_privileges("user", "w") - Devops::API2_0::Handler::User.new(request).change_user_privileges(user) - create_response("Updated") - } - app.multi_routes "/user/:user", {:headers => [:accept, :content_type]}, hash - - # Change user email - # - # * *Request* - # - method : PUT - # - headers : - # - Accept: application/json - # - Content-Type: application/json - # - body : - # { - # "email": "new user email", - # } - # - # * *Returns* : - # 200 - Updated - app.put_with_headers %r{\A/user/#{DevopsConfig::OBJECT_NAME}/email\z}, :headers => [:accept, :content_type] do |user| - current_user = request.env['REMOTE_USER'] - check_privileges("user", "w") unless current_user == user - raise InvalidPrivileges.new("Access denied for '#{current_user}'") if user == Devops::Model::User::ROOT_USER_NAME and current_user != Devops::Model::User::ROOT_USER_NAME - Devops::API2_0::Handler::User.new(request).change_email(user) - create_response("Updated") - end - - # Change user password - # - # * *Request* - # - method : PUT - # - headers : - # - Accept: application/json - # - Content-Type: application/json - # - body : - # { - # "password": "new user password", - # } - # - # * *Returns* : - # 200 - Updated - app.put_with_headers %r{\A/user/#{DevopsConfig::OBJECT_NAME}/password\z}, :headers => [:accept, :content_type] do |user| - current_user = request.env['REMOTE_USER'] - check_privileges("user", "w") unless current_user == user - raise InvalidPrivileges.new("Access denied for '#{current_user}'") if user == Devops::Model::User::ROOT_USER_NAME and current_user != Devops::Model::User::ROOT_USER_NAME - Devops::API2_0::Handler::User.new(request).change_password(user) - create_response("Updated") - end - - puts "User routes initialized" - end - - end - end - end -end diff --git a/devops-service/app/api2/routes/v2.0.rb b/devops-service/app/api2/routes/v2.0.rb deleted file mode 100644 index 3645afc..0000000 --- a/devops-service/app/api2/routes/v2.0.rb +++ /dev/null @@ -1,175 +0,0 @@ -require "sinatra/base" -require "sinatra/streaming" -require "json" - -require "fog" - -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 "exceptions/knife_config_error" -require 'core/devops-logger' - -require_relative "../helpers/version_2" - -module Devops - class Api2 < Sinatra::Base - - include Sinatra::JSON - helpers Sinatra::Streaming - helpers Devops::API2_0::Helpers - - register Sinatra::DevopsAuth - - @@logger = nil - @@access_logger = DevopsLogger.access_logger(File.join(DevopsConfig.config[:log_dir], "devops-api2.access.log")) - - configure :production do - config = DevopsConfig.config - log_file = File.join(config[:log_dir], "devops-api2.log") - @@logger = DevopsLogger.create(log_file, Logger::INFO) -# use Rack::CommonLogger, logger - disable :dump_errors - disable :show_exceptions - #set :logging, Logger::INFO - @@logger.info "Production mode" - end - - configure :development do - config = DevopsConfig.config - log_file = File.join(config[:log_dir], "devops-api2.dev.log") - @@logger = DevopsLogger.create(log_file, Logger::DEBUG) - # logger = DevopsLogger.create(log_file, Logger::DEBUG) -# logger = Logger.new STDOUT -# use Rack::CommonLogger, logger - disable :raise_errors - #set :show_exceptions, :after_handler - set :show_exceptions, false - #set :dump_errors, false - @@logger.info "Development mode" - end - - not_found do - "Not found" - end - - # set current logger and call handlers - def call env - DevopsLogger.logger = @@logger - begin - res = super(env) - rescue ::Devops::Exception::DevopsError => e - return [e.code, {}, e.message] - rescue InvalidRecord => e - return [e.code, {}, e.message] - end - @@access_logger.info(env["REQUEST_METHOD"] + " " + env["REQUEST_URI"] + " - from #{env["HTTP_USER_AGENT"]} (#{env["REMOTE_USER"]}) / #{res[0]}") - res - end - - def handle_exception!(boom) - if boom.is_a?(::Devops::Exception::DevopsError) - boom.http_response - else - super(boom) - end - 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 Devops::Exception::KnifeConfigError do - e = env["sinatra.error"] - logger.error e.message - halt_response(e.message, 500) - end - - error RecordNotFound do - e = env["sinatra.error"] - logger.warn e.message - halt_response(e.message, 404) - end - -=begin - error InvalidRecord do - e = env["sinatra.error"] - logger.warn e.message - logger.warn "Request body: #{request.body.read}" - halt_response(e.message, 400) - end -=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 ConflictException do - e = env["sinatra.error"] - logger.warn e.message - create_response(e.message, e.object, 409) - end - - error InvalidPrivileges do - e = env["sinatra.error"] - logger.warn e.message - halt_response(e.message, 401) - end - - error Excon::Errors::Error do - e = env["sinatra.error"] - logger.warn e.message - halt_response(e.message, 400) - 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 - - end -end diff --git a/devops-service/app/api3/docs/chef.rb b/devops-service/app/api3/docs/chef.rb new file mode 100644 index 0000000..959ee13 --- /dev/null +++ b/devops-service/app/api3/docs/chef.rb @@ -0,0 +1,190 @@ +require 'swagger/blocks' + +require_relative 'devops_error' +require_relative 'devops_response' + +module Devops + module API3 + module Docs + class ChefRoutes + + include Swagger::Blocks + + swagger_path "/chef/bootstrap_templates" do + operation :get do + key :description, 'Get list of available bootstrap templates' + key :operationId, 'getBootstrapTemplates' + key :tags, [ + 'chef' + ] + response 200 do + key :description, 'List of available bootstrap templates' + schema do + key :type, :array + items do + key :type, :string + end + end + end + response :default do + key :description, 'error' + schema do + key :'$ref', :DevopsError + end + end + end + end + + swagger_path "/chef/nodes" do + operation :get do + key :description, 'Get chef nodeslist' + key :operationId, 'getChefNodes' + key :tags, [ + 'chef' + ] + response 200 do + key :description, 'Chef nodes list' + schema do + key :type, :array + items do + key :type, :string + end + end + end + response :default do + key :description, 'error' + schema do + key :'$ref', :DevopsError + end + end + end + end + + swagger_path "/chef/tags/{cm_name}" do + operation :get do + key :description, 'Get node tags' + key :operationId, 'getNodeTags' + key :tags, [ + 'chef' + ] + parameter do + key :name, :cm_name + key :in, :path + key :description, 'Chef node name' + key :required, true + key :type, :string + end + response 200 do + key :description, 'Node tags list' + schema do + key :type, :array + items do + key :type, :string + end + end + end + response :default do + key :description, 'error' + schema do + key :'$ref', :DevopsError + end + end + end + end + + swagger_path "/chef/tags/{cm_name}/set" do + operation :post do + key :description, 'Set node tags' + key :operationId, 'setNodeTags' + key :tags, [ + 'chef' + ] + parameter do + key :name, :cm_name + key :in, :path + key :description, 'Chef node name' + key :required, true + key :type, :string + end + parameter do + key :name, :tags + key :in, :body + key :description, 'Tags to set to node' + key :required, true + schema do + key :'$ref', :PetInput + end + end + response 200 do + key :description, 'Node tags list' + schema do + key :'$ref', :TagsResponse + end + end + response :default do + key :description, 'error' + schema do + key :'$ref', :DevopsError + end + end + end + end + + swagger_path "/chef/tags/{cm_name}/unset" do + operation :post do + key :description, 'Unset node tags' + key :operationId, 'unsetNodeTags' + key :tags, [ + 'chef' + ] + parameter do + key :name, :cm_name + key :in, :path + key :description, 'Chef node name' + key :required, true + key :type, :string + end + parameter do + key :name, :tags + key :in, :body + key :description, 'Tags to unset from node' + key :required, true + schema do + key :'$ref', :PetInput + end + end + response 200 do + key :description, 'Node tags list' + schema do + key :'$ref', :TagsResponse + end + end + response :default do + key :description, 'error' + schema do + key :'$ref', :DevopsError + end + end + end + end + + swagger_schema :TagsResponse do + allOf do + schema do + key :'$ref', :DevopsResponse + end + schema do + property :tags do + key :type, :array + items do + key :type, :string + end + end + end + end + end + + end + end + end +end diff --git a/devops-service/app/api3/docs/devops_error.rb b/devops-service/app/api3/docs/devops_error.rb new file mode 100644 index 0000000..1e434ef --- /dev/null +++ b/devops-service/app/api3/docs/devops_error.rb @@ -0,0 +1,20 @@ +require 'swagger/blocks' + +module Devops + module API3 + module Docs + class DevopsError + + include Swagger::Blocks + + swagger_schema :DevopsError do + key :required, [:message] + property :message do + key :type, :string + end + end + + end + end + end +end diff --git a/devops-service/app/api3/docs/devops_response.rb b/devops-service/app/api3/docs/devops_response.rb new file mode 100644 index 0000000..4d53a76 --- /dev/null +++ b/devops-service/app/api3/docs/devops_response.rb @@ -0,0 +1,21 @@ +require 'swagger/blocks' + +module Devops + module API3 + module Docs + class DevopsResponse + + include Swagger::Blocks + + swagger_schema :DevopsResponse do + key :required, [:message] + property :message do + key :type, :string + end + end + + end + end + end +end + diff --git a/devops-service/app/api3/docs/filter.rb b/devops-service/app/api3/docs/filter.rb new file mode 100644 index 0000000..9e75f38 --- /dev/null +++ b/devops-service/app/api3/docs/filter.rb @@ -0,0 +1,146 @@ +require 'swagger/blocks' + +require_relative 'devops_error' +require_relative 'devops_response' + +module Devops + module API3 + module Docs + class FilterRoutes + + include Swagger::Blocks + + swagger_path "/filter/{provider}/images" do + operation :get do + key :description, 'Get filter for images for provider' + key :operationId, 'getFilterImages' + key :tags, [ + 'filter' + ] + parameter do + key :name, :provider + key :in, :path + key :description, 'Provider name' + key :required, true + key :type, :string + end + response 200 do + key :description, 'List of images filters' + schema do + key :type, :array + items do + key :type, :string + end + end + end + response :default do + key :description, 'error' + schema do + key :'$ref', :DevopsError + end + end + end + end + + swagger_path "/filter/{provider}/images/add" do + operation :post do + key :description, 'Add filters for images for provider' + key :operationId, 'addFilterImages' + key :tags, [ + 'filter' + ] + parameter do + key :name, :provider + key :in, :path + key :description, 'Provider name' + key :required, true + key :type, :string + end + parameter do + key :name, :filtes + key :in, :body + key :description, 'Filters for images' + key :required, true + schema do + key :type, :array + items do + key :type, :string + end + end + end + response 200 do + key :description, 'List of images filters' + schema do + key :'$ref', :FilterResponse + end + end + response :default do + key :description, 'error' + schema do + key :'$ref', :DevopsError + end + end + end + end + + swagger_path "/filter/{provider}/images/delete" do + operation :post do + key :description, 'Delete filters for images for provider' + key :operationId, 'deleteFilterImages' + key :tags, [ + 'filter' + ] + parameter do + key :name, :provider + key :in, :path + key :description, 'Provider name' + key :required, true + key :type, :string + end + parameter do + key :name, :filtes + key :in, :body + key :description, 'Filters for images' + key :required, true + schema do + key :type, :array + items do + key :type, :string + end + end + end + response 200 do + key :description, 'List of images filters' + schema do + key :'$ref', :FilterResponse + end + end + response :default do + key :description, 'error' + schema do + key :'$ref', :DevopsError + end + end + end + end + + swagger_schema :FilterResponse do + allOf do + schema do + key :'$ref', :DevopsResponse + end + schema do + property :images do + key :type, :array + items do + key :type, :string + end + end + end + end + end + + end + end + end +end diff --git a/devops-service/app/api3/docs/image.rb b/devops-service/app/api3/docs/image.rb new file mode 100644 index 0000000..fbb15eb --- /dev/null +++ b/devops-service/app/api3/docs/image.rb @@ -0,0 +1,230 @@ +require 'swagger/blocks' + +require_relative 'devops_error' +require_relative 'devops_response' + +module Devops + module API3 + module Docs + class ImageRoutes + + include Swagger::Blocks + + swagger_schema :ImageResponse do + allOf do + schema do + key :'$ref', :DevopsResponse + end + schema do + property :id do + key :type, :string + end + end + end + end + + swagger_schema :ImageObject do + allOf do + schema do + key :'$ref', :ImageObjectInput + end + schema do + property :id do + key :type, :string + end + property :created_at do + key :type, :integer + key :format, :int64 + end + end + end + end + + swagger_schema :ImageObjectInput do + key :required, [:image_id, :name, :provider, :provider_account, :remote_user] + property :image_id do + key :type, :string + key :pattern, "^[a-z0-9_-]{0,99}$" + key :maxLength, 100 + end + property :name do + key :type, :string + key :maxLength, 255 + end + property :remote_user do + key :type, :string + key :pattern, "^[a-z_][a-z0-9_-]{0,30}$" + key :maxLength, 31 + end + property :provider do + key :type, :string + end + property :provider_account do + key :type, :string + key :pattern, "^[a-z_][a-z0-9_-]{0,99}$" + key :maxLength, 100 + end + end + + swagger_path "/images" do + operation :get do + key :description, 'Get images list' + key :operationId, 'getImages' + key :tags, [ + 'image' + ] + parameter do + key :name, :provider + key :in, :query + key :description, 'Provider name for filtering images' + key :required, false + schema do + key :type, :string + end + end + response 200 do + key :description, 'Images list' + schema do + key :type, :array + items do + key :'$ref', :ImageObject + end + end + end + response :default do + key :description, 'error' + schema do + key :'$ref', :DevopsError + end + end + end + end + + swagger_path "/image" do + operation :post do + key :description, 'Create new image' + key :operationId, 'createImage' + key :tags, [ + 'image' + ] + parameter do + key :name, :image + key :in, :body + key :description, 'New image' + key :required, true + schema do + key :'$ref', :ImageObjectInput + end + end + response 201 do + key :description, 'Create image response' + schema do + key :'$ref', :ImageResponse + end + end + response :default do + key :description, 'error' + schema do + key :'$ref', :DevopsError + end + end + end + end + + swagger_path "/image/(id)" do + operation :get do + key :description, 'Get image by id' + key :operationId, 'getImage' + key :tags, [ + 'image' + ] + parameter do + key :name, :id + key :in, :path + key :description, 'Image id' + key :required, true + schema do + key :type, :string + end + end + response 200 do + key :description, 'Image object' + schema do + key :'$ref', :ImageObject + end + end + response :default do + key :description, 'error' + schema do + key :'$ref', :DevopsError + end + end + end + end + + swagger_path "/image/(id)" do + operation :put do + key :description, 'Update image by id TODO' + key :operationId, 'updateImage' + key :tags, [ + 'image' + ] + parameter do + key :name, :id + key :in, :path + key :description, 'Image id' + key :required, true + schema do + key :type, :string + end + end + response 200 do + key :description, 'Devops response' + schema do + key :'$ref', :ImageResponse + end + end + response :default do + key :description, 'error' + schema do + key :'$ref', :DevopsError + end + end + end + end + + swagger_path "/image/(id)" do + operation :delete do + key :description, 'Delete image by id' + key :operationId, 'deleteImage' + key :tags, [ + 'image' + ] + parameter do + key :name, :id + key :in, :path + key :description, 'Image id' + key :required, true + schema do + key :type, :string + end + end + response 200 do + key :description, 'Devops response' + schema do + key :'$ref', :ImageResponse + end + end + response :default do + key :description, 'error' + schema do + key :'$ref', :DevopsError + end + end + end + end + + end + end + end +end diff --git a/devops-service/app/api3/docs/job_task.rb b/devops-service/app/api3/docs/job_task.rb new file mode 100644 index 0000000..e171a3e --- /dev/null +++ b/devops-service/app/api3/docs/job_task.rb @@ -0,0 +1,260 @@ +require 'swagger/blocks' + +require_relative 'devops_error' +require_relative 'devops_response' + +module Devops + module API3 + module Docs + class JobTaskRoutes + + include Swagger::Blocks + + swagger_path "/tasks/all" do + operation :get do + key :description, 'Get tasks list' + key :operationId, 'getTasks' + key :tags, [ + 'task' + ] + parameter do + key :name, :date_from + key :in, :query + key :description, "Date from in format 'YYYY-MM-DD'" + key :required, false + key :type, :string + end + parameter do + key :name, :date_from_l + key :in, :query + key :description, "Date from in unixtime" + key :required, false + key :type, :integer + end + parameter do + key :name, :date_till + key :in, :query + key :description, "Date till in format 'YYYY-MM-DD'" + key :required, false + key :type, :string + end + parameter do + key :name, :date_till_l + key :in, :query + key :description, "Date till in unixtime" + key :required, false + key :type, :integer + end + parameter do + key :name, :sort_field + key :in, :query + key :description, "Field to sort by, default value: created_at" + key :required, false + key :type, :string + end + parameter do + key :name, :sort_order + key :in, :query + key :description, "Sort order, default value: asc" + key :required, false + key :type, :string + end + parameter do + key :name, :limit + key :in, :query + key :description, "Documents number, default value: 10" + key :required, false + key :type, :integer + end + parameter do + key :name, :project + key :in, :query + key :description, "Project id" + key :required, false + key :type, :string + end + parameter do + key :name, :environment + key :in, :query + key :description, "Environment id" + key :required, false + key :type, :string + end + parameter do + key :name, :category + key :in, :query + key :description, "Category id" + key :required, false + key :type, :string + end + parameter do + key :name, :type + key :in, :query + key :description, "Job task type" + key :required, false + key :type, :integer + end + parameter do + key :name, :server_id + key :in, :query + key :description, "Server id" + key :required, false + key :type, :string + end + parameter do + key :name, :created_by + key :in, :query + key :description, "User how created job task" + key :required, false + key :type, :string + end + response 200 do + key :description, 'Tasks response' + schema do + key :type, :array + items do + key :'$ref', :TaskResponse + end + end + end + response :default do + key :description, 'error' + schema do + key :'$ref', :DevopsError + end + end + end + end + + swagger_path "/task/{id}" do + operation :get do + key :description, 'Get task' + key :operationId, 'getTask' + key :tags, [ + 'task' + ] + parameter do + key :name, :id + key :in, :path + key :description, 'Task id' + key :required, true + key :type, :string + end + response 200 do + key :description, 'Task response' + schema do + key :'$ref', :TaskResponse + end + end + response :default do + key :description, 'error' + schema do + key :'$ref', :DevopsError + end + end + end + end + + swagger_path "/task/{id}/report" do + operation :get do + key :description, 'Get task report' + key :operationId, 'getTaskReport' + key :tags, [ + 'task' + ] + key :produces, [ + 'text/html' + ] + parameter do + key :name, :id + key :in, :path + key :description, 'Task id' + key :required, true + key :type, :string + end + response 200 do + key :description, 'Task report' + end + response :default do + key :description, 'error' + schema do + key :'$ref', :DevopsError + end + end + end + end + + swagger_path "/task/{id}/status" do + operation :get do + key :description, 'Get task status' + key :operationId, 'getTaskStatus' + key :tags, [ + 'task' + ] + key :produces, [ + 'text/html' + ] + parameter do + key :name, :id + key :in, :path + key :description, 'Task id' + key :required, true + key :type, :string + end + response 200 do + key :description, 'Task status' + end + response :default do + key :description, 'error' + schema do + key :'$ref', :DevopsError + end + end + end + end + + swagger_schema :TaskResponse do + property :id do + key :type, :string + end + property :server_id do + key :type, :string + end + property :stack do + key :type, :string + end + property :project do + key :type, :string + end + property :environment do + key :type, :string + end + property :category do + key :type, :string + end + property :created_by do + key :type, :string + end + property :status do + key :type, :string + end + property :job_result_code do + key :type, :integer + end + property :type do + key :type, :integer + end + property :created_at do + key :type, :integer + key :format, :int64 + end + property :updated_at do + key :type, :integer + key :format, :int64 + end + end + + end + end + end +end diff --git a/devops-service/app/api3/docs/key.rb b/devops-service/app/api3/docs/key.rb new file mode 100644 index 0000000..b06ff61 --- /dev/null +++ b/devops-service/app/api3/docs/key.rb @@ -0,0 +1,139 @@ +require 'swagger/blocks' + +require_relative 'devops_error' +require_relative 'devops_response' + +module Devops + module API3 + module Docs + class KeyRoutes + + include Swagger::Blocks + + swagger_schema :KeyObject do + property :id do + key :type, :string + end + property :filename do + key :type, :string + end + property :created_at do + key :type, :integer + key :format, :int64 + end + end + + swagger_schema :KeyObjectInput do + key :required, [:file_name, :key_name, :content] + property :file_name do + key :type, :string + key :pattern, "^[a-z0-9_-]{0,99}$" + key :maxLength, 100 + end + property :key_name do + key :type, :string + key :pattern, "^[a-z0-9_-]{0,99}$" + key :maxLength, 100 + end + property :content do + key :type, :string + end + end + + swagger_path "/keys" do + operation :get do + key :description, 'Get keys list' + key :operationId, 'getKeys' + key :tags, [ + 'key' + ] + response 200 do + key :description, 'Keys list' + schema do + key :type, :array + items do + key :'$ref', :KeyObject + end + end + end + response :default do + key :description, 'error' + schema do + key :'$ref', :DevopsError + end + end + end + end + + swagger_path "/key" do + operation :post do + key :description, 'Create new key' + key :operationId, 'createKey' + key :tags, [ + 'key' + ] + parameter do + key :name, :key + key :in, :body + key :description, 'New key object' + key :required, true + schema do + key :'$ref', :KeyObjectInput + end + end + response 201 do + key :description, 'Devops response' + schema do + key :type, :array + items do + key :'$ref', :DevopsResponse + end + end + end + response :default do + key :description, 'error' + schema do + key :'$ref', :DevopsError + end + end + end + end + + swagger_path "/key/{id}" do + operation :delete do + key :description, 'Delete key by id' + key :operationId, 'deleteKey' + key :tags, [ + 'key' + ] + parameter do + key :name, :id + key :in, :path + key :description, 'Key id' + key :required, true + schema do + key :type, :string + end + end + response 200 do + key :description, 'Devops response' + schema do + key :type, :array + items do + key :'$ref', :DevopsResponse + end + end + end + response :default do + key :description, 'error' + schema do + key :'$ref', :DevopsError + end + end + end + end + + end + end + end +end diff --git a/devops-service/app/api3/docs/project.rb b/devops-service/app/api3/docs/project.rb new file mode 100644 index 0000000..494b6c0 --- /dev/null +++ b/devops-service/app/api3/docs/project.rb @@ -0,0 +1,1323 @@ +require 'swagger/blocks' + +require_relative 'devops_error' +require_relative 'devops_response' +require_relative 'server_model' + +module Devops + module API3 + module Docs + class ProjectRoutes + + include Swagger::Blocks + + swagger_schema :ProjectResponse do + allOf do + schema do + key :'$ref', :DevopsResponse + end + schema do + property :id do + key :type, :string + end + end + end + end + + swagger_schema :CreateCategoryResponse do + allOf do + schema do + key :'$ref', :DevopsResponse + end + schema do + property :category do + key :'$ref', :CategoryObject + end + end + end + end + + swagger_schema :CreateEnvironmentResponse do + allOf do + schema do + key :'$ref', :DevopsResponse + end + schema do + property :environment do + key :'$ref', :CreateEnvironmentObject + end + end + end + end + + swagger_schema :ProjectCreate do + property :id do + key :type, :string + key :maxLength, 100 + end + property :description do + key :type, :string + key :maxLength, 500 + end + property :run_list do + key :type, :array + items do + key :type, :string + end + end + end + + swagger_schema :CreateEnvironmentObject do + property :id do + key :type, :string + key :maxLength, 100 + end + property :expires do + key :type, :string + end + property :run_list do + key :type, :array + items do + key :type, :string + end + end + property :users do + key :type, :array + items do + key :type, :string + end + end + end + + swagger_schema :ServerLastOperationObject do + property :type do + key :type, :string + end + property :date do + key :type, :int64 + end + property :user do + key :type, :string + end + end + + swagger_schema :EnvUsersResponse do + allOf do + schema do + key :'$ref', :ProjectResponse + end + schema do + property :users do + key :type, :array + items do + key :type, :string + end + end + end + end + end + + swagger_schema :ProjectUsersResponse do + allOf do + schema do + key :'$ref', :ProjectResponse + end + schema do + property :project_users do + key :type, :array + items do + key :type, :string + end + end + end + end + end + + swagger_schema :ProjectRunListResponse do + allOf do + schema do + key :'$ref', :ProjectResponse + end + schema do + property :run_list do + key :type, :array + items do + key :type, :string + end + end + end + end + end + + swagger_schema :CategoryProviderObject do + property :name do + key :type, :string + end + property :account do + key :type, :string + end + property :flavor do + key :type, :string + end + property :image do + key :type, :string + end + property :subnet do + key :type, :string + end + property :vpc_id do + key :type, :string + end + property :security_group do + key :type, :array + items do + key :type, :string + end + end + property :stack_template do + key :type, :string + end + end + + swagger_schema :CategoryCmToolObject do + property :name do + key :type, :string + end + property :bootstrap_template do + key :type, :string + end + end + + swagger_schema :CategoryObject do + property :id do + key :type, :string + key :maxLength, 100 + end + property :provider do + key :'$ref', :CategoryProviderObject + end + property :cm_tool do + key :'$ref', :CategoryCmToolObject + end + end + + swagger_schema :EnvironmentObject do + property :id do + key :type, :string + key :maxLength, 100 + end + property :expires do + key :type, :string + end + property :run_list do + key :type, :array + items do + key :type, :string + end + end + property :users do + key :type, :array + items do + key :type, :string + end + end + property :categories do + key :type, :array + items do + key :'$ref', :CategoryObject + end + end + end + + swagger_schema :ProjectShowObject do + allOf do + schema do + key :'$ref', :ProjectListObject + end + schema do + property :archived do + key :type, :boolean + end + property :environments do + key :type, :array + items do + key :'$ref', :EnvironmentObject + end + end + end + end + end + + swagger_schema :ProjectUpdateObject do + property :description do + key :type, :string + key :maxLength, 500 + end + property :run_list do + key :type, :array + items do + key :type, :string + end + end + property :project_users do + key :type, :array + items do + key :type, :string + end + end + end + + swagger_schema :ProjectListObject do + allOf do + schema do + key :'$ref', :ProjectUpdateObject + end + schema do + property :id do + key :type, :string + key :maxLength, 100 + end + property :owner do + key :type, :string + end + property :created_at do + key :type, :integer + key :format, :int64 + end + end + end + end + + swagger_schema :ProjectObjectInput do + key :required, [:image_id, :name, :provider, :provider_account, :remote_user] + property :image_id do + key :type, :string + key :pattern, "^[a-z0-9_-]{0,99}$" + key :maxLength, 100 + end + property :name do + key :type, :string + key :maxLength, 255 + end + property :remote_user do + key :type, :string + key :pattern, "^[a-z_][a-z0-9_-]{0,30}$" + key :maxLength, 31 + end + property :provider do + key :type, :string + end + property :provider_account do + key :type, :string + key :pattern, "^[a-z_][a-z0-9_-]{0,99}$" + key :maxLength, 100 + end + end + + swagger_path "/projects" do + operation :get do + key :description, 'Get projects list' + key :operationId, 'getProjects' + key :tags, [ + 'project' + ] + response 200 do + key :description, 'Projects list' + schema do + key :type, :array + items do + key :'$ref', :ProjectListObject + end + end + end + response :default do + key :description, 'error' + schema do + key :'$ref', :DevopsError + end + end + end + end + + swagger_path "/project/{id}" do + operation :get do + key :description, 'Get project by id' + key :operationId, 'getProjectById' + key :tags, [ + 'project' + ] + parameter do + key :name, :id + key :in, :path + key :description, 'Project id' + key :required, true + schema do + key :type, :string + end + end + response 200 do + key :description, 'Project object' + schema do + key :'$ref', :ProjectShowObject + end + end + response :default do + key :description, 'error' + schema do + key :'$ref', :DevopsError + end + end + end + end + + swagger_path "/project/{id}" do + operation :put do + key :description, 'Update project by id' + key :operationId, 'updateProjectById' + key :tags, [ + 'project' + ] + parameter do + key :name, :id + key :in, :path + key :description, 'Project id' + key :required, true + schema do + key :type, :string + end + end + parameter do + key :name, :project + key :in, :body + key :description, 'Project parameters to rewrite' + key :required, true + schema do + key :'$ref', :ProjectUpdateObject + end + end + response 200 do + key :description, 'Project response' + schema do + key :'$ref', :ProjectResponse + end + end + response :default do + key :description, 'error' + schema do + key :'$ref', :DevopsError + end + end + end + end + + swagger_path "/project/{id}" do + operation :delete do + key :description, 'Delete project by id' + key :operationId, 'deleteProjectById' + key :tags, [ + 'project' + ] + parameter do + key :name, :id + key :in, :path + key :description, 'Project id' + key :required, true + schema do + key :type, :string + end + end + response 200 do + key :description, 'Project response' + schema do + key :'$ref', :ProjectResponse + end + end + response :default do + key :description, 'error' + schema do + key :'$ref', :DevopsError + end + end + end + end + + swagger_path "/project" do + operation :post do + key :description, 'Create project' + key :operationId, 'createProject' + key :tags, [ + 'project' + ] + parameter do + key :name, :project + key :in, :body + key :description, 'New project body' + key :required, true + schema do + key :'$ref', :ProjectCreate + end + end + response 201 do + key :description, 'Create project response' + schema do + key :'$ref', :ProjectResponse + end + end + response :default do + key :description, 'error' + schema do + key :'$ref', :DevopsError + end + end + end + end + + swagger_path "/project/{id}/users/add" do + operation :post do + key :description, 'Add users to project' + key :operationId, 'addUsersToProject' + key :tags, [ + 'project' + ] + parameter do + key :name, :id + key :in, :path + key :description, 'Project id' + key :required, true + schema do + key :type, :string + end + end + parameter do + key :name, :users + key :in, :body + key :description, 'Add users to project list' + key :required, true + schema do + key :type, :array + items do + key :type, :string + end + end + end + response 200 do + key :description, 'Project users response' + schema do + key :'$ref', :ProjectUsersResponse + end + end + response :default do + key :description, 'error' + schema do + key :'$ref', :DevopsError + end + end + end + end + + swagger_path "/project/{id}/users/delete" do + operation :post do + key :description, 'Delete users from project' + key :operationId, 'deleteUsersFromProject' + key :tags, [ + 'project' + ] + parameter do + key :name, :id + key :in, :path + key :description, 'Project id' + key :required, true + schema do + key :type, :string + end + end + parameter do + key :name, :users + key :in, :body + key :description, 'Delete users from project list' + key :required, true + schema do + key :type, :array + items do + key :type, :string + end + end + end + response 200 do + key :description, 'Project response' + schema do + key :'$ref', :ProjectUsersResponse + end + end + response :default do + key :description, 'error' + schema do + key :'$ref', :DevopsError + end + end + end + end + + swagger_path "/project/{id}/run_list" do + operation :put do + key :description, 'Set new run_list elements to project' + key :operationId, 'setRunListToProject' + key :tags, [ + 'project' + ] + parameter do + key :name, :id + key :in, :path + key :description, 'Project id' + key :required, true + schema do + key :type, :string + end + end + parameter do + key :name, :run_list + key :in, :body + key :description, 'run_list elements to set to project list' + key :required, true + schema do + key :type, :array + items do + key :type, :string + end + end + end + response 200 do + key :description, 'Project response' + schema do + key :'$ref', :ProjectRunListResponse + end + end + response :default do + key :description, 'error' + schema do + key :'$ref', :DevopsError + end + end + end + end + + swagger_path "/project/{id}/run_list/add" do + operation :post do + key :description, 'Add new run_list elements to project' + key :operationId, 'addRunListToProject' + key :tags, [ + 'project' + ] + parameter do + key :name, :id + key :in, :path + key :description, 'Project id' + key :required, true + schema do + key :type, :string + end + end + parameter do + key :name, :run_list + key :in, :body + key :description, 'run_list elements to add to project list' + key :required, true + schema do + key :type, :array + items do + key :type, :string + end + end + end + response 200 do + key :description, 'Project response' + schema do + key :'$ref', :ProjectRunListResponse + end + end + response :default do + key :description, 'error' + schema do + key :'$ref', :DevopsError + end + end + end + end + + swagger_path "/project/{id}/run_list/delete" do + operation :post do + key :description, 'Delete run_list elements from project' + key :operationId, 'deleteRunListFromProject' + key :tags, [ + 'project' + ] + parameter do + key :name, :id + key :in, :path + key :description, 'Project id' + key :required, true + schema do + key :type, :string + end + end + parameter do + key :name, :users + key :in, :body + key :description, 'run_list elements to delete from project list' + key :required, true + schema do + key :type, :array + items do + key :type, :string + end + end + end + response 200 do + key :description, 'Project response' + schema do + key :'$ref', :ProjectRunListResponse + end + end + response :default do + key :description, 'error' + schema do + key :'$ref', :DevopsError + end + end + end + end + + swagger_path "/project/{project}/archive" do + operation :post do + key :description, 'Archive project' + key :operationId, 'archiveProject' + key :tags, [ + 'project' + ] + parameter do + key :name, :project + key :in, :path + key :description, 'Project id' + key :required, true + schema do + key :type, :string + end + end + response 200 do + key :description, 'Project response' + schema do + key :'$ref', :ProjectResponse + end + end + response :default do + key :description, 'error' + schema do + key :'$ref', :DevopsError + end + end + end + end + + swagger_path "/project/{project}/unarchive" do + operation :post do + key :description, 'Unarchive project' + key :operationId, 'unarchiveProject' + key :tags, [ + 'project' + ] + parameter do + key :name, :project + key :in, :path + key :description, 'Project id' + key :required, true + schema do + key :type, :string + end + end + response 200 do + key :description, 'Project response' + schema do + key :'$ref', :ProjectResponse + end + end + response :default do + key :description, 'error' + schema do + key :'$ref', :DevopsError + end + end + end + end + + swagger_path "/project/{project}/environment/{env}/users/add" do + operation :post do + key :description, 'Add users to environment' + key :operationId, 'addUsersToEnvironment' + key :tags, [ + 'project' + ] + parameter do + key :name, :project + key :in, :path + key :description, 'Project id' + key :required, true + schema do + key :type, :string + end + end + parameter do + key :name, :env + key :in, :path + key :description, 'Environment id' + key :required, true + schema do + key :type, :string + end + end + parameter do + key :name, :users + key :in, :body + key :description, 'Users list to add to environment list' + key :required, true + schema do + key :type, :array + items do + key :type, :string + end + end + end + response 200 do + key :description, 'Environment users response' + schema do + key :'$ref', :EnvUsersResponse + end + end + response :default do + key :description, 'error' + schema do + key :'$ref', :DevopsError + end + end + end + end + + swagger_path "/project/{project}/environment/{env}/users/delete" do + operation :post do + key :description, 'Delete users from environment' + key :operationId, 'deleteUsersFromEnvironment' + key :tags, [ + 'project' + ] + parameter do + key :name, :project + key :in, :path + key :description, 'Project id' + key :required, true + schema do + key :type, :string + end + end + parameter do + key :name, :env + key :in, :path + key :description, 'Environment id' + key :required, true + schema do + key :type, :string + end + end + parameter do + key :name, :users + key :in, :body + key :description, 'Users list to delete from environment list' + key :required, true + schema do + key :type, :array + items do + key :type, :string + end + end + end + response 200 do + key :description, 'Environment users response' + schema do + key :'$ref', :EnvUsersResponse + end + end + response :default do + key :description, 'error' + schema do + key :'$ref', :DevopsError + end + end + end + end + + swagger_path "/project/{project}/servers" do + operation :get do + key :description, 'Show project servers' + key :operationId, 'showProjectServers' + key :tags, [ + 'project' + ] + parameter do + key :name, :project + key :in, :path + key :description, 'Project id' + key :required, true + schema do + key :type, :string + end + end + response 200 do + key :description, 'Project servers response' + schema do + key :type, :array + items do + key :'$ref', :ServerObject + end + end + end + response :default do + key :description, 'error' + schema do + key :'$ref', :DevopsError + end + end + end + end + + swagger_path "/project/{project}/environment/{env}/servers" do + operation :get do + key :description, 'Show environment servers' + key :operationId, 'showEnvironmentServers' + key :tags, [ + 'project' + ] + parameter do + key :name, :project + key :in, :path + key :description, 'Project id' + key :required, true + schema do + key :type, :string + end + end + parameter do + key :name, :env + key :in, :path + key :description, 'Environment id' + key :required, true + schema do + key :type, :string + end + end + response 200 do + key :description, 'Environment servers response' + schema do + key :type, :array + items do + key :'$ref', :ServerObject + end + end + end + response :default do + key :description, 'error' + schema do + key :'$ref', :DevopsError + end + end + end + end + + swagger_path "/project/{project}/environment/{env}/stacks" do + operation :get do + key :description, 'Show environment stacks' + key :operationId, 'showEnvironmentStacks' + key :tags, [ + 'project' + ] + parameter do + key :name, :project + key :in, :path + key :description, 'Project id' + key :required, true + schema do + key :type, :string + end + end + parameter do + key :name, :env + key :in, :path + key :description, 'Environment id' + key :required, true + schema do + key :type, :string + end + end + response 200 do + key :description, 'Environment stacks response' + schema do + key :type, :array + items do + key :'$ref', :StackObject + end + end + end + response :default do + key :description, 'error' + schema do + key :'$ref', :DevopsError + end + end + end + end + + swagger_path "/project/{project}/environments" do + operation :get do + key :description, 'Get project environments' + key :operationId, 'getProjectEnvironments' + key :tags, [ + 'project' + ] + parameter do + key :name, :project + key :in, :path + key :description, 'Project id' + key :required, true + schema do + key :type, :string + end + end + response 200 do + key :description, 'Environments list' + schema do + key :type, :array + items do + key :'$ref', :EnvironmentObject + end + end + end + response :default do + key :description, 'error' + schema do + key :'$ref', :DevopsError + end + end + end + end + + swagger_path "/project/{project}/environment" do + operation :post do + key :description, 'Create project environment' + key :operationId, 'createProjectEnvironment' + key :tags, [ + 'project' + ] + parameter do + key :name, :project + key :in, :path + key :description, 'Project id' + key :required, true + schema do + key :type, :string + end + end + parameter do + key :name, :environment + key :in, :body + key :description, 'Environment object' + key :required, true + schema do + key :'$ref', :CreateEnvironmentObject + end + end + response 200 do + key :description, 'Create environment response' + schema do + key :'$ref', :CreateEnvironmentResponse + end + end + response :default do + key :description, 'error' + schema do + key :'$ref', :DevopsError + end + end + end + end + + swagger_path "/project/{project}/environment/{env}" do + operation :get do + key :description, 'Show project environment' + key :operationId, 'showProjectEnvironment' + key :tags, [ + 'project' + ] + parameter do + key :name, :project + key :in, :path + key :description, 'Project id' + key :required, true + schema do + key :type, :string + end + end + parameter do + key :name, :env + key :in, :path + key :description, 'Environment id' + key :required, true + schema do + key :type, :string + end + end + response 200 do + key :description, 'Environment object' + schema do + key :'$ref', :EnvironmentObject + end + end + response :default do + key :description, 'error' + schema do + key :'$ref', :DevopsError + end + end + end + end + + swagger_path "/project/{project}/environment/{env}" do + operation :delete do + key :description, 'Delete project environment' + key :operationId, 'deleteProjectEnvironment' + key :tags, [ + 'project' + ] + parameter do + key :name, :project + key :in, :path + key :description, 'Project id' + key :required, true + schema do + key :type, :string + end + end + parameter do + key :name, :env + key :in, :path + key :description, 'Environment id' + key :required, true + schema do + key :type, :string + end + end + response 200 do + key :description, 'Delete environment response' + schema do + key :'$ref', :CreateEnvironmentResponse + end + end + response :default do + key :description, 'error' + schema do + key :'$ref', :DevopsError + end + end + end + end + + swagger_path "/project/{project}/environment/{env}/categories" do + operation :get do + key :description, 'Get environment categories' + key :operationId, 'getEnvironmentCategories' + key :tags, [ + 'project' + ] + parameter do + key :name, :project + key :in, :path + key :description, 'Project id' + key :required, true + schema do + key :type, :string + end + end + parameter do + key :name, :env + key :in, :path + key :description, 'Environment id' + key :required, true + schema do + key :type, :string + end + end + response 200 do + key :description, 'Categories list' + schema do + key :type, :array + items do + key :'$ref', :CategoryObject + end + end + end + response :default do + key :description, 'error' + schema do + key :'$ref', :DevopsError + end + end + end + end + + swagger_path "/project/{project}/environment/{env}/category/{category}" do + operation :get do + key :description, 'Get category by id' + key :operationId, 'getCategoryById' + key :tags, [ + 'project' + ] + parameter do + key :name, :project + key :in, :path + key :description, 'Project id' + key :required, true + schema do + key :type, :string + end + end + parameter do + key :name, :env + key :in, :path + key :description, 'Environment id' + key :required, true + schema do + key :type, :string + end + end + parameter do + key :name, :category + key :in, :path + key :description, 'Category id' + key :required, true + schema do + key :type, :string + end + end + response 200 do + key :description, 'Category' + schema do + key :'$ref', :CategoryObject + end + end + response :default do + key :description, 'error' + schema do + key :'$ref', :DevopsError + end + end + end + end + + swagger_path "/project/{project}/environment/{env}/category" do + operation :post do + key :description, 'Create new category' + key :operationId, 'createCategory' + key :tags, [ + 'project' + ] + parameter do + key :name, :project + key :in, :path + key :description, 'Project id' + key :required, true + schema do + key :type, :string + end + end + parameter do + key :name, :env + key :in, :path + key :description, 'Environment id' + key :required, true + schema do + key :type, :string + end + end + parameter do + key :name, :category + key :in, :body + key :description, 'Category object' + key :required, true + schema do + key :'$ref', :CategoryObject + end + end + response 200 do + key :description, 'Create category response' + schema do + key :'$ref', :CreateCategoryResponse + end + end + response :default do + key :description, 'error' + schema do + key :'$ref', :DevopsError + end + end + end + end + + swagger_path "/project/{project}/environment/{env}/category/{category}" do + operation :delete do + key :description, 'Delete category by id' + key :operationId, 'deleteCategoryById' + key :tags, [ + 'project' + ] + parameter do + key :name, :project + key :in, :path + key :description, 'Project id' + key :required, true + schema do + key :type, :string + end + end + parameter do + key :name, :env + key :in, :path + key :description, 'Environment id' + key :required, true + schema do + key :type, :string + end + end + parameter do + key :name, :category + key :in, :path + key :description, 'Category id' + key :required, true + schema do + key :type, :string + end + end + response 200 do + key :description, 'Delete category response' + schema do + key :'$ref', :CreateCategoryResponse + end + end + response :default do + key :description, 'error' + schema do + key :'$ref', :DevopsError + end + end + end + end + + end + end + end +end diff --git a/devops-service/app/api3/docs/provider.rb b/devops-service/app/api3/docs/provider.rb new file mode 100644 index 0000000..203d81e --- /dev/null +++ b/devops-service/app/api3/docs/provider.rb @@ -0,0 +1,607 @@ +require 'swagger/blocks' + +require_relative 'devops_error' +require_relative 'devops_response' + +module Devops + module API3 + module Docs + class ProviderRoutes + + include Swagger::Blocks + + swagger_path "/providers/available" do + operation :get do + key :description, 'Get providers list from configuration file' + key :operationId, 'getProvidersAvailable' + key :tags, [ + 'provider' + ] + response 200 do + key :description, 'Providers response' + schema do + key :type, :array + items do + key :type, :string + end + end + end + response :default do + key :description, 'error' + schema do + key :'$ref', :DevopsError + end + end + end + end + + swagger_path "/providers" do + operation :get do + key :description, 'Get providers list' + key :operationId, 'getProviders' + key :tags, [ + 'provider' + ] + response 200 do + key :description, 'Providers response' + schema do + key :type, :array + items do + key :type, :string + end + end + end + response :default do + key :description, 'error' + schema do + key :'$ref', :DevopsError + end + end + end + end + + swagger_schema :CommonAccount do + allOf do + schema do + key :'$ref', :CommonAccountInput + end + schema do + property :provider do + key :type, :string + end + property :created_at do + key :type, :integer + key :format, :int64 + end + end + end + end + + swagger_schema :CommonAccountInput do + key :required, [:account_name, :ssh_key] + property :account_name do + key :type, :string + key :pattern, "^[a-z_][a-z0-9_-]{0,99}$" + key :maxLength, 100 + end + property :description do + key :type, :string + key :maxLength, 500 + end + property :ssh_key do + key :type, :string + key :pattern, "^[a-z_][a-z0-9_-]{0,99}$" + key :maxLength, 100 + end + end + + ###### static provider - begin + swagger_path "/provider/static/accounts" do + operation :get do + key :description, 'Get static provider accounts' + key :operationId, 'getStaticProviderAccounts' + key :tags, [ + 'provider' + ] + response 200 do + key :description, 'Static provider account response' + schema do + key :type, :array + items do + key :'$ref', :StaticProviderAccount + end + end + end + response :default do + key :description, 'error' + schema do + key :'$ref', :DevopsError + end + end + end + end + + swagger_path "/provider/static/account" do + operation :post do + key :description, 'Create static provider account' + key :operationId, 'createStaticProviderAccount' + key :tags, [ + 'provider' + ] + parameter do + key :name, :account + key :in, :body + key :description, 'Account to add for static provider' + key :required, true + schema do + key :'$ref', :StaticProviderAccountInput + end + end + response 200 do + key :description, 'Static provider account response' + schema do + key :'$ref', :StaticProviderAccountResponse + end + end + response :default do + key :description, 'error' + schema do + key :'$ref', :DevopsError + end + end + end + end + + swagger_schema :StaticProviderAccount do + allOf do + schema do + key :'$ref', :CommonAccount + end + end + end + + swagger_schema :StaticProviderAccountResponse do + allOf do + schema do + key :'$ref', :DevopsResponse + end + schema do + property :account do + key :'$ref', :StaticProviderAccount + end + end + end + end + + swagger_schema :StaticProviderAccountInput do + allOf do + schema do + key :'$ref', :CommonAccountInput + end + end + end + ###### static provider - end + # + ###### aws provider - begin + swagger_path "/provider/aws/accounts" do + operation :get do + key :description, 'Get aws provider accounts' + key :operationId, 'getAwsProviderAccounts' + key :tags, [ + 'provider' + ] + response 200 do + key :description, 'Aws provider accounts response' + schema do + key :type, :array + items do + key :'$ref', :AwsProviderAccount + end + end + end + response :default do + key :description, 'error' + schema do + key :'$ref', :DevopsError + end + end + end + end + + swagger_path "/provider/aws/account" do + operation :post do + key :description, 'Create aws provider account' + key :operationId, 'createAwsProviderAccount' + key :tags, [ + 'provider' + ] + parameter do + key :name, :account + key :in, :body + key :description, 'Account to add for aws provider' + key :required, true + schema do + key :'$ref', :AwsProviderAccountInput + end + end + response 200 do + key :description, 'Aws provider accounts response' + schema do + key :'$ref', :AwsProviderAccountResponse + end + end + response :default do + key :description, 'error' + schema do + key :'$ref', :DevopsError + end + end + end + end + + swagger_path "/provider/aws/account/{account_name}/vpcs" do + operation :get do + key :description, 'Get aws provider vpcs for account' + key :operationId, 'getAwsProviderVpcs' + key :tags, [ + 'provider' + ] + parameter do + key :name, :account_name + key :in, :path + key :description, 'Aws provider account name' + key :required, true + key :type, :string + end + response 200 do + key :description, 'Aws provider account vpcs response' + schema do + key :type, :array + items do + key :'$ref', :AwsProviderVpcResponse + end + end + end + response :default do + key :description, 'error' + schema do + key :'$ref', :DevopsError + end + end + end + end + + swagger_schema :AwsProviderVpcResponse do + property :vpc_id do + key :type, :string + end + property :cidr do + key :type, :string + end + end + + swagger_schema :AwsProviderAccount do + allOf do + schema do + key :'$ref', :CommonAccount + end + schema do + key :'$ref', :AwsProviderAccountInput + end + end + end + + swagger_schema :AwsProviderAccountResponse do + allOf do + schema do + key :'$ref', :DevopsResponse + end + schema do + property :account do + key :'$ref', :AwsProviderAccount + end + end + end + end + + swagger_schema :AwsProviderAccountInput do + allOf do + schema do + key :'$ref', :CommonAccountInput + end + schema do + key :required, [:account_name, :ssh_key, :use_iam_profile] + property :access_key_id do + key :type, :string + end + property :secret_access_key do + key :type, :string + end + property :use_iam_profile do + key :type, :boolean + end + property :storage_bucket_name do + key :type, :string + end + end + end + end + ###### aws provider - end + + swagger_path "/provider/{provider}/account/{account_name}" do + operation :delete do + key :description, 'Delete provider account' + key :operationId, 'deleteProviderAccount' + key :tags, [ + 'provider' + ] + parameter do + key :name, :provider + key :in, :path + key :description, 'Provider name' + key :required, true + key :type, :string + end + parameter do + key :name, :account_name + key :in, :path + key :description, 'Provider account name' + key :required, true + key :type, :string + end + response 200 do + key :description, 'Provider account response' + schema do + key :'$ref', :DevopsResponse + end + end + response :default do + key :description, 'error' + schema do + key :'$ref', :DevopsError + end + end + end + end + + swagger_path "/provider/{provider}/account/{account_name}/images" do + operation :get do + key :description, 'Get provider account images' + key :operationId, 'getProviderImages' + key :tags, [ + 'provider' + ] + parameter do + key :name, :provider + key :in, :path + key :description, 'Provider name' + key :required, true + key :type, :string + end + parameter do + key :name, :account_name + key :in, :path + key :description, 'Aws provider account name' + key :required, true + key :type, :string + end + response 200 do + key :description, 'Provider images response' + schema do + key :type, :array + items do + key :'$ref', :ProviderImageResponse + end + end + end + response :default do + key :description, 'error' + schema do + key :'$ref', :DevopsError + end + end + end + end + + swagger_schema :ProviderImageResponse do + property :id do + key :type, :string + end + property :name do + key :type, :string + end + property :status do + key :type, :string + end + end + + swagger_path "/provider/{provider}/account/{account_name}/networks" do + operation :get do + key :description, 'Get provider account networks' + key :operationId, 'getProviderNetworks' + key :tags, [ + 'provider' + ] + parameter do + key :name, :provider + key :in, :path + key :description, 'Provider name' + key :required, true + key :type, :string + end + parameter do + key :name, :account_name + key :in, :path + key :description, 'Aws provider account name' + key :required, true + key :type, :string + end + response 200 do + key :description, 'Provider networks response' + schema do + key :type, :array + items do + key :'$ref', :ProviderNetworksResponse + end + end + end + response :default do + key :description, 'error' + schema do + key :'$ref', :DevopsError + end + end + end + end + + swagger_schema :ProviderNetworksResponse do + property :cidr do + key :type, :string + end + property :vpcId do + key :type, :string + end + property :subnetId do + key :type, :string + end + property :name do + key :type, :string + end + property :zone do + key :type, :string + end + end + + swagger_path "/provider/{provider}/account/{account_name}/flavors" do + operation :get do + key :description, 'Get provider account flavors' + key :operationId, 'getProviderFlavors' + key :tags, [ + 'provider' + ] + parameter do + key :name, :provider + key :in, :path + key :description, 'Provider name' + key :required, true + key :type, :string + end + parameter do + key :name, :account_name + key :in, :path + key :description, 'Aws provider account name' + key :required, true + key :type, :string + end + response 200 do + key :description, 'Provider flavors response' + schema do + key :type, :array + items do + key :'$ref', :ProviderFlavorsResponse + end + end + end + response :default do + key :description, 'error' + schema do + key :'$ref', :DevopsError + end + end + end + end + + swagger_schema :ProviderFlavorsResponse do + property :id do + key :type, :string + end + property :cores do + key :type, :integer + end + property :disk do + key :type, :integer + end + property :name do + key :type, :string + end + property :ram do + key :type, :integer + end + end + + swagger_path "/provider/{provider}/account/{account_name}/security_groups" do + operation :get do + key :description, 'Get provider account security_groups' + key :operationId, 'getProviderSecurityGroups' + key :tags, [ + 'provider' + ] + parameter do + key :name, :provider + key :in, :path + key :description, 'Provider name' + key :required, true + key :type, :string + end + parameter do + key :name, :account_name + key :in, :path + key :description, 'Aws provider account name' + key :required, true + key :type, :string + end + response 200 do + key :description, 'Provider security groups response' + schema do + key :'$ref', :ProviderSecurityGroupsResponse + end + end + response :default do + key :description, 'error' + schema do + key :'$ref', :DevopsError + end + end + end + end + + swagger_schema :ProviderSecurityGroupsResponse do + property :name_key do + key :'$ref', :ProviderSecurityGroupsElem + end + end + + swagger_schema :ProviderSecurityGroupsElem do + property :id do + key :type, :string + end + property :description do + key :type, :string + end + property :rules do + key :type, :array + items do + key :'$ref', :ProviderSecurityGroupsRule + end + end + end + + swagger_schema :ProviderSecurityGroupsRule do + property :protocol do + key :type, :string + end + property :from do + key :type, :integer + end + property :to do + key :type, :integer + end + property :cidr do + key :type, :string + end + end + + end + end + end +end diff --git a/devops-service/app/api3/docs/role.rb b/devops-service/app/api3/docs/role.rb new file mode 100644 index 0000000..558d0d6 --- /dev/null +++ b/devops-service/app/api3/docs/role.rb @@ -0,0 +1,212 @@ +require 'swagger/blocks' + +require_relative 'devops_error' +require_relative 'devops_response' + +module Devops + module API3 + module Docs + class RolesRoutes + + include Swagger::Blocks + + swagger_schema :PolicyObject do + property :id do + key :type, :string + end + property :description do + key :type, :string + end + property :dependencies do + key :type, :array + items do + key :type, :string + end + end + end + + swagger_schema :RoleObject do + allOf do + schema do + key :'$ref', :RoleObjectInput + end + schema do + property :id do + key :type, :string + end + property :created_at do + key :type, :integer + key :format, :int64 + end + end + end + end + + swagger_schema :RoleObjectInput do + key :required, [:image_id, :name, :provider, :provider_account, :remote_user] + property :name do + key :type, :string + key :pattern, "^[a-z_\s]{1,99}$" + key :maxLength, 99 + key :minLength, 1 + end + property :description do + key :type, :string + key :maxLength, 500 + end + property :policies do + key :type, :array + items do + key :type, :string + end + end + end + + swagger_path "/security/policies" do + operation :get do + key :description, 'Get available policies list' + key :operationId, 'getPolicies' + key :tags, [ + 'role' + ] + response 200 do + key :description, 'Policies list' + schema do + key :type, :array + items do + key :'$ref', :PolicyObject + end + end + end + response :default do + key :description, 'error' + schema do + key :'$ref', :DevopsError + end + end + end + end + + swagger_path "/security/roles" do + operation :get do + key :description, 'Get roles list' + key :operationId, 'getRoles' + key :tags, [ + 'role' + ] + response 200 do + key :description, 'Roles list' + schema do + key :type, :array + items do + key :'$ref', :RoleObject + end + end + end + response :default do + key :description, 'error' + schema do + key :'$ref', :DevopsError + end + end + end + end + + swagger_path "/security/role" do + operation :post do + key :description, 'Create role' + key :operationId, 'createRole' + key :tags, [ + 'role' + ] + parameter do + key :name, :role + key :in, :body + key :description, 'New role' + key :required, true + schema do + key :'$ref', :RoleObjectInput + end + end + response 201 do + key :description, 'Create role response' + schema do + key :'$ref', :DevopsResponse + end + end + response :default do + key :description, 'error' + schema do + key :'$ref', :DevopsError + end + end + end + end + + swagger_path "/security/role/{id}" do + operation :get do + key :description, 'Get role by id' + key :operationId, 'getRole' + key :tags, [ + 'role' + ] + parameter do + key :name, :id + key :in, :path + key :description, 'Role id' + key :required, true + schema do + key :type, :string + end + end + response 200 do + key :description, 'Role object' + schema do + key :'$ref', :RoleObject + end + end + response :default do + key :description, 'error' + schema do + key :'$ref', :DevopsError + end + end + end + end + + swagger_path "/security/role/{id}" do + operation :delete do + key :description, 'Delete role by id' + key :operationId, 'deleteRole' + key :tags, [ + 'role' + ] + parameter do + key :name, :id + key :in, :path + key :description, 'Role id' + key :required, true + schema do + key :type, :string + end + end + response 200 do + key :description, 'Delete role response' + schema do + key :'$ref', :DevopsResponse + end + end + response :default do + key :description, 'error' + schema do + key :'$ref', :DevopsError + end + end + end + end + + end + end + end +end + diff --git a/devops-service/app/api3/docs/server.rb b/devops-service/app/api3/docs/server.rb new file mode 100644 index 0000000..dcb3f61 --- /dev/null +++ b/devops-service/app/api3/docs/server.rb @@ -0,0 +1,890 @@ +require 'swagger/blocks' + +require_relative 'devops_error' +require_relative 'devops_response' + +module Devops + module API3 + module Docs + class ServerRoutes + + include Swagger::Blocks + + swagger_schema :ServerIdObject do + property :id do + key :type, :string + end + end + + swagger_schema :DevopsServerResponse do + allOf do + schema do + key :'$ref', :DevopsResponse + end + schema do + property :id do + key :type, :string + end + end + end + end + + swagger_path "/servers" do + operation :get do + key :description, 'Get servers list' + key :operationId, 'getServers' + key :tags, [ + 'server' + ] + response 200 do + key :description, 'Servers list' + schema do + key :type, :array + items do + key :'$ref', :ServerObject + end + end + end + response :default do + key :description, 'error' + schema do + key :'$ref', :DevopsError + end + end + end + end + + swagger_path "/servers/provider/{provider}/{account}" do + operation :get do + key :description, 'Get servers list by provider and provider account' + key :operationId, 'getServersByProviderAccount' + key :tags, [ + 'server' + ] + parameter do + key :name, :provider + key :in, :path + key :description, 'Provider name' + key :required, true + schema do + key :type, :string + end + end + parameter do + key :name, :account + key :in, :path + key :description, 'Provider account id' + key :required, true + schema do + key :type, :string + end + end + response 200 do + key :description, 'Servers list' + schema do + key :type, :array + items do + key :'$ref', :ServerObject + end + end + end + response :default do + key :description, 'error' + schema do + key :'$ref', :DevopsError + end + end + end + end + + swagger_path "/server/id/{name}" do + operation :get do + key :description, 'Get server id by name' + key :operationId, 'getServerIdByName' + key :tags, [ + 'server' + ] + parameter do + key :name, :name + key :in, :path + key :description, 'Server name' + key :required, true + schema do + key :type, :string + end + end + response 200 do + key :description, 'Server id' + schema do + key :'$ref', :ServerIdObject + end + end + response :default do + key :description, 'error' + schema do + key :'$ref', :DevopsError + end + end + end + end + + swagger_path "/server/{id}" do + operation :get do + key :description, 'Get server by id' + key :operationId, 'getServerById' + key :tags, [ + 'server' + ] + parameter do + key :name, :id + key :in, :path + key :description, 'Server id' + key :required, true + schema do + key :type, :string + end + end + response 200 do + key :description, 'Server' + schema do + key :'$ref', :ServerObject + end + end + response :default do + key :description, 'error' + schema do + key :'$ref', :DevopsError + end + end + end + end + + swagger_path "/server/{id}" do + operation :delete do + key :description, 'Delete server by id' + key :operationId, 'deleteServerById' + key :tags, [ + 'server' + ] + parameter do + key :name, :id + key :in, :path + key :description, 'Server id' + key :required, true + schema do + key :type, :string + end + end + response 200 do + key :description, 'List of jobs ids' + schema do + key :type, :array + items do + key :type, :string + end + end + end + response :default do + key :description, 'error' + schema do + key :'$ref', :DevopsError + end + end + end + end + + swagger_path "/servers/delete" do + operation :post do + key :description, 'Delete servers' + key :operationId, 'deleteServers' + key :tags, [ + 'server' + ] + parameter do + key :name, :server_ids + key :in, :body + key :description, 'Array of servers ids' + key :required, true + schema do + key :type, :array + items do + key :type, :string + end + end + end + response 200 do + key :description, 'List of jobs ids' + schema do + key :type, :array + items do + key :type, :string + end + end + end + response :default do + key :description, 'error' + schema do + key :'$ref', :DevopsError + end + end + end + end + + swagger_path "/servers/{id}/deploy" do + operation :post do + key :description, 'Deploy server' + key :operationId, 'deployServer' + key :tags, [ + 'server' + ] + parameter do + key :name, :id + key :in, :path + key :description, 'Server id' + key :required, true + schema do + key :type, :string + end + end + parameter do + key :name, :tags + key :in, :body + key :description, 'Chef tags to deploy with' + key :required, false + schema do + key :type, :array + items do + key :type, :string + end + end + end + parameter do + key :name, :run_list + key :in, :body + key :description, 'Chef run_list to deploy with' + key :required, false + schema do + key :type, :array + items do + key :type, :string + end + end + end + parameter do + key :name, :build_number + key :in, :body + key :description, 'Build number to deploy' + key :required, false + schema do + key :type, :string + end + end + response 200 do + key :description, 'List of jobs ids' + schema do + key :type, :array + items do + key :type, :string + end + end + end + response :default do + key :description, 'error' + schema do + key :'$ref', :DevopsError + end + end + end + end + + swagger_path "/server" do + operation :post do + key :description, 'Create server' + key :operationId, 'createServer' + key :tags, [ + 'server' + ] + parameter do + key :name, :project + key :in, :body + key :description, 'Project id' + key :required, true + schema do + key :type, :string + end + end + parameter do + key :name, :environment + key :in, :body + key :description, 'Environment id' + key :required, true + schema do + key :type, :string + end + end + parameter do + key :name, :category + key :in, :body + key :description, 'Category id' + key :required, true + schema do + key :type, :string + end + end + parameter do + key :name, :name + key :in, :body + key :description, 'Server name' + key :required, false + schema do + key :type, :string + end + end + parameter do + key :name, :cm_name + key :in, :body + key :description, 'Server name in configuration manager system' + key :required, false + schema do + key :type, :string + end + end + parameter do + key :name, :without_bootstrap + key :in, :body + key :description, 'Skip bootstrap phase' + key :required, false + schema do + key :type, :bool + end + end + parameter do + key :name, :skip_rollback + key :in, :body + key :description, 'Skip rollback on error' + key :required, false + schema do + key :type, :bool + end + end + parameter do + key :name, :run_list + key :in, :body + key :description, 'Chef run_list to deploy with' + key :required, false + schema do + key :type, :array + items do + key :type, :string + end + end + end + response 200 do + key :description, 'List of jobs ids' + schema do + key :type, :array + items do + key :type, :string + end + end + end + response :default do + key :description, 'error' + schema do + key :'$ref', :DevopsError + end + end + end + end + + swagger_path "/server/{id}/pause" do + operation :post do + key :description, 'Pause server' + key :operationId, 'pauseServer' + key :tags, [ + 'server' + ] + parameter do + key :name, :id + key :in, :path + key :description, 'Server id' + key :required, true + schema do + key :type, :string + end + end + response 200 do + key :description, 'Server response' + schema do + key :'$ref', :DevopsServerResponse + end + end + response 409 do + key :description, 'Conflict error, server in invalid state, operation can not be done' + schema do + key :'$ref', :DevopsError + end + end + response :default do + key :description, 'error' + schema do + key :'$ref', :DevopsError + end + end + end + end + + swagger_path "/server/{id}/unpause" do + operation :post do + key :description, 'Unpause server' + key :operationId, 'unpauseServer' + key :tags, [ + 'server' + ] + parameter do + key :name, :id + key :in, :path + key :description, 'Server id' + key :required, true + schema do + key :type, :string + end + end + response 200 do + key :description, 'Server response' + schema do + key :'$ref', :DevopsServerResponse + end + end + response 409 do + key :description, 'Conflict error, server in invalid state, operation can not be done' + schema do + key :'$ref', :DevopsError + end + end + response :default do + key :description, 'error' + schema do + key :'$ref', :DevopsError + end + end + end + end + + swagger_path "/server/{id}/reserve" do + operation :post do + key :description, 'Reserve server' + key :operationId, 'reserveServer' + key :tags, [ + 'server' + ] + parameter do + key :name, :id + key :in, :path + key :description, 'Server id' + key :required, true + schema do + key :type, :string + end + end + response 200 do + key :description, 'Server response' + schema do + key :'$ref', :DevopsServerResponse + end + end + response 409 do + key :description, 'Conflict error, server in invalid state, operation can not be done' + schema do + key :'$ref', :DevopsError + end + end + response :default do + key :description, 'error' + schema do + key :'$ref', :DevopsError + end + end + end + end + + swagger_path "/server/{id}/unreserve" do + operation :post do + key :description, 'Unreserve server' + key :operationId, 'unreserveServer' + key :tags, [ + 'server' + ] + parameter do + key :name, :id + key :in, :path + key :description, 'Server id' + key :required, true + schema do + key :type, :string + end + end + response 200 do + key :description, 'Server response' + schema do + key :'$ref', :DevopsServerResponse + end + end + response 409 do + key :description, 'Conflict error, server in invalid state, operation can not be done' + schema do + key :'$ref', :DevopsError + end + end + response :default do + key :description, 'error' + schema do + key :'$ref', :DevopsError + end + end + end + end + + swagger_path "/server/{id}/bootstrap" do + operation :post do + key :description, 'Bootstrap server' + key :operationId, 'bootstrapServer' + key :tags, [ + 'server' + ] + parameter do + key :name, :id + key :in, :path + key :description, 'Server id' + key :required, true + schema do + key :type, :string + end + end + parameter do + key :name, :run_list + key :in, :body + key :description, 'Chef run_list to deploy with' + key :required, false + schema do + key :type, :array + items do + key :type, :string + end + end + end + parameter do + key :name, :bootstrap_template + key :in, :body + key :description, 'Owerride bootstrap_template parameter' + key :required, false + schema do + key :type, :string + end + end + parameter do + key :name, :cm_name + key :in, :body + key :description, 'Server name in configuration manager system' + key :required, false + schema do + key :type, :string + end + end + response 200 do + key :description, 'Server response' + schema do + key :'$ref', :DevopsServerResponse + end + end + response 409 do + key :description, 'Conflict error, server in invalid state, operation can not be done' + schema do + key :'$ref', :DevopsError + end + end + response :default do + key :description, 'error' + schema do + key :'$ref', :DevopsError + end + end + end + end + + swagger_path "/server/{id}/unbootstrap" do + operation :post do + key :description, 'Unbootstrap server' + key :operationId, 'unbootstrapServer' + key :tags, [ + 'server' + ] + parameter do + key :name, :id + key :in, :path + key :description, 'Server id' + key :required, true + schema do + key :type, :string + end + end + response 200 do + key :description, 'Server response' + schema do + key :'$ref', :DevopsServerResponse + end + end + response 409 do + key :description, 'Conflict error, server in invalid state, operation can not be done' + schema do + key :'$ref', :DevopsError + end + end + response :default do + key :description, 'error' + schema do + key :'$ref', :DevopsError + end + end + end + end + + swagger_path "/server/add" do + operation :post do + key :description, 'Add static server' + key :operationId, 'addServer' + key :tags, [ + 'server' + ] + parameter do + key :name, :project + key :in, :body + key :description, 'Project id' + key :required, true + schema do + key :type, :string + end + end + parameter do + key :name, :environment + key :in, :body + key :description, 'Environment id' + key :required, true + schema do + key :type, :string + end + end + parameter do + key :name, :category + key :in, :body + key :description, 'Category id' + key :required, true + schema do + key :type, :string + end + end + parameter do + key :name, :private_ip + key :in, :body + key :description, 'Server private ip to connect to' + key :required, true + schema do + key :type, :string + end + end + parameter do + key :name, :key + key :in, :body + key :description, 'Key id' + key :required, true + schema do + key :type, :string + end + end + parameter do + key :name, :remote_user + key :in, :body + key :description, 'Remote user for server to connect to' + key :required, true + schema do + key :type, :string + end + end + parameter do + key :name, :name + key :in, :body + key :description, 'Server name' + key :required, false + schema do + key :type, :string + end + end + parameter do + key :name, :run_list + key :in, :body + key :description, 'Chef run_list to deploy with' + key :required, false + schema do + key :type, :array + items do + key :type, :string + end + end + end + parameter do + key :name, :public_ip + key :in, :body + key :description, 'Server public ip to connect to' + key :required, false + schema do + key :type, :string + end + end + response 200 do + key :description, 'Server response' + schema do + key :'$ref', :DevopsServerResponse + end + end + response 409 do + key :description, 'Conflict error, server in invalid state, operation can not be done' + schema do + key :'$ref', :DevopsError + end + end + response :default do + key :description, 'error' + schema do + key :'$ref', :DevopsError + end + end + end + end + + swagger_path "/server/{id}/tags/add" do + operation :post do + key :description, 'Add tags to provider server' + key :operationId, 'addServerTags' + key :tags, [ + 'server' + ] + parameter do + key :name, :id + key :in, :path + key :description, 'Server id' + key :required, true + schema do + key :type, :string + end + end + parameter do + key :name, :tags + key :in, :body + key :description, 'Key-value object with tags' + key :required, false + schema do + key :type, :string + end + end + response 200 do + key :description, 'Server response' + schema do + key :'$ref', :DevopsServerResponse + end + end + response :default do + key :description, 'error' + schema do + key :'$ref', :DevopsError + end + end + end + end + + swagger_path "/server/{id}/tags/delete" do + operation :post do + key :description, 'Delete tags from provider server' + key :operationId, 'deleteServerTags' + key :tags, [ + 'server' + ] + parameter do + key :name, :id + key :in, :path + key :description, 'Server id' + key :required, true + schema do + key :type, :string + end + end + parameter do + key :name, :tags + key :in, :body + key :description, 'Key-value object with tags' + key :required, false + schema do + key :type, :string + end + end + response 200 do + key :description, 'Server response' + schema do + key :'$ref', :DevopsServerResponse + end + end + response :default do + key :description, 'error' + schema do + key :'$ref', :DevopsError + end + end + end + end + + swagger_path "/server/{id}/run_list" do + operation :post do + key :description, 'Set server run_list' + key :operationId, 'setServerRunList' + key :tags, [ + 'server' + ] + parameter do + key :name, :id + key :in, :path + key :description, 'Server id' + key :required, true + schema do + key :type, :string + end + end + parameter do + key :name, :run_list + key :in, :body + key :description, 'New server run_list' + key :required, false + schema do + key :type, :array + items do + key :type, :string + end + end + end + response 200 do + key :description, 'Server response' + schema do + key :'$ref', :DevopsServerResponse + end + end + response :default do + key :description, 'error' + schema do + key :'$ref', :DevopsError + end + end + end + end + + end + end + end +end diff --git a/devops-service/app/api3/docs/server_model.rb b/devops-service/app/api3/docs/server_model.rb new file mode 100644 index 0000000..6403cda --- /dev/null +++ b/devops-service/app/api3/docs/server_model.rb @@ -0,0 +1,65 @@ +require 'swagger/blocks' + +module Devops + module API3 + module Docs + class ServerModel + + include Swagger::Blocks + + swagger_schema :ServerObject do + property :id do + key :type, :string + end + property :name do + key :type, :string + end + property :cm_name do + key :type, :string + end + property :remote_user do + key :type, :string + end + property :project do + key :type, :string + end + property :environment do + key :type, :string + end + property :category do + key :type, :string + end + property :private_ip do + key :type, :string + end + property :public_ip do + key :type, :string + end + property :created_by do + key :type, :string + end + property :reserved_by do + key :type, :string + end + property :stack do + key :type, :string + end + property :run_list do + key :type, :array + items do + key :type, :string + end + end + property :ssh_key do + key :type, :string + end + property :last_operation do + key :'$ref', :ServerLastOperationObject + end + + end + + end + end + end +end diff --git a/devops-service/app/api3/docs/user.rb b/devops-service/app/api3/docs/user.rb new file mode 100644 index 0000000..8991b40 --- /dev/null +++ b/devops-service/app/api3/docs/user.rb @@ -0,0 +1,435 @@ +require 'swagger/blocks' + +require_relative 'devops_error' +require_relative 'devops_response' + +module Devops + module API3 + module Docs + class UserRoutes + + include Swagger::Blocks + + swagger_schema :UserResponse do + allOf do + schema do + key :'$ref', :DevopsResponse + end + schema do + property :id do + key :type, :string + end + end + end + end + + swagger_schema :UserObject do + allOf do + schema do + key :'$ref', :UserObjectCommon + end + schema do + property :created_at do + key :type, :integer + key :format, :int64 + end + end + end + end + + swagger_schema :UserObjectInput do + allOf do + schema do + key :'$ref', :UserObjectCommon + end + schema do + property :password do + key :type, :string + key :maxLength, 31 + key :minLength, 5 + end + end + end + end + + swagger_schema :UserEmailBody do + key :required, [:email] + property :email do + key :type, :string + end + end + + swagger_schema :UserPasswordBody do + key :required, [:password] + property :password do + key :type, :string + key :maxLength, 31 + key :minLength, 5 + end + end + + swagger_schema :UserBodyToUpdate do + allOf do + schema do + key :'$ref', :UserEmailBody + end + schema do + key :'$ref', :UserPasswordBody + end + schema do + property :roles do + key :type, :array + items do + key :type, :string + end + end + end + end + end + + swagger_schema :UserObjectCommon do + key :required, [:id, :email, :roles] + property :id do + key :type, :string + key :pattern, "^[\w-]{1,100}$" + key :maxLength, 100 + end + property :email do + key :type, :string + end + property :roles do + key :type, :array + items do + key :type, :string + end + end + end + + swagger_path "/users" do + operation :get do + key :description, 'Get users list' + key :operationId, 'getUsers' + key :tags, [ + 'user' + ] + response 200 do + key :description, 'Users list' + schema do + key :type, :array + items do + key :'$ref', :UserObject + end + end + end + response :default do + key :description, 'error' + schema do + key :'$ref', :DevopsError + end + end + end + end + + swagger_path "/user/{id}" do + operation :get do + key :description, 'Get user by id' + key :operationId, 'getUserById' + key :tags, [ + 'user' + ] + parameter do + key :name, :id + key :in, :path + key :description, 'User id' + key :required, true + schema do + key :type, :string + end + end + response 200 do + key :description, 'User' + schema do + key :'$ref', :UserObject + end + end + response :default do + key :description, 'error' + schema do + key :'$ref', :DevopsError + end + end + end + end + + swagger_path "/user" do + operation :post do + key :description, 'Create new user' + key :operationId, 'createUser' + key :tags, [ + 'user' + ] + parameter do + key :name, :user + key :in, :body + key :description, 'New user' + key :required, true + schema do + key :'$ref', :UserObjectInput + end + end + response 201 do + key :description, 'Create user response' + schema do + key :'$ref', :UserResponse + end + end + response :default do + key :description, 'error' + schema do + key :'$ref', :DevopsError + end + end + end + end + + swagger_path "/user/{id}/roles/add" do + operation :post do + key :description, 'Add roles to user' + key :operationId, 'addRolesToUser' + key :tags, [ + 'user' + ] + parameter do + key :name, :id + key :in, :path + key :description, 'User id' + key :required, true + schema do + key :type, :string + end + end + parameter do + key :name, :roles + key :in, :body + key :description, 'Roles list' + key :required, true + schema do + key :type, :array + items do + key :type, :string + end + end + end + response 200 do + key :description, 'User response' + schema do + key :'$ref', :UserResponse + end + end + response :default do + key :description, 'error' + schema do + key :'$ref', :DevopsError + end + end + end + end + + swagger_path "/user/{id}/roles/delete" do + operation :post do + key :description, 'Delete roles from user' + key :operationId, 'deleteRolesFromUser' + key :tags, [ + 'user' + ] + parameter do + key :name, :id + key :in, :path + key :description, 'User id' + key :required, true + schema do + key :type, :string + end + end + parameter do + key :name, :roles + key :in, :body + key :description, 'Roles list' + key :required, true + schema do + key :type, :array + items do + key :type, :string + end + end + end + response 200 do + key :description, 'User response' + schema do + key :'$ref', :UserResponse + end + end + response :default do + key :description, 'error' + schema do + key :'$ref', :DevopsError + end + end + end + end + + swagger_path "/user/{id}/email" do + operation :put do + key :description, 'Update user email' + key :operationId, 'userEmail' + key :tags, [ + 'user' + ] + parameter do + key :name, :id + key :in, :path + key :description, 'User id' + key :required, true + schema do + key :type, :string + end + end + parameter do + key :name, :email + key :in, :body + key :description, 'New email' + key :required, true + schema do + key :'$ref', :UserEmailBody + end + end + response 200 do + key :description, 'User response' + schema do + key :'$ref', :UserResponse + end + end + response :default do + key :description, 'error' + schema do + key :'$ref', :DevopsError + end + end + end + end + + swagger_path "/user/{id}/password" do + operation :put do + key :description, 'Update user password' + key :operationId, 'userPassword' + key :tags, [ + 'user' + ] + parameter do + key :name, :id + key :in, :path + key :description, 'User id' + key :required, true + schema do + key :type, :string + end + end + parameter do + key :name, :password + key :in, :body + key :description, 'New password' + key :required, true + schema do + key :'$ref', :UserPasswordBody + end + end + response 200 do + key :description, 'User response' + schema do + key :'$ref', :UserResponse + end + end + response :default do + key :description, 'error' + schema do + key :'$ref', :DevopsError + end + end + end + end + + swagger_path "/user/{id}" do + operation :delete do + key :description, 'Delete user by id' + key :operationId, 'deleteUserById' + key :tags, [ + 'user' + ] + parameter do + key :name, :id + key :in, :path + key :description, 'User id' + key :required, true + schema do + key :type, :string + end + end + response 200 do + key :description, 'User response' + schema do + key :'$ref', :UserResponse + end + end + response :default do + key :description, 'error' + schema do + key :'$ref', :DevopsError + end + end + end + end + + swagger_path "/user/{id}" do + operation :put do + key :description, 'Update user by id' + key :operationId, 'updateUserById' + key :tags, [ + 'user' + ] + parameter do + key :name, :id + key :in, :path + key :description, 'User id' + key :required, true + schema do + key :type, :string + end + end + parameter do + key :name, :user_data + key :in, :body + key :description, 'User data to update' + key :required, true + schema do + key :'$ref', :UserBodyToUpdate + end + end + response 200 do + key :description, 'User response' + schema do + key :'$ref', :UserResponse + end + end + response :default do + key :description, 'error' + schema do + key :'$ref', :DevopsError + end + end + end + end + + end + end + end +end diff --git a/devops-service/app/api3/handlers/api-docs.rb b/devops-service/app/api3/handlers/api-docs.rb new file mode 100644 index 0000000..7d0981a --- /dev/null +++ b/devops-service/app/api3/handlers/api-docs.rb @@ -0,0 +1,109 @@ +require 'swagger/blocks' +require_relative "request_handler" + +require 'app/api3/docs/devops_error' +require 'app/api3/docs/devops_response' +require 'app/api3/docs/server_model' +require 'app/api3/docs/provider' +require 'app/api3/docs/job_task' +require 'app/api3/docs/chef' +require 'app/api3/docs/filter' +require 'app/api3/docs/image' +require 'app/api3/docs/key' +require 'app/api3/docs/role' +require 'app/api3/docs/user' +require 'app/api3/docs/project' +require 'app/api3/docs/server' + +module Devops + module API3 + module Handler + class ApiDocs < RequestHandler + + include Swagger::Blocks + + swagger_root do + key :swagger, '2.0' + info do + key :version, '3.0' + key :title, 'Devops API' + key :description, 'Devops API v3 specification' + license do + key :name, 'MIT' + key :url, 'https://opensource.org/licenses/MIT' + end + end + + tag do + key :name, 'provider' + key :description, 'Providers operations' + end + tag do + key :name, 'task' + key :description, 'Job tasks operations' + end + tag do + key :name, 'chef' + key :description, 'Chef operations' + end + tag do + key :name, 'filter' + key :description, 'Filter operations' + end + tag do + key :name, 'image' + key :description, 'Image operations' + end + tag do + key :name, 'key' + key :description, 'SSH keys operations' + end + tag do + key :name, 'role' + key :description, 'User roles operations' + end + tag do + key :name, 'user' + key :description, 'Users operations' + end + tag do + key :name, 'project' + key :description, 'Projects operations' + end + tag do + key :name, 'server' + key :description, 'Servers operations' + end +# key :host, 'petstore.swagger.wordnik.com' + key :basePath, DevopsConfig.config[:url_prefix] + '/v3' + key :scheme, 'http' + key :consumes, ['application/json'] + key :produces, ['application/json'] + end + + # A list of all classes that have swagger_* declarations. + SWAGGERED_CLASSES = [ + Devops::API3::Docs::ProviderRoutes, + Devops::API3::Docs::JobTaskRoutes, + Devops::API3::Docs::ChefRoutes, + Devops::API3::Docs::FilterRoutes, + Devops::API3::Docs::ImageRoutes, + Devops::API3::Docs::KeyRoutes, + Devops::API3::Docs::RolesRoutes, + Devops::API3::Docs::UserRoutes, + Devops::API3::Docs::ProjectRoutes, + Devops::API3::Docs::ServerRoutes, + Devops::API3::Docs::DevopsError, + Devops::API3::Docs::DevopsResponse, + Devops::API3::Docs::ServerModel, + self + ].freeze + + def index + Swagger::Blocks.build_root_json(SWAGGERED_CLASSES) + end + + end + end + end +end diff --git a/devops-service/app/api2/handlers/tag.rb b/devops-service/app/api3/handlers/chef.rb similarity index 65% rename from devops-service/app/api2/handlers/tag.rb rename to devops-service/app/api3/handlers/chef.rb index de072e7..afce148 100644 --- a/devops-service/app/api2/handlers/tag.rb +++ b/devops-service/app/api3/handlers/chef.rb @@ -1,18 +1,18 @@ -require "commands/knife_commands" -require "app/api2/parsers/tag" +require "commands/bootstrap_templates" +require "app/api3/parsers/chef" require_relative "request_handler" module Devops - module API2_0 + module API3 module Handler - class Tag < RequestHandler - set_parser Devops::API2_0::Parser::TagParser + class Chef < RequestHandler - def initialize node_name - @node_name = node_name - @server = Devops::DB.connector.server_by_chef_node_name(@node_name) - #TODO: raise - halt_response("No servers found for name '#{@node_name}'", 404) if @server.nil? + set_parser Devops::API3::Parser::ChefParser + + include BootstrapTemplatesCommands + + def chef_nodes + KnifeFactory.instance.chef_node_list end def tags node_name @@ -34,6 +34,7 @@ module Devops halt_response("Cannot delete tags #{tagsStr} from server #{node_name}: #{cmd[0]}", 500) unless cmd[1] tags end + end end end diff --git a/devops-service/app/api2/handlers/deploy.rb b/devops-service/app/api3/handlers/deploy.rb similarity index 76% rename from devops-service/app/api2/handlers/deploy.rb rename to devops-service/app/api3/handlers/deploy.rb index 204d35d..778ebe1 100644 --- a/devops-service/app/api2/handlers/deploy.rb +++ b/devops-service/app/api3/handlers/deploy.rb @@ -2,17 +2,17 @@ require "lib/executors/server_executor" require "commands/status" require "workers/deploy_worker" require "exceptions/deploy_info_error" -require "app/api2/parsers/deploy" +require "app/api3/parsers/deploy" require_relative "request_handler" module Devops - module API2_0 + module API3 module Handler class Deploy < RequestHandler # extend DeployCommands extend StatusCommands - set_parser Devops::API2_0::Parser::DeployParser + set_parser Devops::API3::Parser::DeployParser def deploy body = parser.deploy @@ -25,7 +25,7 @@ module Devops @deploy_info_buf = {} servers(names).each do |s| project = begin - Devops::Db.connector.check_project_auth s.project, s.deploy_env, owner + Devops::Model::Project.check_user_authorization(s.project, s.environment, owner) rescue InvalidPrivileges, RecordNotFound => e DevopsLogger.logger.warn e.message next @@ -45,7 +45,7 @@ module Devops rescue DeployInfoError => e msg = "Can not get deploy info: " + e.message DevopsLogger.logger.error msg - jid = "error_#{s.chef_node_name}_#{Time.new.to_i}" + jid = "error_#{s.name}_#{Time.new.to_i}" file = File.jon(dir, jid) File.open(file, "w") do |out| out.write msg @@ -55,12 +55,12 @@ module Devops "_id" => jid, "created_by" => owner, "project" => s.project, - "deploy_env" => s.deploy_env, - "type" => Report::DEPLOY_TYPE, + "environment" => s.environment, + "type" => JobTask::DEPLOY_TYPE, "status" => Worker::STATUS::FAILED # "attributes" => attributes } - Devops::Db.connector.save_report(Report.new(o)) + JobTask.create(o) end files.push(jid) end @@ -77,8 +77,8 @@ module Devops @deploy_info_buf = {} servers(names).each do |s| project = begin - Devops::Db.connector.check_project_auth s.project, s.deploy_env, owner - rescue InvalidPrivileges, RecordNotFound => e + Devops::Model::Project.check_user_authorization(s.project, s.environment, owner) + rescue InvalidPrivileges, Devops::Exception::RecordNotFound => e out << e.message + "\n" status.push 2 next @@ -97,21 +97,21 @@ module Devops end end status - rescue RecordNotFound => e + rescue Devops::Exception::RecordNotFound => e out << e.message [-10] end def servers names - servers = Devops::Db.connector.servers(nil, nil, names, true) - raise RecordNotFound.new("No reserved servers found for names '#{names.join("', '")}'") if servers.empty? - servers.sort_by!{|s| names.index(s.chef_node_name)} + servers = Devops::Model::Server.find(name: {'$in' => names}, reserved: true) + raise Devops::Exception::RecordNotFound.new("No reserved servers found for names '#{names.join("', '")}'") if servers.empty? + servers.sort_by!{|s| names.index(s.name)} servers end def create_deploy_info server, project, build_number - deploy_env_model = project.deploy_env(server.deploy_env) - buf_key = "#{server.project}_#{server.deploy_env}" + deploy_env_model = project.environment(server.environment) + buf_key = "#{server.project}_#{server.environment}" deploy_info = if @deploy_info_buf.key?(buf_key) @deploy_info_buf[buf_key] else diff --git a/devops-service/app/api3/handlers/filter.rb b/devops-service/app/api3/handlers/filter.rb new file mode 100644 index 0000000..b7850c6 --- /dev/null +++ b/devops-service/app/api3/handlers/filter.rb @@ -0,0 +1,33 @@ +require "app/api3/parsers/filter" +require 'db/mongo/models/filter' +require_relative "request_handler" + +module Devops + module API3 + module Handler + class Filter < RequestHandler + + set_parser Devops::API3::Parser::FilterParser + + def available_images provider + Devops::Model::Filter.available_images(provider) + end + + def add_images provider + images = parser.images + res = Devops::Model::Filter.add_available_images(images, provider) + DevopsLogger.logger.info "Added new image filters '#{images.join("', '")}' for provider #{provider}" + res + end + + def delete_images provider + res = Devops::Model::Filter.delete_available_images(parser.images, provider) + DevopsLogger.logger.info "Removed image filters '#{res.join("', '")}' from provider #{provider}" + res + end + + end + end + end +end + diff --git a/devops-service/app/api3/handlers/image.rb b/devops-service/app/api3/handlers/image.rb new file mode 100644 index 0000000..3a127b7 --- /dev/null +++ b/devops-service/app/api3/handlers/image.rb @@ -0,0 +1,63 @@ +require "commands/image" +require "db/mongo/models/image" +require "app/api3/parsers/image" +require_relative "request_handler" + +module Devops + module API3 + module Handler + class Image < RequestHandler + + set_parser Devops::API3::Parser::ImageParser + + def images + provider = parser.images + if provider + Devops::Model::Image.where(provider: provider) + else + Devops::Model::Image.all + end + end + + def image id + Devops::Model::Image.find(id) + rescue Mongoid::Errors::DocumentNotFound + raise Devops::Exception::RecordNotFound.new("Image with id '#{id}' not found") + end + + def create_image + image = parser.image + image.save! + DevopsLogger.logger.info "Image '#{image.id}' has been created" + image + rescue Mongoid::Errors::Validations => e + raise Devops::Exception::ValidationError.create_from_db_exception(e) + end + + def update_image id + image = image(id) + obj = parser.image + image.update_attributes! obj.to_hash_update + DevopsLogger.logger.info "Image '#{image.id}' has been updated" + image + rescue Mongoid::Errors::Validations => e + raise Devops::Exception::ValidationError.create_from_db_exception(e) + end + + def delete_image id + projects = Devops::Model::Project.find_by('environments.image' => id) + ar = [] + projects.each do |p| + ar += p.environments.select{|e| e.respond_to?(:image)}.select{|e| e.image == id}.map{|e| "#{p.id}.#{e.id}"} + end + raise DependencyError.new "Deleting is forbidden: Image is used in #{ar.join(", ")}" + rescue Mongoid::Errors::DocumentNotFound + image(id).delete + DevopsLogger.logger.info "Image '#{id}' has been deleted" + end + + end + end + end +end + diff --git a/devops-service/app/api3/handlers/job_task.rb b/devops-service/app/api3/handlers/job_task.rb new file mode 100644 index 0000000..ec41851 --- /dev/null +++ b/devops-service/app/api3/handlers/job_task.rb @@ -0,0 +1,68 @@ +require_relative "request_handler" + +module Devops + module API3 + module Handler + class JobTask < RequestHandler + + def options + params = @request.params + options = {} + ["project", "environment", "category", "type", "created_by", "status", "server_id", "max_number"].each do |k| + options[k] = params[k] unless params[k].nil? + end + fill_date_params_for_searching(options) + + #attributes_keys = params.keys.select{|k| k =~ /attributes\.*/} + #attributes_keys.each do |ak| + # options[ak] = params[ak] + #end + options + end + + def all + sort = extract_sort_params_for_searching + limit = extract_limit_params_for_searching(10) + Devops::Model::JobTask.where(options).sort(sort).limit(limit) + end + + def all_latest + # TODO: + #Devops::Db.connector.latest_reports(options()) + [] + end + + def attributes name + # TODO: + #Devops::Db.connector.reports_attributes_values(name) + [] + end + + def task id + Devops::Model::JobTask.find(id) + rescue Mongoid::Errors::DocumentNotFound => e + raise Devops::Exception::RecordNotFound.new("JobTask '#{id}' does not exist") + end + + def report id + t = task(id) + tstatus = t.status + if tstatus == Worker::STATUS::IN_QUEUE + return "Task '#{id}' has been queued", false + end + file = t.file + raise Devops::Exception::RecordNotFound.new("JobTask '#{id}' file does not exist") unless File.exists? file + completed = (tstatus == "completed" or tstatus == "failed") + return Rack::Utils.escape_html(File.read(file).encode('UTF-8', 'binary', invalid: :replace, undef: :replace, replace: '')), completed + end + + def status id + t = task(id) + t.status + end + + end + end + end +end + diff --git a/devops-service/app/api3/handlers/key.rb b/devops-service/app/api3/handlers/key.rb new file mode 100644 index 0000000..fd3ee82 --- /dev/null +++ b/devops-service/app/api3/handlers/key.rb @@ -0,0 +1,56 @@ +require "db/mongo/models/key" +require "fileutils" +require "app/api3/parsers/key" +require_relative "request_handler" + +module Devops + module API3 + module Handler + class Key < RequestHandler + + set_parser Devops::API3::Parser::KeyParser + + def keys + Devops::Model::Key.all + end + + def key id + Devops::Model::Key.find(id) + rescue Mongoid::Errors::DocumentNotFound + raise Devops::Exception::RecordNotFound.new("Key with id '#{id}' not found") + end + + def create(keys_dir) + body = parser.create + fname = body["file_name"] + file_name = File.join(keys_dir, fname) + raise Devops::Exception::ValidationError.new("File '#{fname}' already exist") if File.exists?(file_name) + File.open(file_name, "w") do |f| + f.write(body["content"]) + f.chmod(0400) + end + + key = Devops::Model::Key.create!({"path" => file_name, "id" => body["key_name"]}) + DevopsLogger.logger.info "Key '#{key.id}' has been created" + key + end + + def delete key_id + k = key(key_id) + servers = [] + Devops::Model::Server.where(key: k.id).each do |s| + servers << s.id + end + unless servers.empty? + s_str = servers.join(", ") + raise DependencyError.new "Deleting is forbidden: Key is used in servers: #{s_str}" + end + k.destroy + DevopsLogger.logger.info "Key '#{k.id}' has been deleted" + end + + end + end + end +end + diff --git a/devops-service/app/api3/handlers/project.rb b/devops-service/app/api3/handlers/project.rb new file mode 100644 index 0000000..2bdf327 --- /dev/null +++ b/devops-service/app/api3/handlers/project.rb @@ -0,0 +1,439 @@ +require "commands/status" +require "db/mongo/models/project" +require "db/mongo/models/user" +require "workers/project_test_worker" +require "app/api3/parsers/project" +require "lib/project/type/types_factory" +require "lib/executors/server_executor" + +require_relative "request_handler" + +module Devops + module API3 + module Handler + class Project < RequestHandler + + set_parser Devops::API3::Parser::ProjectParser + + include Devops::API3::Helpers + + extend StatusCommands + + def project_types + Devops::TypesFactory.types_names + end + + def projects + user = parser.current_user + query = {} + if user != Devops::Model::User::ROOT_USER_NAME + query['$or'] = [{owner: user}, {project_users: user}] + end + parser.archived_projects ? query["archived"] = true : query["archived"] = {"$exists" => false} + Devops::Model::Project.where(query) + #Devops::Db.connector.projects(nil, nil, parser.projects, parser.archived_projects) + end + + def project id + Devops::Model::Project.find(id) + rescue Mongoid::Errors::DocumentNotFound + raise Devops::Exception::RecordNotFound.new("Project '#{id}' not found") + end + + def project_environments(id) + project = project(id) + project.environments + end + + def get_project_with_environment id, env + #Devops::Model::Project.where({'environments.id' => env}).only('environments.$.id').find(id) ??? TODO: projection with array index + project = Devops::Model::Project.where({'environments.id' => env}).find(id) + project.environments = [ project.environments.detect{|de| de.id == env} ] + project + rescue Mongoid::Errors::DocumentNotFound + raise Devops::Exception::RecordNotFound.new("Project '#{id}' with deploy environment '#{env}' not found") + end + + def project_environment(id, env) + get_project_with_environment(id, env).environments[0] + end + + def project_env_servers id, env + project = get_project_with_environment(id, env) + user = parser.current_user + users = [ project.owner ] + project.project_users + Devop::Exception::AccessError.new("User can not read this project") unless users.include?(user) + Devops::Model::Server.where({'project' => id, 'environment' => env}).all + end + + def pvroject_servers id + project = project(id) + user = parser.current_user + users = [ project.owner ] + project.project_users + Devop::Exception::AccessError.new("User can not read this project") unless users.include?(user) + Devops::Model::Server.where({'project' => id}).all + end + + def add_project_users id + users = parser.users + #TODO: projection + dbusers = Devops::Model::User.where('_id.in' => users).map{|u| u.id} + invalid_users = users - dbusers + raise Devops::Exception::ValidationError.new("Invalid users: '#{invalid_users.join("', '")}'") unless invalid_users.empty? + add_to_project_array id, :project_users, users + end + + def delete_project_users id + pull_from_project_array id, :project_users, parser.users + end + + def set_project_description id + db_project = project(id) + db_project.description = parser.set_description + db_project.save! + end + + def add_to_project_array id, key, list_to_add + db_project = project(id) + set = Set.new(db_project.send(key)).merge(list_to_add) + db_project.add_to_set({key => list_to_add}) + set.to_a + end + + def pull_from_project_array id, key, list_to_pull + db_project = project(id) + set = Set.new(db_project.send(key)).subtract(list_to_pull) + db_project.pull_all({key => list_to_pull}) + set.to_a + end + + def set_project_run_list id + db_project = project(id) + db_project.run_list = parser.run_list + db_project.save! + db_project.run_list + end + + def add_project_run_list id + add_to_project_array id, :run_list, parser.run_list + end + + def delete_project_run_list id + pull_from_project_array id, :run_list, parser.run_list + end + + def add_project_env_users id, env + project = get_project_with_environment(id, env) + users = parser.users + dbusers = project.project_users + [project.owner] + invalid_users = users - dbusers + raise Devops::Exception::ValidationError.new("User(s) '#{invalid_users.join("', '")}' is/are not a project user(s)") unless invalid_users.empty? + Devops::Model::Project.where({'_id' => id, 'environments.id' => env}).add_to_set('environments.$.users' => users) + Set.new(project.environments[0].users + users).to_a + end + + def delete_project_env_users id, env + project = get_project_with_environment(id, env) + users = parser.users + Devops::Model::Project.where({'_id' => id, 'environments.id' => env}).pull_all('environments.$.users' => users) + project.environments[0].users - users + end + + def project_env_stacks id, env + # check if project exists + get_project_with_environment(id, env) + Devops::Model::StackBase.where({project: id, environment: env}).all + end + + def create_project + p = parser.create_project + + p.owner = parser.current_user + p.environments.each do |env| + env.add_users [parser.current_user] + end + p.save! + info = "Project '#{p.id}' has been created." + DevopsLogger.logger.info info + info + end + +=begin + def set_project_components id + body = parser.set_project_components + project = Devops::Db.connector.project(id) + project.components = body["components"] + project.validate_components + Devops::Db.connector.project_update_field id, "components", body["components"] + "Updated project '#{project.id}' with components '#{body["components"].inspect}'" + end +=end + + def add_environment id + db_project = project(id) + env = parser.add_environment + env.validate! + env.add_users [parser.current_user] + begin + db_env = db_project.environment(env.id) + raise Devops::Exception::ValidationError.new("Can not add new environment for project '#{id}'. Environment '#{env.id}' already exist") + rescue Devops::Exception::RecordNotFound => e + db_project.add_environment(env) + info = "Deploy environment '#{env.id}' has been added to project '#{id}'." + DevopsLogger.logger.info info + [info, env] + end + end + + def project_environment_categories project, env + project = get_project_with_environment(project, env) + penv = project.environments[0] + penv.categories + end + + def add_category id, env + project = get_project_with_environment(id, env) + penv = project.environments[0] + cat = parser.add_category + cat.validate! + db_cat = penv.get_category(cat.id) + if db_cat.nil? + category = project.add_category(penv, cat) + roles = category.create_role(id, env) + roles_response = Model::Category.present_created_roles(roles) + info = "New category '#{cat.id}' has been added to environment '#{env}' of project '#{id}'. " + info += roles_response + DevopsLogger.logger.info info + [info, cat] + else + raise Devops::Exception::ValidationError.new("Category '#{cat.id}' for project '#{id}' and deploy environment '#{env}' already exist") + end + end + + def show_category id, env, category + project = get_project_with_environment(id, env) + penv = project.environments[0] + cat = penv.categories.detect{|c| c.id == category} + raise Devops::Exception::RecordNotFound.new("Category '#{category}' for project '#{id}' and environment '#{env}' not found") if cat.nil? + cat + end + + def delete_category id, env, category + project = get_project_with_environment(id, env) + penv = project.environments[0] + project.delete_category(penv, category) + info = "Category '#{category}' has been removed from environment '#{env}' of project '#{id}'" + DevopsLogger.logger.info info + return info + end + + def update_environment_field id, environment, field + project = Devops::Db.connector.project(id) + db_env = project.environment(environment) + value = parser.update_environment_field + if db_env.respond_to?(field + "=") + if field == "id" + db_env.rename id, value + "Environment '#{environment}' has been renamed to '#{value}'" + else + db_env.update_field(id, field, value) + "Environment's field '#{field}' has been updated" + end + else + raise Devops::Exception::RecordNotFound.new("Field '#{field}' does not exist") + end + end + + def update_environment id, environment + project = Devops::Db.connector.project(id) + db_env = project.environment(environment) + env = parser.update_environment + env.id = environment if env.id.nil? + begin + unless env.id == environment + servers = Devops::Db.connector.servers_by_project_and_environment(id, environment) + raise InvalidRecord.new("Environment '#{environment}' can't be updated: it has #{servers.size} running servers.") unless servers.empty? + end + begin + project.environment(env.id) + raise InvalidRecord.new("Environment '#{environment}' can't be renamed to '#{env.id}', environment '#{env.id}' already exists") unless environment == env.id + rescue Devops::Exception::RecordNotFound => e + end + env.validate! + project.delete_environment(environment) + project.add_environment(env) + "Deploy environment '#{environment}' has been updated in project '#{project.id}'" + rescue Devops::Exception::RecordNotFound => e + env.id = environment + res = project.add_environment env + "Deploy environment '#{env.id}' has been added to project '#{project.id}'." + res + end + end + + def delete_environment id, environment + db_project = get_project_with_environment(id, environment) + servers = Devops::Model::Server.find({'project' => id, 'environment' => environment}) + raise Devops::Exception::DependencyError.new("Can not delete environment '#{environment}', there are #{servers.size} servers on it") + rescue Mongoid::Errors::DocumentNotFound + db_project.delete_environment(environment) + DevopsLogger.logger.info "Deploy environment '#{environment}' for project '#{id}' has been deleted" + end + + def update_project id + body = parser.update + db_project = project(id) + %w(description run_list project_users).each do |key| + db_project.send(key + "=", body[key]) if body.key? key + end + db_project.save! + DevopsLogger.logger.info "Project '#{id}' has been updated" + end + + def set_project_env_run_list id, environment + list = parser.run_list + project = Devops::Db.connector.project(id) + env = project.environment environment + Devops::Db.connector.set_project_env_run_list id, environment, list + "Updated environment '#{env.id}' with run_list '#{list.inspect}' in project '#{project.id}'" + end + + def delete_project id + db_project = project(id) + servers_cnt = Devops::Model::Server.where({'project' => id}).count + if servers_cnt != 0 + raise Devops::Exception::DependencyError.new "Deleting project #{id} is forbidden: Project has #{servers_cnt} server(s)" + else + db_project.delete + "Project '#{id}' has been deleted" + end + end + + def deploy_project_stream out, id + # check if project exist + project = Devops::Db.connector.project(id) + environment, servers = parser.deploy + keys = {} + dbserver = Devops::Db.connector.servers(id, environment, servers, true) + out << (dbservers.empty? ? "No reserved servers to deploy\n" : "Deploy servers: '#{dbservers.map{|s| s.name}.join("', '")}'\n") + status = [] + deploy_info_buf = {} + dbservers.each do |s| + begin + Devops::Db.connector.check_project_auth s.project, s.environment, parser.current_user + rescue InvalidPrivileges, Devops::Exception::RecordNotFound => e + out << e.message + "\n" + status.push 2 + next + end + environment_model = project.environment(s.environment) + deploy_info = if deploy_info_buf[s.environment] + deploy_info_buf[s.environment] + else + # мы не можем указать один build_number для всех окружений, поэтому nil + deploy_info_buf[s.environment] = project.deploy_info(environment_model, nil) + end + status.push(Devops::Executor::ServerExecutor.new(s, out, current_user: parser.current_user).deploy_server(deploy_info)) + end + status + end + + def deploy_project id + # check if project exist + project_model = Devops::Db.connector.project(id) + environment, servers = parser.deploy + files = [] + dbservers = Devops::Db.connector.servers(id, environment, servers, true) + #out << (dbservers.empty? ? "No reserved servers to deploy\n" : "Deploy servers: '#{dbservers.map{|s| s.name}.join("', '")}'\n") + deploy_info_buf = {} + dbservers.each do |s| + begin + Devops::Db.connector.check_project_auth s.project, s.environment, parser.current_user + rescue InvalidPrivileges, Devops::Exception::RecordNotFound => e + next + end + + environment_model = project_model.environment(s.environment) + deploy_info = if deploy_info_buf[s.environment] + deploy_info_buf[s.environment] + else + # мы не можем указать один build_number для всех окружений, поэтому nil + deploy_info_buf[s.environment] = project_model.deploy_info(environment_model, nil) + end + + jid = Worker.start_async(DeployWorker, + server_attrs: s.to_hash, + owner: parser.current_user, + tags: [], + deploy_info: deploy_info + ) + files.push jid + end + files + end + + def archive_project id + db_project = project(id) + Devops::Model::Project.where('_id' => id).set('archived' => true) + msg = "Project '#{id}' has been archived" + DevopsLogger.logger.info msg + msg + end + + def unarchive_project id + db_project = project(id) + Devops::Model::Project.where('_id' => id).unset('archived') + msg = "Project '#{id}' has been unarchived" + DevopsLogger.logger.info msg + msg + end + + def test_project id, environment + project = Devops::Db.connector.project(id) + env = project.environment environment + DevopsLogger.logger.info "Test project '#{project.id}' and environment '#{env.id}'" + if env.provider == ::Provider::Static::PROVIDER + msg = "Can not test environment with provider '#{::Provider::Static::PROVIDER}'" + Logger.warn msg + raise InvalidRecord.new(msg) + end + + jid = Worker.start_async(ProjectTestWorker, + project: project.id, + environment: env.id, + user: @request.env['REMOTE_USER'] + ) + + sleep 1 + return [jid] + end + + def delete_project_env_servers(project_id, env) + dry_run = parser.delete_project_env_servers + servers = project_env_servers project_id, env + info = {to_delete: servers.map(&:id)} + if !dry_run + info.merge!(delete_chosen_servers!(servers)) + end + info + end + + private + + def delete_chosen_servers!(servers) + deleted, failed = [], [] + servers.each do |server| + begin + Devops::Executor::ServerExecutor.new(server, '').delete_server + deleted << server.id + rescue + failed << server.id + end + end + {deleted: deleted, failed: failed} + end + + end + end + end +end + diff --git a/devops-service/app/api3/handlers/provider.rb b/devops-service/app/api3/handlers/provider.rb new file mode 100644 index 0000000..6a07064 --- /dev/null +++ b/devops-service/app/api3/handlers/provider.rb @@ -0,0 +1,86 @@ +require "app/api3/parsers/provider" +require_relative "request_handler" +require "commands/image" + +module Devops + module API3 + module Handler + class Provider < RequestHandler + + set_parser Devops::API3::Parser::ProviderParser + + extend ImageCommands + + def flavors provider, account + ::Provider.get_connector(provider, account).flavors + end + + def networks provider, account + p = ::Provider.get_connector(provider, account) + available_keys = ["vpc-id"] + p.networks_detail(@request.params.select{|k,v| available_keys.include?(k)}) + end + + def security_groups provider, account + available_keys = ["vpc-id"] + ::Provider.get_connector(provider, account).security_groups(@request.params.select{|k,v| available_keys.include?(k)}) + end + + def images provider, account + Provider.get_available_provider_images(provider, account) + end + + def available_providers + DevopsConfig.config[:providers] || DevopsConfig.config["providers"] || [] + end + + def providers + ::Provider.providers + end + + def accounts provider + provider_object = ::Provider.provider(provider) + provider_object.accounts + end + + def add_account provider + provider_object = ::Provider.provider(provider) + body = parser.account + body["provider"] = provider + account = provider_object.create_account(body) + account.save! + DevopsLogger.logger.info("Added #{provider} account '#{account.account_name}'") + provider_object.create_connector(DevopsConfig.config, account) + DevopsLogger.logger.info("Connector for provider '#{provider}' and account '#{account.account_name}' has been created") + account + rescue Mongoid::Errors::Validations => e + raise Devops::Exception::ValidationError.create_from_db_exception(e) + end + + def delete_account name, provider + provider_object = ::Provider.provider(provider) + account = provider_object.account(name) + provider_object.delete_connector(name) + DevopsLogger.logger.info("Connector for provider '#{provider}' and account '#{account.account_name}' has been removed") + + account_hash = account.to_hash + account.delete + DevopsLogger.logger.info("Removed #{provider} account '#{account.account_name}'") + account_hash + rescue Mongoid::Errors::DocumentNotFound + raise Devops::Exception::RecordNotFound.new("Account '#{name}' not found") + end + + def account_vpcs provider, name + provider_object = ::Provider.provider(provider) + account = provider_object.account(name) + p = ::Provider.get_connector(provider, name) + p.describe_vpcs + rescue Mongoid::Errors::DocumentNotFound + raise Devops::Exception::RecordNotFound.new("Account '#{name}' not found") + end + + end + end + end +end diff --git a/devops-service/app/api2/handlers/provider_notification.rb b/devops-service/app/api3/handlers/provider_notification.rb similarity index 61% rename from devops-service/app/api2/handlers/provider_notification.rb rename to devops-service/app/api3/handlers/provider_notification.rb index 27a786f..2675d7b 100644 --- a/devops-service/app/api2/handlers/provider_notification.rb +++ b/devops-service/app/api3/handlers/provider_notification.rb @@ -1,13 +1,16 @@ -require 'workers/stack_sync_worker' +require "lib/executors/server_executor" +require "app/api3/parsers/stack" +require 'db/mongo/models/stack/stack_factory' +require 'workers/stack_bootstrap_worker' require_relative "request_handler" module Devops - module API2_0 + module API3 module Handler - class ProviderNotification < RequestHandler + class Stack < RequestHandler def autoscaling_groups_change(group_id, provider_account) - provider = ::Provider::ProviderFactory.get('ec2', provider_account) + provider = ::Provider::ProviderFactory.get('aws', provider_account) stack_id = provider.stack_id_of_autoscaling_group(group_id) stack = ::Devops::Db.connector.stack_by_id(stack_id) jid = Worker.start_async(StackSyncWorker, stack_name: stack.name) @@ -19,4 +22,3 @@ module Devops end end end - diff --git a/devops-service/app/api3/handlers/request_handler.rb b/devops-service/app/api3/handlers/request_handler.rb new file mode 100644 index 0000000..1d8f13f --- /dev/null +++ b/devops-service/app/api3/handlers/request_handler.rb @@ -0,0 +1,90 @@ +require 'date' +require 'exceptions/parser_error' + +module Devops + module API3 + module Handler + class RequestHandler + + DATE_FORMAT = "%Y-%m-%d" + + class << self + def set_parser parser + define_method("parser") do + @request_parser ||= parser.new(@request) + end + end + end + + def initialize request + @request = request + end + + # supported options: + # sort_field: default 'created_at'. Could also be in [user, path, method, body, response_code, created_at]. + # sort_order: default 'asc'. Could also be 'desc' + def extract_sort_params_for_searching + filters = @request.params + sort = {} + sort[filters["sort_field"] || 'created_at'] = (filters["sort_order"] || 'asc') == 'asc' ? 1 : -1 + sort + end + + # supported options: + # date_from_l (format: unixtime) + # date_til_ll (format: unxitime) + # date_from (format: YYYY-MM-DD) + # date_till (format: YYYY-MM-DD) + def fill_date_params_for_searching search_query + filters = @request.params + from = begin + parse_date(filters["date_from"], filters["date_from_l"]) + rescue ArgumentError + raise Devops::Exception::ParserError.new("Invalid parameter 'date_from' or 'date_from_l'") + end + till = begin + parse_date(filters["date_till"], filters["date_till_l"]) + rescue ArgumentError + raise Devops::Exception::ParserError.new("Invalid parameter 'date_till' or 'date_till_l'") + end + from = {'$gte' => from.to_i} if from + till = {'$lt' => till.to_i} if till + if !from.nil? and !till.nil? + search_query["created_at"] = from.merge(till)#{'$and' => [from, till]} + elsif !from.nil? + search_query["created_at"] = from + elsif !till.nil? + search_query["created_at"] = till + end + end + + def extract_limit_params_for_searching _default=20 + filters = @request.params + unless filters["limit"].nil? + begin + buf = Integer(filters["limit"]) + return buf if buf >= 0 + rescue ArgumentError + end + end + _default + end + + private + def parse_date str, unix + if str + Date.strptime(str, DATE_FORMAT) + elsif unix + Integer(unix) + else + nil + end + end + + def owner_from_request + @request.env['REMOTE_USER'] + end + end + end + end +end diff --git a/devops-service/app/api3/handlers/roles.rb b/devops-service/app/api3/handlers/roles.rb new file mode 100644 index 0000000..f2abca7 --- /dev/null +++ b/devops-service/app/api3/handlers/roles.rb @@ -0,0 +1,60 @@ +require "db/mongo/models/role" +require "app/api3/parsers/roles" +require_relative "request_handler" + +module Devops + module API3 + module Handler + class Roles < RequestHandler + + set_parser Devops::API3::Parser::RolesParser + + def policies + Devops::Api3.policies.values + end + + def roles + Devops::Model::Role.all + end + + def role id + Devops::Model::Role.find(id) + rescue Mongoid::Errors::DocumentNotFound + raise Devops::Exception::RecordNotFound.new("Role with id '#{id}' not found") + end + + def create_role + Devops::Model::Role.create!(parser.create) + rescue Mongoid::Errors::Validations => e + raise Devops::Exception::ValidationError.create_from_db_exception(e) + end + + def add_policies role_id + list_to_add = parser.policies + db_role = role(role_id) + db_role.add_to_set({policies: list_to_add}) + end + + def delete_policies role_id + list_to_pull = parser.policies + db_role = role(role_id) + db_role.pull_all({policies: list_to_pull}) + end + + def delete_role id + role = role(id) + users = [] + Devops::Model::User.where(roles: id).each do |u| + users.push u.id + end + unless users.empty? + raise Devops::Exception::ConflictError.new("Role '#{role.name}' used with users '#{users.join("', '")}'") + end + role.delete + end + + end + end + end +end + diff --git a/devops-service/app/api3/handlers/script.rb b/devops-service/app/api3/handlers/script.rb new file mode 100644 index 0000000..adf4cd6 --- /dev/null +++ b/devops-service/app/api3/handlers/script.rb @@ -0,0 +1,83 @@ +require "fileutils" +require "commands/status" +require "app/api3/parsers/script" +require "lib/ssh/ssh_utils" +require_relative "request_handler" + +module Devops + module API3 + module Handler + class Script < RequestHandler + + set_parser Devops::API3::Parser::ScriptParser + + def scripts + res = [] + Dir.foreach(DevopsConfig.config[:scripts_dir]) {|f| res.push(f) unless f.start_with?(".")} + end + + def execute_command out, server_id + cmd = parse.body + s = begin + Devops::Model::Server.find(server_id) + rescue Mongoid::Errors::DocumentNotFound + raise Devops::Exception::RecordNotFound.new("Server '#{id}' not found") + end + Devops::Model::Project.check_user_authorization(s.project, s.environment, parser.current_user) + cert = begin + Devops::Model::Key.find(s.ssh_key) + rescue Mongoid::Errors::DocumentNotFound + raise Devops::Exception::RecordNotFound.new("SSH key '#{s.ssh_key}' not found") + end + Devops::SSH::Utils.run_command_out(cmd, s.public_ip || s.private_ip, s.remote_user, cert.path, out) + end + + def run_script out, script_name + nodes, script_params = parser.run_script + file = File.join(DevopsConfig.config[:scripts_dir], script_name) + unless File.exists?(file) + out << "File '#{script_name}' does not exist\n" + return + end + servers = ::Devops::Model::Server.where('id.in' => nodes) + if servers.empty? + out << "No servers found for ids '#{nodes.join("', '")}'\n" + return + end + user = parser.current_user + servers.each do |s| + Devops::Model::Project.check_user_authorization(s.project, s.environment, user) + end + status = [] + servers.each do |s| + cert = begin + Devops::Model::Key.find(s.ssh_key) + rescue Mongoid::Errors::DocumentNotFound + out.puts "No SSH key found for '#{s.id}'" + out.flush + status.push 2 + next + end + out.puts "\nRun script on '#{s.id}'" + status.push(Devops::SSH::Utils.run_script(file, s.public_ip || s.private_ip, s.remote_user, cert.path, out)) + end + status + end + + def create_script file_name + file = File.join(DevopsConfig.config[:scripts_dir], file_name) + raise Devops::Exception::ConflictError.new("File '#{file_name}' already exist") if File.exists?(file) + File.open(file, "w") {|f| f.write(parser.body)} + end + + def delete_script file_name + file = File.join(DevopsConfig.config[:scripts_dir], file_name) + raise Devops::Exception::RecordNotFound.new("File '#{file_name}' does not exist") unless File.exists?(file) + FileUtils.rm(file) + end + + end + end + end +end + diff --git a/devops-service/app/api3/handlers/server.rb b/devops-service/app/api3/handlers/server.rb new file mode 100644 index 0000000..f745bed --- /dev/null +++ b/devops-service/app/api3/handlers/server.rb @@ -0,0 +1,390 @@ +require "uri" + +require "commands/status" +require "commands/bootstrap_templates" +require 'exceptions/conflict_exception' +require "lib/executors/server_executor" + +require "db/mongo/models/server" + +require "workers/create_server_worker" +require "workers/delete_server_worker" +require "workers/bootstrap_worker" +require "workers/unbootstrap_worker" +require "app/api3/parsers/server" +require_relative "request_handler" + +module Devops + module API3 + module Handler + class Server < RequestHandler + + set_parser Devops::API3::Parser::ServerParser + + extend StatusCommands + extend BootstrapTemplatesCommands + + def servers + Devops::Model::Server.where(parser.servers).all + end + + def provider_servers provider + provider_servers_with_account provider, nil + end + + def provider_servers_with_account provider, account + ::Provider.get_connector(provider, account).servers + end + + def server id + Devops::Model::Server.find(id) + rescue Mongoid::Errors::DocumentNotFound + raise Devops::Exception::RecordNotFound.new("Server '#{id}' not found") + end + + # ids - array of servers ids + # returns array of jid + def delete ids + user = parser.current_user + jids = [] + ids.each do |id| + DevopsLogger.logger.debug("Trying to delete server '#{id}'") + begin + s = server(id) + Devops::Model::Project.check_user_authorization(s.project, s.environment, user) + jid = Worker.start_async(DeleteServerWorker, + server_id: s.id, + user: user + ) + jids << jid + rescue Devops::Exception::RecordNotFound, Devops::Exception::Unauthorized => e + DevopsLogger.logger.warn(e.message) + end + end + jids + end + + def server_id_by_name name + s = Devops::Model::Server.find_by(name: name) + s.id + rescue Mongoid::Errors::DocumentNotFound + raise Devops::Exception::RecordNotFound.new("Server with name '#{name}' not found") + end + + # ids - array of servers ids + def delete_stream ids, out + user = parser.current_user + ids.each do |id| + begin + s = server(id) + ### Authorization + Devops::Model::Project.check_user_authorization(s.project, s.environment, user) + Devops::Executor::ServerExecutor.new(s, out).delete_server + rescue Devops::Exception::RecordNotFound + out.puts "Server '#{id}' not found" + rescue Devops::Exception::Unauthorized + out.puts "User '#{user}' can not delete server '#{id}'" + end + end + end + + def create_server_stream out + status = [] + prepare_create_server do |project, env, user, body| + e = Devops::Executor::ServerExecutor.new(nil, out) + e.project = project + e.environment = env + body["created_by"] = user + res = e.create_server(body) + status.push res + end + status + end + + def create_server + body = parser.create + user = parser.current_user + + check_if_server_attrs_are_valid(body, user) + jid = Worker.start_async(CreateServerWorker, + server_attrs: body, + owner: user + ) + [jid] + end + + def deploy id + call_deploy(id) do |options| + [ Worker.start_async(DeployWorker, options) ] + end + end + + def call_stream out + yield + rescue Devops::Exception::RecordNotFound => e + out << e.message + NOT_FOUND + rescue Devops::Exception::ConflictError => e + out << e.message + CONFLICT + rescue Devops::Exception::Unauthorized => e + out << e.message + UNAUTHORIZED + end + + def deploy_stream id, out + call_stream(out) do + call_deploy(id) do |options| + Worker.start_sync(DeployWorker, options, out) + end + end + end + + def call_deploy id + body = parser.deploy + tags = body["tags"] || [] + run_list = body["run_list"] + owner = parser.current_user + s = server(id) + project = Devops::Model::Project.check_user_authorization(s.project, s.environment, owner) + deploy_info = create_deploy_info(s, project, body["build_number"]) + deploy_info["run_list"] = run_list if run_list + + yield({ + server_id: id, + owner: owner, + tags: tags, + deploy_info: deploy_info + }) + end + + def create_deploy_info server, project, build_number + env_model = project.environment(server.environment) + project.deploy_info(env_model, build_number) + end + + def pause_server id + s = Devops::Model::Server.find(id) + ## Authorization + Devops::Model::Project.check_user_authorization(s.project, s.environment, parser.current_user) + provider = s.provider_instance + r = provider.pause_server s + if r.nil? + set_last_operation_and_save(s, Devops::Model::Server::OperationType::PAUSE) + "Server with instance ID '#{s.id}' has been paused" + else + raise Devops::Exception::ConflictError.new("Server with instance ID '#{s.id}' can not be paused, It in state '#{r}'") + end + end + + def unpause_server id + s = Devops::Model::Server.find(id) + ## Authorization + Devops::Model::Project.check_user_authorization(s.project, s.environment, parser.current_user) + provider = s.provider_instance + r = provider.unpause_server s + if r.nil? + set_last_operation_and_save(s, Devops::Model::Server::OperationType::UNPAUSE) + "Server with instance ID '#{s.id}' has been unpaused" + else + raise Devops::Exception::ConflictError.new("Server with instance ID '#{s.id}' can not be unpaused, It in state '#{r}'") + end + end + + def reserve_server id + s = Devops::Model::Server.find(id) + user = parser.current_user + Devops::Model::Project.check_user_authorization(s.project, s.environment, user) + raise Devops::Exception::ConflictError.new("Server '#{id}' already reserved") unless s.reserved_by.nil? + s.reserved_by = user + set_last_operation_and_save(s, Devops::Model::Server::OperationType::RESERVE) + end + + def unreserve_server id + s = Devops::Model::Server.find(id) + user = parser.current_user + Devops::Model::Project.check_user_authorization(s.project, s.environment, user) + raise Devops::Exception::ConflictError.new("Server '#{id}' is not reserved") if s.reserved_by.nil? + s.reserved_by = nil + set_last_operation_and_save(s, Devops::Model::Server::OperationType::UNRESERVE) + end + + # TODO: check bootstrap template name + def bootstrap_server_stream id, out + call_stream(out) do + call_bootstrap(id) do |options| + Worker.start_sync(BootstrapWorker, options, out) + end + end + end + + def bootstrap_server(id) + call_bootstrap(id) do |options| + Worker.start_async(BootstrapWorker, options) + end + end + + def call_bootstrap id + body = parser.bootstrap + name = body["cm_name"] + rl = body["run_list"] + t = body["bootstrap_template"] + s = server(id) + + user = parser.current_user + p = Devops::Model::Project.check_user_authorization(s.project, s.environment, user) + raise Devops::Exception::ConflictError.new("Server '#{id}' already bootstrapped") unless s.cm_name.nil? + attrs = { + server_id: id, + owner: user + } + + d = p.environment(s.environment) + + provider = s.provider_instance + + if name + d.get_category(s.category).cm_tool.check_node_name(name) + attrs[:cm_name] = name + end + unless t.nil? + templates = get_templates + raise ValidationError.new("Invalid bootstrap template '#{t}', available values: #{templates.join(", ")}") unless templates.include?(t) + attrs[:bootstrap_template] = t + end + attrs[:run_list] = rl if rl + + yield(attrs) + end + + def unbootstrap_server id + call_unbootstrap(id) do |options| + Worker.start_async(UnbootstrapWorker, options) + end + end + + def unbootstrap_server_stream id, out + call_stream(out) do + call_unbootstrap(id) do |options| + Worker.start_sync(UnbootstrapWorker, options) + end + end + end + + def call_unbootstrap id + s = server(id) + user = parser.current_user + ### Authorization + Devops::Model::Project.check_user_authorization(s.project, s.environment, user) + raise Devops::Exception::ConflictError.new("Server '#{id}' is not bootstrapped") if s.cm_name.nil? + attrs = { + server_id: id, + owner: parser.current_user + } + yield(attrs) + end + + def add_server + body = parser.add_server + user = parser.current_user + project = Devops::Model::Project.check_user_authorization(body[:project], body[:environment], user) + env = project.environment(body[:environment]) + category = env.get_category!(body[:category]) + raise 'Provider should be static' if category.provider.name != 'static' + provider_account = Model::ProviderAccount.find(category.provider.account) + provider = ::Provider.provider('static') + Devops::Model::Server.create!( + "provider" => provider.name, + "provider_account" => provider_account.id, + "project" => project.id, + "environment" => env.id, + "category" => category.id, + "remote_user" => body[:remote_user], + "private_ip" => body[:private_ip], + "public_ip" => body[:public_ip], + "id" => "static_#{provider_account.ssh_key}-#{Time.now.to_i}", + "ssh_key" => provider_account.ssh_key, + 'created_by' => user, + 'cm_name' => nil, + 'name' => body[:name] + ) + end + + def set_tags id + tags = parser.tags + prepare_tags(id) do |provider| + provider.set_tags id, tags + end + end + + def unset_tags id + tags = parser.tags + prepare_tags(id) do |provider| + provider.unset_tags id, tags + end + end + + def prepare_tags id + s = Devops::Model::Server.find(id) + p = Devops::Model::Project.check_user_authorization(s.project, s.environment, parser.current_user) + provider = s.provider_instance + yield provider + end + + def set_run_list id + s = Devops::Model::Server.find(id) + Devops::Model::Project.check_user_authorization(s.project, s.environment, parser.current_user) + s.set(run_list: parser.run_list) + end + + private + + def check_if_server_attrs_are_valid(body, user) + if body["project"].nil? or body["environment"].nil? or body["category"].nil? + raise Devops::Exception::ValidationError.new("Properties 'project', 'environment' and 'category' are mandatory") + end + + key_name = body["ssh_key"] + unless key_name.nil? + begin + Devops::Model::Key.find(key_name) + rescue Mongoid::Errors::DocumentNotFound + raise Devops::Exception::ValidationError.new("Key with id '#{key_name}' not found") + end + end + + project = Devops::Model::Project.check_user_authorization(body["project"], body["environment"], user) + env = project.environment(body["environment"]) + category = env.get_category(body["category"]) + if body["name"] + begin + Devops::Model::Server.find_by(name: body["name"]) + raise Devops::Exception::ValidationError.new("Server with name '#{body["name"]}' already exists" ) + rescue Mongoid::Errors::DocumentNotFound + category.provider.provider_instance.check_node_name(body["name"]) + category.cm_tool.check_node_name(body["name"]) + end + end + +=begin + provider = env.provider_instance + server_name = body["name"] + check_chef_node_name(server_name, provider, KnifeFactory.instance) unless server_name.nil? + groups = body["groups"] + unless groups.nil? + buf = groups - provider.groups.keys + halt_response("Invalid security groups '#{buf.join("', '")}' for provider '#{provider.name}'") if buf.empty? + end +=end + end + + def set_last_operation_and_save(server, operation_type) + server.set_last_operation(operation_type, parser.current_user, nil) + server.save + end + + end + end + end +end + diff --git a/devops-service/app/api2/handlers/stack.rb b/devops-service/app/api3/handlers/stack.rb similarity index 76% rename from devops-service/app/api2/handlers/stack.rb rename to devops-service/app/api3/handlers/stack.rb index d22eae5..7472150 100644 --- a/devops-service/app/api2/handlers/stack.rb +++ b/devops-service/app/api3/handlers/stack.rb @@ -1,51 +1,53 @@ require "lib/executors/server_executor" +require "app/api3/parsers/stack" require 'db/mongo/models/stack/stack_factory' -require "app/api2/parsers/stack" require 'workers/stack_bootstrap_worker' require_relative "request_handler" module Devops - module API2_0 + module API3 module Handler class Stack < RequestHandler - set_parser Devops::API2_0::Parser::StackParser + set_parser Devops::API3::Parser::StackParser def stacks - Devops::Db.connector.stacks + Model::StackAws.all end + # We support only aws, actually def stacks_for_provider provider - Devops::Db.connector.stacks(provider: provider) + Model::StackAws.all end def create_stack - stack_attrs = parser.create - project = Devops::Db.connector.project(stack_attrs['project']) - env = project.deploy_env(stack_attrs['deploy_env']) - raise InvalidRecord.new("Environment '#{env.identifier}' of project '#{project.id}' has no stack template") if env.stack_template.nil? - add_stack_attributes(stack_attrs, env, parser) - - jid = Worker.start_async(StackBootstrapWorker, stack_attributes: stack_attrs) + object = parser.create + attrs = object['stack_attributes'] + env, category = fetch_env_and_category(attrs) + fill_attributes_from_category(attrs, env, category) + jid = Worker.start_async(StackBootstrapWorker, + stack_attributes: attrs, + without_bootstrap: object['without_bootstrap'], + skip_rollback: object['skip_rollback'] + ) [jid] end - def stack id - Devops::Db.connector.stack(id) + def stack name + Model::StackAws.where(name: name).first end def delete_stack name stack = self.stack(name) stack.delete_stack_in_cloud! - Devops::Db.connector.stack_servers_delete(stack.name) - Devops::Db.connector.stack_delete(stack.id) + Model::Server.where(stack: stack.id).delete_all + stack.delete end def sync id stack = self.stack(id) stack.sync_status_and_events! Devops::Db.connector.stack_update(stack) - # do not remove syncing status and events, just add stack sync worker here. stack end @@ -118,10 +120,10 @@ module Devops "created_by" => owner, "project" => s.project, "deploy_env" => s.deploy_env, - "type" => Report::DEPLOY_TYPE, + "type" => JobTask::DEPLOY_TYPE, "status" => Worker::STATUS::FAILED } - Devops::Db.connector.save_report(Report.new(o)) + JobTask.create(o) end files.push jid end @@ -199,11 +201,25 @@ module Devops private - def add_stack_attributes(stack_attrs, env, parser) - stack_attrs['stack_template'] = env.stack_template + # env is used in devops-nibr + def fill_attributes_from_category(stack_attrs, env, category) + stack_attrs['stack_template'] = category.provider.stack_template stack_attrs['owner'] = parser.current_user - stack_attrs['provider'] = env.provider - stack_attrs['provider_account'] = env.provider_account + stack_attrs['provider'] = category.provider.name + stack_attrs['provider_account'] = category.provider.account + end + + def fetch_env_and_category(attrs) + project = Model::Project.find_with_category(*attrs.values_at('project', 'environment', 'category')) + unless project + raise InvalidRecord.new("Project '#{attrs['project']}' has no env '#{attrs['environment']}' or category '#{attrs['category']}") + end + env = project.environment(attrs['environment']) + category = env.get_category!(attrs['category']) + if category.provider.type != Model::CategoryProvider::STACK_TYPE + raise InvalidRecord.new("Category '#{category.id}' type isn't 'stack'") + end + [env, category] end end diff --git a/devops-service/app/api3/handlers/stack_template.rb b/devops-service/app/api3/handlers/stack_template.rb new file mode 100644 index 0000000..67f2a2e --- /dev/null +++ b/devops-service/app/api3/handlers/stack_template.rb @@ -0,0 +1,65 @@ +require 'db/mongo/models/stack_template/stack_template_factory' +require 'app/api3/parsers/stack_template' +require_relative "request_handler" +require 'exceptions/conflict_exception' + +module Devops + module API3 + module Handler + class StackTemplate < RequestHandler + + set_parser Devops::API3::Parser::StackTemplateParser + + def stack_templates + # we just need to build json from attributes hash, so there is no need + # to build appropriate (not Base) class + Model::StackTemplateBase.all + end + + def stack_templates_for_provider provider + Model::StackTemplateBase.where(provider: provider) + end + + def create_stack_template provider + template_model = Model::StackTemplateFactory.create(provider, parser.create) + template_model.owner = parser.current_user + template_model.save + template_model + end + + def get_stack_template id + Model::StackTemplateBase.find(id) + end + + def delete_stack_template id + envs_with_this_template = envs_using_stack_template(id) + + if envs_with_this_template.empty? + Devops::Model::StackTemplateBase.find(id).delete + else + raise Exception::ConflictError.new("Stack template '#{id}' is already in use in #{envs_with_this_template.map{|project, envs| "#{project}: #{envs.join(', ')}"}.join('; ')}") + end + end + + private + + # returns: + # { "project" => ["environment"] } + def envs_using_stack_template(stack_template_id) + Devops::Model::Project.all.inject({}) do |usages, project| + envs_with_this_template = project.environments.select do |env| + stack_categories = env.categories.select {|t| t.provider.type == Model::CategoryProvider::STACK_TYPE} + used_templates = stack_categories.map {|c| c.provider.stack_template} + used_templates.include?(stack_template_id) + end + next usages if envs_with_this_template.empty? + + usages[project.id] = envs_with_this_template.map(&:id) + usages + end + end + + end + end + end +end diff --git a/devops-service/app/api3/handlers/statistic.rb b/devops-service/app/api3/handlers/statistic.rb new file mode 100644 index 0000000..c341813 --- /dev/null +++ b/devops-service/app/api3/handlers/statistic.rb @@ -0,0 +1,42 @@ +require 'db/mongo/models/statistic' +require_relative "request_handler" + +module Devops + module API3 + module Handler + class Statistic < RequestHandler + + # supported options: + # user + # response_code (format: 200) + # method + # path + # path_contains + # date_from (format: timestamp) + # date_till (format: timestamp) + # limit: default 20. Zero value is equal to no limit. + # sort_field: default 'created_at'. Could also be in [user, path, method, body, response_code, created_at]. + # sort_order: default 'asc'. Could also be 'desc' + def statistic + filters = @request.params + limit =extract_limit_params_for_searching(20) + sort = extract_sort_params_for_searching + query = {} + %w(user method path).each do |key| + val = filters[key] + query[key] = val if val + end + + query["response_code"] = filters["response_code"].to_i if filters["response_code"] + query["path"] = Regexp.new(filters["path_contains"], 'i') if filters["path_contains"] + + fill_date_params_for_searching(query) + + Devops::Model::Statistic.where(query).sort(sort).limit(limit) + end + + end + end + end +end + diff --git a/devops-service/app/api3/handlers/user.rb b/devops-service/app/api3/handlers/user.rb new file mode 100644 index 0000000..6043510 --- /dev/null +++ b/devops-service/app/api3/handlers/user.rb @@ -0,0 +1,68 @@ +require "db/mongo/models/user" +require "app/api3/parsers/user" +require_relative "request_handler" + +module Devops + module API3 + module Handler + class User < RequestHandler + + set_parser Devops::API3::Parser::UserParser + + def users + Devops::Model::User.all + end + + def create + Devops::Model::User.create! parser.create + end + + def get_user id + Devops::Model::User.find(id) + rescue Mongoid::Errors::DocumentNotFound + raise Devops::Exception::RecordNotFound.new("User with id '#{id}' not found") + end + + def delete user_id + user = get_user(user_id) + projects = Devops::Model::Project.find({'environments.users' => user_id}) + str = "" + projects.each do |p| + p.environments.each do |e| + str+="#{p.id}.#{e.id} " if e.users.include? user_id + end + end + raise Devops::Exception::ConflictError.new "Deleting is forbidden: User is included in #{str}" + rescue Mongoid::Errors::DocumentNotFound + user.delete + end + + def add_roles id + user = get_user(id) + user.add_to_set({roles: parser.roles}) + end + + def delete_roles id + user = get_user(id) + user.pull_all({roles: parser.roles}) + end + + def change user_id, action + user = get_user(user_id) + user.send action + "=", parser.change(action) + user.save! + end + + def update_user id + user = get_user(id) + obj = parser.update_user + %w(email password roles).each do |key| + user.send(key + "=", obj[key]) if obj.key?(key) + end + user.save! + end + end + end + end +end + diff --git a/devops-service/app/api2/helpers/parser.rb b/devops-service/app/api3/helpers/parser.rb similarity index 68% rename from devops-service/app/api2/helpers/parser.rb rename to devops-service/app/api3/helpers/parser.rb index dc5b4d3..9811f26 100644 --- a/devops-service/app/api2/helpers/parser.rb +++ b/devops-service/app/api3/helpers/parser.rb @@ -3,7 +3,7 @@ require "exceptions/parser_error" require "exceptions/validation_error" module Devops - module API2_0 + module API3 module ParserHelpers def create_object_from_json_body type=Hash, empty_body=false @@ -13,15 +13,15 @@ module Devops ::JSON.parse(json) rescue ::JSON::ParserError => e DevopsLogger.logger.error e.message - raise Devops::ParserError.new("Invalid JSON: #{e.message}") + raise Devops::Exception::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) + raise Devops::Exception::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) + list = ::Provider.providers + raise Devops::Exception::ValidationError.new("Invalid provider '#{provider}', available providers: '#{list.join("', '")}'") unless list.include?(provider) end def check_string val, msg, _nil=false, empty=false @@ -38,7 +38,7 @@ module Devops 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.each {|v| raise Devops::Exception::ValidationError.new(msg) unless v.is_a?(vals_type)} unless val.nil? val end @@ -47,7 +47,7 @@ module Devops 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) + raise Devops::Exception::ValidationError.new(msg, json_resp) =begin if json_resp halt_response(msg) @@ -64,14 +64,14 @@ module Devops if _nil return val else - raise Devops::ValidationError.new(msg) + raise Devops::Exception::ParserError.new(msg) end end if val.is_a?(type) - raise Devops::ValidationError.new(msg) if !empty && val.empty? + raise Devops::Exception::ParserError.new(msg) if !empty && val.empty? val else - raise Devops::ValidationError.new(msg) + raise Devops::Exception::ParserError.new(msg) end end diff --git a/devops-service/app/api2/helpers/version_2.rb b/devops-service/app/api3/helpers/query.rb similarity index 60% rename from devops-service/app/api2/helpers/version_2.rb rename to devops-service/app/api3/helpers/query.rb index 2e4ce94..1829a11 100644 --- a/devops-service/app/api2/helpers/version_2.rb +++ b/devops-service/app/api3/helpers/query.rb @@ -1,11 +1,10 @@ require "json" require 'sinatra/base' require "sinatra/json" - -require "providers/provider_factory" +require "db/mongo/models/statistic" module Devops - module API2_0 + module API3 module Helpers include Sinatra::JSON @@ -23,19 +22,25 @@ module Devops halt(rstatus, json(obj)) end - def check_privileges cmd, p - user = request.env['USER'] - user.check_privileges(cmd, p) + def check_provider provider + list = ::Provider.providers + halt_response("Invalid provider '#{provider}', available providers: '#{list.join("', '")}'", 400) unless list.include?(provider) end - def check_provider provider - list = ::Provider::ProviderFactory.providers - halt_response("Invalid provider '#{provider}', available providers: '#{list.join("', '")}'", 400) unless list.include?(provider) + def check_provider_account provider, account + halt_response("Provider acount '#{account}' not found", 400) if ::Provider.get_connector(provider, account).nil? + end + + def check_policy policy + return unless policy + user = request.env['USER'] + user.check_policy(policy) end # Save information about requests with methods POST, PUT, DELETE def insert_statistic msg=nil unless request.get? + return if response.status == 401 and request.env['REMOTE_USER'].nil? # parse body request.body.rewind raw_body = request.body.read @@ -45,8 +50,13 @@ module Devops raw_body end - # store statistic - settings.mongo.insert_statistic request.env['REMOTE_USER'], request.path, request.request_method, body, response.status + Devops::Model::Statistic.create({ + user: request.env['REMOTE_USER'], + path: request.path, + method: request.request_method, + body: body, + response_code: response.status + }) end end diff --git a/devops-service/app/api2/parsers/tag.rb b/devops-service/app/api3/parsers/chef.rb similarity index 82% rename from devops-service/app/api2/parsers/tag.rb rename to devops-service/app/api3/parsers/chef.rb index 2ed6d03..4b04195 100644 --- a/devops-service/app/api2/parsers/tag.rb +++ b/devops-service/app/api3/parsers/chef.rb @@ -1,9 +1,9 @@ require_relative "request_parser" module Devops - module API2_0 + module API3 module Parser - class TagParser < RequestParser + class ChefParser < RequestParser def tags tags = create_object_from_json_body(Array) @@ -14,4 +14,3 @@ module Devops end end end - diff --git a/devops-service/app/api2/parsers/bootstrap_template.rb b/devops-service/app/api3/parsers/deploy.rb similarity index 58% rename from devops-service/app/api2/parsers/bootstrap_template.rb rename to devops-service/app/api3/parsers/deploy.rb index 78ef743..f6a912f 100644 --- a/devops-service/app/api2/parsers/bootstrap_template.rb +++ b/devops-service/app/api3/parsers/deploy.rb @@ -1,9 +1,9 @@ require_relative "request_parser" module Devops - module API2_0 + module API3 module Parser - class BootstrapTemplateParser < RequestParser + class DeployParser < RequestParser end end diff --git a/devops-service/app/api2/parsers/filter.rb b/devops-service/app/api3/parsers/filter.rb similarity index 95% rename from devops-service/app/api2/parsers/filter.rb rename to devops-service/app/api3/parsers/filter.rb index 5752dab..3f1251c 100644 --- a/devops-service/app/api2/parsers/filter.rb +++ b/devops-service/app/api3/parsers/filter.rb @@ -1,7 +1,7 @@ require_relative "request_parser" module Devops - module API2_0 + module API3 module Parser class FilterParser < RequestParser diff --git a/devops-service/app/api2/parsers/image.rb b/devops-service/app/api3/parsers/image.rb similarity index 87% rename from devops-service/app/api2/parsers/image.rb rename to devops-service/app/api3/parsers/image.rb index 4e5c348..1238204 100644 --- a/devops-service/app/api2/parsers/image.rb +++ b/devops-service/app/api3/parsers/image.rb @@ -1,13 +1,12 @@ require_relative "request_parser" module Devops - module API2_0 + module API3 module Parser class ImageParser < RequestParser def images provider = @params["provider"] - puts "Provider: #{provider}" check_provider(provider) if provider provider end diff --git a/devops-service/app/api2/parsers/key.rb b/devops-service/app/api3/parsers/key.rb similarity index 97% rename from devops-service/app/api2/parsers/key.rb rename to devops-service/app/api3/parsers/key.rb index fcf1db2..3d58514 100644 --- a/devops-service/app/api2/parsers/key.rb +++ b/devops-service/app/api3/parsers/key.rb @@ -1,7 +1,7 @@ require_relative "request_parser" module Devops - module API2_0 + module API3 module Parser class KeyParser < RequestParser diff --git a/devops-service/app/api2/parsers/project.rb b/devops-service/app/api3/parsers/project.rb similarity index 61% rename from devops-service/app/api2/parsers/project.rb rename to devops-service/app/api3/parsers/project.rb index 5dbd78f..0b877e5 100644 --- a/devops-service/app/api2/parsers/project.rb +++ b/devops-service/app/api3/parsers/project.rb @@ -1,17 +1,16 @@ -require "app/api2/helpers/version_2" require_relative "request_parser" module Devops - module API2_0 + module API3 module Parser class ProjectParser < RequestParser - include Devops::API2_0::Helpers + include Devops::API3::Helpers def projects fields = [] if @params.key?("fields") and @params["fields"].is_a?(Array) - Devops::Model::Project.fields.each do |k| + Devops::Model::Project.list_fields.each do |k| fields.push k if @params["fields"].include?(k) end end @@ -23,20 +22,27 @@ module Devops end def project_servers - @params["deploy_env"] + @params["environment"] end def project_stacks - @params["deploy_env"] + @params["environment"] end def create_project 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) - rl = check_array(body["run_list"], "Parameter 'run_list' should be an array of string", String, true, true) - Validators::Helpers::RunList.new(rl).validate! unless rl.nil? - Devops::Model::Project.new(body) + project = Devops::Model::Project.new(body) + #project.validate! + project + end + + def users + create_object_from_json_body(Array) + end + + def set_description + body = create_object_from_json_body + body["description"] end def set_project_components @@ -45,64 +51,70 @@ module Devops c end - def add_deploy_env + def add_environment body = create_object_from_json_body - Devops::Model::DeployEnvFactory.create(body) + Devops::Model::Environment.new(body) end - def update_deploy_env_field + def update_environment_field body = create_object_from_json_body raise InvalidRecord.new("'value' key not found") if body["value"].nil? body["value"] end - def update_deploy_env + def update_environment body = create_object_from_json_body # rl = check_array(body["run_list"], "Parameter 'run_list' should be an array of string", String, false, true) # Validators::Helpers::RunList.new(rl).validate! - Devops::Model::DeployEnvFactory.create(body) + Devops::Model::EnvironmentFactory.create(body) end def update body = create_object_from_json_body +=begin check_string(body["description"], "Parameter 'description' must be a string", true, true) rl = check_array(body["run_list"], "Parameter 'run_list' must be an array of string", String, true, true) Validators::Helpers::RunList.new(rl).validate! unless rl.nil? #Devops::Model::Project.new(body) +=end body end + def add_category + Devops::Model::Category.new(create_object_from_json_body) + end + def delete 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) + environment = unless body.nil? + check_string(body["environment"], "Parameter 'environment' should be a not empty string", true) end end def project_users body = create_object_from_json_body users = check_array(body["users"], "Parameter 'users' must be a not empty array of strings") - deploy_env = check_string(body["deploy_env"], "Parameter 'deploy_env' must be a not empty string", true) - return deploy_env, users + environment = check_string(body["environment"], "Parameter 'environment' must be a not empty string", true) + return environment, users end def run_list list = create_object_from_json_body(Array) - check_array(list, "Body must contains not empty array of strings") + RunListArrayValidator.validate_list(list) + list end def deploy obj = create_object_from_json_body - deploy_env = check_string(obj["deploy_env"], "Parameter 'deploy_env' should be a not empty string", true) + environment = check_string(obj["environment"], "Parameter 'environment' should be a not empty string", true) servers = check_array(obj["servers"], "Parameter 'servers' should be a not empty array of strings", String, true) - return deploy_env, servers + return environment, servers end - def delete_project_servers + def delete_project_env_servers body = create_object_from_json_body dry_run = check_boolean(body["dry_run"], "Parameter 'dry_run' must be a boolean") - deploy_env = check_string(body["deploy_env"], "Parameter 'deploy_env' must be a not empty string", true) - [deploy_env, dry_run] + dry_run end end end diff --git a/devops-service/app/api2/parsers/provider.rb b/devops-service/app/api3/parsers/provider.rb similarity index 92% rename from devops-service/app/api2/parsers/provider.rb rename to devops-service/app/api3/parsers/provider.rb index 38d3670..1638b6f 100644 --- a/devops-service/app/api2/parsers/provider.rb +++ b/devops-service/app/api3/parsers/provider.rb @@ -1,7 +1,7 @@ require_relative "request_parser" module Devops - module API2_0 + module API3 module Parser class ProviderParser < RequestParser diff --git a/devops-service/app/api2/parsers/request_parser.rb b/devops-service/app/api3/parsers/request_parser.rb similarity index 79% rename from devops-service/app/api2/parsers/request_parser.rb rename to devops-service/app/api3/parsers/request_parser.rb index 621a69f..046b749 100644 --- a/devops-service/app/api2/parsers/request_parser.rb +++ b/devops-service/app/api3/parsers/request_parser.rb @@ -1,11 +1,11 @@ -require "app/api2/helpers/parser" +require "app/api3/helpers/parser" module Devops - module API2_0 + module API3 module Parser class RequestParser - include Devops::API2_0::ParserHelpers + include Devops::API3::ParserHelpers def initialize request @request = request diff --git a/devops-service/app/api3/parsers/roles.rb b/devops-service/app/api3/parsers/roles.rb new file mode 100644 index 0000000..89adcf1 --- /dev/null +++ b/devops-service/app/api3/parsers/roles.rb @@ -0,0 +1,22 @@ +require_relative "request_parser" + +module Devops + module API3 + module Parser + class RolesParser < RequestParser + + def create + create_object_from_json_body + end + + def policies + policies = create_object_from_json_body(Array) + res = Role.check_policies(policies) + raise Devops::Exception::ValidationError.new(res) unless res.nil? + policies + end + end + end + end +end + diff --git a/devops-service/app/api2/parsers/script.rb b/devops-service/app/api3/parsers/script.rb similarity index 77% rename from devops-service/app/api2/parsers/script.rb rename to devops-service/app/api3/parsers/script.rb index a495f02..e610f3a 100644 --- a/devops-service/app/api2/parsers/script.rb +++ b/devops-service/app/api3/parsers/script.rb @@ -1,12 +1,12 @@ require_relative "request_parser" module Devops - module API2_0 + module API3 module Parser class ScriptParser < RequestParser - def execute_command - @request.body.read + def body + @body ||= @request.body.read end def run_script @@ -16,10 +16,6 @@ module Devops return nodes, p end - def create_script - @request.body.read - end - end end end diff --git a/devops-service/app/api2/parsers/security_groups.rb b/devops-service/app/api3/parsers/security_groups.rb similarity index 100% rename from devops-service/app/api2/parsers/security_groups.rb rename to devops-service/app/api3/parsers/security_groups.rb diff --git a/devops-service/app/api2/parsers/server.rb b/devops-service/app/api3/parsers/server.rb similarity index 72% rename from devops-service/app/api2/parsers/server.rb rename to devops-service/app/api3/parsers/server.rb index 6675554..ee1ce87 100644 --- a/devops-service/app/api2/parsers/server.rb +++ b/devops-service/app/api3/parsers/server.rb @@ -1,34 +1,38 @@ require_relative "request_parser" module Devops - module API2_0 + module API3 module Parser class ServerParser < RequestParser def servers - (@params.key?("reserved") ? true : nil) + q = {} + if @params.key?("reserved") + q[:reserved] = true if @params["reserved"] == "true" + end + if @params.key?("provider") + q[:provider] = @params["provider"] + end + q end def server @params[:key] || @params["key"] end - def instance_key - @body ||= create_object_from_json_body(Hash, true) - (@body.nil? ? nil : @body["key"]) - end - + # TODO: skip_rollback flag def create @body ||= create_object_from_json_body project_name = check_string(@body["project"], "Parameter 'project' must be a not empty string") - env_name = check_string(@body["deploy_env"], "Parameter 'deploy_env' must be a not empty string") + env_name = check_string(@body["environment"], "Parameter 'environment' must be a not empty string") + category = check_string(@body["category"], "Parameter 'category' must be a not empty string") server_name = check_string(@body["name"], "Parameter 'name' should be null or not empty string", true) without_bootstrap = @body["without_bootstrap"] force = @body["force"] raise InvalidRecord.new("Parameter 'without_bootstrap' should be a null or true") unless without_bootstrap.nil? or without_bootstrap == true raise InvalidRecord.new("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) + key_name = check_string(@body["ssh_key"], "Parameter 'key' should be null or not empty string", true) rl = check_array(@body["run_list"], "Parameter 'run_list' should be a not empty array of string", String, true, true) Validators::Helpers::RunList.new(rl).validate! unless rl.nil? @body @@ -36,34 +40,49 @@ module Devops def bootstrap @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) + check_string(@body["cm_name"], "Parameter 'cm_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) Validators::Helpers::RunList.new(rl).validate! unless rl.nil? t = check_string(@body["bootstrap_template"], "Parameter 'bootstrap_template' should be a not empty string", true) @body end + def deploy + r = create_object_from_json_body + tags = check_array(r["tags"], "Parameter 'tags' should be an array of strings", String, true) + build_number = check_string(r["build_number"], "Parameter 'build_number' should be a not empty string", true) + rl = check_array(r["run_list"], "Parameter 'run_list' should be an array of string", String, true) + Validators::Helpers::RunList.new(rl).validate! unless rl.nil? + r + end + + def delete_list + body = create_object_from_json_body + check_array(body["servers_ids"], "Parameter 'servers_ids' must be not empty array of string", String) + end + def add_server @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") + env = check_string(@body["environment"], "Parameter 'environment' must be a not empty string") + category = check_string(@body["category"], "Parameter 'category' 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) rl = check_array(@body["run_list"], "Parameter 'run_list' should be a not empty array of string", String, true, true) Validators::Helpers::RunList.new(rl).validate! unless rl.nil? + name = check_string(@body["name"], "Parameter 'name' should be a not empty string") server_attrs = { project: project, - deploy_env: deploy_env, - key: key, + environment: env, + category: category, + name: name, remote_user: remote_user, private_ip: private_ip, public_ip: public_ip, - run_list: rl + run_list: rl, + name: name } - [project, deploy_env, server_attrs] end def add_and_bootstrap_servers @@ -88,6 +107,7 @@ module Devops run_list: rl } end + servers_attrs[:public_ip] = @body['public_ip'] if @body['public_ip'] [@body, servers_attrs] end diff --git a/devops-service/app/api2/parsers/stack.rb b/devops-service/app/api3/parsers/stack.rb similarity index 63% rename from devops-service/app/api2/parsers/stack.rb rename to devops-service/app/api3/parsers/stack.rb index ef1df79..7062bb7 100644 --- a/devops-service/app/api2/parsers/stack.rb +++ b/devops-service/app/api3/parsers/stack.rb @@ -1,20 +1,19 @@ require_relative "request_parser" module Devops - module API2_0 + module API3 module Parser class StackParser < RequestParser def create @body ||= create_object_from_json_body - project_name = check_string(@body["project"], "Parameter 'project' must be a not empty string") - env_name = check_string(@body["deploy_env"], "Parameter 'deploy_env' must be a not empty string") - check_string(@body["name"], "Parameter 'name' must be a not empty string", true, false) - list = check_array(@body["run_list"], "Parameter 'run_list' is invalid, it should be not empty array of strings", String, true, true) - check_param(@body['launch_options'], Hash, "Parameter 'launch_options' should be a hash with 'without_bootstrap' and 'skip_rollback' keys") - if !@body['launch_options'].key?('without_bootstrap') || !@body['launch_options'].key?('skip_rollback') - raise Devops::ValidationError.new("Parameter 'launch_options' should contain 'without_bootstrap' and 'skip_rollback' keys") - end + + stack_attributes = @body.fetch('stack_attributes') + check_string(stack_attributes['project'], "Parameter 'project' must be a not empty string") + check_string(stack_attributes['environment'], "Parameter 'environment' must be a not empty string") + check_string(stack_attributes['category'], "Parameter 'category' must be a not empty string") + check_string(stack_attributes['name'], "Parameter 'name' must be a not empty string", true, false) + list = check_array(stack_attributes['run_list'], "Parameter 'run_list' is invalid, it should be not empty array of strings", String, true, true) Validators::Helpers::RunList.new(list).validate! unless list.nil? @body end diff --git a/devops-service/app/api2/parsers/stack_template.rb b/devops-service/app/api3/parsers/stack_template.rb similarity index 93% rename from devops-service/app/api2/parsers/stack_template.rb rename to devops-service/app/api3/parsers/stack_template.rb index 3817adf..6be61d9 100644 --- a/devops-service/app/api2/parsers/stack_template.rb +++ b/devops-service/app/api3/parsers/stack_template.rb @@ -1,7 +1,7 @@ require_relative "request_parser" module Devops - module API2_0 + module API3 module Parser class StackTemplateParser < RequestParser diff --git a/devops-service/app/api3/parsers/user.rb b/devops-service/app/api3/parsers/user.rb new file mode 100644 index 0000000..98b5a3f --- /dev/null +++ b/devops-service/app/api3/parsers/user.rb @@ -0,0 +1,36 @@ +require_relative "request_parser" + +module Devops + module API3 + module Parser + class UserParser < RequestParser + + def create + create_object_from_json_body + end + + def update_user + create_object_from_json_body + end + + def roles + roles = create_object_from_json_body(Array) + check_array(roles, "Body must be a not empty array of strings") + roles + end + + def change_password + body = create_object_from_json_body + check_string(body["password"], "Parameter 'password' must be a not empty string") + end + + def change action + body = create_object_from_json_body + check_string(body[action], "Parameter '#{action}' must be a not empty string") + end + + end + end + end +end + diff --git a/devops-service/app/api3/public/swagger-ui/css/print.css b/devops-service/app/api3/public/swagger-ui/css/print.css new file mode 100644 index 0000000..2e6b310 --- /dev/null +++ b/devops-service/app/api3/public/swagger-ui/css/print.css @@ -0,0 +1,1187 @@ +/* Original style from softwaremaniacs.org (c) Ivan Sagalaev */ +.swagger-section pre code { + display: block; + padding: 0.5em; + background: #F0F0F0; +} +.swagger-section pre code, +.swagger-section pre .subst, +.swagger-section pre .tag .title, +.swagger-section pre .lisp .title, +.swagger-section pre .clojure .built_in, +.swagger-section pre .nginx .title { + color: black; +} +.swagger-section pre .string, +.swagger-section pre .title, +.swagger-section pre .constant, +.swagger-section pre .parent, +.swagger-section pre .tag .value, +.swagger-section pre .rules .value, +.swagger-section pre .rules .value .number, +.swagger-section pre .preprocessor, +.swagger-section pre .ruby .symbol, +.swagger-section pre .ruby .symbol .string, +.swagger-section pre .aggregate, +.swagger-section pre .template_tag, +.swagger-section pre .django .variable, +.swagger-section pre .smalltalk .class, +.swagger-section pre .addition, +.swagger-section pre .flow, +.swagger-section pre .stream, +.swagger-section pre .bash .variable, +.swagger-section pre .apache .tag, +.swagger-section pre .apache .cbracket, +.swagger-section pre .tex .command, +.swagger-section pre .tex .special, +.swagger-section pre .erlang_repl .function_or_atom, +.swagger-section pre .markdown .header { + color: #800; +} +.swagger-section pre .comment, +.swagger-section pre .annotation, +.swagger-section pre .template_comment, +.swagger-section pre .diff .header, +.swagger-section pre .chunk, +.swagger-section pre .markdown .blockquote { + color: #888; +} +.swagger-section pre .number, +.swagger-section pre .date, +.swagger-section pre .regexp, +.swagger-section pre .literal, +.swagger-section pre .smalltalk .symbol, +.swagger-section pre .smalltalk .char, +.swagger-section pre .go .constant, +.swagger-section pre .change, +.swagger-section pre .markdown .bullet, +.swagger-section pre .markdown .link_url { + color: #080; +} +.swagger-section pre .label, +.swagger-section pre .javadoc, +.swagger-section pre .ruby .string, +.swagger-section pre .decorator, +.swagger-section pre .filter .argument, +.swagger-section pre .localvars, +.swagger-section pre .array, +.swagger-section pre .attr_selector, +.swagger-section pre .important, +.swagger-section pre .pseudo, +.swagger-section pre .pi, +.swagger-section pre .doctype, +.swagger-section pre .deletion, +.swagger-section pre .envvar, +.swagger-section pre .shebang, +.swagger-section pre .apache .sqbracket, +.swagger-section pre .nginx .built_in, +.swagger-section pre .tex .formula, +.swagger-section pre .erlang_repl .reserved, +.swagger-section pre .prompt, +.swagger-section pre .markdown .link_label, +.swagger-section pre .vhdl .attribute, +.swagger-section pre .clojure .attribute, +.swagger-section pre .coffeescript .property { + color: #8888ff; +} +.swagger-section pre .keyword, +.swagger-section pre .id, +.swagger-section pre .phpdoc, +.swagger-section pre .title, +.swagger-section pre .built_in, +.swagger-section pre .aggregate, +.swagger-section pre .css .tag, +.swagger-section pre .javadoctag, +.swagger-section pre .phpdoc, +.swagger-section pre .yardoctag, +.swagger-section pre .smalltalk .class, +.swagger-section pre .winutils, +.swagger-section pre .bash .variable, +.swagger-section pre .apache .tag, +.swagger-section pre .go .typename, +.swagger-section pre .tex .command, +.swagger-section pre .markdown .strong, +.swagger-section pre .request, +.swagger-section pre .status { + font-weight: bold; +} +.swagger-section pre .markdown .emphasis { + font-style: italic; +} +.swagger-section pre .nginx .built_in { + font-weight: normal; +} +.swagger-section pre .coffeescript .javascript, +.swagger-section pre .javascript .xml, +.swagger-section pre .tex .formula, +.swagger-section pre .xml .javascript, +.swagger-section pre .xml .vbscript, +.swagger-section pre .xml .css, +.swagger-section pre .xml .cdata { + opacity: 0.5; +} +.swagger-section .swagger-ui-wrap { + line-height: 1; + font-family: "Droid Sans", sans-serif; + max-width: 960px; + margin-left: auto; + margin-right: auto; + /* JSONEditor specific styling */ +} +.swagger-section .swagger-ui-wrap b, +.swagger-section .swagger-ui-wrap strong { + font-family: "Droid Sans", sans-serif; + font-weight: bold; +} +.swagger-section .swagger-ui-wrap q, +.swagger-section .swagger-ui-wrap blockquote { + quotes: none; +} +.swagger-section .swagger-ui-wrap p { + line-height: 1.4em; + padding: 0 0 10px; + color: #333333; +} +.swagger-section .swagger-ui-wrap q:before, +.swagger-section .swagger-ui-wrap q:after, +.swagger-section .swagger-ui-wrap blockquote:before, +.swagger-section .swagger-ui-wrap blockquote:after { + content: none; +} +.swagger-section .swagger-ui-wrap .heading_with_menu h1, +.swagger-section .swagger-ui-wrap .heading_with_menu h2, +.swagger-section .swagger-ui-wrap .heading_with_menu h3, +.swagger-section .swagger-ui-wrap .heading_with_menu h4, +.swagger-section .swagger-ui-wrap .heading_with_menu h5, +.swagger-section .swagger-ui-wrap .heading_with_menu h6 { + display: block; + clear: none; + float: left; + -moz-box-sizing: border-box; + -webkit-box-sizing: border-box; + -ms-box-sizing: border-box; + box-sizing: border-box; + width: 60%; +} +.swagger-section .swagger-ui-wrap table { + border-collapse: collapse; + border-spacing: 0; +} +.swagger-section .swagger-ui-wrap table thead tr th { + padding: 5px; + font-size: 0.9em; + color: #666666; + border-bottom: 1px solid #999999; +} +.swagger-section .swagger-ui-wrap table tbody tr:last-child td { + border-bottom: none; +} +.swagger-section .swagger-ui-wrap table tbody tr.offset { + background-color: #f0f0f0; +} +.swagger-section .swagger-ui-wrap table tbody tr td { + padding: 6px; + font-size: 0.9em; + border-bottom: 1px solid #cccccc; + vertical-align: top; + line-height: 1.3em; +} +.swagger-section .swagger-ui-wrap ol { + margin: 0px 0 10px; + padding: 0 0 0 18px; + list-style-type: decimal; +} +.swagger-section .swagger-ui-wrap ol li { + padding: 5px 0px; + font-size: 0.9em; + color: #333333; +} +.swagger-section .swagger-ui-wrap ol, +.swagger-section .swagger-ui-wrap ul { + list-style: none; +} +.swagger-section .swagger-ui-wrap h1 a, +.swagger-section .swagger-ui-wrap h2 a, +.swagger-section .swagger-ui-wrap h3 a, +.swagger-section .swagger-ui-wrap h4 a, +.swagger-section .swagger-ui-wrap h5 a, +.swagger-section .swagger-ui-wrap h6 a { + text-decoration: none; +} +.swagger-section .swagger-ui-wrap h1 a:hover, +.swagger-section .swagger-ui-wrap h2 a:hover, +.swagger-section .swagger-ui-wrap h3 a:hover, +.swagger-section .swagger-ui-wrap h4 a:hover, +.swagger-section .swagger-ui-wrap h5 a:hover, +.swagger-section .swagger-ui-wrap h6 a:hover { + text-decoration: underline; +} +.swagger-section .swagger-ui-wrap h1 span.divider, +.swagger-section .swagger-ui-wrap h2 span.divider, +.swagger-section .swagger-ui-wrap h3 span.divider, +.swagger-section .swagger-ui-wrap h4 span.divider, +.swagger-section .swagger-ui-wrap h5 span.divider, +.swagger-section .swagger-ui-wrap h6 span.divider { + color: #aaaaaa; +} +.swagger-section .swagger-ui-wrap a { + color: #547f00; +} +.swagger-section .swagger-ui-wrap a img { + border: none; +} +.swagger-section .swagger-ui-wrap article, +.swagger-section .swagger-ui-wrap aside, +.swagger-section .swagger-ui-wrap details, +.swagger-section .swagger-ui-wrap figcaption, +.swagger-section .swagger-ui-wrap figure, +.swagger-section .swagger-ui-wrap footer, +.swagger-section .swagger-ui-wrap header, +.swagger-section .swagger-ui-wrap hgroup, +.swagger-section .swagger-ui-wrap menu, +.swagger-section .swagger-ui-wrap nav, +.swagger-section .swagger-ui-wrap section, +.swagger-section .swagger-ui-wrap summary { + display: block; +} +.swagger-section .swagger-ui-wrap pre { + font-family: "Anonymous Pro", "Menlo", "Consolas", "Bitstream Vera Sans Mono", "Courier New", monospace; + background-color: #fcf6db; + border: 1px solid #e5e0c6; + padding: 10px; +} +.swagger-section .swagger-ui-wrap pre code { + line-height: 1.6em; + background: none; +} +.swagger-section .swagger-ui-wrap .content > .content-type > div > label { + clear: both; + display: block; + color: #0F6AB4; + font-size: 1.1em; + margin: 0; + padding: 15px 0 5px; +} +.swagger-section .swagger-ui-wrap .content pre { + font-size: 12px; + margin-top: 5px; + padding: 5px; +} +.swagger-section .swagger-ui-wrap .icon-btn { + cursor: pointer; +} +.swagger-section .swagger-ui-wrap .info_title { + padding-bottom: 10px; + font-weight: bold; + font-size: 25px; +} +.swagger-section .swagger-ui-wrap .footer { + margin-top: 20px; +} +.swagger-section .swagger-ui-wrap p.big, +.swagger-section .swagger-ui-wrap div.big p { + font-size: 1em; + margin-bottom: 10px; +} +.swagger-section .swagger-ui-wrap form.fullwidth ol li.string input, +.swagger-section .swagger-ui-wrap form.fullwidth ol li.url input, +.swagger-section .swagger-ui-wrap form.fullwidth ol li.text textarea, +.swagger-section .swagger-ui-wrap form.fullwidth ol li.numeric input { + width: 500px !important; +} +.swagger-section .swagger-ui-wrap .info_license { + padding-bottom: 5px; +} +.swagger-section .swagger-ui-wrap .info_tos { + padding-bottom: 5px; +} +.swagger-section .swagger-ui-wrap .message-fail { + color: #cc0000; +} +.swagger-section .swagger-ui-wrap .info_url { + padding-bottom: 5px; +} +.swagger-section .swagger-ui-wrap .info_email { + padding-bottom: 5px; +} +.swagger-section .swagger-ui-wrap .info_name { + padding-bottom: 5px; +} +.swagger-section .swagger-ui-wrap .info_description { + padding-bottom: 10px; + font-size: 15px; +} +.swagger-section .swagger-ui-wrap .markdown ol li, +.swagger-section .swagger-ui-wrap .markdown ul li { + padding: 3px 0px; + line-height: 1.4em; + color: #333333; +} +.swagger-section .swagger-ui-wrap form.formtastic fieldset.inputs ol li.string input, +.swagger-section .swagger-ui-wrap form.formtastic fieldset.inputs ol li.url input, +.swagger-section .swagger-ui-wrap form.formtastic fieldset.inputs ol li.numeric input { + display: block; + padding: 4px; + width: auto; + clear: both; +} +.swagger-section .swagger-ui-wrap form.formtastic fieldset.inputs ol li.string input.title, +.swagger-section .swagger-ui-wrap form.formtastic fieldset.inputs ol li.url input.title, +.swagger-section .swagger-ui-wrap form.formtastic fieldset.inputs ol li.numeric input.title { + font-size: 1.3em; +} +.swagger-section .swagger-ui-wrap table.fullwidth { + width: 100%; +} +.swagger-section .swagger-ui-wrap .model-signature { + font-family: "Droid Sans", sans-serif; + font-size: 1em; + line-height: 1.5em; +} +.swagger-section .swagger-ui-wrap .model-signature .signature-nav a { + text-decoration: none; + color: #AAA; +} +.swagger-section .swagger-ui-wrap .model-signature .signature-nav a:hover { + text-decoration: underline; + color: black; +} +.swagger-section .swagger-ui-wrap .model-signature .signature-nav .selected { + color: black; + text-decoration: none; +} +.swagger-section .swagger-ui-wrap .model-signature .propType { + color: #5555aa; +} +.swagger-section .swagger-ui-wrap .model-signature pre:hover { + background-color: #ffffdd; +} +.swagger-section .swagger-ui-wrap .model-signature pre { + font-size: .85em; + line-height: 1.2em; + overflow: auto; + max-height: 200px; + cursor: pointer; +} +.swagger-section .swagger-ui-wrap .model-signature ul.signature-nav { + display: block; + margin: 0; + padding: 0; +} +.swagger-section .swagger-ui-wrap .model-signature ul.signature-nav li:last-child { + padding-right: 0; + border-right: none; +} +.swagger-section .swagger-ui-wrap .model-signature ul.signature-nav li { + float: left; + margin: 0 5px 5px 0; + padding: 2px 5px 2px 0; + border-right: 1px solid #ddd; +} +.swagger-section .swagger-ui-wrap .model-signature .propOpt { + color: #555; +} +.swagger-section .swagger-ui-wrap .model-signature .snippet small { + font-size: 0.75em; +} +.swagger-section .swagger-ui-wrap .model-signature .propOptKey { + font-style: italic; +} +.swagger-section .swagger-ui-wrap .model-signature .description .strong { + font-weight: bold; + color: #000; + font-size: .9em; +} +.swagger-section .swagger-ui-wrap .model-signature .description div { + font-size: 0.9em; + line-height: 1.5em; + margin-left: 1em; +} +.swagger-section .swagger-ui-wrap .model-signature .description .stronger { + font-weight: bold; + color: #000; +} +.swagger-section .swagger-ui-wrap .model-signature .description .propWrap .optionsWrapper { + border-spacing: 0; + position: absolute; + background-color: #ffffff; + border: 1px solid #bbbbbb; + display: none; + font-size: 11px; + max-width: 400px; + line-height: 30px; + color: black; + padding: 5px; + margin-left: 10px; +} +.swagger-section .swagger-ui-wrap .model-signature .description .propWrap .optionsWrapper th { + text-align: center; + background-color: #eeeeee; + border: 1px solid #bbbbbb; + font-size: 11px; + color: #666666; + font-weight: bold; + padding: 5px; + line-height: 15px; +} +.swagger-section .swagger-ui-wrap .model-signature .description .propWrap .optionsWrapper .optionName { + font-weight: bold; +} +.swagger-section .swagger-ui-wrap .model-signature .description .propDesc.markdown > p:first-child, +.swagger-section .swagger-ui-wrap .model-signature .description .propDesc.markdown > p:last-child { + display: inline; +} +.swagger-section .swagger-ui-wrap .model-signature .description .propDesc.markdown > p:not(:first-child):before { + display: block; + content: ''; +} +.swagger-section .swagger-ui-wrap .model-signature .description span:last-of-type.propDesc.markdown > p:only-child { + margin-right: -3px; +} +.swagger-section .swagger-ui-wrap .model-signature .propName { + font-weight: bold; +} +.swagger-section .swagger-ui-wrap .model-signature .signature-container { + clear: both; +} +.swagger-section .swagger-ui-wrap .body-textarea { + width: 300px; + height: 100px; + border: 1px solid #aaa; +} +.swagger-section .swagger-ui-wrap .markdown p code, +.swagger-section .swagger-ui-wrap .markdown li code { + font-family: "Anonymous Pro", "Menlo", "Consolas", "Bitstream Vera Sans Mono", "Courier New", monospace; + background-color: #f0f0f0; + color: black; + padding: 1px 3px; +} +.swagger-section .swagger-ui-wrap .required { + font-weight: bold; +} +.swagger-section .swagger-ui-wrap .editor_holder { + font-family: "Anonymous Pro", "Menlo", "Consolas", "Bitstream Vera Sans Mono", "Courier New", monospace; + font-size: 0.9em; +} +.swagger-section .swagger-ui-wrap .editor_holder label { + font-weight: normal!important; + /* JSONEditor uses bold by default for all labels, we revert that back to normal to not give the impression that by default fields are required */ +} +.swagger-section .swagger-ui-wrap .editor_holder label.required { + font-weight: bold!important; +} +.swagger-section .swagger-ui-wrap input.parameter { + width: 300px; + border: 1px solid #aaa; +} +.swagger-section .swagger-ui-wrap h1 { + color: black; + font-size: 1.5em; + line-height: 1.3em; + padding: 10px 0 10px 0; + font-family: "Droid Sans", sans-serif; + font-weight: bold; +} +.swagger-section .swagger-ui-wrap .heading_with_menu { + float: none; + clear: both; + overflow: hidden; + display: block; +} +.swagger-section .swagger-ui-wrap .heading_with_menu ul { + display: block; + clear: none; + float: right; + -moz-box-sizing: border-box; + -webkit-box-sizing: border-box; + -ms-box-sizing: border-box; + box-sizing: border-box; + margin-top: 10px; +} +.swagger-section .swagger-ui-wrap h2 { + color: black; + font-size: 1.3em; + padding: 10px 0 10px 0; +} +.swagger-section .swagger-ui-wrap h2 a { + color: black; +} +.swagger-section .swagger-ui-wrap h2 span.sub { + font-size: 0.7em; + color: #999999; + font-style: italic; +} +.swagger-section .swagger-ui-wrap h2 span.sub a { + color: #777777; +} +.swagger-section .swagger-ui-wrap span.weak { + color: #666666; +} +.swagger-section .swagger-ui-wrap .message-success { + color: #89BF04; +} +.swagger-section .swagger-ui-wrap caption, +.swagger-section .swagger-ui-wrap th, +.swagger-section .swagger-ui-wrap td { + text-align: left; + font-weight: normal; + vertical-align: middle; +} +.swagger-section .swagger-ui-wrap .code { + font-family: "Anonymous Pro", "Menlo", "Consolas", "Bitstream Vera Sans Mono", "Courier New", monospace; +} +.swagger-section .swagger-ui-wrap form.formtastic fieldset.inputs ol li.text textarea { + font-family: "Droid Sans", sans-serif; + height: 250px; + padding: 4px; + display: block; + clear: both; +} +.swagger-section .swagger-ui-wrap form.formtastic fieldset.inputs ol li.select select { + display: block; + clear: both; +} +.swagger-section .swagger-ui-wrap form.formtastic fieldset.inputs ol li.boolean { + float: none; + clear: both; + overflow: hidden; + display: block; +} +.swagger-section .swagger-ui-wrap form.formtastic fieldset.inputs ol li.boolean label { + display: block; + float: left; + clear: none; + margin: 0; + padding: 0; +} +.swagger-section .swagger-ui-wrap form.formtastic fieldset.inputs ol li.boolean input { + display: block; + float: left; + clear: none; + margin: 0 5px 0 0; +} +.swagger-section .swagger-ui-wrap form.formtastic fieldset.inputs ol li.required label { + color: black; +} +.swagger-section .swagger-ui-wrap form.formtastic fieldset.inputs ol li label { + display: block; + clear: both; + width: auto; + padding: 0 0 3px; + color: #666666; +} +.swagger-section .swagger-ui-wrap form.formtastic fieldset.inputs ol li label abbr { + padding-left: 3px; + color: #888888; +} +.swagger-section .swagger-ui-wrap form.formtastic fieldset.inputs ol li p.inline-hints { + margin-left: 0; + font-style: italic; + font-size: 0.9em; + margin: 0; +} +.swagger-section .swagger-ui-wrap form.formtastic fieldset.buttons { + margin: 0; + padding: 0; +} +.swagger-section .swagger-ui-wrap span.blank, +.swagger-section .swagger-ui-wrap span.empty { + color: #888888; + font-style: italic; +} +.swagger-section .swagger-ui-wrap .markdown h3 { + color: #547f00; +} +.swagger-section .swagger-ui-wrap .markdown h4 { + color: #666666; +} +.swagger-section .swagger-ui-wrap .markdown pre { + font-family: "Anonymous Pro", "Menlo", "Consolas", "Bitstream Vera Sans Mono", "Courier New", monospace; + background-color: #fcf6db; + border: 1px solid #e5e0c6; + padding: 10px; + margin: 0 0 10px 0; +} +.swagger-section .swagger-ui-wrap .markdown pre code { + line-height: 1.6em; +} +.swagger-section .swagger-ui-wrap div.gist { + margin: 20px 0 25px 0 !important; +} +.swagger-section .swagger-ui-wrap ul#resources { + font-family: "Droid Sans", sans-serif; + font-size: 0.9em; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource { + border-bottom: 1px solid #dddddd; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource:hover div.heading h2 a, +.swagger-section .swagger-ui-wrap ul#resources li.resource.active div.heading h2 a { + color: black; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource:hover div.heading ul.options li a, +.swagger-section .swagger-ui-wrap ul#resources li.resource.active div.heading ul.options li a { + color: #555555; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource:last-child { + border-bottom: none; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource div.heading { + border: 1px solid transparent; + float: none; + clear: both; + overflow: hidden; + display: block; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource div.heading ul.options { + overflow: hidden; + padding: 0; + display: block; + clear: none; + float: right; + margin: 14px 10px 0 0; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource div.heading ul.options li { + float: left; + clear: none; + margin: 0; + padding: 2px 10px; + border-right: 1px solid #dddddd; + color: #666666; + font-size: 0.9em; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource div.heading ul.options li a { + color: #aaaaaa; + text-decoration: none; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource div.heading ul.options li a:hover { + text-decoration: underline; + color: black; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource div.heading ul.options li a:hover, +.swagger-section .swagger-ui-wrap ul#resources li.resource div.heading ul.options li a:active, +.swagger-section .swagger-ui-wrap ul#resources li.resource div.heading ul.options li a.active { + text-decoration: underline; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource div.heading ul.options li:first-child, +.swagger-section .swagger-ui-wrap ul#resources li.resource div.heading ul.options li.first { + padding-left: 0; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource div.heading ul.options li:last-child, +.swagger-section .swagger-ui-wrap ul#resources li.resource div.heading ul.options li.last { + padding-right: 0; + border-right: none; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource div.heading ul.options:first-child, +.swagger-section .swagger-ui-wrap ul#resources li.resource div.heading ul.options.first { + padding-left: 0; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource div.heading h2 { + color: #999999; + padding-left: 0; + display: block; + clear: none; + float: left; + font-family: "Droid Sans", sans-serif; + font-weight: bold; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource div.heading h2 a { + color: #999999; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource div.heading h2 a:hover { + color: black; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation { + float: none; + clear: both; + overflow: hidden; + display: block; + margin: 0 0 10px; + padding: 0; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.heading { + float: none; + clear: both; + overflow: hidden; + display: block; + margin: 0; + padding: 0; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.heading h3 { + display: block; + clear: none; + float: left; + width: auto; + margin: 0; + padding: 0; + line-height: 1.1em; + color: black; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.heading h3 span.path { + padding-left: 10px; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.heading h3 span.path a { + color: black; + text-decoration: none; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.heading h3 span.path a:hover { + text-decoration: underline; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.heading h3 span.http_method a { + text-transform: uppercase; + text-decoration: none; + color: white; + display: inline-block; + width: 50px; + font-size: 0.7em; + text-align: center; + padding: 7px 0 4px; + -moz-border-radius: 2px; + -webkit-border-radius: 2px; + -o-border-radius: 2px; + -ms-border-radius: 2px; + -khtml-border-radius: 2px; + border-radius: 2px; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.heading h3 span { + margin: 0; + padding: 0; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.heading ul.options { + overflow: hidden; + padding: 0; + display: block; + clear: none; + float: right; + margin: 6px 10px 0 0; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.heading ul.options li { + float: left; + clear: none; + margin: 0; + padding: 2px 10px; + font-size: 0.9em; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.heading ul.options li a { + text-decoration: none; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.heading ul.options li.access { + color: black; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.content { + border-top: none; + padding: 10px; + -moz-border-radius-bottomleft: 6px; + -webkit-border-bottom-left-radius: 6px; + -o-border-bottom-left-radius: 6px; + -ms-border-bottom-left-radius: 6px; + -khtml-border-bottom-left-radius: 6px; + border-bottom-left-radius: 6px; + -moz-border-radius-bottomright: 6px; + -webkit-border-bottom-right-radius: 6px; + -o-border-bottom-right-radius: 6px; + -ms-border-bottom-right-radius: 6px; + -khtml-border-bottom-right-radius: 6px; + border-bottom-right-radius: 6px; + margin: 0 0 20px; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.content h4 { + font-size: 1.1em; + margin: 0; + padding: 15px 0 5px; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.content div.sandbox_header { + float: none; + clear: both; + overflow: hidden; + display: block; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.content div.sandbox_header a { + padding: 4px 0 0 10px; + display: inline-block; + font-size: 0.9em; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.content div.sandbox_header input.submit { + display: block; + clear: none; + float: left; + padding: 6px 8px; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.content div.sandbox_header span.response_throbber { + background-image: url('../images/throbber.gif'); + width: 128px; + height: 16px; + display: block; + clear: none; + float: right; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.content form input[type='text'].error { + outline: 2px solid black; + outline-color: #cc0000; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.content form select[name='parameterContentType'] { + max-width: 300px; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.content div.response div.block pre { + font-family: "Anonymous Pro", "Menlo", "Consolas", "Bitstream Vera Sans Mono", "Courier New", monospace; + padding: 10px; + font-size: 0.9em; + max-height: 400px; + overflow-y: auto; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put div.heading { + background-color: #f9f2e9; + border: 1px solid #f0e0ca; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put div.heading h3 span.http_method a { + background-color: #c5862b; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put div.heading ul.options li { + border-right: 1px solid #dddddd; + border-right-color: #f0e0ca; + color: #c5862b; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put div.heading ul.options li a { + color: #c5862b; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put div.content { + background-color: #faf5ee; + border: 1px solid #f0e0ca; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put div.content h4 { + color: #c5862b; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put div.content div.sandbox_header a { + color: #dcb67f; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.head div.heading { + background-color: #fcffcd; + border: 1px solid black; + border-color: #ffd20f; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.head div.heading h3 span.http_method a { + text-transform: uppercase; + background-color: #ffd20f; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.head div.heading ul.options li { + border-right: 1px solid #dddddd; + border-right-color: #ffd20f; + color: #ffd20f; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.head div.heading ul.options li a { + color: #ffd20f; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.head div.content { + background-color: #fcffcd; + border: 1px solid black; + border-color: #ffd20f; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.head div.content h4 { + color: #ffd20f; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.head div.content div.sandbox_header a { + color: #6fc992; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete div.heading { + background-color: #f5e8e8; + border: 1px solid #e8c6c7; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete div.heading h3 span.http_method a { + text-transform: uppercase; + background-color: #a41e22; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete div.heading ul.options li { + border-right: 1px solid #dddddd; + border-right-color: #e8c6c7; + color: #a41e22; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete div.heading ul.options li a { + color: #a41e22; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete div.content { + background-color: #f7eded; + border: 1px solid #e8c6c7; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete div.content h4 { + color: #a41e22; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete div.content div.sandbox_header a { + color: #c8787a; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post div.heading { + background-color: #e7f6ec; + border: 1px solid #c3e8d1; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post div.heading h3 span.http_method a { + background-color: #10a54a; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post div.heading ul.options li { + border-right: 1px solid #dddddd; + border-right-color: #c3e8d1; + color: #10a54a; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post div.heading ul.options li a { + color: #10a54a; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post div.content { + background-color: #ebf7f0; + border: 1px solid #c3e8d1; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post div.content h4 { + color: #10a54a; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post div.content div.sandbox_header a { + color: #6fc992; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.patch div.heading { + background-color: #FCE9E3; + border: 1px solid #F5D5C3; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.patch div.heading h3 span.http_method a { + background-color: #D38042; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.patch div.heading ul.options li { + border-right: 1px solid #dddddd; + border-right-color: #f0cecb; + color: #D38042; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.patch div.heading ul.options li a { + color: #D38042; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.patch div.content { + background-color: #faf0ef; + border: 1px solid #f0cecb; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.patch div.content h4 { + color: #D38042; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.patch div.content div.sandbox_header a { + color: #dcb67f; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get div.heading { + background-color: #e7f0f7; + border: 1px solid #c3d9ec; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get div.heading h3 span.http_method a { + background-color: #0f6ab4; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get div.heading ul.options li { + border-right: 1px solid #dddddd; + border-right-color: #c3d9ec; + color: #0f6ab4; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get div.heading ul.options li a { + color: #0f6ab4; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get div.content { + background-color: #ebf3f9; + border: 1px solid #c3d9ec; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get div.content h4 { + color: #0f6ab4; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get div.content div.sandbox_header a { + color: #6fa5d2; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.options div.heading { + background-color: #e7f0f7; + border: 1px solid #c3d9ec; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.options div.heading h3 span.http_method a { + background-color: #0f6ab4; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.options div.heading ul.options li { + border-right: 1px solid #dddddd; + border-right-color: #c3d9ec; + color: #0f6ab4; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.options div.heading ul.options li a { + color: #0f6ab4; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.options div.content { + background-color: #ebf3f9; + border: 1px solid #c3d9ec; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.options div.content h4 { + color: #0f6ab4; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.options div.content div.sandbox_header a { + color: #6fa5d2; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get div.content, +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post div.content, +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.head div.content, +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put div.content, +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.patch div.content, +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete div.content { + border-top: none; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get div.heading ul.options li:last-child, +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post div.heading ul.options li:last-child, +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.head div.heading ul.options li:last-child, +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put div.heading ul.options li:last-child, +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.patch div.heading ul.options li:last-child, +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete div.heading ul.options li:last-child, +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get div.heading ul.options li.last, +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post div.heading ul.options li.last, +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.head div.heading ul.options li.last, +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put div.heading ul.options li.last, +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.patch div.heading ul.options li.last, +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete div.heading ul.options li.last { + padding-right: 0; + border-right: none; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations ul.options li a:hover, +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations ul.options li a:active, +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations ul.options li a.active { + text-decoration: underline; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations ul.options li:first-child, +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations ul.options li.first { + padding-left: 0; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations:first-child, +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations.first { + padding-left: 0; +} +.swagger-section .swagger-ui-wrap p#colophon { + margin: 0 15px 40px 15px; + padding: 10px 0; + font-size: 0.8em; + border-top: 1px solid #dddddd; + font-family: "Droid Sans", sans-serif; + color: #999999; + font-style: italic; +} +.swagger-section .swagger-ui-wrap p#colophon a { + text-decoration: none; + color: #547f00; +} +.swagger-section .swagger-ui-wrap h3 { + color: black; + font-size: 1.1em; + padding: 10px 0 10px 0; +} +.swagger-section .swagger-ui-wrap .markdown ol, +.swagger-section .swagger-ui-wrap .markdown ul { + font-family: "Droid Sans", sans-serif; + margin: 5px 0 10px; + padding: 0 0 0 18px; + list-style-type: disc; +} +.swagger-section .swagger-ui-wrap form.form_box { + background-color: #ebf3f9; + border: 1px solid #c3d9ec; + padding: 10px; +} +.swagger-section .swagger-ui-wrap form.form_box label { + color: #0f6ab4 !important; +} +.swagger-section .swagger-ui-wrap form.form_box input[type=submit] { + display: block; + padding: 10px; +} +.swagger-section .swagger-ui-wrap form.form_box p.weak { + font-size: 0.8em; +} +.swagger-section .swagger-ui-wrap form.form_box p { + font-size: 0.9em; + padding: 0 0 15px; + color: #7e7b6d; +} +.swagger-section .swagger-ui-wrap form.form_box p a { + color: #646257; +} +.swagger-section .swagger-ui-wrap form.form_box p strong { + color: black; +} +.swagger-section .swagger-ui-wrap .operation-status td.markdown > p:last-child { + padding-bottom: 0; +} +.swagger-section .title { + font-style: bold; +} +.swagger-section .secondary_form { + display: none; +} +.swagger-section .main_image { + display: block; + margin-left: auto; + margin-right: auto; +} +.swagger-section .oauth_body { + margin-left: 100px; + margin-right: 100px; +} +.swagger-section .oauth_submit { + text-align: center; +} +.swagger-section .api-popup-dialog { + z-index: 10000; + position: absolute; + width: 500px; + background: #FFF; + padding: 20px; + border: 1px solid #ccc; + border-radius: 5px; + display: none; + font-size: 13px; + color: #777; +} +.swagger-section .api-popup-dialog .api-popup-title { + font-size: 24px; + padding: 10px 0; +} +.swagger-section .api-popup-dialog .api-popup-title { + font-size: 24px; + padding: 10px 0; +} +.swagger-section .api-popup-dialog .error-msg { + padding-left: 5px; + padding-bottom: 5px; +} +.swagger-section .api-popup-dialog .api-popup-authbtn { + height: 30px; +} +.swagger-section .api-popup-dialog .api-popup-cancel { + height: 30px; +} +.swagger-section .api-popup-scopes { + padding: 10px 20px; +} +.swagger-section .api-popup-scopes li { + padding: 5px 0; + line-height: 20px; +} +.swagger-section .api-popup-scopes li input { + position: relative; + top: 2px; +} +.swagger-section .api-popup-scopes .api-scope-desc { + padding-left: 20px; + font-style: italic; +} +.swagger-section .api-popup-actions { + padding-top: 10px; +} +#header { + display: none; +} +.swagger-section .swagger-ui-wrap .model-signature pre { + max-height: none; +} +.swagger-section .swagger-ui-wrap .body-textarea { + width: 100px; +} +.swagger-section .swagger-ui-wrap input.parameter { + width: 100px; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource div.heading ul.options { + display: none; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints { + display: block !important; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.content { + display: block !important; +} diff --git a/devops-service/app/api3/public/swagger-ui/css/reset.css b/devops-service/app/api3/public/swagger-ui/css/reset.css new file mode 100644 index 0000000..b2b0789 --- /dev/null +++ b/devops-service/app/api3/public/swagger-ui/css/reset.css @@ -0,0 +1,125 @@ +/* http://meyerweb.com/eric/tools/css/reset/ v2.0 | 20110126 */ +html, +body, +div, +span, +applet, +object, +iframe, +h1, +h2, +h3, +h4, +h5, +h6, +p, +blockquote, +pre, +a, +abbr, +acronym, +address, +big, +cite, +code, +del, +dfn, +em, +img, +ins, +kbd, +q, +s, +samp, +small, +strike, +strong, +sub, +sup, +tt, +var, +b, +u, +i, +center, +dl, +dt, +dd, +ol, +ul, +li, +fieldset, +form, +label, +legend, +table, +caption, +tbody, +tfoot, +thead, +tr, +th, +td, +article, +aside, +canvas, +details, +embed, +figure, +figcaption, +footer, +header, +hgroup, +menu, +nav, +output, +ruby, +section, +summary, +time, +mark, +audio, +video { + margin: 0; + padding: 0; + border: 0; + font-size: 100%; + font: inherit; + vertical-align: baseline; +} +/* HTML5 display-role reset for older browsers */ +article, +aside, +details, +figcaption, +figure, +footer, +header, +hgroup, +menu, +nav, +section { + display: block; +} +body { + line-height: 1; +} +ol, +ul { + list-style: none; +} +blockquote, +q { + quotes: none; +} +blockquote:before, +blockquote:after, +q:before, +q:after { + content: ''; + content: none; +} +table { + border-collapse: collapse; + border-spacing: 0; +} diff --git a/devops-service/app/api3/public/swagger-ui/css/screen.css b/devops-service/app/api3/public/swagger-ui/css/screen.css new file mode 100644 index 0000000..ef4673d --- /dev/null +++ b/devops-service/app/api3/public/swagger-ui/css/screen.css @@ -0,0 +1,1300 @@ +/* Original style from softwaremaniacs.org (c) Ivan Sagalaev */ +.swagger-section pre code { + display: block; + padding: 0.5em; + background: #F0F0F0; +} +.swagger-section pre code, +.swagger-section pre .subst, +.swagger-section pre .tag .title, +.swagger-section pre .lisp .title, +.swagger-section pre .clojure .built_in, +.swagger-section pre .nginx .title { + color: black; +} +.swagger-section pre .string, +.swagger-section pre .title, +.swagger-section pre .constant, +.swagger-section pre .parent, +.swagger-section pre .tag .value, +.swagger-section pre .rules .value, +.swagger-section pre .rules .value .number, +.swagger-section pre .preprocessor, +.swagger-section pre .ruby .symbol, +.swagger-section pre .ruby .symbol .string, +.swagger-section pre .aggregate, +.swagger-section pre .template_tag, +.swagger-section pre .django .variable, +.swagger-section pre .smalltalk .class, +.swagger-section pre .addition, +.swagger-section pre .flow, +.swagger-section pre .stream, +.swagger-section pre .bash .variable, +.swagger-section pre .apache .tag, +.swagger-section pre .apache .cbracket, +.swagger-section pre .tex .command, +.swagger-section pre .tex .special, +.swagger-section pre .erlang_repl .function_or_atom, +.swagger-section pre .markdown .header { + color: #800; +} +.swagger-section pre .comment, +.swagger-section pre .annotation, +.swagger-section pre .template_comment, +.swagger-section pre .diff .header, +.swagger-section pre .chunk, +.swagger-section pre .markdown .blockquote { + color: #888; +} +.swagger-section pre .number, +.swagger-section pre .date, +.swagger-section pre .regexp, +.swagger-section pre .literal, +.swagger-section pre .smalltalk .symbol, +.swagger-section pre .smalltalk .char, +.swagger-section pre .go .constant, +.swagger-section pre .change, +.swagger-section pre .markdown .bullet, +.swagger-section pre .markdown .link_url { + color: #080; +} +.swagger-section pre .label, +.swagger-section pre .javadoc, +.swagger-section pre .ruby .string, +.swagger-section pre .decorator, +.swagger-section pre .filter .argument, +.swagger-section pre .localvars, +.swagger-section pre .array, +.swagger-section pre .attr_selector, +.swagger-section pre .important, +.swagger-section pre .pseudo, +.swagger-section pre .pi, +.swagger-section pre .doctype, +.swagger-section pre .deletion, +.swagger-section pre .envvar, +.swagger-section pre .shebang, +.swagger-section pre .apache .sqbracket, +.swagger-section pre .nginx .built_in, +.swagger-section pre .tex .formula, +.swagger-section pre .erlang_repl .reserved, +.swagger-section pre .prompt, +.swagger-section pre .markdown .link_label, +.swagger-section pre .vhdl .attribute, +.swagger-section pre .clojure .attribute, +.swagger-section pre .coffeescript .property { + color: #8888ff; +} +.swagger-section pre .keyword, +.swagger-section pre .id, +.swagger-section pre .phpdoc, +.swagger-section pre .title, +.swagger-section pre .built_in, +.swagger-section pre .aggregate, +.swagger-section pre .css .tag, +.swagger-section pre .javadoctag, +.swagger-section pre .phpdoc, +.swagger-section pre .yardoctag, +.swagger-section pre .smalltalk .class, +.swagger-section pre .winutils, +.swagger-section pre .bash .variable, +.swagger-section pre .apache .tag, +.swagger-section pre .go .typename, +.swagger-section pre .tex .command, +.swagger-section pre .markdown .strong, +.swagger-section pre .request, +.swagger-section pre .status { + font-weight: bold; +} +.swagger-section pre .markdown .emphasis { + font-style: italic; +} +.swagger-section pre .nginx .built_in { + font-weight: normal; +} +.swagger-section pre .coffeescript .javascript, +.swagger-section pre .javascript .xml, +.swagger-section pre .tex .formula, +.swagger-section pre .xml .javascript, +.swagger-section pre .xml .vbscript, +.swagger-section pre .xml .css, +.swagger-section pre .xml .cdata { + opacity: 0.5; +} +.swagger-section .swagger-ui-wrap { + line-height: 1; + font-family: "Droid Sans", sans-serif; + max-width: 960px; + margin-left: auto; + margin-right: auto; + /* JSONEditor specific styling */ +} +.swagger-section .swagger-ui-wrap b, +.swagger-section .swagger-ui-wrap strong { + font-family: "Droid Sans", sans-serif; + font-weight: bold; +} +.swagger-section .swagger-ui-wrap q, +.swagger-section .swagger-ui-wrap blockquote { + quotes: none; +} +.swagger-section .swagger-ui-wrap p { + line-height: 1.4em; + padding: 0 0 10px; + color: #333333; +} +.swagger-section .swagger-ui-wrap q:before, +.swagger-section .swagger-ui-wrap q:after, +.swagger-section .swagger-ui-wrap blockquote:before, +.swagger-section .swagger-ui-wrap blockquote:after { + content: none; +} +.swagger-section .swagger-ui-wrap .heading_with_menu h1, +.swagger-section .swagger-ui-wrap .heading_with_menu h2, +.swagger-section .swagger-ui-wrap .heading_with_menu h3, +.swagger-section .swagger-ui-wrap .heading_with_menu h4, +.swagger-section .swagger-ui-wrap .heading_with_menu h5, +.swagger-section .swagger-ui-wrap .heading_with_menu h6 { + display: block; + clear: none; + float: left; + -moz-box-sizing: border-box; + -webkit-box-sizing: border-box; + -ms-box-sizing: border-box; + box-sizing: border-box; + width: 60%; +} +.swagger-section .swagger-ui-wrap table { + border-collapse: collapse; + border-spacing: 0; +} +.swagger-section .swagger-ui-wrap table thead tr th { + padding: 5px; + font-size: 0.9em; + color: #666666; + border-bottom: 1px solid #999999; +} +.swagger-section .swagger-ui-wrap table tbody tr:last-child td { + border-bottom: none; +} +.swagger-section .swagger-ui-wrap table tbody tr.offset { + background-color: #f0f0f0; +} +.swagger-section .swagger-ui-wrap table tbody tr td { + padding: 6px; + font-size: 0.9em; + border-bottom: 1px solid #cccccc; + vertical-align: top; + line-height: 1.3em; +} +.swagger-section .swagger-ui-wrap ol { + margin: 0px 0 10px; + padding: 0 0 0 18px; + list-style-type: decimal; +} +.swagger-section .swagger-ui-wrap ol li { + padding: 5px 0px; + font-size: 0.9em; + color: #333333; +} +.swagger-section .swagger-ui-wrap ol, +.swagger-section .swagger-ui-wrap ul { + list-style: none; +} +.swagger-section .swagger-ui-wrap h1 a, +.swagger-section .swagger-ui-wrap h2 a, +.swagger-section .swagger-ui-wrap h3 a, +.swagger-section .swagger-ui-wrap h4 a, +.swagger-section .swagger-ui-wrap h5 a, +.swagger-section .swagger-ui-wrap h6 a { + text-decoration: none; +} +.swagger-section .swagger-ui-wrap h1 a:hover, +.swagger-section .swagger-ui-wrap h2 a:hover, +.swagger-section .swagger-ui-wrap h3 a:hover, +.swagger-section .swagger-ui-wrap h4 a:hover, +.swagger-section .swagger-ui-wrap h5 a:hover, +.swagger-section .swagger-ui-wrap h6 a:hover { + text-decoration: underline; +} +.swagger-section .swagger-ui-wrap h1 span.divider, +.swagger-section .swagger-ui-wrap h2 span.divider, +.swagger-section .swagger-ui-wrap h3 span.divider, +.swagger-section .swagger-ui-wrap h4 span.divider, +.swagger-section .swagger-ui-wrap h5 span.divider, +.swagger-section .swagger-ui-wrap h6 span.divider { + color: #aaaaaa; +} +.swagger-section .swagger-ui-wrap a { + color: #547f00; +} +.swagger-section .swagger-ui-wrap a img { + border: none; +} +.swagger-section .swagger-ui-wrap article, +.swagger-section .swagger-ui-wrap aside, +.swagger-section .swagger-ui-wrap details, +.swagger-section .swagger-ui-wrap figcaption, +.swagger-section .swagger-ui-wrap figure, +.swagger-section .swagger-ui-wrap footer, +.swagger-section .swagger-ui-wrap header, +.swagger-section .swagger-ui-wrap hgroup, +.swagger-section .swagger-ui-wrap menu, +.swagger-section .swagger-ui-wrap nav, +.swagger-section .swagger-ui-wrap section, +.swagger-section .swagger-ui-wrap summary { + display: block; +} +.swagger-section .swagger-ui-wrap pre { + font-family: "Anonymous Pro", "Menlo", "Consolas", "Bitstream Vera Sans Mono", "Courier New", monospace; + background-color: #fcf6db; + border: 1px solid #e5e0c6; + padding: 10px; +} +.swagger-section .swagger-ui-wrap pre code { + line-height: 1.6em; + background: none; +} +.swagger-section .swagger-ui-wrap .content > .content-type > div > label { + clear: both; + display: block; + color: #0F6AB4; + font-size: 1.1em; + margin: 0; + padding: 15px 0 5px; +} +.swagger-section .swagger-ui-wrap .content pre { + font-size: 12px; + margin-top: 5px; + padding: 5px; +} +.swagger-section .swagger-ui-wrap .icon-btn { + cursor: pointer; +} +.swagger-section .swagger-ui-wrap .info_title { + padding-bottom: 10px; + font-weight: bold; + font-size: 25px; +} +.swagger-section .swagger-ui-wrap .footer { + margin-top: 20px; +} +.swagger-section .swagger-ui-wrap p.big, +.swagger-section .swagger-ui-wrap div.big p { + font-size: 1em; + margin-bottom: 10px; +} +.swagger-section .swagger-ui-wrap form.fullwidth ol li.string input, +.swagger-section .swagger-ui-wrap form.fullwidth ol li.url input, +.swagger-section .swagger-ui-wrap form.fullwidth ol li.text textarea, +.swagger-section .swagger-ui-wrap form.fullwidth ol li.numeric input { + width: 500px !important; +} +.swagger-section .swagger-ui-wrap .info_license { + padding-bottom: 5px; +} +.swagger-section .swagger-ui-wrap .info_tos { + padding-bottom: 5px; +} +.swagger-section .swagger-ui-wrap .message-fail { + color: #cc0000; +} +.swagger-section .swagger-ui-wrap .info_url { + padding-bottom: 5px; +} +.swagger-section .swagger-ui-wrap .info_email { + padding-bottom: 5px; +} +.swagger-section .swagger-ui-wrap .info_name { + padding-bottom: 5px; +} +.swagger-section .swagger-ui-wrap .info_description { + padding-bottom: 10px; + font-size: 15px; +} +.swagger-section .swagger-ui-wrap .markdown ol li, +.swagger-section .swagger-ui-wrap .markdown ul li { + padding: 3px 0px; + line-height: 1.4em; + color: #333333; +} +.swagger-section .swagger-ui-wrap form.formtastic fieldset.inputs ol li.string input, +.swagger-section .swagger-ui-wrap form.formtastic fieldset.inputs ol li.url input, +.swagger-section .swagger-ui-wrap form.formtastic fieldset.inputs ol li.numeric input { + display: block; + padding: 4px; + width: auto; + clear: both; +} +.swagger-section .swagger-ui-wrap form.formtastic fieldset.inputs ol li.string input.title, +.swagger-section .swagger-ui-wrap form.formtastic fieldset.inputs ol li.url input.title, +.swagger-section .swagger-ui-wrap form.formtastic fieldset.inputs ol li.numeric input.title { + font-size: 1.3em; +} +.swagger-section .swagger-ui-wrap table.fullwidth { + width: 100%; +} +.swagger-section .swagger-ui-wrap .model-signature { + font-family: "Droid Sans", sans-serif; + font-size: 1em; + line-height: 1.5em; +} +.swagger-section .swagger-ui-wrap .model-signature .signature-nav a { + text-decoration: none; + color: #AAA; +} +.swagger-section .swagger-ui-wrap .model-signature .signature-nav a:hover { + text-decoration: underline; + color: black; +} +.swagger-section .swagger-ui-wrap .model-signature .signature-nav .selected { + color: black; + text-decoration: none; +} +.swagger-section .swagger-ui-wrap .model-signature .propType { + color: #5555aa; +} +.swagger-section .swagger-ui-wrap .model-signature pre:hover { + background-color: #ffffdd; +} +.swagger-section .swagger-ui-wrap .model-signature pre { + font-size: .85em; + line-height: 1.2em; + overflow: auto; + max-height: 200px; + cursor: pointer; +} +.swagger-section .swagger-ui-wrap .model-signature ul.signature-nav { + display: block; + margin: 0; + padding: 0; +} +.swagger-section .swagger-ui-wrap .model-signature ul.signature-nav li:last-child { + padding-right: 0; + border-right: none; +} +.swagger-section .swagger-ui-wrap .model-signature ul.signature-nav li { + float: left; + margin: 0 5px 5px 0; + padding: 2px 5px 2px 0; + border-right: 1px solid #ddd; +} +.swagger-section .swagger-ui-wrap .model-signature .propOpt { + color: #555; +} +.swagger-section .swagger-ui-wrap .model-signature .snippet small { + font-size: 0.75em; +} +.swagger-section .swagger-ui-wrap .model-signature .propOptKey { + font-style: italic; +} +.swagger-section .swagger-ui-wrap .model-signature .description .strong { + font-weight: bold; + color: #000; + font-size: .9em; +} +.swagger-section .swagger-ui-wrap .model-signature .description div { + font-size: 0.9em; + line-height: 1.5em; + margin-left: 1em; +} +.swagger-section .swagger-ui-wrap .model-signature .description .stronger { + font-weight: bold; + color: #000; +} +.swagger-section .swagger-ui-wrap .model-signature .description .propWrap .optionsWrapper { + border-spacing: 0; + position: absolute; + background-color: #ffffff; + border: 1px solid #bbbbbb; + display: none; + font-size: 11px; + max-width: 400px; + line-height: 30px; + color: black; + padding: 5px; + margin-left: 10px; +} +.swagger-section .swagger-ui-wrap .model-signature .description .propWrap .optionsWrapper th { + text-align: center; + background-color: #eeeeee; + border: 1px solid #bbbbbb; + font-size: 11px; + color: #666666; + font-weight: bold; + padding: 5px; + line-height: 15px; +} +.swagger-section .swagger-ui-wrap .model-signature .description .propWrap .optionsWrapper .optionName { + font-weight: bold; +} +.swagger-section .swagger-ui-wrap .model-signature .description .propDesc.markdown > p:first-child, +.swagger-section .swagger-ui-wrap .model-signature .description .propDesc.markdown > p:last-child { + display: inline; +} +.swagger-section .swagger-ui-wrap .model-signature .description .propDesc.markdown > p:not(:first-child):before { + display: block; + content: ''; +} +.swagger-section .swagger-ui-wrap .model-signature .description span:last-of-type.propDesc.markdown > p:only-child { + margin-right: -3px; +} +.swagger-section .swagger-ui-wrap .model-signature .propName { + font-weight: bold; +} +.swagger-section .swagger-ui-wrap .model-signature .signature-container { + clear: both; +} +.swagger-section .swagger-ui-wrap .body-textarea { + width: 300px; + height: 100px; + border: 1px solid #aaa; +} +.swagger-section .swagger-ui-wrap .markdown p code, +.swagger-section .swagger-ui-wrap .markdown li code { + font-family: "Anonymous Pro", "Menlo", "Consolas", "Bitstream Vera Sans Mono", "Courier New", monospace; + background-color: #f0f0f0; + color: black; + padding: 1px 3px; +} +.swagger-section .swagger-ui-wrap .required { + font-weight: bold; +} +.swagger-section .swagger-ui-wrap .editor_holder { + font-family: "Anonymous Pro", "Menlo", "Consolas", "Bitstream Vera Sans Mono", "Courier New", monospace; + font-size: 0.9em; +} +.swagger-section .swagger-ui-wrap .editor_holder label { + font-weight: normal!important; + /* JSONEditor uses bold by default for all labels, we revert that back to normal to not give the impression that by default fields are required */ +} +.swagger-section .swagger-ui-wrap .editor_holder label.required { + font-weight: bold!important; +} +.swagger-section .swagger-ui-wrap input.parameter { + width: 300px; + border: 1px solid #aaa; +} +.swagger-section .swagger-ui-wrap h1 { + color: black; + font-size: 1.5em; + line-height: 1.3em; + padding: 10px 0 10px 0; + font-family: "Droid Sans", sans-serif; + font-weight: bold; +} +.swagger-section .swagger-ui-wrap .heading_with_menu { + float: none; + clear: both; + overflow: hidden; + display: block; +} +.swagger-section .swagger-ui-wrap .heading_with_menu ul { + display: block; + clear: none; + float: right; + -moz-box-sizing: border-box; + -webkit-box-sizing: border-box; + -ms-box-sizing: border-box; + box-sizing: border-box; + margin-top: 10px; +} +.swagger-section .swagger-ui-wrap h2 { + color: black; + font-size: 1.3em; + padding: 10px 0 10px 0; +} +.swagger-section .swagger-ui-wrap h2 a { + color: black; +} +.swagger-section .swagger-ui-wrap h2 span.sub { + font-size: 0.7em; + color: #999999; + font-style: italic; +} +.swagger-section .swagger-ui-wrap h2 span.sub a { + color: #777777; +} +.swagger-section .swagger-ui-wrap span.weak { + color: #666666; +} +.swagger-section .swagger-ui-wrap .message-success { + color: #89BF04; +} +.swagger-section .swagger-ui-wrap caption, +.swagger-section .swagger-ui-wrap th, +.swagger-section .swagger-ui-wrap td { + text-align: left; + font-weight: normal; + vertical-align: middle; +} +.swagger-section .swagger-ui-wrap .code { + font-family: "Anonymous Pro", "Menlo", "Consolas", "Bitstream Vera Sans Mono", "Courier New", monospace; +} +.swagger-section .swagger-ui-wrap form.formtastic fieldset.inputs ol li.text textarea { + font-family: "Droid Sans", sans-serif; + height: 250px; + padding: 4px; + display: block; + clear: both; +} +.swagger-section .swagger-ui-wrap form.formtastic fieldset.inputs ol li.select select { + display: block; + clear: both; +} +.swagger-section .swagger-ui-wrap form.formtastic fieldset.inputs ol li.boolean { + float: none; + clear: both; + overflow: hidden; + display: block; +} +.swagger-section .swagger-ui-wrap form.formtastic fieldset.inputs ol li.boolean label { + display: block; + float: left; + clear: none; + margin: 0; + padding: 0; +} +.swagger-section .swagger-ui-wrap form.formtastic fieldset.inputs ol li.boolean input { + display: block; + float: left; + clear: none; + margin: 0 5px 0 0; +} +.swagger-section .swagger-ui-wrap form.formtastic fieldset.inputs ol li.required label { + color: black; +} +.swagger-section .swagger-ui-wrap form.formtastic fieldset.inputs ol li label { + display: block; + clear: both; + width: auto; + padding: 0 0 3px; + color: #666666; +} +.swagger-section .swagger-ui-wrap form.formtastic fieldset.inputs ol li label abbr { + padding-left: 3px; + color: #888888; +} +.swagger-section .swagger-ui-wrap form.formtastic fieldset.inputs ol li p.inline-hints { + margin-left: 0; + font-style: italic; + font-size: 0.9em; + margin: 0; +} +.swagger-section .swagger-ui-wrap form.formtastic fieldset.buttons { + margin: 0; + padding: 0; +} +.swagger-section .swagger-ui-wrap span.blank, +.swagger-section .swagger-ui-wrap span.empty { + color: #888888; + font-style: italic; +} +.swagger-section .swagger-ui-wrap .markdown h3 { + color: #547f00; +} +.swagger-section .swagger-ui-wrap .markdown h4 { + color: #666666; +} +.swagger-section .swagger-ui-wrap .markdown pre { + font-family: "Anonymous Pro", "Menlo", "Consolas", "Bitstream Vera Sans Mono", "Courier New", monospace; + background-color: #fcf6db; + border: 1px solid #e5e0c6; + padding: 10px; + margin: 0 0 10px 0; +} +.swagger-section .swagger-ui-wrap .markdown pre code { + line-height: 1.6em; +} +.swagger-section .swagger-ui-wrap div.gist { + margin: 20px 0 25px 0 !important; +} +.swagger-section .swagger-ui-wrap ul#resources { + font-family: "Droid Sans", sans-serif; + font-size: 0.9em; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource { + border-bottom: 1px solid #dddddd; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource:hover div.heading h2 a, +.swagger-section .swagger-ui-wrap ul#resources li.resource.active div.heading h2 a { + color: black; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource:hover div.heading ul.options li a, +.swagger-section .swagger-ui-wrap ul#resources li.resource.active div.heading ul.options li a { + color: #555555; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource:last-child { + border-bottom: none; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource div.heading { + border: 1px solid transparent; + float: none; + clear: both; + overflow: hidden; + display: block; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource div.heading ul.options { + overflow: hidden; + padding: 0; + display: block; + clear: none; + float: right; + margin: 14px 10px 0 0; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource div.heading ul.options li { + float: left; + clear: none; + margin: 0; + padding: 2px 10px; + border-right: 1px solid #dddddd; + color: #666666; + font-size: 0.9em; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource div.heading ul.options li a { + color: #aaaaaa; + text-decoration: none; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource div.heading ul.options li a:hover { + text-decoration: underline; + color: black; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource div.heading ul.options li a:hover, +.swagger-section .swagger-ui-wrap ul#resources li.resource div.heading ul.options li a:active, +.swagger-section .swagger-ui-wrap ul#resources li.resource div.heading ul.options li a.active { + text-decoration: underline; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource div.heading ul.options li:first-child, +.swagger-section .swagger-ui-wrap ul#resources li.resource div.heading ul.options li.first { + padding-left: 0; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource div.heading ul.options li:last-child, +.swagger-section .swagger-ui-wrap ul#resources li.resource div.heading ul.options li.last { + padding-right: 0; + border-right: none; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource div.heading ul.options:first-child, +.swagger-section .swagger-ui-wrap ul#resources li.resource div.heading ul.options.first { + padding-left: 0; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource div.heading h2 { + color: #999999; + padding-left: 0; + display: block; + clear: none; + float: left; + font-family: "Droid Sans", sans-serif; + font-weight: bold; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource div.heading h2 a { + color: #999999; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource div.heading h2 a:hover { + color: black; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation { + float: none; + clear: both; + overflow: hidden; + display: block; + margin: 0 0 10px; + padding: 0; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.heading { + float: none; + clear: both; + overflow: hidden; + display: block; + margin: 0; + padding: 0; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.heading h3 { + display: block; + clear: none; + float: left; + width: auto; + margin: 0; + padding: 0; + line-height: 1.1em; + color: black; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.heading h3 span.path { + padding-left: 10px; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.heading h3 span.path a { + color: black; + text-decoration: none; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.heading h3 span.path a:hover { + text-decoration: underline; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.heading h3 span.http_method a { + text-transform: uppercase; + text-decoration: none; + color: white; + display: inline-block; + width: 50px; + font-size: 0.7em; + text-align: center; + padding: 7px 0 4px; + -moz-border-radius: 2px; + -webkit-border-radius: 2px; + -o-border-radius: 2px; + -ms-border-radius: 2px; + -khtml-border-radius: 2px; + border-radius: 2px; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.heading h3 span { + margin: 0; + padding: 0; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.heading ul.options { + overflow: hidden; + padding: 0; + display: block; + clear: none; + float: right; + margin: 6px 10px 0 0; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.heading ul.options li { + float: left; + clear: none; + margin: 0; + padding: 2px 10px; + font-size: 0.9em; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.heading ul.options li a { + text-decoration: none; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.heading ul.options li.access { + color: black; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.content { + border-top: none; + padding: 10px; + -moz-border-radius-bottomleft: 6px; + -webkit-border-bottom-left-radius: 6px; + -o-border-bottom-left-radius: 6px; + -ms-border-bottom-left-radius: 6px; + -khtml-border-bottom-left-radius: 6px; + border-bottom-left-radius: 6px; + -moz-border-radius-bottomright: 6px; + -webkit-border-bottom-right-radius: 6px; + -o-border-bottom-right-radius: 6px; + -ms-border-bottom-right-radius: 6px; + -khtml-border-bottom-right-radius: 6px; + border-bottom-right-radius: 6px; + margin: 0 0 20px; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.content h4 { + font-size: 1.1em; + margin: 0; + padding: 15px 0 5px; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.content div.sandbox_header { + float: none; + clear: both; + overflow: hidden; + display: block; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.content div.sandbox_header a { + padding: 4px 0 0 10px; + display: inline-block; + font-size: 0.9em; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.content div.sandbox_header input.submit { + display: block; + clear: none; + float: left; + padding: 6px 8px; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.content div.sandbox_header span.response_throbber { + background-image: url('../images/throbber.gif'); + width: 128px; + height: 16px; + display: block; + clear: none; + float: right; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.content form input[type='text'].error { + outline: 2px solid black; + outline-color: #cc0000; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.content form select[name='parameterContentType'] { + max-width: 300px; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.content div.response div.block pre { + font-family: "Anonymous Pro", "Menlo", "Consolas", "Bitstream Vera Sans Mono", "Courier New", monospace; + padding: 10px; + font-size: 0.9em; + max-height: 400px; + overflow-y: auto; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put div.heading { + background-color: #f9f2e9; + border: 1px solid #f0e0ca; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put div.heading h3 span.http_method a { + background-color: #c5862b; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put div.heading ul.options li { + border-right: 1px solid #dddddd; + border-right-color: #f0e0ca; + color: #c5862b; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put div.heading ul.options li a { + color: #c5862b; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put div.content { + background-color: #faf5ee; + border: 1px solid #f0e0ca; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put div.content h4 { + color: #c5862b; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put div.content div.sandbox_header a { + color: #dcb67f; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.head div.heading { + background-color: #fcffcd; + border: 1px solid black; + border-color: #ffd20f; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.head div.heading h3 span.http_method a { + text-transform: uppercase; + background-color: #ffd20f; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.head div.heading ul.options li { + border-right: 1px solid #dddddd; + border-right-color: #ffd20f; + color: #ffd20f; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.head div.heading ul.options li a { + color: #ffd20f; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.head div.content { + background-color: #fcffcd; + border: 1px solid black; + border-color: #ffd20f; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.head div.content h4 { + color: #ffd20f; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.head div.content div.sandbox_header a { + color: #6fc992; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete div.heading { + background-color: #f5e8e8; + border: 1px solid #e8c6c7; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete div.heading h3 span.http_method a { + text-transform: uppercase; + background-color: #a41e22; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete div.heading ul.options li { + border-right: 1px solid #dddddd; + border-right-color: #e8c6c7; + color: #a41e22; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete div.heading ul.options li a { + color: #a41e22; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete div.content { + background-color: #f7eded; + border: 1px solid #e8c6c7; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete div.content h4 { + color: #a41e22; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete div.content div.sandbox_header a { + color: #c8787a; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post div.heading { + background-color: #e7f6ec; + border: 1px solid #c3e8d1; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post div.heading h3 span.http_method a { + background-color: #10a54a; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post div.heading ul.options li { + border-right: 1px solid #dddddd; + border-right-color: #c3e8d1; + color: #10a54a; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post div.heading ul.options li a { + color: #10a54a; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post div.content { + background-color: #ebf7f0; + border: 1px solid #c3e8d1; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post div.content h4 { + color: #10a54a; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post div.content div.sandbox_header a { + color: #6fc992; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.patch div.heading { + background-color: #FCE9E3; + border: 1px solid #F5D5C3; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.patch div.heading h3 span.http_method a { + background-color: #D38042; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.patch div.heading ul.options li { + border-right: 1px solid #dddddd; + border-right-color: #f0cecb; + color: #D38042; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.patch div.heading ul.options li a { + color: #D38042; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.patch div.content { + background-color: #faf0ef; + border: 1px solid #f0cecb; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.patch div.content h4 { + color: #D38042; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.patch div.content div.sandbox_header a { + color: #dcb67f; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get div.heading { + background-color: #e7f0f7; + border: 1px solid #c3d9ec; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get div.heading h3 span.http_method a { + background-color: #0f6ab4; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get div.heading ul.options li { + border-right: 1px solid #dddddd; + border-right-color: #c3d9ec; + color: #0f6ab4; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get div.heading ul.options li a { + color: #0f6ab4; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get div.content { + background-color: #ebf3f9; + border: 1px solid #c3d9ec; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get div.content h4 { + color: #0f6ab4; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get div.content div.sandbox_header a { + color: #6fa5d2; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.options div.heading { + background-color: #e7f0f7; + border: 1px solid #c3d9ec; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.options div.heading h3 span.http_method a { + background-color: #0f6ab4; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.options div.heading ul.options li { + border-right: 1px solid #dddddd; + border-right-color: #c3d9ec; + color: #0f6ab4; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.options div.heading ul.options li a { + color: #0f6ab4; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.options div.content { + background-color: #ebf3f9; + border: 1px solid #c3d9ec; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.options div.content h4 { + color: #0f6ab4; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.options div.content div.sandbox_header a { + color: #6fa5d2; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get div.content, +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post div.content, +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.head div.content, +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put div.content, +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.patch div.content, +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete div.content { + border-top: none; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get div.heading ul.options li:last-child, +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post div.heading ul.options li:last-child, +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.head div.heading ul.options li:last-child, +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put div.heading ul.options li:last-child, +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.patch div.heading ul.options li:last-child, +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete div.heading ul.options li:last-child, +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get div.heading ul.options li.last, +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post div.heading ul.options li.last, +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.head div.heading ul.options li.last, +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put div.heading ul.options li.last, +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.patch div.heading ul.options li.last, +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete div.heading ul.options li.last { + padding-right: 0; + border-right: none; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations ul.options li a:hover, +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations ul.options li a:active, +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations ul.options li a.active { + text-decoration: underline; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations ul.options li:first-child, +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations ul.options li.first { + padding-left: 0; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations:first-child, +.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations.first { + padding-left: 0; +} +.swagger-section .swagger-ui-wrap p#colophon { + margin: 0 15px 40px 15px; + padding: 10px 0; + font-size: 0.8em; + border-top: 1px solid #dddddd; + font-family: "Droid Sans", sans-serif; + color: #999999; + font-style: italic; +} +.swagger-section .swagger-ui-wrap p#colophon a { + text-decoration: none; + color: #547f00; +} +.swagger-section .swagger-ui-wrap h3 { + color: black; + font-size: 1.1em; + padding: 10px 0 10px 0; +} +.swagger-section .swagger-ui-wrap .markdown ol, +.swagger-section .swagger-ui-wrap .markdown ul { + font-family: "Droid Sans", sans-serif; + margin: 5px 0 10px; + padding: 0 0 0 18px; + list-style-type: disc; +} +.swagger-section .swagger-ui-wrap form.form_box { + background-color: #ebf3f9; + border: 1px solid #c3d9ec; + padding: 10px; +} +.swagger-section .swagger-ui-wrap form.form_box label { + color: #0f6ab4 !important; +} +.swagger-section .swagger-ui-wrap form.form_box input[type=submit] { + display: block; + padding: 10px; +} +.swagger-section .swagger-ui-wrap form.form_box p.weak { + font-size: 0.8em; +} +.swagger-section .swagger-ui-wrap form.form_box p { + font-size: 0.9em; + padding: 0 0 15px; + color: #7e7b6d; +} +.swagger-section .swagger-ui-wrap form.form_box p a { + color: #646257; +} +.swagger-section .swagger-ui-wrap form.form_box p strong { + color: black; +} +.swagger-section .swagger-ui-wrap .operation-status td.markdown > p:last-child { + padding-bottom: 0; +} +.swagger-section .title { + font-style: bold; +} +.swagger-section .secondary_form { + display: none; +} +.swagger-section .main_image { + display: block; + margin-left: auto; + margin-right: auto; +} +.swagger-section .oauth_body { + margin-left: 100px; + margin-right: 100px; +} +.swagger-section .oauth_submit { + text-align: center; +} +.swagger-section .api-popup-dialog { + z-index: 10000; + position: absolute; + width: 500px; + background: #FFF; + padding: 20px; + border: 1px solid #ccc; + border-radius: 5px; + display: none; + font-size: 13px; + color: #777; +} +.swagger-section .api-popup-dialog .api-popup-title { + font-size: 24px; + padding: 10px 0; +} +.swagger-section .api-popup-dialog .api-popup-title { + font-size: 24px; + padding: 10px 0; +} +.swagger-section .api-popup-dialog .error-msg { + padding-left: 5px; + padding-bottom: 5px; +} +.swagger-section .api-popup-dialog .api-popup-authbtn { + height: 30px; +} +.swagger-section .api-popup-dialog .api-popup-cancel { + height: 30px; +} +.swagger-section .api-popup-scopes { + padding: 10px 20px; +} +.swagger-section .api-popup-scopes li { + padding: 5px 0; + line-height: 20px; +} +.swagger-section .api-popup-scopes li input { + position: relative; + top: 2px; +} +.swagger-section .api-popup-scopes .api-scope-desc { + padding-left: 20px; + font-style: italic; +} +.swagger-section .api-popup-actions { + padding-top: 10px; +} +.swagger-section .access { + float: right; +} +.swagger-section .auth { + float: right; +} +.swagger-section .api-ic { + height: 18px; + vertical-align: middle; + display: inline-block; + background: url(../images/explorer_icons.png) no-repeat; +} +.swagger-section .api-ic .api_information_panel { + position: relative; + margin-top: 20px; + margin-left: -5px; + background: #FFF; + border: 1px solid #ccc; + border-radius: 5px; + display: none; + font-size: 13px; + max-width: 300px; + line-height: 30px; + color: black; + padding: 5px; +} +.swagger-section .api-ic .api_information_panel p .api-msg-enabled { + color: green; +} +.swagger-section .api-ic .api_information_panel p .api-msg-disabled { + color: red; +} +.swagger-section .api-ic:hover .api_information_panel { + position: absolute; + display: block; +} +.swagger-section .ic-info { + background-position: 0 0; + width: 18px; + margin-top: -6px; + margin-left: 4px; +} +.swagger-section .ic-warning { + background-position: -60px 0; + width: 18px; + margin-top: -6px; + margin-left: 4px; +} +.swagger-section .ic-error { + background-position: -30px 0; + width: 18px; + margin-top: -6px; + margin-left: 4px; +} +.swagger-section .ic-off { + background-position: -90px 0; + width: 58px; + margin-top: -4px; + cursor: pointer; +} +.swagger-section .ic-on { + background-position: -160px 0; + width: 58px; + margin-top: -4px; + cursor: pointer; +} +.swagger-section #header { + background-color: #89bf04; + padding: 14px; +} +.swagger-section #input_baseUrl { + width: 400px; +} +.swagger-section #api_selector { + display: block; + clear: none; + float: right; +} +.swagger-section #api_selector .input { + display: block; + clear: none; + float: left; + margin: 0 10px 0 0; +} +.swagger-section #api_selector input { + font-size: 0.9em; + padding: 3px; + margin: 0; +} +.swagger-section #input_apiKey { + width: 200px; +} +.swagger-section #explore { + display: block; + text-decoration: none; + font-weight: bold; + padding: 6px 8px; + font-size: 0.9em; + color: white; + background-color: #547f00; + -moz-border-radius: 4px; + -webkit-border-radius: 4px; + -o-border-radius: 4px; + -ms-border-radius: 4px; + -khtml-border-radius: 4px; + border-radius: 4px; +} +.swagger-section #explore:hover { + background-color: #547f00; +} +.swagger-section #header #logo { + font-size: 1.5em; + font-weight: bold; + text-decoration: none; + background: transparent url(../images/logo_small.png) no-repeat left center; + padding: 20px 0 20px 40px; + color: white; +} +.swagger-section #content_message { + margin: 10px 15px; + font-style: italic; + color: #999999; +} +.swagger-section #message-bar { + min-height: 30px; + text-align: center; + padding-top: 10px; +} +.swagger-section .swagger-collapse:before { + content: "-"; +} +.swagger-section .swagger-expand:before { + content: "+"; +} diff --git a/devops-service/app/api3/public/swagger-ui/css/style.css b/devops-service/app/api3/public/swagger-ui/css/style.css new file mode 100644 index 0000000..fc21a31 --- /dev/null +++ b/devops-service/app/api3/public/swagger-ui/css/style.css @@ -0,0 +1,250 @@ +.swagger-section #header a#logo { + font-size: 1.5em; + font-weight: bold; + text-decoration: none; + background: transparent url(../images/logo.png) no-repeat left center; + padding: 20px 0 20px 40px; +} +#text-head { + font-size: 80px; + font-family: 'Roboto', sans-serif; + color: #ffffff; + float: right; + margin-right: 20%; +} +.navbar-fixed-top .navbar-nav { + height: auto; +} +.navbar-fixed-top .navbar-brand { + height: auto; +} +.navbar-header { + height: auto; +} +.navbar-inverse { + background-color: #000; + border-color: #000; +} +#navbar-brand { + margin-left: 20%; +} +.navtext { + font-size: 10px; +} +.h1, +h1 { + font-size: 60px; +} +.navbar-default .navbar-header .navbar-brand { + color: #a2dfee; +} +/* tag titles */ +.swagger-section .swagger-ui-wrap ul#resources li.resource div.heading h2 a { + color: #393939; + font-family: 'Arvo', serif; + font-size: 1.5em; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource div.heading h2 a:hover { + color: black; +} +.swagger-section .swagger-ui-wrap ul#resources li.resource div.heading h2 { + color: #525252; + padding-left: 0px; + display: block; + clear: none; + float: left; + font-family: 'Arvo', serif; + font-weight: bold; +} +.navbar-default .navbar-collapse, +.navbar-default .navbar-form { + border-color: #0A0A0A; +} +.container1 { + width: 1500px; + margin: auto; + margin-top: 0; + background-image: url('../images/shield.png'); + background-repeat: no-repeat; + background-position: -40px -20px; + margin-bottom: 210px; +} +.container-inner { + width: 1200px; + margin: auto; + background-color: rgba(223, 227, 228, 0.75); + padding-bottom: 40px; + padding-top: 40px; + border-radius: 15px; +} +.header-content { + padding: 0; + width: 1000px; +} +.title1 { + font-size: 80px; + font-family: 'Vollkorn', serif; + color: #404040; + text-align: center; + padding-top: 40px; + padding-bottom: 100px; +} +#icon { + margin-top: -18px; +} +.subtext { + font-size: 25px; + font-style: italic; + color: #08b; + text-align: right; + padding-right: 250px; +} +.bg-primary { + background-color: #00468b; +} +.navbar-default .nav > li > a, +.navbar-default .nav > li > a:focus { + color: #08b; +} +.navbar-default .nav > li > a, +.navbar-default .nav > li > a:hover { + color: #08b; +} +.navbar-default .nav > li > a, +.navbar-default .nav > li > a:focus:hover { + color: #08b; +} +.text-faded { + font-size: 25px; + font-family: 'Vollkorn', serif; +} +.section-heading { + font-family: 'Vollkorn', serif; + font-size: 45px; + padding-bottom: 10px; +} +hr { + border-color: #00468b; + padding-bottom: 10px; +} +.description { + margin-top: 20px; + padding-bottom: 200px; +} +.description li { + font-family: 'Vollkorn', serif; + font-size: 25px; + color: #525252; + margin-left: 28%; + padding-top: 5px; +} +.gap { + margin-top: 200px; +} +.troubleshootingtext { + color: rgba(255, 255, 255, 0.7); + padding-left: 30%; +} +.troubleshootingtext li { + list-style-type: circle; + font-size: 25px; + padding-bottom: 5px; +} +.overlay { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + z-index: 1000; +} +.block.response_body.json:hover { + cursor: pointer; +} +.backdrop { + color: blue; +} +#myModal { + height: 100%; +} +.modal-backdrop { + bottom: 0; + position: fixed; +} +.curl { + padding: 10px; + font-family: "Anonymous Pro", "Menlo", "Consolas", "Bitstream Vera Sans Mono", "Courier New", monospace; + font-size: 0.9em; + max-height: 400px; + margin-top: 5px; + overflow-y: auto; + background-color: #fcf6db; + border: 1px solid #e5e0c6; + border-radius: 4px; +} +.curl_title { + font-size: 1.1em; + margin: 0; + padding: 15px 0 5px; + font-family: 'Open Sans', 'Helvetica Neue', Arial, sans-serif; + font-weight: 500; + line-height: 1.1; +} +.footer { + display: none; +} +.swagger-section .swagger-ui-wrap h2 { + padding: 0; +} +h2 { + margin: 0; + margin-bottom: 5px; +} +.markdown p { + font-size: 15px; + font-family: 'Arvo', serif; +} +.swagger-section .swagger-ui-wrap .code { + font-size: 15px; + font-family: 'Arvo', serif; +} +.swagger-section .swagger-ui-wrap b { + font-family: 'Arvo', serif; +} +#signin:hover { + cursor: pointer; +} +.dropdown-menu { + padding: 15px; +} +.navbar-right .dropdown-menu { + left: 0; + right: auto; +} +#signinbutton { + width: 100%; + height: 32px; + font-size: 13px; + font-weight: bold; + color: #08b; +} +.navbar-default .nav > li .details { + color: #000000; + text-transform: none; + font-size: 15px; + font-weight: normal; + font-family: 'Open Sans', sans-serif; + font-style: italic; + line-height: 20px; + top: -2px; +} +.navbar-default .nav > li .details:hover { + color: black; +} +#signout { + width: 100%; + height: 32px; + font-size: 13px; + font-weight: bold; + color: #08b; +} diff --git a/devops-service/app/api3/public/swagger-ui/css/typography.css b/devops-service/app/api3/public/swagger-ui/css/typography.css new file mode 100644 index 0000000..3235edd --- /dev/null +++ b/devops-service/app/api3/public/swagger-ui/css/typography.css @@ -0,0 +1,14 @@ +/* Google Font's Droid Sans */ +@font-face { + font-family: 'Droid Sans'; + font-style: normal; + font-weight: 400; + src: local('Droid Sans'), local('DroidSans'), url('../fonts/DroidSans.ttf') format('truetype'); +} +/* Google Font's Droid Sans Bold */ +@font-face { + font-family: 'Droid Sans'; + font-style: normal; + font-weight: 700; + src: local('Droid Sans Bold'), local('DroidSans-Bold'), url('../fonts/DroidSans-Bold.ttf') format('truetype'); +} diff --git a/devops-service/app/api3/public/swagger-ui/fonts/DroidSans-Bold.ttf b/devops-service/app/api3/public/swagger-ui/fonts/DroidSans-Bold.ttf new file mode 100644 index 0000000..942bbf5 Binary files /dev/null and b/devops-service/app/api3/public/swagger-ui/fonts/DroidSans-Bold.ttf differ diff --git a/devops-service/app/api3/public/swagger-ui/fonts/DroidSans.ttf b/devops-service/app/api3/public/swagger-ui/fonts/DroidSans.ttf new file mode 100644 index 0000000..efd1f8b Binary files /dev/null and b/devops-service/app/api3/public/swagger-ui/fonts/DroidSans.ttf differ diff --git a/devops-service/app/api3/public/swagger-ui/images/collapse.gif b/devops-service/app/api3/public/swagger-ui/images/collapse.gif new file mode 100644 index 0000000..8843e8c Binary files /dev/null and b/devops-service/app/api3/public/swagger-ui/images/collapse.gif differ diff --git a/devops-service/app/api3/public/swagger-ui/images/expand.gif b/devops-service/app/api3/public/swagger-ui/images/expand.gif new file mode 100644 index 0000000..477bf13 Binary files /dev/null and b/devops-service/app/api3/public/swagger-ui/images/expand.gif differ diff --git a/devops-service/app/api3/public/swagger-ui/images/explorer_icons.png b/devops-service/app/api3/public/swagger-ui/images/explorer_icons.png new file mode 100644 index 0000000..ed9d2ff Binary files /dev/null and b/devops-service/app/api3/public/swagger-ui/images/explorer_icons.png differ diff --git a/devops-service/app/api3/public/swagger-ui/images/favicon-16x16.png b/devops-service/app/api3/public/swagger-ui/images/favicon-16x16.png new file mode 100755 index 0000000..66b1a5b Binary files /dev/null and b/devops-service/app/api3/public/swagger-ui/images/favicon-16x16.png differ diff --git a/devops-service/app/api3/public/swagger-ui/images/favicon-32x32.png b/devops-service/app/api3/public/swagger-ui/images/favicon-32x32.png new file mode 100755 index 0000000..32f319f Binary files /dev/null and b/devops-service/app/api3/public/swagger-ui/images/favicon-32x32.png differ diff --git a/devops-service/app/api3/public/swagger-ui/images/favicon.ico b/devops-service/app/api3/public/swagger-ui/images/favicon.ico new file mode 100755 index 0000000..8b60bcf Binary files /dev/null and b/devops-service/app/api3/public/swagger-ui/images/favicon.ico differ diff --git a/devops-service/app/api3/public/swagger-ui/images/logo_small.png b/devops-service/app/api3/public/swagger-ui/images/logo_small.png new file mode 100644 index 0000000..5496a65 Binary files /dev/null and b/devops-service/app/api3/public/swagger-ui/images/logo_small.png differ diff --git a/devops-service/app/api3/public/swagger-ui/images/pet_store_api.png b/devops-service/app/api3/public/swagger-ui/images/pet_store_api.png new file mode 100644 index 0000000..f9f9cd4 Binary files /dev/null and b/devops-service/app/api3/public/swagger-ui/images/pet_store_api.png differ diff --git a/devops-service/app/api3/public/swagger-ui/images/throbber.gif b/devops-service/app/api3/public/swagger-ui/images/throbber.gif new file mode 100644 index 0000000..0639388 Binary files /dev/null and b/devops-service/app/api3/public/swagger-ui/images/throbber.gif differ diff --git a/devops-service/app/api3/public/swagger-ui/images/wordnik_api.png b/devops-service/app/api3/public/swagger-ui/images/wordnik_api.png new file mode 100644 index 0000000..dca4f14 Binary files /dev/null and b/devops-service/app/api3/public/swagger-ui/images/wordnik_api.png differ diff --git a/devops-service/app/api3/public/swagger-ui/lang/en.js b/devops-service/app/api3/public/swagger-ui/lang/en.js new file mode 100644 index 0000000..9ccd65a --- /dev/null +++ b/devops-service/app/api3/public/swagger-ui/lang/en.js @@ -0,0 +1,55 @@ +'use strict'; + +/* jshint quotmark: double */ +window.SwaggerTranslator.learn({ + "Warning: Deprecated":"Warning: Deprecated", + "Implementation Notes":"Implementation Notes", + "Response Class":"Response Class", + "Status":"Status", + "Parameters":"Parameters", + "Parameter":"Parameter", + "Value":"Value", + "Description":"Description", + "Parameter Type":"Parameter Type", + "Data Type":"Data Type", + "Response Messages":"Response Messages", + "HTTP Status Code":"HTTP Status Code", + "Reason":"Reason", + "Response Model":"Response Model", + "Request URL":"Request URL", + "Response Body":"Response Body", + "Response Code":"Response Code", + "Response Headers":"Response Headers", + "Hide Response":"Hide Response", + "Headers":"Headers", + "Try it out!":"Try it out!", + "Show/Hide":"Show/Hide", + "List Operations":"List Operations", + "Expand Operations":"Expand Operations", + "Raw":"Raw", + "can't parse JSON. Raw result":"can't parse JSON. Raw result", + "Model Schema":"Model Schema", + "Model":"Model", + "Click to set as parameter value":"Click to set as parameter value", + "apply":"apply", + "Username":"Username", + "Password":"Password", + "Terms of service":"Terms of service", + "Created by":"Created by", + "See more at":"See more at", + "Contact the developer":"Contact the developer", + "api version":"api version", + "Response Content Type":"Response Content Type", + "Parameter content type:":"Parameter content type:", + "fetching resource":"fetching resource", + "fetching resource list":"fetching resource list", + "Explore":"Explore", + "Show Swagger Petstore Example Apis":"Show Swagger Petstore Example Apis", + "Can't read from server. It may not have the appropriate access-control-origin settings.":"Can't read from server. It may not have the appropriate access-control-origin settings.", + "Please specify the protocol for":"Please specify the protocol for", + "Can't read swagger JSON from":"Can't read swagger JSON from", + "Finished Loading Resource Information. Rendering Swagger UI":"Finished Loading Resource Information. Rendering Swagger UI", + "Unable to read api":"Unable to read api", + "from path":"from path", + "server returned":"server returned" +}); diff --git a/devops-service/app/api3/public/swagger-ui/lang/es.js b/devops-service/app/api3/public/swagger-ui/lang/es.js new file mode 100644 index 0000000..a8dff60 --- /dev/null +++ b/devops-service/app/api3/public/swagger-ui/lang/es.js @@ -0,0 +1,52 @@ +'use strict'; + +/* jshint quotmark: double */ +window.SwaggerTranslator.learn({ + "Warning: Deprecated":"Advertencia: Obsoleto", + "Implementation Notes":"Notas de implementación", + "Response Class":"Clase de la Respuesta", + "Status":"Status", + "Parameters":"Parámetros", + "Parameter":"Parámetro", + "Value":"Valor", + "Description":"Descripción", + "Parameter Type":"Tipo del Parámetro", + "Data Type":"Tipo del Dato", + "Response Messages":"Mensajes de la Respuesta", + "HTTP Status Code":"Código de Status HTTP", + "Reason":"Razón", + "Response Model":"Modelo de la Respuesta", + "Request URL":"URL de la Solicitud", + "Response Body":"Cuerpo de la Respuesta", + "Response Code":"Código de la Respuesta", + "Response Headers":"Encabezados de la Respuesta", + "Hide Response":"Ocultar Respuesta", + "Try it out!":"Pruébalo!", + "Show/Hide":"Mostrar/Ocultar", + "List Operations":"Listar Operaciones", + "Expand Operations":"Expandir Operaciones", + "Raw":"Crudo", + "can't parse JSON. Raw result":"no puede parsear el JSON. Resultado crudo", + "Model Schema":"Esquema del Modelo", + "Model":"Modelo", + "apply":"aplicar", + "Username":"Nombre de usuario", + "Password":"Contraseña", + "Terms of service":"Términos de Servicio", + "Created by":"Creado por", + "See more at":"Ver más en", + "Contact the developer":"Contactar al desarrollador", + "api version":"versión de la api", + "Response Content Type":"Tipo de Contenido (Content Type) de la Respuesta", + "fetching resource":"buscando recurso", + "fetching resource list":"buscando lista del recurso", + "Explore":"Explorar", + "Show Swagger Petstore Example Apis":"Mostrar Api Ejemplo de Swagger Petstore", + "Can't read from server. It may not have the appropriate access-control-origin settings.":"No se puede leer del servidor. Tal vez no tiene la configuración de control de acceso de origen (access-control-origin) apropiado.", + "Please specify the protocol for":"Por favor, especificar el protocola para", + "Can't read swagger JSON from":"No se puede leer el JSON de swagger desde", + "Finished Loading Resource Information. Rendering Swagger UI":"Finalizada la carga del recurso de Información. Mostrando Swagger UI", + "Unable to read api":"No se puede leer la api", + "from path":"desde ruta", + "server returned":"el servidor retornó" +}); diff --git a/devops-service/app/api3/public/swagger-ui/lang/fr.js b/devops-service/app/api3/public/swagger-ui/lang/fr.js new file mode 100644 index 0000000..2e095ad --- /dev/null +++ b/devops-service/app/api3/public/swagger-ui/lang/fr.js @@ -0,0 +1,53 @@ +'use strict'; + +/* jshint quotmark: double */ +window.SwaggerTranslator.learn({ + "Warning: Deprecated":"Avertissement : Obsolète", + "Implementation Notes":"Notes d'implementation", + "Response Class":"Classe de la réponse", + "Status":"Statut", + "Parameters":"Paramètres", + "Parameter":"Paramètre", + "Value":"Valeur", + "Description":"Description", + "Parameter Type":"Type du paramètre", + "Data Type":"Type de données", + "Response Messages":"Messages de la réponse", + "HTTP Status Code":"Code de statut HTTP", + "Reason":"Raison", + "Response Model":"Modèle de réponse", + "Request URL":"URL appelée", + "Response Body":"Corps de la réponse", + "Response Code":"Code de la réponse", + "Response Headers":"En-têtes de la réponse", + "Hide Response":"Cacher la réponse", + "Headers":"En-têtes", + "Try it out!":"Testez !", + "Show/Hide":"Afficher/Masquer", + "List Operations":"Liste des opérations", + "Expand Operations":"Développer les opérations", + "Raw":"Brut", + "can't parse JSON. Raw result":"impossible de décoder le JSON. Résultat brut", + "Model Schema":"Définition du modèle", + "Model":"Modèle", + "apply":"appliquer", + "Username":"Nom d'utilisateur", + "Password":"Mot de passe", + "Terms of service":"Conditions de service", + "Created by":"Créé par", + "See more at":"Voir plus sur", + "Contact the developer":"Contacter le développeur", + "api version":"version de l'api", + "Response Content Type":"Content Type de la réponse", + "fetching resource":"récupération de la ressource", + "fetching resource list":"récupération de la liste de ressources", + "Explore":"Explorer", + "Show Swagger Petstore Example Apis":"Montrer les Apis de l'exemple Petstore de Swagger", + "Can't read from server. It may not have the appropriate access-control-origin settings.":"Impossible de lire à partir du serveur. Il se peut que les réglages access-control-origin ne soient pas appropriés.", + "Please specify the protocol for":"Veuillez spécifier un protocole pour", + "Can't read swagger JSON from":"Impossible de lire le JSON swagger à partir de", + "Finished Loading Resource Information. Rendering Swagger UI":"Chargement des informations terminé. Affichage de Swagger UI", + "Unable to read api":"Impossible de lire l'api", + "from path":"à partir du chemin", + "server returned":"réponse du serveur" +}); diff --git a/devops-service/app/api3/public/swagger-ui/lang/it.js b/devops-service/app/api3/public/swagger-ui/lang/it.js new file mode 100644 index 0000000..8529c2a --- /dev/null +++ b/devops-service/app/api3/public/swagger-ui/lang/it.js @@ -0,0 +1,52 @@ +'use strict'; + +/* jshint quotmark: double */ +window.SwaggerTranslator.learn({ + "Warning: Deprecated":"Attenzione: Deprecato", + "Implementation Notes":"Note di implementazione", + "Response Class":"Classe della risposta", + "Status":"Stato", + "Parameters":"Parametri", + "Parameter":"Parametro", + "Value":"Valore", + "Description":"Descrizione", + "Parameter Type":"Tipo di parametro", + "Data Type":"Tipo di dato", + "Response Messages":"Messaggi della risposta", + "HTTP Status Code":"Codice stato HTTP", + "Reason":"Motivo", + "Response Model":"Modello di risposta", + "Request URL":"URL della richiesta", + "Response Body":"Corpo della risposta", + "Response Code":"Oggetto della risposta", + "Response Headers":"Intestazioni della risposta", + "Hide Response":"Nascondi risposta", + "Try it out!":"Provalo!", + "Show/Hide":"Mostra/Nascondi", + "List Operations":"Mostra operazioni", + "Expand Operations":"Espandi operazioni", + "Raw":"Grezzo (raw)", + "can't parse JSON. Raw result":"non è possibile parsare il JSON. Risultato grezzo (raw).", + "Model Schema":"Schema del modello", + "Model":"Modello", + "apply":"applica", + "Username":"Nome utente", + "Password":"Password", + "Terms of service":"Condizioni del servizio", + "Created by":"Creato da", + "See more at":"Informazioni aggiuntive:", + "Contact the developer":"Contatta lo sviluppatore", + "api version":"versione api", + "Response Content Type":"Tipo di contenuto (content type) della risposta", + "fetching resource":"recuperando la risorsa", + "fetching resource list":"recuperando lista risorse", + "Explore":"Esplora", + "Show Swagger Petstore Example Apis":"Mostra le api di esempio di Swagger Petstore", + "Can't read from server. It may not have the appropriate access-control-origin settings.":"Non è possibile leggere dal server. Potrebbe non avere le impostazioni di controllo accesso origine (access-control-origin) appropriate.", + "Please specify the protocol for":"Si prega di specificare il protocollo per", + "Can't read swagger JSON from":"Impossibile leggere JSON swagger da:", + "Finished Loading Resource Information. Rendering Swagger UI":"Lettura informazioni risorse termianta. Swagger UI viene mostrata", + "Unable to read api":"Impossibile leggere la api", + "from path":"da cartella", + "server returned":"il server ha restituito" +}); diff --git a/devops-service/app/api3/public/swagger-ui/lang/ja.js b/devops-service/app/api3/public/swagger-ui/lang/ja.js new file mode 100755 index 0000000..3207bfc --- /dev/null +++ b/devops-service/app/api3/public/swagger-ui/lang/ja.js @@ -0,0 +1,53 @@ +'use strict'; + +/* jshint quotmark: double */ +window.SwaggerTranslator.learn({ + "Warning: Deprecated":"警告: 廃止予定", + "Implementation Notes":"実装メモ", + "Response Class":"レスポンスクラス", + "Status":"ステータス", + "Parameters":"パラメータ群", + "Parameter":"パラメータ", + "Value":"値", + "Description":"説明", + "Parameter Type":"パラメータタイプ", + "Data Type":"データタイプ", + "Response Messages":"レスポンスメッセージ", + "HTTP Status Code":"HTTPステータスコード", + "Reason":"理由", + "Response Model":"レスポンスモデル", + "Request URL":"リクエストURL", + "Response Body":"レスポンスボディ", + "Response Code":"レスポンスコード", + "Response Headers":"レスポンスヘッダ", + "Hide Response":"レスポンスを隠す", + "Headers":"ヘッダ", + "Try it out!":"実際に実行!", + "Show/Hide":"表示/非表示", + "List Operations":"操作一覧", + "Expand Operations":"操作の展開", + "Raw":"Raw", + "can't parse JSON. Raw result":"JSONへ解釈できません. 未加工の結果", + "Model Schema":"モデルスキーマ", + "Model":"モデル", + "apply":"実行", + "Username":"ユーザ名", + "Password":"パスワード", + "Terms of service":"サービス利用規約", + "Created by":"Created by", + "See more at":"See more at", + "Contact the developer":"開発者に連絡", + "api version":"APIバージョン", + "Response Content Type":"レスポンス コンテンツタイプ", + "fetching resource":"リソースの取得", + "fetching resource list":"リソース一覧の取得", + "Explore":"Explore", + "Show Swagger Petstore Example Apis":"SwaggerペットストアAPIの表示", + "Can't read from server. It may not have the appropriate access-control-origin settings.":"サーバから読み込めません. 適切なaccess-control-origin設定を持っていない可能性があります.", + "Please specify the protocol for":"プロトコルを指定してください", + "Can't read swagger JSON from":"次からswagger JSONを読み込めません", + "Finished Loading Resource Information. Rendering Swagger UI":"リソース情報の読み込みが完了しました. Swagger UIを描画しています", + "Unable to read api":"APIを読み込めません", + "from path":"次のパスから", + "server returned":"サーバからの返答" +}); diff --git a/devops-service/app/api3/public/swagger-ui/lang/pl.js b/devops-service/app/api3/public/swagger-ui/lang/pl.js new file mode 100644 index 0000000..ce41e91 --- /dev/null +++ b/devops-service/app/api3/public/swagger-ui/lang/pl.js @@ -0,0 +1,53 @@ +'use strict'; + +/* jshint quotmark: double */ +window.SwaggerTranslator.learn({ + "Warning: Deprecated":"Uwaga: Wycofane", + "Implementation Notes":"Uwagi Implementacji", + "Response Class":"Klasa Odpowiedzi", + "Status":"Status", + "Parameters":"Parametry", + "Parameter":"Parametr", + "Value":"Wartość", + "Description":"Opis", + "Parameter Type":"Typ Parametru", + "Data Type":"Typ Danych", + "Response Messages":"Wiadomości Odpowiedzi", + "HTTP Status Code":"Kod Statusu HTTP", + "Reason":"Przyczyna", + "Response Model":"Model Odpowiedzi", + "Request URL":"URL Wywołania", + "Response Body":"Treść Odpowiedzi", + "Response Code":"Kod Odpowiedzi", + "Response Headers":"Nagłówki Odpowiedzi", + "Hide Response":"Ukryj Odpowiedź", + "Headers":"Nagłówki", + "Try it out!":"Wypróbuj!", + "Show/Hide":"Pokaż/Ukryj", + "List Operations":"Lista Operacji", + "Expand Operations":"Rozwiń Operacje", + "Raw":"Nieprzetworzone", + "can't parse JSON. Raw result":"nie można przetworzyć pliku JSON. Nieprzetworzone dane", + "Model Schema":"Schemat Modelu", + "Model":"Model", + "apply":"użyj", + "Username":"Nazwa użytkownika", + "Password":"Hasło", + "Terms of service":"Warunki używania", + "Created by":"Utworzone przez", + "See more at":"Zobacz więcej na", + "Contact the developer":"Kontakt z deweloperem", + "api version":"wersja api", + "Response Content Type":"Typ Zasobu Odpowiedzi", + "fetching resource":"ładowanie zasobu", + "fetching resource list":"ładowanie listy zasobów", + "Explore":"Eksploruj", + "Show Swagger Petstore Example Apis":"Pokaż Przykładowe Api Swagger Petstore", + "Can't read from server. It may not have the appropriate access-control-origin settings.":"Brak połączenia z serwerem. Może on nie mieć odpowiednich ustawień access-control-origin.", + "Please specify the protocol for":"Proszę podać protokół dla", + "Can't read swagger JSON from":"Nie można odczytać swagger JSON z", + "Finished Loading Resource Information. Rendering Swagger UI":"Ukończono Ładowanie Informacji o Zasobie. Renderowanie Swagger UI", + "Unable to read api":"Nie można odczytać api", + "from path":"ze ścieżki", + "server returned":"serwer zwrócił" +}); diff --git a/devops-service/app/api3/public/swagger-ui/lang/pt.js b/devops-service/app/api3/public/swagger-ui/lang/pt.js new file mode 100644 index 0000000..f2e7c13 --- /dev/null +++ b/devops-service/app/api3/public/swagger-ui/lang/pt.js @@ -0,0 +1,53 @@ +'use strict'; + +/* jshint quotmark: double */ +window.SwaggerTranslator.learn({ + "Warning: Deprecated":"Aviso: Depreciado", + "Implementation Notes":"Notas de Implementação", + "Response Class":"Classe de resposta", + "Status":"Status", + "Parameters":"Parâmetros", + "Parameter":"Parâmetro", + "Value":"Valor", + "Description":"Descrição", + "Parameter Type":"Tipo de parâmetro", + "Data Type":"Tipo de dados", + "Response Messages":"Mensagens de resposta", + "HTTP Status Code":"Código de status HTTP", + "Reason":"Razão", + "Response Model":"Modelo resposta", + "Request URL":"URL requisição", + "Response Body":"Corpo da resposta", + "Response Code":"Código da resposta", + "Response Headers":"Cabeçalho da resposta", + "Headers":"Cabeçalhos", + "Hide Response":"Esconder resposta", + "Try it out!":"Tente agora!", + "Show/Hide":"Mostrar/Esconder", + "List Operations":"Listar operações", + "Expand Operations":"Expandir operações", + "Raw":"Cru", + "can't parse JSON. Raw result":"Falha ao analisar JSON. Resulto cru", + "Model Schema":"Modelo esquema", + "Model":"Modelo", + "apply":"Aplicar", + "Username":"Usuário", + "Password":"Senha", + "Terms of service":"Termos do serviço", + "Created by":"Criado por", + "See more at":"Veja mais em", + "Contact the developer":"Contate o desenvolvedor", + "api version":"Versão api", + "Response Content Type":"Tipo de conteúdo da resposta", + "fetching resource":"busca recurso", + "fetching resource list":"buscando lista de recursos", + "Explore":"Explorar", + "Show Swagger Petstore Example Apis":"Show Swagger Petstore Example Apis", + "Can't read from server. It may not have the appropriate access-control-origin settings.":"Não é possível ler do servidor. Pode não ter as apropriadas configurações access-control-origin", + "Please specify the protocol for":"Por favor especifique o protocolo", + "Can't read swagger JSON from":"Não é possível ler o JSON Swagger de", + "Finished Loading Resource Information. Rendering Swagger UI":"Carregar informação de recurso finalizada. Renderizando Swagger UI", + "Unable to read api":"Não foi possível ler api", + "from path":"do caminho", + "server returned":"servidor retornou" +}); diff --git a/devops-service/app/api3/public/swagger-ui/lang/ru.js b/devops-service/app/api3/public/swagger-ui/lang/ru.js new file mode 100644 index 0000000..381f1b3 --- /dev/null +++ b/devops-service/app/api3/public/swagger-ui/lang/ru.js @@ -0,0 +1,55 @@ +'use strict'; + +/* jshint quotmark: double */ +window.SwaggerTranslator.learn({ + "Warning: Deprecated":"Предупреждение: Устарело", + "Implementation Notes":"Заметки", + "Response Class":"Пример ответа", + "Status":"Статус", + "Parameters":"Параметры", + "Parameter":"Параметр", + "Value":"Значение", + "Description":"Описание", + "Parameter Type":"Тип параметра", + "Data Type":"Тип данных", + "HTTP Status Code":"HTTP код", + "Reason":"Причина", + "Response Model":"Структура ответа", + "Request URL":"URL запроса", + "Response Body":"Тело ответа", + "Response Code":"HTTP код ответа", + "Response Headers":"Заголовки ответа", + "Hide Response":"Спрятать ответ", + "Headers":"Заголовки", + "Response Messages":"Что может прийти в ответ", + "Try it out!":"Попробовать!", + "Show/Hide":"Показать/Скрыть", + "List Operations":"Операции кратко", + "Expand Operations":"Операции подробно", + "Raw":"В сыром виде", + "can't parse JSON. Raw result":"Не удается распарсить ответ:", + "Model Schema":"Структура", + "Model":"Описание", + "Click to set as parameter value":"Нажмите, чтобы испльзовать в качестве значения параметра", + "apply":"применить", + "Username":"Имя пользователя", + "Password":"Пароль", + "Terms of service":"Условия использования", + "Created by":"Разработано", + "See more at":"Еще тут", + "Contact the developer":"Связаться с разработчиком", + "api version":"Версия API", + "Response Content Type":"Content Type ответа", + "Parameter content type:":"Content Type параметра:", + "fetching resource":"Получение ресурса", + "fetching resource list":"Получение ресурсов", + "Explore":"Показать", + "Show Swagger Petstore Example Apis":"Показать примеры АПИ", + "Can't read from server. It may not have the appropriate access-control-origin settings.":"Не удается получить ответ от сервера. Возможно, проблема с настройками доступа", + "Please specify the protocol for":"Пожалуйста, укажите протокол для", + "Can't read swagger JSON from":"Не получается прочитать swagger json из", + "Finished Loading Resource Information. Rendering Swagger UI":"Загрузка информации о ресурсах завершена. Рендерим", + "Unable to read api":"Не удалось прочитать api", + "from path":"по адресу", + "server returned":"сервер сказал" +}); diff --git a/devops-service/app/api3/public/swagger-ui/lang/tr.js b/devops-service/app/api3/public/swagger-ui/lang/tr.js new file mode 100644 index 0000000..16426a9 --- /dev/null +++ b/devops-service/app/api3/public/swagger-ui/lang/tr.js @@ -0,0 +1,53 @@ +'use strict'; + +/* jshint quotmark: double */ +window.SwaggerTranslator.learn({ + "Warning: Deprecated":"Uyarı: Deprecated", + "Implementation Notes":"Gerçekleştirim Notları", + "Response Class":"Dönen Sınıf", + "Status":"Statü", + "Parameters":"Parametreler", + "Parameter":"Parametre", + "Value":"Değer", + "Description":"Açıklama", + "Parameter Type":"Parametre Tipi", + "Data Type":"Veri Tipi", + "Response Messages":"Dönüş Mesajı", + "HTTP Status Code":"HTTP Statü Kodu", + "Reason":"Gerekçe", + "Response Model":"Dönüş Modeli", + "Request URL":"İstek URL", + "Response Body":"Dönüş İçeriği", + "Response Code":"Dönüş Kodu", + "Response Headers":"Dönüş Üst Bilgileri", + "Hide Response":"Dönüşü Gizle", + "Headers":"Üst Bilgiler", + "Try it out!":"Dene!", + "Show/Hide":"Göster/Gizle", + "List Operations":"Operasyonları Listele", + "Expand Operations":"Operasyonları Aç", + "Raw":"Ham", + "can't parse JSON. Raw result":"JSON çözümlenemiyor. Ham sonuç", + "Model Schema":"Model Şema", + "Model":"Model", + "apply":"uygula", + "Username":"Kullanıcı Adı", + "Password":"Parola", + "Terms of service":"Servis şartları", + "Created by":"Oluşturan", + "See more at":"Daha fazlası için", + "Contact the developer":"Geliştirici ile İletişime Geçin", + "api version":"api versiyon", + "Response Content Type":"Dönüş İçerik Tipi", + "fetching resource":"kaynak getiriliyor", + "fetching resource list":"kaynak listesi getiriliyor", + "Explore":"Keşfet", + "Show Swagger Petstore Example Apis":"Swagger Petstore Örnek Api'yi Gör", + "Can't read from server. It may not have the appropriate access-control-origin settings.":"Sunucudan okuma yapılamıyor. Sunucu access-control-origin ayarlarınızı kontrol edin.", + "Please specify the protocol for":"Lütfen istenen adres için protokol belirtiniz", + "Can't read swagger JSON from":"Swagger JSON bu kaynaktan okunamıyor", + "Finished Loading Resource Information. Rendering Swagger UI":"Kaynak baglantısı tamamlandı. Swagger UI gösterime hazırlanıyor", + "Unable to read api":"api okunamadı", + "from path":"yoldan", + "server returned":"sunucuya dönüldü" +}); diff --git a/devops-service/app/api3/public/swagger-ui/lang/translator.js b/devops-service/app/api3/public/swagger-ui/lang/translator.js new file mode 100644 index 0000000..591f6d4 --- /dev/null +++ b/devops-service/app/api3/public/swagger-ui/lang/translator.js @@ -0,0 +1,39 @@ +'use strict'; + +/** + * Translator for documentation pages. + * + * To enable translation you should include one of language-files in your index.html + * after . + * For example - + * + * If you wish to translate some new texsts you should do two things: + * 1. Add a new phrase pair ("New Phrase": "New Translation") into your language file (for example lang/ru.js). It will be great if you add it in other language files too. + * 2. Mark that text it templates this way New Phrase or . + * The main thing here is attribute data-sw-translate. Only inner html, title-attribute and value-attribute are going to translate. + * + */ +window.SwaggerTranslator = { + + _words:[], + + translate: function(sel) { + var $this = this; + sel = sel || '[data-sw-translate]'; + + $(sel).each(function() { + $(this).html($this._tryTranslate($(this).html())); + + $(this).val($this._tryTranslate($(this).val())); + $(this).attr('title', $this._tryTranslate($(this).attr('title'))); + }); + }, + + _tryTranslate: function(word) { + return this._words[$.trim(word)] !== undefined ? this._words[$.trim(word)] : word; + }, + + learn: function(wordsMap) { + this._words = wordsMap; + } +}; diff --git a/devops-service/app/api3/public/swagger-ui/lang/zh-cn.js b/devops-service/app/api3/public/swagger-ui/lang/zh-cn.js new file mode 100644 index 0000000..570319b --- /dev/null +++ b/devops-service/app/api3/public/swagger-ui/lang/zh-cn.js @@ -0,0 +1,53 @@ +'use strict'; + +/* jshint quotmark: double */ +window.SwaggerTranslator.learn({ + "Warning: Deprecated":"警告:已过时", + "Implementation Notes":"实现备注", + "Response Class":"响应类", + "Status":"状态", + "Parameters":"参数", + "Parameter":"参数", + "Value":"值", + "Description":"描述", + "Parameter Type":"参数类型", + "Data Type":"数据类型", + "Response Messages":"响应消息", + "HTTP Status Code":"HTTP状态码", + "Reason":"原因", + "Response Model":"响应模型", + "Request URL":"请求URL", + "Response Body":"响应体", + "Response Code":"响应码", + "Response Headers":"响应头", + "Hide Response":"隐藏响应", + "Headers":"头", + "Try it out!":"试一下!", + "Show/Hide":"显示/隐藏", + "List Operations":"显示操作", + "Expand Operations":"展开操作", + "Raw":"原始", + "can't parse JSON. Raw result":"无法解析JSON. 原始结果", + "Model Schema":"模型架构", + "Model":"模型", + "apply":"应用", + "Username":"用户名", + "Password":"密码", + "Terms of service":"服务条款", + "Created by":"创建者", + "See more at":"查看更多:", + "Contact the developer":"联系开发者", + "api version":"api版本", + "Response Content Type":"响应Content Type", + "fetching resource":"正在获取资源", + "fetching resource list":"正在获取资源列表", + "Explore":"浏览", + "Show Swagger Petstore Example Apis":"显示 Swagger Petstore 示例 Apis", + "Can't read from server. It may not have the appropriate access-control-origin settings.":"无法从服务器读取。可能没有正确设置access-control-origin。", + "Please specify the protocol for":"请指定协议:", + "Can't read swagger JSON from":"无法读取swagger JSON于", + "Finished Loading Resource Information. Rendering Swagger UI":"已加载资源信息。正在渲染Swagger UI", + "Unable to read api":"无法读取api", + "from path":"从路径", + "server returned":"服务器返回" +}); diff --git a/devops-service/app/api3/public/swagger-ui/lib/backbone-min.js b/devops-service/app/api3/public/swagger-ui/lib/backbone-min.js new file mode 100644 index 0000000..a3f544b --- /dev/null +++ b/devops-service/app/api3/public/swagger-ui/lib/backbone-min.js @@ -0,0 +1,15 @@ +// Backbone.js 1.1.2 + +(function(t,e){if(typeof define==="function"&&define.amd){define(["underscore","jquery","exports"],function(i,r,s){t.Backbone=e(t,s,i,r)})}else if(typeof exports!=="undefined"){var i=require("underscore");e(t,exports,i)}else{t.Backbone=e(t,{},t._,t.jQuery||t.Zepto||t.ender||t.$)}})(this,function(t,e,i,r){var s=t.Backbone;var n=[];var a=n.push;var o=n.slice;var h=n.splice;e.VERSION="1.1.2";e.$=r;e.noConflict=function(){t.Backbone=s;return this};e.emulateHTTP=false;e.emulateJSON=false;var u=e.Events={on:function(t,e,i){if(!c(this,"on",t,[e,i])||!e)return this;this._events||(this._events={});var r=this._events[t]||(this._events[t]=[]);r.push({callback:e,context:i,ctx:i||this});return this},once:function(t,e,r){if(!c(this,"once",t,[e,r])||!e)return this;var s=this;var n=i.once(function(){s.off(t,n);e.apply(this,arguments)});n._callback=e;return this.on(t,n,r)},off:function(t,e,r){var s,n,a,o,h,u,l,f;if(!this._events||!c(this,"off",t,[e,r]))return this;if(!t&&!e&&!r){this._events=void 0;return this}o=t?[t]:i.keys(this._events);for(h=0,u=o.length;h").attr(t);this.setElement(r,false)}else{this.setElement(i.result(this,"el"),false)}}});e.sync=function(t,r,s){var n=T[t];i.defaults(s||(s={}),{emulateHTTP:e.emulateHTTP,emulateJSON:e.emulateJSON});var a={type:n,dataType:"json"};if(!s.url){a.url=i.result(r,"url")||M()}if(s.data==null&&r&&(t==="create"||t==="update"||t==="patch")){a.contentType="application/json";a.data=JSON.stringify(s.attrs||r.toJSON(s))}if(s.emulateJSON){a.contentType="application/x-www-form-urlencoded";a.data=a.data?{model:a.data}:{}}if(s.emulateHTTP&&(n==="PUT"||n==="DELETE"||n==="PATCH")){a.type="POST";if(s.emulateJSON)a.data._method=n;var o=s.beforeSend;s.beforeSend=function(t){t.setRequestHeader("X-HTTP-Method-Override",n);if(o)return o.apply(this,arguments)}}if(a.type!=="GET"&&!s.emulateJSON){a.processData=false}if(a.type==="PATCH"&&k){a.xhr=function(){return new ActiveXObject("Microsoft.XMLHTTP")}}var h=s.xhr=e.ajax(i.extend(a,s));r.trigger("request",r,h,s);return h};var k=typeof window!=="undefined"&&!!window.ActiveXObject&&!(window.XMLHttpRequest&&(new XMLHttpRequest).dispatchEvent);var T={create:"POST",update:"PUT",patch:"PATCH","delete":"DELETE",read:"GET"};e.ajax=function(){return e.$.ajax.apply(e.$,arguments)};var $=e.Router=function(t){t||(t={});if(t.routes)this.routes=t.routes;this._bindRoutes();this.initialize.apply(this,arguments)};var S=/\((.*?)\)/g;var H=/(\(\?)?:\w+/g;var A=/\*\w+/g;var I=/[\-{}\[\]+?.,\\\^$|#\s]/g;i.extend($.prototype,u,{initialize:function(){},route:function(t,r,s){if(!i.isRegExp(t))t=this._routeToRegExp(t);if(i.isFunction(r)){s=r;r=""}if(!s)s=this[r];var n=this;e.history.route(t,function(i){var a=n._extractParameters(t,i);n.execute(s,a);n.trigger.apply(n,["route:"+r].concat(a));n.trigger("route",r,a);e.history.trigger("route",n,r,a)});return this},execute:function(t,e){if(t)t.apply(this,e)},navigate:function(t,i){e.history.navigate(t,i);return this},_bindRoutes:function(){if(!this.routes)return;this.routes=i.result(this,"routes");var t,e=i.keys(this.routes);while((t=e.pop())!=null){this.route(t,this.routes[t])}},_routeToRegExp:function(t){t=t.replace(I,"\\$&").replace(S,"(?:$1)?").replace(H,function(t,e){return e?t:"([^/?]+)"}).replace(A,"([^?]*?)");return new RegExp("^"+t+"(?:\\?([\\s\\S]*))?$")},_extractParameters:function(t,e){var r=t.exec(e).slice(1);return i.map(r,function(t,e){if(e===r.length-1)return t||null;return t?decodeURIComponent(t):null})}});var N=e.History=function(){this.handlers=[];i.bindAll(this,"checkUrl");if(typeof window!=="undefined"){this.location=window.location;this.history=window.history}};var R=/^[#\/]|\s+$/g;var O=/^\/+|\/+$/g;var P=/msie [\w.]+/;var C=/\/$/;var j=/#.*$/;N.started=false;i.extend(N.prototype,u,{interval:50,atRoot:function(){return this.location.pathname.replace(/[^\/]$/,"$&/")===this.root},getHash:function(t){var e=(t||this).location.href.match(/#(.*)$/);return e?e[1]:""},getFragment:function(t,e){if(t==null){if(this._hasPushState||!this._wantsHashChange||e){t=decodeURI(this.location.pathname+this.location.search);var i=this.root.replace(C,"");if(!t.indexOf(i))t=t.slice(i.length)}else{t=this.getHash()}}return t.replace(R,"")},start:function(t){if(N.started)throw new Error("Backbone.history has already been started");N.started=true;this.options=i.extend({root:"/"},this.options,t);this.root=this.options.root;this._wantsHashChange=this.options.hashChange!==false;this._wantsPushState=!!this.options.pushState;this._hasPushState=!!(this.options.pushState&&this.history&&this.history.pushState);var r=this.getFragment();var s=document.documentMode;var n=P.exec(navigator.userAgent.toLowerCase())&&(!s||s<=7);this.root=("/"+this.root+"/").replace(O,"/");if(n&&this._wantsHashChange){var a=e.$('