Merge branch 'qa' of /home/git/repositories/cloudtechlab/devops-service into release
This commit is contained in:
commit
47954e9a63
@ -10,10 +10,9 @@ gem "sinatra-websocket"#, "~>0.3.0"
|
||||
gem "fog", "~>1.20"
|
||||
gem "mixlib-shellout"
|
||||
gem "chef", ">=12"
|
||||
gem "mongo"
|
||||
gem "mongo", '1.12.3'
|
||||
gem "bson_ext"
|
||||
gem "multi_json", "1.7.8"
|
||||
# gem "rufus-scheduler", "2.0.24"
|
||||
gem "sidekiq", "3.2.6"
|
||||
gem 'wisper'
|
||||
gem 'rake', '10.2.0'
|
||||
@ -31,6 +30,7 @@ group :test do
|
||||
gem 'rspec', '~>3.3'
|
||||
gem 'factory_girl', '~>4.5'
|
||||
gem 'activesupport'
|
||||
gem 'rspec_junit_formatter'
|
||||
end
|
||||
|
||||
group :devepoment do
|
||||
|
||||
@ -344,12 +344,13 @@ DEPENDENCIES
|
||||
httpclient
|
||||
mime-types (~> 1.25.1)
|
||||
mixlib-shellout
|
||||
mongo
|
||||
mongo (= 1.12.3)
|
||||
multi_json (= 1.7.8)
|
||||
rack (= 1.5.2)
|
||||
rack-accept-media-types
|
||||
rake (= 10.2.0)
|
||||
rspec (~> 3.3)
|
||||
rspec_junit_formatter
|
||||
sidekiq (= 3.2.6)
|
||||
sinatra (= 1.4.5)
|
||||
sinatra-contrib
|
||||
@ -357,6 +358,3 @@ DEPENDENCIES
|
||||
test-unit
|
||||
thin (~> 1.5.1)
|
||||
wisper
|
||||
|
||||
BUNDLED WITH
|
||||
1.10.5
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
require "app/api2/parsers/security_groups"
|
||||
require "providers/provider_factory"
|
||||
require_relative "request_handler"
|
||||
|
||||
@ -6,13 +7,15 @@ module Devops
|
||||
module Handler
|
||||
class Group < RequestHandler
|
||||
|
||||
# TODO: vpc support for ec2
|
||||
set_parser Devops::API2_0::Parser::SecurityGroupsParser
|
||||
|
||||
def groups provider
|
||||
groups_with_account(provider, nil)
|
||||
end
|
||||
|
||||
def groups_with_account provider, account
|
||||
::Provider::ProviderFactory.get(provider, account).groups()#params
|
||||
available_keys = ["vpc-id"]
|
||||
::Provider::ProviderFactory.get(provider, account).groups(parser.security_groups.select{|k,v| available_keys.include?(k)})
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
require "app/api2/parsers/network"
|
||||
require "providers/provider_factory"
|
||||
require_relative "request_handler"
|
||||
|
||||
@ -6,13 +7,16 @@ module Devops
|
||||
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)
|
||||
p.networks_detail
|
||||
available_keys = ["vpc-id"]
|
||||
p.networks_detail(parser.networks.select{|k,v| available_keys.include?(k)})
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@ -33,12 +33,17 @@ module Devops
|
||||
end
|
||||
|
||||
def delete_account name, provider
|
||||
account = Devops::Db.connector.provider_accounts_show(name)
|
||||
account = Devops::Db.connector.provider_account(provider, name)
|
||||
Devops::Db.connector.provider_accounts_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
|
||||
|
||||
15
devops-service/app/api2/parsers/network.rb
Normal file
15
devops-service/app/api2/parsers/network.rb
Normal file
@ -0,0 +1,15 @@
|
||||
require_relative "request_parser"
|
||||
|
||||
module Devops
|
||||
module API2_0
|
||||
module Parser
|
||||
class NetworkParser < RequestParser
|
||||
|
||||
def networks
|
||||
@params
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
15
devops-service/app/api2/parsers/security_groups.rb
Normal file
15
devops-service/app/api2/parsers/security_groups.rb
Normal file
@ -0,0 +1,15 @@
|
||||
require_relative "request_parser"
|
||||
|
||||
module Devops
|
||||
module API2_0
|
||||
module Parser
|
||||
class SecurityGroupsParser < RequestParser
|
||||
|
||||
def security_groups
|
||||
@params
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@ -13,6 +13,9 @@ module Devops
|
||||
# - headers :
|
||||
# - Accept: application/json
|
||||
#
|
||||
# * Params:
|
||||
# vpc-id - string
|
||||
#
|
||||
# * *Returns* :
|
||||
# - ec2:
|
||||
# {
|
||||
@ -43,7 +46,6 @@ module Devops
|
||||
# ]
|
||||
# }
|
||||
# }
|
||||
# TODO: vpc support for ec2
|
||||
app.get_with_headers "/groups/:provider", :headers => [:accept] do |provider|
|
||||
check_privileges("group", "r")
|
||||
check_provider(provider)
|
||||
|
||||
@ -13,6 +13,9 @@ module Devops
|
||||
# - headers :
|
||||
# - Accept: application/json
|
||||
#
|
||||
# * Params:
|
||||
# vpc-id - string
|
||||
#
|
||||
# * *Returns* : array of strings
|
||||
# - ec2:
|
||||
# [
|
||||
|
||||
@ -175,7 +175,7 @@ module Devops
|
||||
# Deletes project servers
|
||||
#
|
||||
# * *Request*
|
||||
# - method : PATCH
|
||||
# - method : DELETE
|
||||
# - headers :
|
||||
# - Accept: application/json
|
||||
# - Content-Type: application/json
|
||||
|
||||
@ -115,7 +115,23 @@ module Devops
|
||||
app.delete_with_headers "/provider/:provider/account/:account_name", :headers => [:accept, :content_type] do |provider, account_name|
|
||||
check_privileges("provider", "w")
|
||||
check_provider(provider)
|
||||
create_response("Deleted", {:account => Devops::API2_0::Handler::Provider.new(request).delete_account(provider)})
|
||||
create_response("Deleted", {:account => Devops::API2_0::Handler::Provider.new(request).delete_account(account_name, provider)})
|
||||
end
|
||||
|
||||
# Describe vpc for account with name :account_name for provider ec2
|
||||
#
|
||||
# * *Request*
|
||||
# - method : GET
|
||||
# - headers :
|
||||
# - Accept: application/json
|
||||
# - Content-Type: application/json
|
||||
#
|
||||
# * *Returns* : 200
|
||||
app.get_with_headers "/provider/ec2/account/:account_name/vpcs", :headers => [:accept, :content_type] do |account_name|
|
||||
provider = "ec2"
|
||||
check_privileges("provider", "r")
|
||||
check_provider(provider)
|
||||
json Devops::API2_0::Handler::Provider.new(request).account_vpcs(provider, account_name)
|
||||
end
|
||||
|
||||
puts "Provider routes initialized"
|
||||
|
||||
@ -29,6 +29,7 @@ config[:openstack_ssh_key] = "ssh_key"
|
||||
config[:openstack_certificate] = "/path/to/.ssh/openstack.pem"
|
||||
|
||||
# aws settings
|
||||
config[:aws_use_iam_profile] = false
|
||||
config[:aws_access_key_id] = "access_key_id"
|
||||
config[:aws_secret_access_key] = "secret_access_key"
|
||||
config[:aws_ssh_key] = "ssh_key"
|
||||
|
||||
@ -20,23 +20,24 @@ module Connectors
|
||||
f = collection.find('type' => 'image', 'provider' => provider).to_a.first
|
||||
if f.nil?
|
||||
collection.insert('type' => 'image', 'provider' => provider, 'images' => images)
|
||||
return images
|
||||
images
|
||||
else
|
||||
f['images'] |= images
|
||||
collection.update({'_id' => f['_id']}, f)
|
||||
return f['images']
|
||||
f['images']
|
||||
end
|
||||
end
|
||||
|
||||
def delete_available_images images, provider
|
||||
return unless images.is_a?(Array)
|
||||
f = collection.find('type' => 'image', 'provider' => provider).to_a.first
|
||||
unless f.nil?
|
||||
f['images'] -= images
|
||||
collection.update({'_id' => f['_id']}, f)
|
||||
return f['images']
|
||||
end
|
||||
filter = collection.find('type' => 'image', 'provider' => provider).to_a.first
|
||||
if filter
|
||||
filter['images'] -= images
|
||||
collection.update({'_id' => filter['_id']}, filter)
|
||||
filter['images']
|
||||
else
|
||||
[]
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@ -14,16 +14,10 @@ module Connectors
|
||||
end
|
||||
|
||||
def update(record)
|
||||
begin
|
||||
record.validate!
|
||||
collection.update({"_id" => record.id}, record.to_mongo_hash)
|
||||
r = collection.update({"_id" => record.id}, record.to_mongo_hash)
|
||||
raise RecordNotFound.new("'#{record.id}' not found") if r['n'] == 0
|
||||
record
|
||||
rescue Mongo::OperationFailure => e
|
||||
if e.message =~ /^11000/
|
||||
resource_name = StringHelper.underscore_class(record.class)
|
||||
raise InvalidRecord.new("Duplicate key error: #{resource_name} with id '#{record.id}'")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
@ -2,9 +2,7 @@ module Connectors
|
||||
class Project < Base
|
||||
include Helpers::InsertCommand,
|
||||
Helpers::ShowCommand,
|
||||
# Helpers::ListCommand,
|
||||
Helpers::DeleteCommand
|
||||
# Helpers::UpdateCommand
|
||||
|
||||
|
||||
def initialize(db)
|
||||
@ -73,7 +71,7 @@ module Connectors
|
||||
res.each do |ar|
|
||||
r[ar['_id']] = ar['envs']
|
||||
end
|
||||
return r
|
||||
r
|
||||
end
|
||||
|
||||
def projects_by_image(image)
|
||||
@ -98,10 +96,9 @@ module Connectors
|
||||
project
|
||||
end
|
||||
|
||||
def projects_and_deploy_envs_by_field field, value
|
||||
q = {}
|
||||
q[field] = value
|
||||
# {find all projects with deploy_envs with field=value}, {return deploy_envs with field=value}
|
||||
def projects_and_deploy_envs_by_field field, value
|
||||
q = {field => value}
|
||||
list( {'deploy_envs' => {'$elemMatch' => q}}, {:fields => {'deploy_envs' => {'$elemMatch' => q}}} )
|
||||
end
|
||||
|
||||
@ -114,12 +111,12 @@ module Connectors
|
||||
end
|
||||
|
||||
def set_project_env_run_list(project_id, env, run_list)
|
||||
Helpers::RunList.new(run_list).validate!
|
||||
::Validators::Helpers::RunList.new(run_list).validate!
|
||||
set_project_deploy_env_field(project_id, env, {"run_list" => run_list})
|
||||
end
|
||||
|
||||
def set_project_run_list(project_id, env, run_list)
|
||||
Helpers::RunList.new(run_list).validate!
|
||||
def set_project_run_list(project_id, run_list)
|
||||
::Validators::Helpers::RunList.new(run_list).validate!
|
||||
@collection.update({"_id" => project_id}, {"$set" => {run_list: run_list}})
|
||||
end
|
||||
|
||||
@ -128,17 +125,16 @@ module Connectors
|
||||
end
|
||||
|
||||
def remove_deploy_env_from_project id, env
|
||||
raise ArgumentError unless env.is_a?(String)
|
||||
@collection.update({"_id" => id}, {'$pull' => {deploy_envs: {identifier: env}} })
|
||||
end
|
||||
|
||||
def project_update_field id, field, value
|
||||
obj = {}
|
||||
obj[field] = value
|
||||
obj = {field => value}
|
||||
@collection.update({"_id" => id}, {'$set' => obj })
|
||||
end
|
||||
|
||||
def project_update id, params
|
||||
#raise InvalidRecord.new("You can not change project name for '#{id}'.") if params["name"]
|
||||
keys = %w(run_list description)
|
||||
params.delete_if{|k,v| !keys.include?(k)}
|
||||
@collection.update({"_id" => id}, {'$set' => params })
|
||||
|
||||
@ -13,6 +13,13 @@ module Connectors
|
||||
collection.find({provider: provider}).to_a.map{|bson| c.build_from_bson(bson)}
|
||||
end
|
||||
|
||||
def provider_account provider, account
|
||||
c = Provider::ProviderFactory.get_account_class(provider)
|
||||
bson = collection.find({provider: provider, _id: account}).to_a.first
|
||||
raise RecordNotFound.new("'Account #{account}' for provider '#{provider}' not found") unless bson
|
||||
c.build_from_bson(bson)
|
||||
end
|
||||
|
||||
def collection_name
|
||||
'provider_accounts'
|
||||
end
|
||||
|
||||
@ -17,22 +17,22 @@ module Devops
|
||||
::Validators::DeployEnv::Image,
|
||||
::Validators::DeployEnv::Groups,
|
||||
::Validators::DeployEnv::StackTemplate
|
||||
# set_validators ::Validators::DeployEnv::CloudParameters
|
||||
set_field_validators :flavor, ::Validators::FieldValidator::Nil,
|
||||
set_field_validators :flavor, [::Validators::FieldValidator::Nil,
|
||||
::Validators::FieldValidator::FieldType::String,
|
||||
::Validators::FieldValidator::Flavor
|
||||
set_field_validators :image, ::Validators::FieldValidator::Nil,
|
||||
::Validators::FieldValidator::Flavor], order: 2
|
||||
set_field_validators :image, [::Validators::FieldValidator::Nil,
|
||||
::Validators::FieldValidator::FieldType::String,
|
||||
::Validators::FieldValidator::Image
|
||||
set_field_validators :subnets, ::Validators::FieldValidator::Nil,
|
||||
::Validators::FieldValidator::FieldType::Array
|
||||
::Validators::FieldValidator::Image], order: 2
|
||||
set_field_validators :subnets, [::Validators::FieldValidator::Nil,
|
||||
::Validators::FieldValidator::FieldType::Array], order: 4
|
||||
# ::Validators::FieldValidator::Subnets.new
|
||||
set_field_validators :groups, ::Validators::FieldValidator::Nil,
|
||||
::Validators::FieldValidator::FieldType::Array
|
||||
set_field_validators :groups, [::Validators::FieldValidator::Nil,
|
||||
::Validators::FieldValidator::FieldType::Array], order: 4
|
||||
# ::Validators::FieldValidator::Groups.new
|
||||
set_field_validators :stack_template, ::Validators::FieldValidator::Nil,
|
||||
set_field_validators :stack_template, [::Validators::FieldValidator::Nil,
|
||||
::Validators::FieldValidator::FieldType::String,
|
||||
::Validators::FieldValidator::NotEmpty
|
||||
::Validators::FieldValidator::NotEmpty], order: 2
|
||||
# ::Validators::FieldValidator::StackTemplate.new
|
||||
|
||||
def initialize d={}
|
||||
super(d)
|
||||
|
||||
@ -8,27 +8,27 @@ module Devops
|
||||
|
||||
include ModelWithProvider
|
||||
|
||||
attr_accessor :identifier, :run_list, :expires, :users
|
||||
# attr_accessor :identifier, :run_list, :expires, :users
|
||||
|
||||
set_validators ::Validators::DeployEnv::RunList,
|
||||
::Validators::DeployEnv::Expiration,
|
||||
::Validators::DeployEnv::Users
|
||||
|
||||
set_field_validators :identifier, ::Validators::FieldValidator::NotNil,
|
||||
set_field_validators :identifier, [::Validators::FieldValidator::NotNil,
|
||||
::Validators::FieldValidator::FieldType::String,
|
||||
::Validators::FieldValidator::NotEmpty,
|
||||
::Validators::FieldValidator::Name
|
||||
::Validators::FieldValidator::Name]
|
||||
|
||||
set_field_validators :run_list, ::Validators::FieldValidator::NotNil,
|
||||
set_field_validators :run_list, [::Validators::FieldValidator::NotNil,
|
||||
::Validators::FieldValidator::FieldType::Array,
|
||||
::Validators::FieldValidator::RunList
|
||||
::Validators::FieldValidator::RunList]
|
||||
|
||||
set_field_validators :users, ::Validators::FieldValidator::NotNil,
|
||||
::Validators::FieldValidator::FieldType::Array
|
||||
set_field_validators :users, [::Validators::FieldValidator::NotNil,
|
||||
::Validators::FieldValidator::FieldType::Array]
|
||||
|
||||
set_field_validators :expires, ::Validators::FieldValidator::Nil,
|
||||
set_field_validators :expires, [::Validators::FieldValidator::Nil,
|
||||
::Validators::FieldValidator::FieldType::String,
|
||||
::Validators::FieldValidator::Expires
|
||||
::Validators::FieldValidator::Expires]
|
||||
|
||||
def initialize d={}
|
||||
self.identifier = d["identifier"]
|
||||
|
||||
@ -4,6 +4,11 @@ module Devops
|
||||
module Model
|
||||
class DeployEnvEc2 < CloudDeployEnv
|
||||
|
||||
# attr_accessor :vpc_id
|
||||
|
||||
set_field_validators :vpc_id, [::Validators::FieldValidator::Nil,
|
||||
::Validators::FieldValidator::FieldType::String,
|
||||
::Validators::FieldValidator::Vpc], order: 3
|
||||
=begin
|
||||
@Deprecated
|
||||
types :identifier => {:type => String, :empty => false},
|
||||
@ -34,6 +39,11 @@ module Devops
|
||||
if self.subnets.size > 1
|
||||
self.subnets = [ self.subnets[0] ]
|
||||
end
|
||||
self.vpc_id = d["vpc_id"]
|
||||
end
|
||||
|
||||
def to_hash
|
||||
super().merge({"vpc_id" => self.vpc_id})
|
||||
end
|
||||
|
||||
def self.create hash
|
||||
|
||||
@ -8,7 +8,7 @@ module Devops
|
||||
class Image < MongoModel
|
||||
include ModelWithProvider
|
||||
|
||||
attr_accessor :id, :remote_user, :name, :bootstrap_template
|
||||
# attr_accessor :id, :remote_user, :name, :bootstrap_template
|
||||
=begin
|
||||
types :id => {:type => String, :empty => false},
|
||||
:provider => {:type => String, :empty => false},
|
||||
@ -20,27 +20,27 @@ module Devops
|
||||
# set_validators ::Validators::Image::ImageInFilter,
|
||||
# ::Validators::Image::BootstrapTemplate
|
||||
|
||||
set_field_validators :id, ::Validators::FieldValidator::NotNil,
|
||||
set_field_validators :id, [::Validators::FieldValidator::NotNil,
|
||||
::Validators::FieldValidator::FieldType::String,
|
||||
::Validators::FieldValidator::NotEmpty,
|
||||
::Validators::FieldValidator::ImageName,
|
||||
::Validators::Image::ImageInFilter
|
||||
::Validators::Image::ImageInFilter]
|
||||
|
||||
set_field_validators :remote_user, ::Validators::FieldValidator::NotNil,
|
||||
set_field_validators :remote_user, [::Validators::FieldValidator::NotNil,
|
||||
::Validators::FieldValidator::FieldType::String,
|
||||
::Validators::FieldValidator::NotEmpty,
|
||||
::Validators::FieldValidator::ImageName
|
||||
::Validators::FieldValidator::ImageName]
|
||||
|
||||
set_field_validators :name, ::Validators::FieldValidator::NotNil,
|
||||
set_field_validators :name, [::Validators::FieldValidator::NotNil,
|
||||
::Validators::FieldValidator::FieldType::String,
|
||||
::Validators::FieldValidator::NotEmpty,
|
||||
::Validators::FieldValidator::ImageName
|
||||
::Validators::FieldValidator::ImageName]
|
||||
|
||||
set_field_validators :bootstrap_template, ::Validators::FieldValidator::Nil,
|
||||
set_field_validators :bootstrap_template, [::Validators::FieldValidator::Nil,
|
||||
::Validators::FieldValidator::FieldType::String,
|
||||
::Validators::FieldValidator::NotEmpty,
|
||||
::Validators::FieldValidator::Name,
|
||||
::Validators::Image::BootstrapTemplate
|
||||
::Validators::Image::BootstrapTemplate]
|
||||
|
||||
def validate!
|
||||
validate_id!
|
||||
|
||||
@ -4,14 +4,19 @@ module Devops
|
||||
module Model
|
||||
module ModelWithProvider
|
||||
|
||||
attr_accessor :provider, :provider_account
|
||||
# attr_accessor :provider, :provider_account
|
||||
|
||||
def ModelWithProvider.included(mod)
|
||||
|
||||
mod.set_field_validators :provider, ::Validators::FieldValidator::NotNil,
|
||||
mod.set_field_validators :provider, [::Validators::FieldValidator::NotNil,
|
||||
::Validators::FieldValidator::FieldType::String,
|
||||
::Validators::FieldValidator::NotEmpty,
|
||||
::Validators::FieldValidator::Provider
|
||||
::Validators::FieldValidator::Provider]
|
||||
|
||||
mod.set_field_validators :provider_account, [::Validators::FieldValidator::Nil,
|
||||
::Validators::FieldValidator::FieldType::String,
|
||||
::Validators::FieldValidator::NotEmpty,
|
||||
::Validators::FieldValidator::ProviderAccount], order: 1
|
||||
end
|
||||
|
||||
def provider_instance
|
||||
|
||||
@ -69,7 +69,11 @@ module Devops
|
||||
|
||||
def validate_fields!
|
||||
result = []
|
||||
self.class.field_validators.each do |field, validation_method|
|
||||
orders = self.class.field_validators.keys.sort
|
||||
orders.each do |order|
|
||||
self.class.field_validators[order].each do |elem|
|
||||
field = elem[:field]
|
||||
validation_method = elem[:method]
|
||||
begin
|
||||
self.send(validation_method)
|
||||
rescue InvalidRecord => e
|
||||
@ -79,6 +83,7 @@ module Devops
|
||||
unless result.empty?
|
||||
raise InvalidRecord.new(error_data: result)
|
||||
end
|
||||
end
|
||||
true
|
||||
end
|
||||
|
||||
@ -150,6 +155,12 @@ module Devops
|
||||
class << self
|
||||
|
||||
attr_accessor :validators
|
||||
|
||||
# hash:
|
||||
# key - (integer) validators order
|
||||
# value - (hash) validator params:
|
||||
# field: (string) field name
|
||||
# method: (string) field validator method
|
||||
attr_accessor :field_validators
|
||||
|
||||
def inherited(subclass)
|
||||
@ -168,14 +179,29 @@ module Devops
|
||||
|
||||
# validate field value
|
||||
# if method validate! returns false, then stop validation without error
|
||||
def set_field_validators field, *validators
|
||||
#
|
||||
# field - (string) field name to validate
|
||||
# validators - (array) validators list
|
||||
# options - (hash) options for validator
|
||||
# order: integer - run validator in order with index order:
|
||||
def set_field_validators field, validators, options={}
|
||||
attr_accessor field
|
||||
method_name = "validate_" + field.to_s + "!"
|
||||
define_method(method_name) do
|
||||
validators.each do |validator|
|
||||
break unless validator.new(self, send(field)).validate!
|
||||
break unless validator.new(self, field).validate!
|
||||
end
|
||||
end
|
||||
self.field_validators[field] = method_name
|
||||
order = options[:order] || 0
|
||||
obj = {
|
||||
field: field,
|
||||
method: method_name
|
||||
}
|
||||
unless self.field_validators[order]
|
||||
self.field_validators[order] = [obj]
|
||||
else
|
||||
self.field_validators[order] << obj
|
||||
end
|
||||
end
|
||||
|
||||
# private class methods
|
||||
|
||||
@ -23,16 +23,27 @@ module Devops
|
||||
|
||||
attr_accessor :id, :deploy_envs, :type, :archived, :description, :run_list
|
||||
|
||||
types :id => {:type => String, :empty => false},
|
||||
:deploy_envs => {:type => Array, :value_type => false, :empty => false},
|
||||
:description => {:type => String, :empty => true, :nil => true},
|
||||
:run_list => {:type => Array, :value_type => String, :empty => true, :nil => false}
|
||||
|
||||
MULTI_TYPE = "multi"
|
||||
|
||||
set_field_validators :id, [::Validators::FieldValidator::NotNil,
|
||||
::Validators::FieldValidator::FieldType::String,
|
||||
::Validators::FieldValidator::NotEmpty]
|
||||
|
||||
set_field_validators :deploy_envs, [::Validators::FieldValidator::NotNil,
|
||||
::Validators::FieldValidator::FieldType::Array,
|
||||
::Validators::FieldValidator::NotEmpty]
|
||||
|
||||
set_field_validators :description, [::Validators::FieldValidator::Nil,
|
||||
::Validators::FieldValidator::FieldType::String]
|
||||
|
||||
set_field_validators :run_list, [::Validators::FieldValidator::NotNil,
|
||||
::Validators::FieldValidator::FieldType::Array,
|
||||
::Validators::FieldValidator::RunList]
|
||||
|
||||
set_validators ::Validators::DeployEnv::RunList,
|
||||
::Validators::DeployEnv::DeployEnvs
|
||||
|
||||
|
||||
def self.fields
|
||||
["deploy_envs", "type", "description"]
|
||||
end
|
||||
@ -70,6 +81,9 @@ module Devops
|
||||
Project.create_roles_response(res)
|
||||
end
|
||||
|
||||
# user could be a String or an Array of strings.
|
||||
# if env is nil, add given user(s) to all project's envs,
|
||||
# otherwise only to specified one.
|
||||
def add_authorized_user user, env=nil
|
||||
return if user.nil?
|
||||
new_users = ( user.is_a?(Array) ? user : [ user ] )
|
||||
@ -93,11 +107,16 @@ module Devops
|
||||
def check_authorization user_id, env
|
||||
e = self.deploy_env(env)
|
||||
return true if user_id == User::ROOT_USER_NAME
|
||||
return true if is_sandbox?
|
||||
return e.users.include? user_id
|
||||
rescue RecordNotFound => e
|
||||
return false
|
||||
end
|
||||
|
||||
def is_sandbox?
|
||||
id.start_with?('sandbox-')
|
||||
end
|
||||
|
||||
=begin
|
||||
def validate!
|
||||
super
|
||||
@ -197,7 +216,8 @@ module Devops
|
||||
end
|
||||
|
||||
def self.create_roles_response roles
|
||||
if !roles || roles.is_a?(String)
|
||||
return "error in creating roles" unless roles
|
||||
if roles.is_a?(String)
|
||||
roles
|
||||
else
|
||||
info = ""
|
||||
|
||||
@ -4,15 +4,18 @@ module Devops
|
||||
module Model
|
||||
class Ec2ProviderAccount < ProviderAccount
|
||||
|
||||
attr_accessor :access_key_id, :availability_zone, :secret_access_key
|
||||
attr_accessor :availability_zone
|
||||
|
||||
set_field_validators :access_key_id, ::Validators::FieldValidator::NotNil,
|
||||
set_field_validators :access_key_id, [::Validators::FieldValidator::NotNil,
|
||||
::Validators::FieldValidator::FieldType::String,
|
||||
::Validators::FieldValidator::NotEmpty
|
||||
::Validators::FieldValidator::NotEmpty]
|
||||
|
||||
set_field_validators :secret_access_key, ::Validators::FieldValidator::NotNil,
|
||||
set_field_validators :secret_access_key, [::Validators::FieldValidator::NotNil,
|
||||
::Validators::FieldValidator::FieldType::String,
|
||||
::Validators::FieldValidator::NotEmpty
|
||||
::Validators::FieldValidator::NotEmpty]
|
||||
|
||||
set_field_validators :use_iam_profile, [::Validators::FieldValidator::Nil,
|
||||
::Validators::FieldValidator::FieldType::Boolean]
|
||||
def initialize a={}
|
||||
super(a)
|
||||
self.provider = Provider::Ec2::PROVIDER
|
||||
@ -45,6 +48,7 @@ module Devops
|
||||
{
|
||||
access_key_id: "AWS account access key",
|
||||
secret_access_key: "AWS account secret key",
|
||||
use_iam_profile: "Should use iam profile?",
|
||||
availability_zone: "Availability zone, todo: remove field?"
|
||||
}.merge(ProviderAccount::ACCOUNT_FIELDS)
|
||||
end
|
||||
|
||||
@ -7,22 +7,22 @@ module Devops
|
||||
|
||||
include ModelWithProvider
|
||||
|
||||
attr_accessor :account_name, :description, :ssh_key
|
||||
# attr_accessor :account_name, :description, :ssh_key
|
||||
|
||||
set_field_validators :account_name, ::Validators::FieldValidator::NotNil,
|
||||
set_field_validators :account_name, [::Validators::FieldValidator::NotNil,
|
||||
::Validators::FieldValidator::FieldType::String,
|
||||
::Validators::FieldValidator::NotEmpty,
|
||||
::Validators::FieldValidator::Name
|
||||
::Validators::FieldValidator::Name]
|
||||
|
||||
set_field_validators :description, ::Validators::FieldValidator::Nil,
|
||||
set_field_validators :description, [::Validators::FieldValidator::Nil,
|
||||
::Validators::FieldValidator::FieldType::String,
|
||||
::Validators::FieldValidator::NotEmpty,
|
||||
::Validators::FieldValidator::Description
|
||||
::Validators::FieldValidator::Description]
|
||||
|
||||
set_field_validators :ssh_key, ::Validators::FieldValidator::NotNil,
|
||||
set_field_validators :ssh_key, [::Validators::FieldValidator::NotNil,
|
||||
::Validators::FieldValidator::FieldType::String,
|
||||
::Validators::FieldValidator::NotEmpty,
|
||||
::Validators::FieldValidator::SshKey
|
||||
::Validators::FieldValidator::SshKey]
|
||||
|
||||
ACCOUNT_FIELDS = {
|
||||
account_name: "Account name (id)",
|
||||
|
||||
@ -19,37 +19,37 @@ module Devops
|
||||
run_list: {type: Array, value_type: String, empty: true, nil: true}
|
||||
# details: {type: Hash, nil: true} # Hash type isn't supported yet
|
||||
|
||||
set_field_validators :id, ::Validators::FieldValidator::NotNil,
|
||||
set_field_validators :id, [::Validators::FieldValidator::NotNil,
|
||||
::Validators::FieldValidator::FieldType::String,
|
||||
::Validators::FieldValidator::NotEmpty
|
||||
::Validators::FieldValidator::NotEmpty]
|
||||
|
||||
set_field_validators :provider, ::Validators::FieldValidator::NotNil,
|
||||
set_field_validators :provider, [::Validators::FieldValidator::NotNil,
|
||||
::Validators::FieldValidator::FieldType::String,
|
||||
::Validators::FieldValidator::NotEmpty
|
||||
::Validators::FieldValidator::NotEmpty]
|
||||
|
||||
set_field_validators :project, ::Validators::FieldValidator::NotNil,
|
||||
set_field_validators :project, [::Validators::FieldValidator::NotNil,
|
||||
::Validators::FieldValidator::FieldType::String,
|
||||
::Validators::FieldValidator::NotEmpty
|
||||
::Validators::FieldValidator::NotEmpty]
|
||||
|
||||
set_field_validators :deploy_env, ::Validators::FieldValidator::NotNil,
|
||||
set_field_validators :deploy_env, [::Validators::FieldValidator::NotNil,
|
||||
::Validators::FieldValidator::FieldType::String,
|
||||
::Validators::FieldValidator::NotEmpty
|
||||
::Validators::FieldValidator::NotEmpty]
|
||||
|
||||
set_field_validators :stack_template, ::Validators::FieldValidator::NotNil,
|
||||
set_field_validators :stack_template, [::Validators::FieldValidator::NotNil,
|
||||
::Validators::FieldValidator::FieldType::String,
|
||||
::Validators::FieldValidator::NotEmpty
|
||||
::Validators::FieldValidator::NotEmpty]
|
||||
|
||||
set_field_validators :name, ::Validators::FieldValidator::Nil,
|
||||
set_field_validators :name, [::Validators::FieldValidator::Nil,
|
||||
::Validators::FieldValidator::FieldType::String,
|
||||
::Validators::FieldValidator::NotEmpty
|
||||
::Validators::FieldValidator::NotEmpty]
|
||||
|
||||
set_field_validators :owner, ::Validators::FieldValidator::NotNil,
|
||||
set_field_validators :owner, [::Validators::FieldValidator::NotNil,
|
||||
::Validators::FieldValidator::FieldType::String,
|
||||
::Validators::FieldValidator::NotEmpty
|
||||
::Validators::FieldValidator::NotEmpty]
|
||||
|
||||
set_field_validators :run_list, ::Validators::FieldValidator::NotNil,
|
||||
set_field_validators :run_list, [::Validators::FieldValidator::NotNil,
|
||||
::Validators::FieldValidator::FieldType::Array,
|
||||
::Validators::FieldValidator::RunList
|
||||
::Validators::FieldValidator::RunList]
|
||||
|
||||
def initialize attrs={}
|
||||
# self.provider = self.class.provider
|
||||
|
||||
@ -16,22 +16,22 @@ module Devops
|
||||
template_body: {type: String, empty: false},
|
||||
owner: {type: String, empty: false}
|
||||
|
||||
set_field_validators :id, ::Validators::FieldValidator::NotNil,
|
||||
set_field_validators :id, [::Validators::FieldValidator::NotNil,
|
||||
::Validators::FieldValidator::FieldType::String,
|
||||
::Validators::FieldValidator::NotEmpty,
|
||||
::Validators::FieldValidator::Name
|
||||
::Validators::FieldValidator::Name]
|
||||
|
||||
set_field_validators :provider, ::Validators::FieldValidator::NotNil,
|
||||
set_field_validators :provider, [::Validators::FieldValidator::NotNil,
|
||||
::Validators::FieldValidator::FieldType::String,
|
||||
::Validators::FieldValidator::NotEmpty
|
||||
::Validators::FieldValidator::NotEmpty]
|
||||
|
||||
set_field_validators :template_body, ::Validators::FieldValidator::NotNil,
|
||||
set_field_validators :template_body, [::Validators::FieldValidator::NotNil,
|
||||
::Validators::FieldValidator::FieldType::String,
|
||||
::Validators::FieldValidator::NotEmpty
|
||||
::Validators::FieldValidator::NotEmpty]
|
||||
|
||||
set_field_validators :owner, ::Validators::FieldValidator::NotNil,
|
||||
set_field_validators :owner, [::Validators::FieldValidator::NotNil,
|
||||
::Validators::FieldValidator::FieldType::String,
|
||||
::Validators::FieldValidator::NotEmpty
|
||||
::Validators::FieldValidator::NotEmpty]
|
||||
|
||||
set_validators ::Validators::StackTemplate::TemplateContent
|
||||
|
||||
|
||||
@ -1,6 +1,8 @@
|
||||
require_relative "stack_template_base"
|
||||
require_relative "stack_template_openstack"
|
||||
require_relative "stack_template_ec2"
|
||||
require 'providers/openstack'
|
||||
require 'providers/ec2'
|
||||
|
||||
module Devops
|
||||
module Model
|
||||
|
||||
@ -17,15 +17,15 @@ module Devops
|
||||
|
||||
attr_accessor :id, :password, :privileges, :email
|
||||
|
||||
set_field_validators :id, ::Validators::FieldValidator::NotNil,
|
||||
set_field_validators :id, [::Validators::FieldValidator::NotNil,
|
||||
::Validators::FieldValidator::FieldType::String,
|
||||
::Validators::FieldValidator::Name
|
||||
set_field_validators :password, ::Validators::FieldValidator::NotNil,
|
||||
::Validators::FieldValidator::FieldType::String
|
||||
set_field_validators :email, ::Validators::FieldValidator::NotNil,
|
||||
::Validators::FieldValidator::FieldType::String
|
||||
set_field_validators :privileges, ::Validators::FieldValidator::NotNil,
|
||||
::Validators::FieldValidator::FieldType::Hash
|
||||
::Validators::FieldValidator::Name]
|
||||
set_field_validators :password, [::Validators::FieldValidator::NotNil,
|
||||
::Validators::FieldValidator::FieldType::String]
|
||||
set_field_validators :email, [::Validators::FieldValidator::NotNil,
|
||||
::Validators::FieldValidator::FieldType::String]
|
||||
set_field_validators :privileges, [::Validators::FieldValidator::NotNil,
|
||||
::Validators::FieldValidator::FieldType::Hash]
|
||||
def initialize p={}
|
||||
self.id = p['username']
|
||||
self.email = p['email']
|
||||
|
||||
@ -33,7 +33,7 @@ class MongoConnector
|
||||
[:keys, :key, :key_insert, :key_delete] => :keys_connector,
|
||||
[:save_report, :report, :reports, :set_report_status, :set_report_server_data, :add_report_subreports] => :reports_connector,
|
||||
[:insert_statistic, :search_statistic] => :statistics_connector,
|
||||
[:provider_accounts, :provider_accounts_insert, :provider_accounts_delete, :provider_accounts_show] => :provider_accounts_connector
|
||||
[:provider_accounts, :provider_accounts_insert, :provider_accounts_delete, :provider_account] => :provider_accounts_connector
|
||||
)
|
||||
|
||||
def initialize(db, host, port=27017, user=nil, password=nil)
|
||||
|
||||
@ -2,9 +2,10 @@ module Validators
|
||||
module FieldValidator
|
||||
class Base
|
||||
|
||||
def initialize model, value
|
||||
def initialize model, field
|
||||
@model = model
|
||||
@value = value
|
||||
@field = field
|
||||
@value = model.send(field)
|
||||
end
|
||||
|
||||
def validate!
|
||||
|
||||
@ -25,6 +25,17 @@ module Validators
|
||||
end
|
||||
end
|
||||
|
||||
class Boolean < FieldType
|
||||
|
||||
def valid?
|
||||
@value == true or @value == false
|
||||
end
|
||||
|
||||
def type_name
|
||||
"boolean"
|
||||
end
|
||||
end
|
||||
|
||||
class Array < FieldType
|
||||
|
||||
def type
|
||||
|
||||
@ -4,14 +4,14 @@ module Validators
|
||||
class Name < Base
|
||||
|
||||
MAX_NAME_LEN = 200
|
||||
NAME_REGEX = /\A\w{1,#{MAX_NAME_LEN}}\z/
|
||||
NAME_REGEX = /\A[\w\-]{1,#{MAX_NAME_LEN}}\z/
|
||||
|
||||
def valid?
|
||||
!NAME_REGEX.match(@value).nil?
|
||||
end
|
||||
|
||||
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} symbols"
|
||||
"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
|
||||
|
||||
@ -0,0 +1,17 @@
|
||||
require_relative "base"
|
||||
|
||||
module Validators
|
||||
module FieldValidator
|
||||
class ProviderAccount < Base
|
||||
|
||||
def valid?
|
||||
accounts = AccountsFactory.accounts(@model.provider)
|
||||
accounts.map{|a| a.account_name}.include?(@value)
|
||||
end
|
||||
|
||||
def message
|
||||
"Account '#{@value}' for provider '#{@model.provider}' does not exist"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
21
devops-service/db/validators/field_validators/vpc.rb
Normal file
21
devops-service/db/validators/field_validators/vpc.rb
Normal file
@ -0,0 +1,21 @@
|
||||
require_relative "base"
|
||||
|
||||
module Validators
|
||||
module FieldValidator
|
||||
class Vpc < Base
|
||||
|
||||
def valid?
|
||||
provider = ::Provider::ProviderFactory.get(@model.provider, @model.provider_account)
|
||||
vpcs = provider.describe_vpcs
|
||||
vpcs.keys.include?(@value)
|
||||
rescue
|
||||
raise "Invalid provider account '#{@model.provider_account}'"
|
||||
end
|
||||
|
||||
def message
|
||||
"Invalid vpc '#{@value}'."
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@ -1,6 +1,10 @@
|
||||
require_relative "devops_error"
|
||||
class InvalidRecord < ::Devops::Exception::DevopsError
|
||||
|
||||
# message could be a String or a hash like
|
||||
# {
|
||||
# error_data: [{:key=>:provider, :message=>"Value can not be undefined"}]
|
||||
# }
|
||||
def initialize msg
|
||||
if msg.is_a?(String)
|
||||
super(msg)
|
||||
@ -9,6 +13,17 @@ class InvalidRecord < ::Devops::Exception::DevopsError
|
||||
end
|
||||
end
|
||||
|
||||
def message
|
||||
if @object
|
||||
messages = @object[:error_data].map do |error_item|
|
||||
"#{error_item[:key]}: #{error_item[:message]}"
|
||||
end
|
||||
"Following errors occured: \n#{messages.join('\n')}"
|
||||
else
|
||||
super
|
||||
end
|
||||
end
|
||||
|
||||
def http_status
|
||||
400
|
||||
end
|
||||
|
||||
@ -2,6 +2,7 @@ require "lib/knife/knife_factory"
|
||||
require "workers/worker"
|
||||
require "workers/delete_server_worker"
|
||||
require "hooks"
|
||||
require 'net/ssh'
|
||||
|
||||
module Devops
|
||||
module Executor
|
||||
@ -312,15 +313,26 @@ module Devops
|
||||
res = delete_from_chef_server(@server.chef_node_name)
|
||||
begin
|
||||
new_name = "/etc/chef.backup_#{Time.now.strftime("%d-%m-%Y_%H.%M.%S")}"
|
||||
# r = `ssh -i #{cert_path} -q #{@server.remote_user}@#{@server.private_ip} rm -Rf /etc/chef`
|
||||
cmd = "ssh -i #{cert_path} -q #{@server.remote_user}@#{@server.private_ip} \"/bin/sh -c 'if [[ -d /etc/chef ]]; then mv /etc/chef #{new_name}; else echo not found; fi'\""
|
||||
DevopsLogger.logger.info("Trying to run command '#{cmd}'")
|
||||
r = `#{cmd}`.strip
|
||||
if r == 'not found'
|
||||
cmd = (@server.remote_user == 'root' ? "" : "sudo ")
|
||||
cmd = cmd + "/bin/sh -c 'if [[ -d /etc/chef ]]; then mv /etc/chef #{new_name} && echo ok; else echo not found; fi'"
|
||||
DevopsLogger.logger.info("SSH: trying to run command '#{cmd}'")
|
||||
Net::SSH.start(@server.private_ip, @server.remote_user, :keys => [cert_path]) do |session|
|
||||
session.open_channel do |channel|
|
||||
channel.request_pty(:modes => { Net::SSH::Connection::Term::ECHO => 0 }) do |c, success|
|
||||
raise "could not request pty" unless success
|
||||
channel.exec cmd
|
||||
channel.on_data do |c_, data|
|
||||
if data == 'not found'
|
||||
res[:server] = "Directory '/etc/chef' does not exists"
|
||||
else
|
||||
raise(r) unless $?.success?
|
||||
elsif data == 'ok'
|
||||
res[:server] = "'/etc/chef' renamed to '#{new_name}'"
|
||||
else
|
||||
DevopsLogger.logger.error "Unexpected error: " + data
|
||||
raise(data)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
rescue => e
|
||||
DevopsLogger.logger.error "Unbootstrap error: " + e.message
|
||||
|
||||
@ -1,6 +1,14 @@
|
||||
module Provider
|
||||
class AccountsFactory
|
||||
|
||||
class << self
|
||||
|
||||
def accounts provider_name
|
||||
Devops::Db.connector.provider_accounts(provider_name)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
def init config
|
||||
|
||||
end
|
||||
@ -22,7 +30,7 @@ module Provider
|
||||
end
|
||||
|
||||
def accounts
|
||||
Devops::Db.connector.provider_accounts(provider_name)
|
||||
AccountsFactory.accounts(provider_name)
|
||||
end
|
||||
|
||||
def create_account hash
|
||||
|
||||
@ -14,6 +14,18 @@ module Provider
|
||||
"stack_#{self.ssh_key}-#{s.project}-#{s.deploy_env}-#{Time.now.to_i}"
|
||||
end
|
||||
|
||||
def networks_detail filters={}
|
||||
networks(filters)
|
||||
end
|
||||
|
||||
def networks filters={}
|
||||
[]
|
||||
end
|
||||
|
||||
def groups filters={}
|
||||
{}
|
||||
end
|
||||
|
||||
protected
|
||||
def connection_compute options
|
||||
Fog::Compute.new( options )
|
||||
|
||||
@ -15,10 +15,14 @@ module Provider
|
||||
self.certificate_path = config[:aws_certificate]
|
||||
self.ssh_key = config[:aws_ssh_key]
|
||||
options = {
|
||||
:provider => "aws",
|
||||
:aws_access_key_id => config[:aws_access_key_id],
|
||||
:aws_secret_access_key => config[:aws_secret_access_key]
|
||||
:provider => "aws"
|
||||
}
|
||||
if config[:aws_use_iam_profile]
|
||||
options[:use_iam_profile] = true
|
||||
else
|
||||
options[:aws_access_key_id] = config[:aws_access_key_id]
|
||||
options[:aws_secret_access_key] = config[:aws_secret_access_key]
|
||||
end
|
||||
if config[:aws_proxy] and config[:aws_no_proxy]
|
||||
options[:connection_options] = {
|
||||
:proxy => config[:aws_proxy],
|
||||
@ -51,14 +55,8 @@ module Provider
|
||||
end
|
||||
end
|
||||
|
||||
def groups filters=nil
|
||||
buf = {}
|
||||
buf = filters.select{|k,v| ["vpc-id"].include?(k)} unless filters.nil?
|
||||
g = if buf.empty?
|
||||
self.compute.describe_security_groups
|
||||
else
|
||||
self.compute.describe_security_groups(buf)
|
||||
end
|
||||
def groups filters={}
|
||||
g = self.compute.describe_security_groups(filters)
|
||||
convert_groups(g.body["securityGroupInfo"])
|
||||
end
|
||||
|
||||
@ -72,12 +70,8 @@ module Provider
|
||||
end
|
||||
end
|
||||
|
||||
def networks_detail
|
||||
self.networks
|
||||
end
|
||||
|
||||
def networks
|
||||
self.compute.describe_subnets.body["subnetSet"].select{|n| n["state"] == "available"}.map do |n|
|
||||
def networks filters={}
|
||||
self.compute.describe_subnets(filters).body["subnetSet"].select{|n| n["state"] == "available"}.map do |n|
|
||||
{
|
||||
"cidr" => n["cidrBlock"],
|
||||
"vpcId" => n["vpcId"],
|
||||
@ -267,8 +261,9 @@ module Provider
|
||||
end
|
||||
|
||||
def validate_stack_template template
|
||||
r = cloud_formation.validate_template({'TemplateBody' => template})
|
||||
pp r.body
|
||||
#r = cloud_formation.validate_template({'TemplateBody' => template})
|
||||
#pp r.body
|
||||
true
|
||||
end
|
||||
|
||||
def delete_stack(stack)
|
||||
@ -321,6 +316,10 @@ module Provider
|
||||
def create_default_stack_name s
|
||||
"stack-#{self.ssh_key}-#{s.project}-#{s.deploy_env}-#{Time.now.to_i}".gsub('_', '-')
|
||||
end
|
||||
|
||||
def describe_vpcs
|
||||
self.compute.describe_vpcs.body["vpcSet"].select{|v| v["state"] == "available"}.map{|v| {"vpc_id" => v["vpcId"], "cidr" => v["cidrBlock"] } }
|
||||
end
|
||||
private
|
||||
|
||||
def convert_groups list
|
||||
|
||||
@ -20,6 +20,7 @@ module Provider
|
||||
aws_ssh_key: account.ssh_key,
|
||||
aws_access_key_id: account.access_key_id,
|
||||
aws_secret_access_key: account.secret_access_key,
|
||||
aws_use_iam_profile: account.use_iam_profile,
|
||||
aws_availability_zone: account.availability_zone,
|
||||
|
||||
aws_proxy: config[:aws_proxy],
|
||||
|
||||
@ -30,7 +30,7 @@ module Provider
|
||||
PROVIDER
|
||||
end
|
||||
|
||||
def groups filter=nil
|
||||
def groups filters={}
|
||||
convert_groups(compute.list_security_groups.body["security_groups"])
|
||||
end
|
||||
|
||||
@ -55,8 +55,8 @@ module Provider
|
||||
end
|
||||
end
|
||||
|
||||
def networks_detail
|
||||
net = self.network
|
||||
def networks_detail filters={}
|
||||
net = self.network(filters)
|
||||
subnets = net.list_subnets.body["subnets"].select{|s| net.current_tenant["id"] == s["tenant_id"]}
|
||||
net.list_networks.body["networks"].select{|n| n["router:external"] == false and n["status"] == "ACTIVE" and net.current_tenant["id"] == n["tenant_id"]}.map{|n|
|
||||
sn = subnets.detect{|s| n["subnets"][0] == s["id"]}
|
||||
@ -68,7 +68,7 @@ module Provider
|
||||
}
|
||||
end
|
||||
|
||||
def networks
|
||||
def networks filters={}
|
||||
net = self.network
|
||||
net.list_networks.body["networks"].select{|n| n["router:external"] == false and n["status"] == "ACTIVE" and net.current_tenant["id"] == n["tenant_id"]}.map{|n|
|
||||
{
|
||||
|
||||
@ -23,22 +23,10 @@ module Provider
|
||||
[]
|
||||
end
|
||||
|
||||
def groups filter=nil
|
||||
{}
|
||||
end
|
||||
|
||||
def images filters
|
||||
[]
|
||||
end
|
||||
|
||||
def networks
|
||||
[]
|
||||
end
|
||||
|
||||
def networks_detail
|
||||
self.networks
|
||||
end
|
||||
|
||||
def servers
|
||||
@@mongo.servers_find({:provider => PROVIDER}).map{|s| s.to_hash}
|
||||
end
|
||||
|
||||
90
devops-service/spec/connectors/filter_connector_spec.rb
Normal file
90
devops-service/spec/connectors/filter_connector_spec.rb
Normal file
@ -0,0 +1,90 @@
|
||||
require 'db/mongo/connectors/filter'
|
||||
require 'spec/connectors/tester_connector/filter'
|
||||
require_relative 'shared_connectors_context'
|
||||
|
||||
RSpec.describe Connectors::Filter, type: :connector do
|
||||
set_tester_connector TesterConnector::Filter
|
||||
include_context 'connectors'
|
||||
let(:provider) {'ec2'}
|
||||
|
||||
describe '#available_images' do
|
||||
subject { @connector.available_images(provider) }
|
||||
|
||||
context 'when there is no filter for given provider' do
|
||||
it 'returns empty array' do
|
||||
expect(subject).to eq []
|
||||
end
|
||||
|
||||
context 'when there is filter for given provider but for another type' do
|
||||
it 'returns empty array' do
|
||||
test_filter = {provider: provider, type: 'foo', images: ['foo', 'bar']}
|
||||
@tester_connector.create(test_filter) do
|
||||
expect(subject).to eq []
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when there is filter for given provider' do
|
||||
it "returns array with images' names" do
|
||||
test_filter = {provider: provider, type: 'image', images: ['foo', 'bar']}
|
||||
@tester_connector.create(test_filter) do
|
||||
expect(subject).to match_array ['foo', 'bar']
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#add_available_images', cleanup_after: :each do
|
||||
subject { @connector.add_available_images(['foo'], provider) }
|
||||
|
||||
it "do nothing if images is not Array" do
|
||||
expect {
|
||||
result = @connector.add_available_images('foo', provider)
|
||||
expect(result).to be_nil
|
||||
}.not_to change {@tester_connector.list}
|
||||
end
|
||||
|
||||
it 'creates filter if there is no one' do
|
||||
expect(@tester_connector.list.empty?).to be true
|
||||
expect(subject).to match_array ['foo']
|
||||
expect(@tester_connector.list.empty?).to be false
|
||||
end
|
||||
|
||||
it 'updates filter if one already exists' do
|
||||
@tester_connector.create(provider: provider, type: 'image', images: ['bar'])
|
||||
expect(subject).to match_array ['bar', 'foo']
|
||||
expect(@tester_connector.list.first['images']).to match_array ['bar', 'foo']
|
||||
end
|
||||
|
||||
it "doesn't duplicate images in filter" do
|
||||
@tester_connector.create(provider: provider, type: 'image', images: ['foo'])
|
||||
expect(subject).to match_array ['foo']
|
||||
expect(@tester_connector.list.first['images']).to match_array ['foo']
|
||||
end
|
||||
end
|
||||
|
||||
describe '#delete_available_images' do
|
||||
subject { @connector.delete_available_images(['foo'], provider) }
|
||||
after { @tester_connector.cleanup }
|
||||
let(:create_filter) { @tester_connector.create(provider: provider, type: 'image', images: ['foo', 'bar']) }
|
||||
|
||||
it 'does nothing if images is not Array' do
|
||||
create_filter
|
||||
expect {
|
||||
result = @connector.delete_available_images('foo', provider)
|
||||
expect(result).to be_nil
|
||||
}.not_to change{ @tester_connector.list.first['images'] }
|
||||
end
|
||||
|
||||
it 'removes given images from filter' do
|
||||
create_filter
|
||||
expect(subject).to match_array ['bar']
|
||||
expect(@tester_connector.list.first['images']).to match_array ['bar']
|
||||
end
|
||||
|
||||
it 'returns empty array if there is no filter' do
|
||||
expect(subject).to eq []
|
||||
end
|
||||
end
|
||||
end
|
||||
37
devops-service/spec/connectors/image_connector_spec.rb
Normal file
37
devops-service/spec/connectors/image_connector_spec.rb
Normal file
@ -0,0 +1,37 @@
|
||||
require 'db/mongo/connectors/image'
|
||||
require 'spec/connectors/tester_connector/image'
|
||||
require_relative 'shared_connectors_context'
|
||||
|
||||
RSpec.describe Connectors::Image, type: :connector do
|
||||
set_tester_connector TesterConnector::Image
|
||||
include_context 'connectors'
|
||||
let(:model_class) { Devops::Model::Image }
|
||||
|
||||
include_examples 'mongo connector', {
|
||||
model_name: :image,
|
||||
only: [:insert, :show, :update, :delete],
|
||||
field_to_update: :name
|
||||
}
|
||||
|
||||
describe '#images', cleanup_after: :each do
|
||||
subject { @connector.images('ec2') }
|
||||
|
||||
it 'should be empty if collection is empty' do
|
||||
expect(subject).to eq []
|
||||
end
|
||||
|
||||
it "returns array of Model::Key's of given provider" do
|
||||
@tester_connector.create(provider: 'ec2')
|
||||
@tester_connector.create(provider: 'openstack')
|
||||
expect(subject).to be_an_array_of(model_class).and have_size(1)
|
||||
expect(subject.first.provider).to eq 'ec2'
|
||||
end
|
||||
|
||||
it 'returns images for both providers if is is unset' do
|
||||
@tester_connector.create(provider: 'ec2')
|
||||
@tester_connector.create(provider: 'openstack')
|
||||
expect(@connector.images.length).to eq 2
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
62
devops-service/spec/connectors/key_connector_spec.rb
Normal file
62
devops-service/spec/connectors/key_connector_spec.rb
Normal file
@ -0,0 +1,62 @@
|
||||
require 'db/mongo/connectors/key'
|
||||
require 'db/mongo/models/key'
|
||||
require 'spec/connectors/tester_connector/key'
|
||||
require_relative 'shared_connectors_context'
|
||||
|
||||
RSpec.describe Connectors::Key, type: :connector do
|
||||
set_tester_connector TesterConnector::Key
|
||||
include_context 'connectors'
|
||||
let(:model_class) { Devops::Model::Key }
|
||||
|
||||
include_examples 'mongo connector', model_name: :key, only: [:insert, :list]
|
||||
|
||||
describe '#key' do
|
||||
context 'when scope was passed' do
|
||||
subject { @connector.key('foo') }
|
||||
|
||||
it 'raises RecordNotFound when there is no such record' do
|
||||
expect { subject }.to raise_error(RecordNotFound)
|
||||
end
|
||||
|
||||
it 'returns record if was found' do
|
||||
@tester_connector.create(id: 'foo') do
|
||||
expect(subject).to be_an_instance_of(model_class)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when scope was passed' do
|
||||
subject { @connector.key('foo', 'user') }
|
||||
|
||||
it 'raises RecordNotFound when there is no such record' do
|
||||
expect { subject }.to raise_error(RecordNotFound)
|
||||
end
|
||||
|
||||
it 'returns record if was found' do
|
||||
@tester_connector.create(id: 'foo', scope: 'user') do
|
||||
expect(subject).to be_an_instance_of(model_class)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#key_delete' do
|
||||
subject { @connector.key_delete('foo') }
|
||||
|
||||
it 'raises RecordNotFound if there is no such record' do
|
||||
expect{ subject }.to raise_error(RecordNotFound)
|
||||
end
|
||||
|
||||
it 'remove key in "user" scope' do
|
||||
@tester_connector.create(id: 'foo', scope: 'user')
|
||||
subject
|
||||
expect(@tester_connector.list).to eq []
|
||||
end
|
||||
|
||||
it "doesn't remove key in 'system' scope" do
|
||||
@tester_connector.create(id: 'foo', scope: 'system') do
|
||||
expect {subject}.to raise_error RecordNotFound
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
295
devops-service/spec/connectors/project_connector_spec.rb
Normal file
295
devops-service/spec/connectors/project_connector_spec.rb
Normal file
@ -0,0 +1,295 @@
|
||||
require 'db/mongo/connectors/project'
|
||||
require 'spec/connectors/tester_connector/project'
|
||||
require_relative 'shared_connectors_context'
|
||||
|
||||
RSpec.describe Connectors::Project, type: :connector do
|
||||
set_tester_connector TesterConnector::Project
|
||||
include_context 'connectors'
|
||||
let(:model_class) { Devops::Model::Project }
|
||||
|
||||
include_examples 'mongo connector', {
|
||||
model_name: :project,
|
||||
factory_name: :project,
|
||||
only: [:insert, :show, :delete],
|
||||
field_to_update: :deploy_envs
|
||||
}
|
||||
|
||||
describe '#is_project_exists?' do
|
||||
subject { @connector.is_project_exists?(build(:project, id: 'foo')) }
|
||||
it 'returns true if project exists' do
|
||||
@tester_connector.create(id: 'foo') do
|
||||
expect(subject).to be true
|
||||
end
|
||||
end
|
||||
it 'returns false if project doesn\'t exists' do
|
||||
expect(subject).to be false
|
||||
end
|
||||
end
|
||||
|
||||
describe '#projects_all' do
|
||||
it 'returns array of projects' do
|
||||
@tester_connector.create_list(2) do
|
||||
result = @connector.projects_all
|
||||
expect(result).to be_an_array_of(model_class).and have_size(2)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#projects', cleanup_after: :all do
|
||||
before(:all) do
|
||||
@tester_connector.create build(:project, id: 'foo', type: 'multi').to_mongo_hash
|
||||
@tester_connector.create build(:project, id: 'bar', archived: true).to_mongo_hash
|
||||
@tester_connector.create build(:project, id: 'baz').to_mongo_hash
|
||||
end
|
||||
|
||||
it 'returns non archived projects with all params unset' do
|
||||
expect(@connector.projects).to have_size(2)
|
||||
end
|
||||
|
||||
it 'returns projects with given ids' do
|
||||
result = @connector.projects(%w(foo baz))
|
||||
expect(result).to be_an_array_of(model_class)
|
||||
expect(result.map(&:id)).to match_array(%w(foo baz))
|
||||
end
|
||||
|
||||
it 'returns multi projects if @type == :multi' do
|
||||
expect(
|
||||
@connector.projects(nil, :multi).map(&:id)
|
||||
).to match_array ['foo']
|
||||
end
|
||||
|
||||
it 'returns only given fields and id if @fields is set' do
|
||||
result = @connector.projects(nil, nil, [:deploy_envs])
|
||||
expect(result.map(&:id).compact).not_to eq []
|
||||
expect(result.map(&:deploy_envs).compact).not_to eq []
|
||||
expect(result.map(&:description).compact).to eq []
|
||||
end
|
||||
|
||||
it 'returns only archived projects if @archived=true' do
|
||||
result = @connector.projects(nil, nil, [], true)
|
||||
expect(result.map(&:id)).to match_array(%w(bar))
|
||||
end
|
||||
end
|
||||
|
||||
describe '#project_names_with_envs', cleanup_after: :all do
|
||||
before(:all) do
|
||||
@tester_connector.create(
|
||||
id: 'foo',
|
||||
deploy_envs: [{identifier: 'env1'}, {identifier: 'env2'}]
|
||||
)
|
||||
@tester_connector.create(
|
||||
id: 'bar',
|
||||
deploy_envs: [{identifier: 'env3'}, {identifier: 'env4'}]
|
||||
)
|
||||
end
|
||||
|
||||
it 'returns hash like {"project_name" => ["env1", "env2]}' do
|
||||
result = @connector.project_names_with_envs
|
||||
expect(result.keys.sort).to match_array %w(foo bar)
|
||||
expect(result['foo'].sort).to match_array %w(env1 env2)
|
||||
expect(result['bar'].sort).to match_array %w(env3 env4)
|
||||
end
|
||||
|
||||
it 'returns only projects with given names' do
|
||||
expect(@connector.project_names_with_envs(['bar']).keys).to match_array %w(bar)
|
||||
end
|
||||
end
|
||||
|
||||
describe '#projects_by_image', cleanup_after: :each do
|
||||
def env(image)
|
||||
{image: image, provider: 'ec2'}
|
||||
end
|
||||
|
||||
it 'returns projects deploy_envs of which have given image' do
|
||||
@tester_connector.create(id: 'foo', deploy_envs: [env('a'), env('b')])
|
||||
@tester_connector.create(id: 'bar', deploy_envs: [env('a'), env('a')])
|
||||
@tester_connector.create(id: 'baz', deploy_envs: [env('b'), env('b')])
|
||||
result = @connector.projects_by_image('a')
|
||||
expect(result).to be_an_array_of(model_class)
|
||||
expect(result.map(&:id)).to match_array %w(foo bar)
|
||||
end
|
||||
end
|
||||
|
||||
describe '#projects_by_user', cleanup_after: :each do
|
||||
def env(users)
|
||||
{users: users, provider: 'ec2'}
|
||||
end
|
||||
|
||||
it 'returns projects deploy_envs of which have given user' do
|
||||
@tester_connector.create(id: 'foo', deploy_envs: [ env(%w(user1 user2)) ])
|
||||
@tester_connector.create(id: 'bar', deploy_envs: [ env(%w(user1 user1)) ])
|
||||
@tester_connector.create(id: 'baz', deploy_envs: [ env(%w(user2 user2)) ])
|
||||
@tester_connector.create(id: 'baf', deploy_envs: [ env(%w(user1)), env(%w(user2)) ])
|
||||
result = @connector.projects_by_user('user1')
|
||||
expect(result).to be_an_array_of(model_class)
|
||||
expect(result.map(&:id)).to match_array %w(foo bar baf)
|
||||
end
|
||||
end
|
||||
|
||||
describe '#archive_project' do
|
||||
it 'sets archived to true' do
|
||||
@tester_connector.create(id: 'foo') do
|
||||
@connector.archive_project('foo')
|
||||
expect(@tester_connector.show('foo')).to include('archived' => true)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#unarchive_project' do
|
||||
it 'unsets archived' do
|
||||
@tester_connector.create(id: 'foo', archived: true) do
|
||||
@connector.unarchive_project('foo')
|
||||
expect(@tester_connector.show('foo')).not_to include('archived')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#check_project_auth', cleanup_after: :all do
|
||||
before(:all) do
|
||||
@tester_connector.create(id: 'foo', deploy_envs: [
|
||||
{identifier: 'bar', provider: 'ec2', users: %w(user1)}
|
||||
])
|
||||
end
|
||||
|
||||
it "raises InvalidPrivileges if given env users don't include given user" do
|
||||
expect {
|
||||
@connector.check_project_auth('foo', 'bar', 'user2')
|
||||
}.to raise_error(InvalidPrivileges)
|
||||
end
|
||||
|
||||
it "returns project if env's users include given user" do
|
||||
result = @connector.check_project_auth('foo', 'bar', 'user1')
|
||||
expect(result).to be_an_instance_of(model_class)
|
||||
expect(result.id).to eq 'foo'
|
||||
end
|
||||
end
|
||||
|
||||
describe '#projects_and_deploy_envs_by_field', cleanup_after: :all do
|
||||
def env(field, value)
|
||||
{provider: 'ec2', field => value}
|
||||
end
|
||||
before(:all) do
|
||||
@tester_connector.create(id: 'foo', deploy_envs: [
|
||||
env(:image, 'image1'), env(:stack_template, 'template1')
|
||||
])
|
||||
end
|
||||
|
||||
it 'returns projects with deploy envs containing given field with given value' do
|
||||
expect(
|
||||
@connector.projects_and_deploy_envs_by_field(:image, 'image1').map(&:id)
|
||||
).to match_array %w(foo)
|
||||
|
||||
expect(
|
||||
@connector.projects_and_deploy_envs_by_field(:stack_template, 'template1').map(&:id)
|
||||
).to match_array %w(foo)
|
||||
end
|
||||
end
|
||||
|
||||
describe '#set_project_deploy_env_field', cleanup_after: :each do
|
||||
it 'updates given env from given field_value_hash' do
|
||||
@tester_connector.create(id: 'foo', deploy_envs: [
|
||||
{identifier: 'bar', provider: 'ec2'}
|
||||
])
|
||||
@connector.set_project_deploy_env_field('foo', 'bar', image: 'a', stack_template: 'b')
|
||||
updated_project = @tester_connector.show('foo')
|
||||
expect(updated_project['deploy_envs'].first['image']).to eq 'a'
|
||||
expect(updated_project['deploy_envs'].first['stack_template']).to eq 'b'
|
||||
end
|
||||
end
|
||||
|
||||
describe '#set_project_env_run_list', cleanup_after: :all do
|
||||
before(:all) do
|
||||
@tester_connector.create(id: 'foo', deploy_envs: [{identifier: 'bar', provider: 'ec2'}])
|
||||
end
|
||||
before { allow_any_instance_of(Validators::Helpers::RunList).to receive(:validate!) }
|
||||
|
||||
it 'validates run list' do
|
||||
run_list = []
|
||||
expect_any_instance_of(Validators::Helpers::RunList).to receive(:validate!)
|
||||
@connector.set_project_env_run_list('foo', 'bar', run_list)
|
||||
end
|
||||
|
||||
it "updates env's RunList" do
|
||||
run_list = ['role[foo]']
|
||||
@connector.set_project_env_run_list('foo', 'bar', run_list)
|
||||
expect(@tester_connector.show('foo')['deploy_envs'].first['run_list']).to eq run_list
|
||||
end
|
||||
end
|
||||
|
||||
describe '#set_project_env_run_list', cleanup_after: :all do
|
||||
before(:all) do
|
||||
@tester_connector.create(id: 'foo')
|
||||
end
|
||||
before { allow_any_instance_of(Validators::Helpers::RunList).to receive(:validate!) }
|
||||
|
||||
it 'validates run list' do
|
||||
run_list = []
|
||||
expect_any_instance_of(Validators::Helpers::RunList).to receive(:validate!)
|
||||
@connector.set_project_run_list('foo', run_list)
|
||||
end
|
||||
|
||||
it "updates project's RunList" do
|
||||
run_list = ['role[foo]']
|
||||
@connector.set_project_run_list('foo', run_list)
|
||||
expect(@tester_connector.show('foo')['run_list']).to eq run_list
|
||||
end
|
||||
end
|
||||
|
||||
describe '#add_deploy_env_to_project' do
|
||||
it 'adds env to project' do
|
||||
@tester_connector.create(id: 'foo', deploy_envs: []) do
|
||||
@connector.add_deploy_env_to_project('foo', build(:deploy_env))
|
||||
expect(@tester_connector.show('foo')['deploy_envs']).not_to be_empty
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#remove_deploy_env_from_project', cleanup_after: :each do
|
||||
before { @tester_connector.create(id: 'foo', deploy_envs: [{identifier: 'bar'}]) }
|
||||
|
||||
it "removes env from project" do
|
||||
@connector.remove_deploy_env_from_project('foo', 'bar')
|
||||
expect(@tester_connector.show('foo')['deploy_envs']).to be_empty
|
||||
end
|
||||
|
||||
it 'raises ArgumentError if given env is not a String' do
|
||||
env = build(:deploy_env_ec2, identifier: 'bar')
|
||||
expect { @connector.remove_deploy_env_from_project('foo', env) }.to raise_error(ArgumentError)
|
||||
end
|
||||
end
|
||||
|
||||
describe '#project_update_field', cleanup_after: :each do
|
||||
before { @tester_connector.create(id: 'foo', description: 'desc', run_list: []) }
|
||||
subject { @connector.project_update_field('foo', 'run_list', ['role[a]']) }
|
||||
|
||||
it 'updates given field of given project' do
|
||||
expect {subject}.to change { @tester_connector.show('foo')['run_list'] }.to ['role[a]']
|
||||
end
|
||||
|
||||
it "doesn't affect other fields" do
|
||||
expect {subject}.not_to change { @tester_connector.show('foo')['desc'] }
|
||||
end
|
||||
end
|
||||
|
||||
describe '#project_update', cleanup_after: :each do
|
||||
before { @tester_connector.create(id: 'foo', deploy_envs: [], description: 'desc', run_list: []) }
|
||||
subject {
|
||||
attrs = {'id' => 'foo2', 'deploy_envs' => [build(:deploy_env)], 'description' => 'desc2', 'run_list' => ['role[asd]']}
|
||||
@connector.project_update('foo', attrs)
|
||||
}
|
||||
let(:updated_project) { @tester_connector.show('foo') }
|
||||
|
||||
it 'can update run_list and description' do
|
||||
subject
|
||||
expect(updated_project['run_list']).to eq ['role[asd]']
|
||||
expect(updated_project['description']).to eq 'desc2'
|
||||
end
|
||||
|
||||
it 'can not update other fields' do
|
||||
subject
|
||||
expect(updated_project['_id']).to eq 'foo'
|
||||
expect(updated_project['deploy_envs']).to eq []
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
22
devops-service/spec/connectors/shared_connectors_context.rb
Normal file
22
devops-service/spec/connectors/shared_connectors_context.rb
Normal file
@ -0,0 +1,22 @@
|
||||
def set_tester_connector(klass)
|
||||
define_method :tester_connector_class do
|
||||
klass
|
||||
end
|
||||
end
|
||||
|
||||
RSpec.shared_context 'connectors' do
|
||||
before(:all) do
|
||||
@connector = described_class.new(SpecSupport.db)
|
||||
@tester_connector = tester_connector_class.new
|
||||
@tester_connector.cleanup
|
||||
end
|
||||
after(:all){ @tester_connector.cleanup }
|
||||
end
|
||||
|
||||
RSpec.shared_context 'cleanup after all', cleanup_after: :all do
|
||||
after(:all){ @tester_connector.cleanup }
|
||||
end
|
||||
|
||||
RSpec.shared_context 'cleanup after each', cleanup_after: :each do
|
||||
after { @tester_connector.cleanup }
|
||||
end
|
||||
@ -0,0 +1,42 @@
|
||||
require 'db/mongo/connectors/stack_template'
|
||||
require 'spec/connectors/tester_connector/stack_template'
|
||||
require_relative 'shared_connectors_context'
|
||||
|
||||
RSpec.describe Connectors::StackTemplate, type: :connector do
|
||||
set_tester_connector TesterConnector::StackTemplate
|
||||
include_context 'connectors'
|
||||
let(:model_class) { Devops::Model::StackTemplateEc2 }
|
||||
|
||||
include_examples 'mongo connector', {
|
||||
model_name: :stack_template,
|
||||
factory_name: :stack_template_ec2,
|
||||
only: [:insert, :show, :update, :delete],
|
||||
field_to_update: :owner
|
||||
}
|
||||
|
||||
describe '#stack_templates' do
|
||||
subject { @connector.stack_templates('ec2') }
|
||||
|
||||
it 'should be empty if collection is empty' do
|
||||
expect(subject).to eq []
|
||||
end
|
||||
|
||||
it "returns array of stack_templates of given provider" do
|
||||
@tester_connector.create(provider: 'ec2')
|
||||
@tester_connector.create(provider: 'openstack')
|
||||
expect(subject).to be_a(Array)
|
||||
expect(subject.length).to eq 1
|
||||
expect(subject.first).to be_an_instance_of(model_class)
|
||||
expect(subject.first.provider).to eq 'ec2'
|
||||
@tester_connector.cleanup
|
||||
end
|
||||
|
||||
it 'returns stack_templates for both providers if is is unset' do
|
||||
@tester_connector.create(provider: 'ec2')
|
||||
@tester_connector.create(provider: 'openstack')
|
||||
expect(@connector.stack_templates.length).to eq 2
|
||||
@tester_connector.cleanup
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
53
devops-service/spec/connectors/tester_connector/base.rb
Normal file
53
devops-service/spec/connectors/tester_connector/base.rb
Normal file
@ -0,0 +1,53 @@
|
||||
module TesterConnector
|
||||
class Base
|
||||
attr_reader :collection
|
||||
|
||||
def initialize
|
||||
collection_name = self.class.name.demodulize.underscore.pluralize
|
||||
@collection = SpecSupport.db.collection(collection_name)
|
||||
@next_id = 1
|
||||
end
|
||||
|
||||
def create(hash={})
|
||||
collection.insert(create_params(hash))
|
||||
if block_given?
|
||||
yield
|
||||
cleanup
|
||||
end
|
||||
end
|
||||
|
||||
def create_list(size=2, hash={})
|
||||
size.times { create(hash) }
|
||||
if block_given?
|
||||
yield
|
||||
cleanup
|
||||
end
|
||||
end
|
||||
|
||||
def list
|
||||
collection.find().to_a
|
||||
end
|
||||
|
||||
def show(id)
|
||||
collection.find({'_id' => id}).to_a.first
|
||||
end
|
||||
|
||||
def cleanup
|
||||
collection.remove
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def create_params(hash)
|
||||
params = hash.dup
|
||||
if params[:id]
|
||||
params['_id'] = params.delete(:id)
|
||||
end
|
||||
unless params['_id']
|
||||
params['_id'] = @next_id
|
||||
@next_id += 1
|
||||
end
|
||||
params
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -0,0 +1,6 @@
|
||||
require_relative 'base'
|
||||
|
||||
module TesterConnector
|
||||
class Filter < Base
|
||||
end
|
||||
end
|
||||
6
devops-service/spec/connectors/tester_connector/image.rb
Normal file
6
devops-service/spec/connectors/tester_connector/image.rb
Normal file
@ -0,0 +1,6 @@
|
||||
require_relative 'base'
|
||||
|
||||
module TesterConnector
|
||||
class Image < Base
|
||||
end
|
||||
end
|
||||
6
devops-service/spec/connectors/tester_connector/key.rb
Normal file
6
devops-service/spec/connectors/tester_connector/key.rb
Normal file
@ -0,0 +1,6 @@
|
||||
require_relative 'base'
|
||||
|
||||
module TesterConnector
|
||||
class Key < Base
|
||||
end
|
||||
end
|
||||
@ -0,0 +1,6 @@
|
||||
require_relative 'base'
|
||||
|
||||
module TesterConnector
|
||||
class Project < Base
|
||||
end
|
||||
end
|
||||
@ -0,0 +1,6 @@
|
||||
require_relative 'base'
|
||||
|
||||
module TesterConnector
|
||||
class StackTemplate < Base
|
||||
end
|
||||
end
|
||||
@ -2,6 +2,7 @@ require 'db/mongo/models/key'
|
||||
|
||||
FactoryGirl.define do
|
||||
factory :key, class: Devops::Model::Key do
|
||||
id 'user_key'
|
||||
path SpecSupport::BLANK_FILE
|
||||
scope 'user'
|
||||
end
|
||||
|
||||
23
devops-service/spec/factories/project.rb
Normal file
23
devops-service/spec/factories/project.rb
Normal file
@ -0,0 +1,23 @@
|
||||
require 'db/mongo/models/project'
|
||||
|
||||
FactoryGirl.define do
|
||||
factory :project, class: Devops::Model::Project do
|
||||
transient do
|
||||
with_deploy_env_identifier false
|
||||
with_deploy_env_identifiers ['foo']
|
||||
end
|
||||
|
||||
id 'my_project'
|
||||
run_list []
|
||||
description 'desc'
|
||||
|
||||
after(:build) do |project, evaluator|
|
||||
unless project.deploy_envs
|
||||
project.deploy_envs = []
|
||||
evaluator.with_deploy_env_identifiers.each do |env_id|
|
||||
project.deploy_envs << build(:deploy_env_ec2, identifier: env_id)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -13,8 +13,6 @@ FactoryGirl.define do
|
||||
updated_at Time.now
|
||||
status 'completed'
|
||||
|
||||
initialize_with {
|
||||
new(attributes.stringify_keys)
|
||||
}
|
||||
initialize_with { new(attributes.stringify_keys) }
|
||||
end
|
||||
end
|
||||
@ -1,19 +1,9 @@
|
||||
require 'db/mongo/models/deploy_env/deploy_env_ec2'
|
||||
require_relative '../shared_models_context'
|
||||
|
||||
RSpec.describe Devops::Model::DeployEnvEc2, type: :model do
|
||||
let(:env) { build(:deploy_env_ec2) }
|
||||
|
||||
before do
|
||||
allow(Provider::ProviderFactory).to receive(:providers).and_return(%w(ec2))
|
||||
allow_any_instance_of(Validators::Helpers::Users).to receive(:available_users).and_return(['root'])
|
||||
allow_any_instance_of(Validators::DeployEnv::Flavor).to receive(:available_flavors).and_return([{'id' => 'flavor'}])
|
||||
allow_any_instance_of(Validators::FieldValidator::Flavor).to receive(:available_flavors).and_return([{'id' => 'flavor'}])
|
||||
allow_any_instance_of(Validators::DeployEnv::Groups).to receive(:available_groups).and_return(['default'])
|
||||
allow_any_instance_of(Validators::DeployEnv::Image).to receive(:available_images).and_return([{'id' => 'image'}])
|
||||
allow_any_instance_of(Validators::DeployEnv::Image).to receive(:available_images).and_return([{'id' => 'image'}])
|
||||
allow_any_instance_of(Validators::DeployEnv::StackTemplate).to receive(:available_stack_templates).and_return([{'id' => 'template'}])
|
||||
allow_any_instance_of(Validators::FieldValidator::Image).to receive(:available_images).and_return([{'id' => 'image'}])
|
||||
end
|
||||
include_context 'stubbed calls to connector in env validators'
|
||||
|
||||
it_behaves_like 'deploy env'
|
||||
it_behaves_like 'cloud deploy env'
|
||||
|
||||
@ -1,19 +1,9 @@
|
||||
require 'db/mongo/models/deploy_env/deploy_env_openstack'
|
||||
require_relative '../shared_models_context'
|
||||
|
||||
RSpec.describe Devops::Model::DeployEnvOpenstack, type: :model do
|
||||
let(:env) { build(:deploy_env_openstack) }
|
||||
|
||||
before do
|
||||
allow(Provider::ProviderFactory).to receive(:providers).and_return(%w(openstack))
|
||||
allow_any_instance_of(Validators::Helpers::Users).to receive(:available_users).and_return(['root'])
|
||||
allow_any_instance_of(Validators::DeployEnv::Flavor).to receive(:available_flavors).and_return([{'id' => 'flavor'}])
|
||||
allow_any_instance_of(Validators::FieldValidator::Flavor).to receive(:available_flavors).and_return([{'id' => 'flavor'}])
|
||||
allow_any_instance_of(Validators::DeployEnv::Groups).to receive(:available_groups).and_return(['default'])
|
||||
allow_any_instance_of(Validators::DeployEnv::Image).to receive(:available_images).and_return([{'id' => 'image'}])
|
||||
allow_any_instance_of(Validators::DeployEnv::Image).to receive(:available_images).and_return([{'id' => 'image'}])
|
||||
allow_any_instance_of(Validators::DeployEnv::StackTemplate).to receive(:available_stack_templates).and_return([{'id' => 'template'}])
|
||||
allow_any_instance_of(Validators::FieldValidator::Image).to receive(:available_images).and_return([{'id' => 'image'}])
|
||||
end
|
||||
include_context 'stubbed calls to connector in env validators'
|
||||
|
||||
it_behaves_like 'deploy env'
|
||||
it_behaves_like 'cloud deploy env'
|
||||
|
||||
@ -16,7 +16,7 @@ RSpec.describe Devops::Model::Image, type: :model do
|
||||
|
||||
describe 'validation' do
|
||||
include_examples 'field type validation', :id, :not_nil, :non_empty_string, :field_validator
|
||||
include_examples 'field type validation', :remote_user, :not_nil, :non_empty_string, :only_word_symbols, :field_validator
|
||||
include_examples 'field type validation', :remote_user, :not_nil, :non_empty_string, :field_validator
|
||||
include_examples 'field type validation', :name, :not_nil, :non_empty_string, :field_validator
|
||||
include_examples 'field type validation', :bootstrap_template, :maybe_nil, :non_empty_string, :only_word_symbols, :field_validator
|
||||
|
||||
@ -36,6 +36,12 @@ RSpec.describe Devops::Model::Image, type: :model do
|
||||
it 'bootstrap_template should be included in available bootstrap templates' do
|
||||
expect(build(:image, bootstrap_template: 'wrong')).not_to be_valid
|
||||
end
|
||||
|
||||
it 'remote_user should contain only a-zA-Z0-9_-.' do
|
||||
expect(build(:image, remote_user: 'aA0-.')).to be_valid
|
||||
expect(build(:image, remote_user: 'name/')).not_to be_valid
|
||||
expect(build(:image, remote_user: 'name!')).not_to be_valid
|
||||
end
|
||||
end
|
||||
|
||||
it '#to_hash_without_id returns provider, name, remote_user and bootstrap_template' do
|
||||
|
||||
274
devops-service/spec/models/project_spec.rb
Normal file
274
devops-service/spec/models/project_spec.rb
Normal file
@ -0,0 +1,274 @@
|
||||
require 'db/mongo/models/project'
|
||||
require_relative 'shared_models_context'
|
||||
|
||||
RSpec.describe Devops::Model::Project, type: :model do
|
||||
let(:project) { build(:project) }
|
||||
include_context 'stubbed calls to connector in env validators'
|
||||
|
||||
describe 'validation rules:' do
|
||||
include_examples 'field type validation', :id, :not_nil, :non_empty_string
|
||||
include_examples 'field type validation', :deploy_envs, :not_nil, :non_empty_array
|
||||
include_examples 'field type validation', :description, :maybe_nil, :maybe_empty_string
|
||||
include_examples 'field type validation', :run_list, :not_nil, :maybe_empty_array, :run_list
|
||||
|
||||
it "isn't valid when has envs with same identifier" do
|
||||
project = build(:project, with_deploy_env_identifiers: %w(foo foo))
|
||||
expect(project).not_to be_valid
|
||||
end
|
||||
|
||||
it "is valid when all envs have uniq identifiers" do
|
||||
project = build(:project, with_deploy_env_identifiers: %w(foo bar))
|
||||
expect(project).to be_valid
|
||||
end
|
||||
|
||||
it "isn't valid when at least one of envs isn't valid" do
|
||||
project = build(:project, with_deploy_env_identifiers: ['foo', nil])
|
||||
expect(project).not_to be_valid
|
||||
end
|
||||
end
|
||||
|
||||
describe '.fields' do
|
||||
subject { described_class.fields }
|
||||
it { should eq %w(deploy_envs type description) }
|
||||
end
|
||||
|
||||
describe '#initialize' do
|
||||
it 'sets @type to generic by default' do
|
||||
expect(described_class.new.type).to eq 'generic'
|
||||
end
|
||||
|
||||
it 'sets @archived to false by default' do
|
||||
expect(described_class.new.archived).to eq false
|
||||
end
|
||||
|
||||
it 'sets run_list to empty_array by default' do
|
||||
expect(described_class.new.run_list).to eq []
|
||||
end
|
||||
|
||||
describe 'deploy envs building' do
|
||||
let(:params) { {'deploy_envs' => [ {'provider' => @env_provider, 'identifier' => 'foo'} ]} }
|
||||
|
||||
it 'builds envs array from given params' do
|
||||
@env_provider = 'ec2'
|
||||
expect(
|
||||
described_class.new(params).deploy_envs
|
||||
).to be_an_array_of(Devops::Model::DeployEnvEc2).and have_size(1)
|
||||
end
|
||||
|
||||
it 'builds ec2 deploy envs from given params' do
|
||||
@env_provider = 'ec2'
|
||||
builded_env = described_class.new(params).deploy_envs.first
|
||||
expect(builded_env).to be_a(Devops::Model::DeployEnvEc2)
|
||||
expect(builded_env.identifier).to eq 'foo'
|
||||
end
|
||||
|
||||
it 'build openstack deploy envs from given params' do
|
||||
@env_provider = 'openstack'
|
||||
builded_env = described_class.new(params).deploy_envs.first
|
||||
expect(builded_env).to be_a(Devops::Model::DeployEnvOpenstack)
|
||||
end
|
||||
|
||||
it 'build static deploy envs from given params' do
|
||||
@env_provider = 'static'
|
||||
builded_env = described_class.new(params).deploy_envs.first
|
||||
expect(builded_env).to be_a(Devops::Model::DeployEnvStatic)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#deploy_env' do
|
||||
let(:project) { project = build(:project, with_deploy_env_identifiers: %w(foo bar)) }
|
||||
|
||||
it 'returns found env' do
|
||||
expect(project.deploy_env('bar')).to be_an(Devops::Model::DeployEnvEc2)
|
||||
end
|
||||
|
||||
it 'raises RecordNotFound if there is no such env' do
|
||||
expect {
|
||||
project.deploy_env('missing')
|
||||
}.to raise_error RecordNotFound
|
||||
end
|
||||
end
|
||||
|
||||
describe '#add_deploy_env', stub_logger: true do
|
||||
let(:env) {build(:deploy_env_ec2)}
|
||||
subject { project.add_deploy_env(env) }
|
||||
before do
|
||||
allow(Devops::Db).to receive_message_chain('connector.add_deploy_env_to_project')
|
||||
end
|
||||
|
||||
it 'inserts deploy env into mongo via connector' do
|
||||
expect(
|
||||
Devops::Db
|
||||
).to receive_message_chain('connector.add_deploy_env_to_project').with(project.id, env)
|
||||
subject
|
||||
end
|
||||
|
||||
it 'creates chef role' do
|
||||
expect(env).to receive(:create_role).with(project.id)
|
||||
subject
|
||||
end
|
||||
|
||||
it 'returns string' do
|
||||
expect(subject).to be_a(String)
|
||||
end
|
||||
end
|
||||
|
||||
describe '#add_authorized_user' do
|
||||
before do
|
||||
allow(Devops::Db).to receive_message_chain('connector.set_project_deploy_env_field')
|
||||
end
|
||||
let(:env1) { build(:deploy_env_ec2, identifier: 'foo') }
|
||||
let(:env2) { build(:deploy_env_ec2, identifier: 'bar') }
|
||||
let(:project) { build(:project, deploy_envs: [env1, env2]) }
|
||||
|
||||
it 'returns nil if user is nil' do
|
||||
expect(project.add_authorized_user(nil)).to be_nil
|
||||
end
|
||||
|
||||
context "when env isn't given" do
|
||||
context 'when user is a String' do
|
||||
it 'adds given user to all envs' do
|
||||
project.add_authorized_user('John')
|
||||
expect(env1.users).to match_array(%w(root John))
|
||||
expect(env2.users).to match_array(%w(root John))
|
||||
end
|
||||
end
|
||||
|
||||
context 'when user is an Array of strings' do
|
||||
it 'adds given users to all envs' do
|
||||
project.add_authorized_user(['John', 'Matz'])
|
||||
expect(env1.users).to match_array(%w(root John Matz))
|
||||
expect(env2.users).to match_array(%w(root John Matz))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when env is given' do
|
||||
context 'when user is a String' do
|
||||
it 'adds given user to given env' do
|
||||
project.add_authorized_user('John', 'bar')
|
||||
expect(env1.users).to match_array(%w(root))
|
||||
expect(env2.users).to match_array(%w(root John))
|
||||
end
|
||||
end
|
||||
|
||||
context 'when user is an Array of strings' do
|
||||
it 'adds given users to all envs' do
|
||||
project.add_authorized_user(['John', 'Matz'], 'bar')
|
||||
expect(env1.users).to match_array(%w(root))
|
||||
expect(env2.users).to match_array(%w(root John Matz))
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#remove_authorized_user' do
|
||||
before do
|
||||
allow(Devops::Db).to receive_message_chain('connector.set_project_deploy_env_field')
|
||||
end
|
||||
let(:env1) { build(:deploy_env_ec2, identifier: 'foo', users: %w(root John Matz)) }
|
||||
let(:env2) { build(:deploy_env_ec2, identifier: 'bar', users: %w(root John Matz)) }
|
||||
let(:project) { build(:project, deploy_envs: [env1, env2]) }
|
||||
|
||||
it 'returns nil if user is nil' do
|
||||
expect(project.remove_authorized_user(nil)).to be_nil
|
||||
end
|
||||
|
||||
context "when env isn't given" do
|
||||
context 'when user is a String' do
|
||||
it 'adds given user to all envs' do
|
||||
project.remove_authorized_user('John')
|
||||
expect(env1.users).to match_array(%w(root Matz))
|
||||
expect(env2.users).to match_array(%w(root Matz))
|
||||
end
|
||||
end
|
||||
|
||||
context 'when user is an Array of strings' do
|
||||
it 'adds given users to all envs' do
|
||||
project.remove_authorized_user(['John', 'Matz'])
|
||||
expect(env1.users).to match_array(%w(root))
|
||||
expect(env2.users).to match_array(%w(root))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when env is given' do
|
||||
context 'when user is a String' do
|
||||
it 'adds given user to given env' do
|
||||
project.remove_authorized_user('John', 'bar')
|
||||
expect(env1.users).to match_array(%w(root John Matz))
|
||||
expect(env2.users).to match_array(%w(root Matz))
|
||||
end
|
||||
end
|
||||
|
||||
context 'when user is an Array of strings' do
|
||||
it 'adds given users to all envs' do
|
||||
project.remove_authorized_user(['John', 'Matz'], 'bar')
|
||||
expect(env1.users).to match_array(%w(root John Matz))
|
||||
expect(env2.users).to match_array(%w(root))
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#check_authorization' do
|
||||
subject { project.check_authorization(@user || 'Matz', 'foo') }
|
||||
|
||||
it 'returns true for root user' do
|
||||
@user = 'root'
|
||||
expect(subject).to be true
|
||||
end
|
||||
|
||||
it "returns false if env's users don't include given user" do
|
||||
expect(subject).to be false
|
||||
end
|
||||
|
||||
it "returns true if env's users include given user" do
|
||||
project.deploy_env('foo').users = %w(root Matz)
|
||||
expect(subject).to be true
|
||||
end
|
||||
|
||||
it 'returns false if there is no such env' do
|
||||
expect(project.check_authorization('root', 'wrong')).to be false
|
||||
end
|
||||
end
|
||||
|
||||
describe '#delete_deploy_env' do
|
||||
it 'removes env' do
|
||||
allow(Devops::Db).to receive_message_chain('connector.remove_deploy_env_from_project')
|
||||
expect(Devops::Db).to receive_message_chain('connector.remove_deploy_env_from_project').with(project.id, 'foo')
|
||||
project.delete_deploy_env('foo')
|
||||
expect(project.deploy_envs).to match_array []
|
||||
end
|
||||
end
|
||||
|
||||
describe '#to_hash' do
|
||||
subject { project.to_hash }
|
||||
it 'returns hash' do
|
||||
expect(subject).to be_a(Hash)
|
||||
end
|
||||
|
||||
it 'contains project id under name key' do
|
||||
expect(subject['name']).to eq project.id
|
||||
end
|
||||
|
||||
it 'contains deploy_envs converted to hashes' do
|
||||
expect(subject['deploy_envs']).to be_an_array_of(Hash)
|
||||
end
|
||||
|
||||
it 'also contains descriptions and run_list' do
|
||||
expect(subject).to include('description', 'run_list')
|
||||
end
|
||||
|
||||
it 'contains archived key if project is archived' do
|
||||
project.archived = true
|
||||
expect(subject).to include('archived')
|
||||
end
|
||||
|
||||
it "doesn't contain archived if project isn't archived" do
|
||||
expect(subject).not_to include('archived')
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
@ -4,20 +4,16 @@ RSpec.describe Devops::Model::Report, type: :model do
|
||||
let(:report) { build(:report) }
|
||||
|
||||
describe '#initialize' do
|
||||
let(:given_moment) { Time.new(2007,11,1,15,25,0, "+01:00") }
|
||||
|
||||
it 'converts created_at to localtime' do
|
||||
now = Time.now.utc
|
||||
expect(now.zone).to eq 'UTC'
|
||||
expect(
|
||||
build(:report, created_at: now).created_at.zone
|
||||
).not_to eq 'UTC'
|
||||
converted = build(:report, created_at: given_moment).created_at
|
||||
expect(converted).to eq given_moment.localtime
|
||||
end
|
||||
|
||||
it 'converts updated_at to localtime' do
|
||||
now = Time.now.utc
|
||||
expect(now.zone).to eq 'UTC'
|
||||
expect(
|
||||
build(:report, updated_at: now).updated_at.zone
|
||||
).not_to eq 'UTC'
|
||||
converted = build(:report, updated_at: given_moment).updated_at
|
||||
expect(converted).to eq given_moment.localtime
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@ -24,8 +24,7 @@ RSpec.describe Devops::Model::Server, type: :model do
|
||||
include_examples 'field type validation', :chef_node_name, :not_nil, :maybe_empty_string
|
||||
include_examples 'field type validation', :reserved_by, :not_nil, :maybe_empty_string
|
||||
include_examples 'field type validation', :stack, :maybe_nil, :non_empty_string
|
||||
include_examples 'field type validation', :run_list, :not_nil, :maybe_empty_array
|
||||
include_examples 'field type validation', :run_list, :run_list
|
||||
include_examples 'field type validation', :run_list, :not_nil, :maybe_empty_array, :run_list
|
||||
end
|
||||
|
||||
describe '#initialize' do
|
||||
|
||||
21
devops-service/spec/models/shared_models_context.rb
Normal file
21
devops-service/spec/models/shared_models_context.rb
Normal file
@ -0,0 +1,21 @@
|
||||
RSpec.shared_context 'stubbed calls to connector in env validators' do
|
||||
before do
|
||||
allow(Provider::ProviderFactory).to receive(:providers).and_return(%w(ec2 openstack))
|
||||
allow_any_instance_of(Validators::Helpers::Users).to receive(:available_users).and_return(['root'])
|
||||
allow_any_instance_of(Validators::DeployEnv::Flavor).to receive(:available_flavors).and_return([{'id' => 'flavor'}])
|
||||
allow_any_instance_of(Validators::FieldValidator::Flavor).to receive(:available_flavors).and_return([{'id' => 'flavor'}])
|
||||
allow_any_instance_of(Validators::DeployEnv::Groups).to receive(:available_groups).and_return(['default'])
|
||||
allow_any_instance_of(Validators::DeployEnv::Image).to receive(:available_images).and_return([{'id' => 'image'}])
|
||||
allow_any_instance_of(Validators::DeployEnv::Image).to receive(:available_images).and_return([{'id' => 'image'}])
|
||||
allow_any_instance_of(Validators::DeployEnv::StackTemplate).to receive(:available_stack_templates).and_return([{'id' => 'template'}])
|
||||
allow_any_instance_of(Validators::FieldValidator::Image).to receive(:available_images).and_return([{'id' => 'image'}])
|
||||
end
|
||||
end
|
||||
|
||||
RSpec.shared_context 'stubbed calls to logger', stub_logger: true do
|
||||
before do
|
||||
allow(DevopsLogger).to receive_message_chain('logger.debug')
|
||||
allow(DevopsLogger).to receive_message_chain('logger.info')
|
||||
allow(DevopsLogger).to receive_message_chain('logger.error')
|
||||
end
|
||||
end
|
||||
@ -8,6 +8,10 @@ require 'active_support/inflector'
|
||||
root = File.join(File.dirname(__FILE__), "..")
|
||||
$LOAD_PATH.push root unless $LOAD_PATH.include? root
|
||||
|
||||
# suppress output
|
||||
original_stdout = $stdout
|
||||
$stdout = File.open(File::NULL, "w")
|
||||
|
||||
Dir[("./spec/support/**/*.rb")].each { |f| require f }
|
||||
|
||||
# Factory girl configuration
|
||||
@ -21,6 +25,10 @@ FactoryGirl.find_definitions
|
||||
RSpec.configure do |config|
|
||||
config.include FactoryGirl::Syntax::Methods
|
||||
|
||||
config.after(:all) do
|
||||
$stdout = original_stdout
|
||||
end
|
||||
|
||||
# rspec-expectations config goes here. You can use an alternate
|
||||
# assertion/expectation library such as wrong or the stdlib/minitest
|
||||
# assertions if you prefer.
|
||||
|
||||
13
devops-service/spec/support/array_matcher.rb
Normal file
13
devops-service/spec/support/array_matcher.rb
Normal file
@ -0,0 +1,13 @@
|
||||
RSpec::Matchers.define :be_an_array_of do |klass|
|
||||
match do |actual|
|
||||
actual.class == Array &&
|
||||
actual.all? {|item| item.class == klass}
|
||||
end
|
||||
end
|
||||
|
||||
RSpec::Matchers.define :have_size do |length|
|
||||
match { |actual| actual.length == length }
|
||||
failure_message do |actual|
|
||||
"expected #{actual} to have size #{expected} but have #{actual.length}"
|
||||
end
|
||||
end
|
||||
7
devops-service/spec/support/config.yml
Normal file
7
devops-service/spec/support/config.yml
Normal file
@ -0,0 +1,7 @@
|
||||
# only :db key is required
|
||||
mongo:
|
||||
:db: devops_test
|
||||
:host:
|
||||
:port:
|
||||
:user:
|
||||
:password:
|
||||
127
devops-service/spec/support/shared_connectors_specs.rb
Normal file
127
devops-service/spec/support/shared_connectors_specs.rb
Normal file
@ -0,0 +1,127 @@
|
||||
RSpec.shared_examples 'mongo connector' do |options|
|
||||
model_name = options.fetch(:model_name)
|
||||
factory_name = options[:factory_name] || model_name
|
||||
commands = options.fetch(:only)
|
||||
|
||||
if commands.include?(:insert)
|
||||
insert_method_name = "#{model_name}_insert"
|
||||
|
||||
describe "##{insert_method_name}" do
|
||||
let(:model) { build(factory_name) }
|
||||
subject { @connector.send(insert_method_name, model) }
|
||||
|
||||
before { allow(model).to receive(:validate!).and_return(true) }
|
||||
after { @tester_connector.cleanup }
|
||||
|
||||
it 'inserts new record' do
|
||||
expect {subject}.to change {@tester_connector.list.size}.from(0).to(1)
|
||||
end
|
||||
|
||||
it 'validates inserted record' do
|
||||
expect(model).to receive(:validate!)
|
||||
subject
|
||||
end
|
||||
|
||||
it "doesn't insert nonvalid records" do
|
||||
allow(model).to receive(:validate!) { raise InvalidRecord.new('') }
|
||||
expect {subject}.to raise_error(InvalidRecord)
|
||||
end
|
||||
|
||||
it 'sets created_at of record' do
|
||||
expect(model.created_at).to be nil
|
||||
subject
|
||||
expect(@tester_connector.list.first['created_at']).not_to be nil
|
||||
end
|
||||
|
||||
it 'raises error if record with such id already exists' do
|
||||
@tester_connector.create(id: model.id)
|
||||
expect {subject}.to raise_error(InvalidRecord)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if commands.include?(:list)
|
||||
list_method_name = "#{model_name.to_s.pluralize}"
|
||||
|
||||
describe "##{list_method_name}" do
|
||||
subject { @connector.send(list_method_name) }
|
||||
|
||||
it 'should be empty if collection is empty' do
|
||||
expect(subject).to eq []
|
||||
end
|
||||
|
||||
it "returns array of #{model_name.to_s.pluralize} if collection isn't empty" do
|
||||
@tester_connector.create_list(2) do
|
||||
expect(subject).to be_an_array_of(model_class).and have_size(2)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if commands.include?(:show)
|
||||
show_method_name = model_name
|
||||
|
||||
describe "##{show_method_name}" do
|
||||
subject { @connector.send(show_method_name, 'foo') }
|
||||
|
||||
it 'raises RecordNotFound when there is no such record' do
|
||||
expect { subject }.to raise_error(RecordNotFound)
|
||||
end
|
||||
|
||||
it 'returns record if was found' do
|
||||
@tester_connector.create(build(factory_name, id: 'foo').to_mongo_hash) do
|
||||
expect(subject).to be_an_instance_of(model_class)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if commands.include?(:update)
|
||||
update_method_name = "#{model_name}_update"
|
||||
field_to_update = options.fetch(:field_to_update).to_s
|
||||
|
||||
describe "##{update_method_name}" do
|
||||
let(:model) { build(model_name, field_to_update => 'new_value') }
|
||||
let(:insert_model_to_update) { @tester_connector.create(attributes_for(factory_name)) }
|
||||
subject { @connector.send(update_method_name, model) }
|
||||
before { allow(model).to receive(:validate!).and_return(true) }
|
||||
after { @tester_connector.cleanup }
|
||||
|
||||
it 'validates updated record' do
|
||||
insert_model_to_update
|
||||
expect(model).to receive(:validate!)
|
||||
subject
|
||||
end
|
||||
|
||||
it 'updates record' do
|
||||
insert_model_to_update
|
||||
subject
|
||||
updated_value = @tester_connector.list.first[field_to_update]
|
||||
expect(updated_value).to eq 'new_value'
|
||||
end
|
||||
|
||||
it 'raises RecordNotFound if there is no such record' do
|
||||
expect{ subject }.to raise_error(RecordNotFound)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if commands.include?(:delete)
|
||||
delete_method_name = "#{model_name}_delete"
|
||||
describe "##{delete_method_name}" do
|
||||
let(:model) { build(factory_name) }
|
||||
let(:insert_model_to_delete) { @tester_connector.create(model.to_mongo_hash) }
|
||||
subject { @connector.send(delete_method_name, model.id) }
|
||||
|
||||
it 'deletes record' do
|
||||
insert_model_to_delete
|
||||
expect {subject}.to change {@tester_connector.list.empty?}.to(true)
|
||||
@tester_connector.cleanup
|
||||
end
|
||||
|
||||
it 'raises RecordNotFound if there is no such record' do
|
||||
expect { subject }.to raise_error(RecordNotFound)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -103,10 +103,9 @@ RSpec.shared_examples 'deploy env' do
|
||||
end
|
||||
end
|
||||
|
||||
describe '#create_role' do
|
||||
describe '#create_role', stub_logger: true do
|
||||
subject { env.create_role('project_name') }
|
||||
before do
|
||||
stub_loggers
|
||||
allow(env).to receive_message_chain('knife_instance.role_name') { 'role_name' }
|
||||
end
|
||||
|
||||
@ -153,7 +152,7 @@ RSpec.shared_examples 'deploy env' do
|
||||
end
|
||||
end
|
||||
|
||||
describe '#rename' do
|
||||
describe '#rename', stub_logger: true do
|
||||
subject { env.rename('project_id', 'new_name') }
|
||||
let(:old_role_name) {'project_id_name'}
|
||||
let(:new_role_name) {'project_id_new_name'}
|
||||
@ -161,7 +160,6 @@ RSpec.shared_examples 'deploy env' do
|
||||
let(:suggested_new_roles) {["role[#{new_role_name}]"]}
|
||||
|
||||
before do
|
||||
stub_loggers
|
||||
# simulate correct start conditions
|
||||
env.run_list = suggested_old_roles
|
||||
|
||||
|
||||
@ -9,7 +9,9 @@ RSpec.shared_examples 'field type validation' do |field, *properties|
|
||||
|
||||
describe field do
|
||||
it 'should not be nil' do
|
||||
expect(build(validated_model_name, field => nil)).not_to be_valid
|
||||
model = build(validated_model_name)
|
||||
model.send("#{field}=", nil)
|
||||
expect(model).not_to be_valid
|
||||
end if properties.include?(:not_nil)
|
||||
|
||||
it 'may be nil' do
|
||||
@ -37,7 +39,8 @@ RSpec.shared_examples 'field type validation' do |field, *properties|
|
||||
end if properties.include?(:maybe_empty_array)
|
||||
|
||||
it 'should contain only word symbols' do
|
||||
expect(build(validated_model_name, field => 'asd-asd')).not_to be_valid
|
||||
expect(build(validated_model_name, field => '!')).not_to be_valid
|
||||
expect(build(validated_model_name, field => '/')).not_to be_valid
|
||||
end if properties.include?(:only_word_symbols)
|
||||
|
||||
it 'should contain elements like role[asd] or recipe[asd]' do
|
||||
@ -99,9 +102,12 @@ RSpec.shared_examples 'field type validation' do |field, *properties|
|
||||
}.not_to raise_error
|
||||
end if properties.include?(:maybe_empty_array)
|
||||
|
||||
it 'should contain only word symbols' do
|
||||
it 'should contain only symbols in [a-zA-Z0-9_-]' do
|
||||
expect{
|
||||
build(validated_model_name, field => 'asd-asd').send(field_validation_method)
|
||||
build(validated_model_name, field => '!').send(field_validation_method)
|
||||
}.to raise_error InvalidRecord
|
||||
expect{
|
||||
build(validated_model_name, field => '/').send(field_validation_method)
|
||||
}.to raise_error InvalidRecord
|
||||
end if properties.include?(:only_word_symbols)
|
||||
|
||||
|
||||
@ -1,11 +1,35 @@
|
||||
require 'core/devops-application'
|
||||
require 'yaml'
|
||||
|
||||
module SpecSupport
|
||||
BLANK_FILE = File.join(Devops::Application.root, 'spec/support/blank_file')
|
||||
ROOT = File.join(__dir__, '../../')
|
||||
BLANK_FILE = File.join(ROOT, 'spec/support/blank_file')
|
||||
|
||||
def stub_loggers
|
||||
allow(DevopsLogger).to receive_message_chain('logger.debug')
|
||||
allow(DevopsLogger).to receive_message_chain('logger.info')
|
||||
allow(DevopsLogger).to receive_message_chain('logger.error')
|
||||
def self.db_params
|
||||
@db ||= begin
|
||||
conf = config['mongo']
|
||||
db_name = conf.fetch(:db)
|
||||
[db_name, conf[:host], conf[:port], conf[:user], conf[:password]]
|
||||
end
|
||||
end
|
||||
|
||||
def self.db
|
||||
unless @db
|
||||
require 'mongo'
|
||||
db_name, host, port, user, password = db_params
|
||||
@db = MongoClient.new(host, port).db(db_name)
|
||||
@db.authenticate(user, password) unless user.nil? or password.nil?
|
||||
end
|
||||
@db
|
||||
end
|
||||
|
||||
def self.config
|
||||
@config ||= begin
|
||||
config_file = ENV['RSPEC_CONFIG_PATH'] || File.join(ROOT, 'spec/support/config.yml')
|
||||
if File.exists?(config_file)
|
||||
YAML.load_file(config_file)
|
||||
else
|
||||
raise "There is no config file: '#{config_file}'"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -184,6 +184,7 @@ class StackBootstrapWorker < Worker
|
||||
stack_servers_with_priority = {}
|
||||
stack_servers_info.each do |priority, info_array|
|
||||
stack_servers_with_priority[priority] = info_array.map do |extended_info|
|
||||
@out.puts "Instance '#{extended_info["id"]}' has been launched with stack."
|
||||
server_attrs = {
|
||||
'provider' => provider.name,
|
||||
'project' => project.id,
|
||||
|
||||
Loading…
Reference in New Issue
Block a user