#789: validation

This commit is contained in:
amartynov 2015-11-02 17:33:25 +03:00
parent 57f545d109
commit 5549b028c4
17 changed files with 167 additions and 27 deletions

View File

@ -17,7 +17,7 @@ module Devops
end end
def accounts provider def accounts provider
::Provider::ProviderFactory.get(provider).accounts ::Provider::ProviderFactory.get_accounts_factory(provider).accounts
end end
def account_fields provider def account_fields provider
@ -25,8 +25,8 @@ module Devops
end end
def add_account provider def add_account provider
account = ::Provider::ProviderFactory.get(provider).create_account(parser.account) account = ::Provider::ProviderFactory.get_accounts_factory(provider).create_account(parser.account)
key = Devops::Db.connector.key account.ssh_key account.validate_fields!
Devops::Db.connector.provider_accounts_insert(account) Devops::Db.connector.provider_accounts_insert(account)
::Provider::ProviderFactory.add_account(provider, account) ::Provider::ProviderFactory.add_account(provider, account)
account.to_hash account.to_hash
@ -35,6 +35,7 @@ module Devops
def delete_account name, provider def delete_account name, provider
account = Devops::Db.connector.provider_accounts_show(name) account = Devops::Db.connector.provider_accounts_show(name)
Devops::Db.connector.provider_accounts_delete(name) Devops::Db.connector.provider_accounts_delete(name)
::Provider::ProviderFactory.delete_account(provider, account)
account.to_hash account.to_hash
end end

View File

@ -30,7 +30,7 @@ module Devops
def check_provider provider def check_provider provider
list = ::Provider::ProviderFactory.providers list = ::Provider::ProviderFactory.providers
halt_response("Invalid provider '#{provider}', available providers: '#{list.join("', '")}'", 404) unless list.include?(provider) halt_response("Invalid provider '#{provider}', available providers: '#{list.join("', '")}'", 400) unless list.include?(provider)
end end
# Save information about requests with methods POST, PUT, DELETE # Save information about requests with methods POST, PUT, DELETE

View File

@ -61,13 +61,23 @@ module Devops
DevopsLogger.logger = @@logger DevopsLogger.logger = @@logger
begin begin
res = super(env) res = super(env)
rescue DevopsError => e rescue ::Devops::Exception::DevopsError => e
return [e.code, {}, e.message]
rescue InvalidRecord => e
return [e.code, {}, e.message] return [e.code, {}, e.message]
end end
@@access_logger.info(env["REQUEST_METHOD"] + " " + env["REQUEST_URI"] + " - from #{env["HTTP_USER_AGENT"]} (#{env["REMOTE_USER"]}) / #{res[0]}") @@access_logger.info(env["REQUEST_METHOD"] + " " + env["REQUEST_URI"] + " - from #{env["HTTP_USER_AGENT"]} (#{env["REMOTE_USER"]}) / #{res[0]}")
res res
end end
def handle_exception!(boom)
if boom.is_a?(::Devops::Exception::DevopsError)
boom.http_response
else
super(boom)
end
end
error Devops::ValidationError do error Devops::ValidationError do
e = env["sinatra.error"] e = env["sinatra.error"]
#logger.warn e.message #logger.warn e.message
@ -92,12 +102,14 @@ module Devops
halt_response(e.message, 404) halt_response(e.message, 404)
end end
=begin
error InvalidRecord do error InvalidRecord do
e = env["sinatra.error"] e = env["sinatra.error"]
logger.warn e.message logger.warn e.message
logger.warn "Request body: #{request.body.read}" logger.warn "Request body: #{request.body.read}"
halt_response(e.message, 400) halt_response(e.message, 400)
end end
=end
error InvalidCommand do error InvalidCommand do
e = env["sinatra.error"] e = env["sinatra.error"]

View File

@ -78,7 +78,7 @@ module Devops
Devops::Api2.register r Devops::Api2.register r
end end
Routes.route "/v2.0", Devops::Api2 Routes.route "/v2.0", Devops::Api2
Devops::Api2.routes_list #Devops::Api2.routes_list
end end
private private

View File

@ -66,6 +66,21 @@ module Devops
end end
end end
def validate_fields!
result = []
self.class.field_validators.each do |field, validation_method|
begin
self.send(validation_method)
rescue InvalidRecord => e
result << {key: field, message: e.message}
end
end
unless result.empty?
raise InvalidRecord.new(error_data: result)
end
true
end
def build_error_message(message) def build_error_message(message)
# overrided in descendants # overrided in descendants
message message
@ -123,17 +138,16 @@ module Devops
end end
@validators = [] @validators = []
# @field_validators = [] @field_validators = {}
class << self class << self
attr_accessor :validators attr_accessor :validators
# attr_accessor :field_validators attr_accessor :field_validators
def inherited(subclass) def inherited(subclass)
subclass.validators = [] subclass.validators = []
subclass.validators += self.validators subclass.validators += self.validators
# subclass.field_validators = [] subclass.field_validators = self.field_validators.clone
# subclass.field_validators += self.field_validators
end end
# all exceptions are handled in @validate! method # all exceptions are handled in @validate! method
@ -146,11 +160,13 @@ module Devops
# validate field value # validate field value
# if method validate! returns false, then stop validation without error # if method validate! returns false, then stop validation without error
def set_field_validators field, *validators def set_field_validators field, *validators
define_method("validate_" + field.to_s + "!") do method_name = "validate_" + field.to_s + "!"
define_method(method_name) do
validators.each do |validator| validators.each do |validator|
break unless validator.new(self, send(field)).validate! break unless validator.new(self, send(field)).validate!
end end
end end
self.field_validators[field] = method_name
end end
# private class methods # private class methods

View File

@ -6,6 +6,13 @@ module Devops
attr_accessor :access_key_id, :availability_zone, :secret_access_key attr_accessor :access_key_id, :availability_zone, :secret_access_key
set_field_validators :access_key_id, ::Validators::FieldValidator::NotNil,
::Validators::FieldValidator::FieldType::String,
::Validators::FieldValidator::NotEmpty
set_field_validators :secret_access_key, ::Validators::FieldValidator::NotNil,
::Validators::FieldValidator::FieldType::String,
::Validators::FieldValidator::NotEmpty
def initialize a={} def initialize a={}
super(a) super(a)
self.provider = Provider::Ec2::PROVIDER self.provider = Provider::Ec2::PROVIDER

View File

@ -9,6 +9,21 @@ module Devops
attr_accessor :account_name, :description, :ssh_key attr_accessor :account_name, :description, :ssh_key
set_field_validators :account_name, ::Validators::FieldValidator::NotNil,
::Validators::FieldValidator::FieldType::String,
::Validators::FieldValidator::NotEmpty,
::Validators::FieldValidator::Name
set_field_validators :description, ::Validators::FieldValidator::Nil,
::Validators::FieldValidator::FieldType::String,
::Validators::FieldValidator::NotEmpty,
::Validators::FieldValidator::Description
set_field_validators :ssh_key, ::Validators::FieldValidator::NotNil,
::Validators::FieldValidator::FieldType::String,
::Validators::FieldValidator::NotEmpty,
::Validators::FieldValidator::SshKey
ACCOUNT_FIELDS = { ACCOUNT_FIELDS = {
account_name: "Account name (id)", account_name: "Account name (id)",
description: "Account description", description: "Account description",

View File

@ -0,0 +1,17 @@
require_relative "base"
module Validators
module FieldValidator
class Description < Base
MAX_LEN = 500
def valid?
@value.size <= 500
end
def message
"Invalid value '#{@value}': it should be less or equals then #{MAX_LEN} symbols"
end
end
end
end

View File

@ -11,7 +11,7 @@ module Validators
end end
def message def message
"Invalid value '#{@value}': it should contains symbols 'a-zA-Z0-9_' and length should be more then 1 and less or equals then #{MAX_NAME_LEN}" "Invalid value '#{@value}': it should contains symbols 'a-zA-Z0-9_' and length should be more then 1 and less or equals then #{MAX_NAME_LEN} symbols"
end end
end end
end end

View File

@ -0,0 +1,20 @@
require_relative "base"
module Validators
module FieldValidator
class SshKey < Base
MAX_LEN = 500
def valid?
Devops::Db.connector.key @value
true
rescue RecordNotFound
false
end
def message
"Invalid value '#{@value}': ssh key '#{@value}' not found"
end
end
end
end

View File

@ -1,12 +1,25 @@
require "json"
module Devops module Devops
module Exception module Exception
class DevopsError < StandardError class DevopsError < StandardError
def code def http_status
500 500
end end
def http_response
[self.http_status, self.http_headers, self.http_body]
end
def http_body
JSON.pretty_generate(message: self.message)
end
def http_headers
{"Content-Type" => "application/json"}
end
end end
end end

View File

@ -1,3 +1,23 @@
class InvalidRecord < StandardError require_relative "devops_error"
class InvalidRecord < ::Devops::Exception::DevopsError
def initialize msg
if msg.is_a?(String)
super(msg)
else
@object = msg
end
end
def http_status
400
end
def http_body
if @object.nil?
super
else
JSON.pretty_generate(@object)
end
end
end end

View File

@ -14,8 +14,20 @@ module Provider
@connections[name] = conn @connections[name] = conn
end end
def delete_connection name
@connections.delete(name)
end
def create_connection_from_account config, account def create_connection_from_account config, account
end end
def accounts
Devops::Db.connector.provider_accounts(provider_name)
end
def create_account hash
raise "override me"
end
end end
end end

View File

@ -6,14 +6,6 @@ module Provider
attr_accessor :ssh_key, :certificate_path, :connection_options, :run_list attr_accessor :ssh_key, :certificate_path, :connection_options, :run_list
def accounts
Devops::Db.connector.provider_accounts(self.name)
end
def create_account hash
raise "override me"
end
def create_default_chef_node_name s def create_default_chef_node_name s
"#{self.ssh_key}-#{s.project}-#{s.deploy_env}-#{Time.now.to_i}" "#{self.ssh_key}-#{s.project}-#{s.deploy_env}-#{Time.now.to_i}"
end end

View File

@ -35,10 +35,6 @@ module Provider
super and !(empty_param?(o[:aws_access_key_id]) or empty_param?(o[:aws_secret_access_key])) super and !(empty_param?(o[:aws_access_key_id]) or empty_param?(o[:aws_secret_access_key]))
end end
def create_account hash
Devops::Model::Ec2ProviderAccount.new(hash)
end
def name def name
PROVIDER PROVIDER
end end

View File

@ -4,13 +4,17 @@ module Provider
def init config def init config
@connections = {} @connections = {}
Devops::Db.connector.provider_accounts(Ec2::PROVIDER).each do |account| accounts.each do |account|
create_connection_from_account(config, account) create_connection_from_account(config, account)
puts "\tFound ec2 account '#{account.account_name}'" puts "\tFound ec2 account '#{account.account_name}'"
end end
ProviderFactory.add_provider Ec2::PROVIDER unless @connections.empty? ProviderFactory.add_provider Ec2::PROVIDER unless @connections.empty?
end end
def provider_name
Ec2::PROVIDER
end
def create_connection_from_account config, account def create_connection_from_account config, account
options = { options = {
aws_ssh_key: account.ssh_key, aws_ssh_key: account.ssh_key,
@ -25,5 +29,9 @@ module Provider
add_connection(account.account_name, Ec2.new(options)) add_connection(account.account_name, Ec2.new(options))
end end
def create_account hash
Devops::Model::Ec2ProviderAccount.new(hash)
end
end end
end end

View File

@ -50,6 +50,7 @@ module Provider
next next
end end
end end
puts "Available providers: #{@@available_providers}"
end end
def self.add_account provider, account def self.add_account provider, account
@ -58,6 +59,12 @@ module Provider
DevopsLogger.logger.info("Added #{provider} account '#{account.account_name}'") DevopsLogger.logger.info("Added #{provider} account '#{account.account_name}'")
end end
def self.delete_account provider, account
factory = @@providers_with_accounts_factories[provider]
factory.delete_connection(account.account_name)
DevopsLogger.logger.info("Removed #{provider} account '#{account.account_name}'")
end
def self.require_all def self.require_all
["ec2", "openstack", "static"].each do |provider| ["ec2", "openstack", "static"].each do |provider|
begin begin
@ -69,6 +76,10 @@ module Provider
end end
end end
def self.get_accounts_factory provider
@@providers_with_accounts_factories[provider]
end
def self.get_account_class provider def self.get_account_class provider
case(provider) case(provider)
when ::Provider::Static::PROVIDER when ::Provider::Static::PROVIDER