This commit is contained in:
Tim Lianov 2018-04-04 22:44:39 +03:00
parent bdeaa57271
commit 03dc3d8d99
544 changed files with 49820 additions and 15769 deletions

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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,18 +116,21 @@ 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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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 <project> <env> <private_ip> <ssh_username> <keyname> --public-ip <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 <project> <env> <private_ip> <ssh_username> <keyname> --public-ip <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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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")

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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")

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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]

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

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

View File

@ -1,3 +1,3 @@
module DevopsClient
VERSION = "2.1.34"
VERSION = "3.0.1"
end

View File

@ -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)"

View File

@ -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: "Показать все образы без фильтра"

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

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