current progress

This commit is contained in:
Anton Chuchkalov 2014-11-27 19:45:35 +04:00
parent f5aced5827
commit fc662ff519
16 changed files with 455 additions and 103 deletions

View File

@ -35,6 +35,10 @@ class DeployEnvBase < MongoModel
}
end
def provider_instance
@provider_instance ||= ::Provider::ProviderFactory.get(self.provider)
end
# class methods
class << self

View File

@ -15,6 +15,14 @@ class DeployEnvOpenstack < DeployEnvBase
:subnets => {:type => Array, :empty => true},
:groups => {:type => Array, :empty => false}
set_validators ::Validators::DeployEnv::RunList,
::Validators::DeployEnv::Expiration,
::Validators::DeployEnv::Users,
::Validators::DeployEnv::Flavor,
::Validators::DeployEnv::Image,
::Validators::DeployEnv::SubnetNotEmpty,
::Validators::DeployEnv::SubnetBelongsToProvider
def initialize d={}
super(d)
self.flavor = d["flavor"]
@ -28,9 +36,7 @@ class DeployEnvOpenstack < DeployEnvBase
def validate!
super
p = ::Provider::ProviderFactory.get(self.provider)
check_flavor!(p, self.flavor)
check_image!(p, self.image)
p = provider_instance
check_subnets_and_groups!(p, self.subnets, self.groups) do |networks|
if self.subnets.empty?
raise InvalidRecord.new "Subnets array can not be empty"
@ -56,4 +62,10 @@ class DeployEnvOpenstack < DeployEnvBase
DeployEnvOpenstack.new(hash)
end
private
def subnets_filter
nil
end
end

View File

@ -1,7 +1,8 @@
class Validators::Base
def initialize(model)
def initialize(model, options={})
@model = model
@options = options
end
def validate!

View File

@ -0,0 +1,14 @@
module Validators
class DeployEnv::Flavor < Base
def valid?
@model.provider_instance.flavors.detect do |flavor|
flavor['id'] == @model.flavor
end
end
def message
"Invalid flavor '#{@model.flavor}'."
end
end
end

View File

@ -0,0 +1,14 @@
module Validators
class DeployEnv::Groups < Base
def valid?
subnets_filter = @model.send(:subnets_filter)
@invalid_groups = @model.groups - @model.provider_instance.groups(subnets_filter).keys
@invalid_groups.empty?
end
def message
"Invalid groups '#{@invalid_groups.join("', '")}'"
end
end
end

View File

@ -0,0 +1,18 @@
require "commands/image"
module Validators
class DeployEnv::Image < Base
include ::ImageCommands
def valid?
images = get_images(DevopsService.mongo, @model.provider)
images.detect do |image|
image["id"] == @model.image
end
end
def message
"Invalid image '#{@model.image}'."
end
end
end

View File

@ -0,0 +1,14 @@
module Validators
class DeployEnv::SubnetBelongsToProvider < Base
def valid?
provider_subnets = @model.provider_instance.networks.map { |n| n["name"] }
@invalid_subnets = @model.subnets - provider_subnets
@invalid_subnets.empty?
end
def message
"Invalid subnets '#{@invalid_subnets.join("', '")}'."
end
end
end

View File

@ -0,0 +1,12 @@
module Validators
class DeployEnv::SubnetNotEmpty < Base
def valid?
!@model.subnets.empty?
end
def message
'Subnets array can not be empty'
end
end
end

View File

@ -0,0 +1,64 @@
# Stub some methods in Openstack Provider
puts '!!! WARNING !!!'
puts '!!! Some Openstack methods are stubbed !!!'
class Provider::Openstack
def groups filter=nil
{
'test' => {
'description' => 'Description',
'rules' => [{
"protocol" => "ip_protocol",
"from" => "from_port",
"to" => "to_port",
"cidr" => "cidr"
}]
},
'default' => {
'description' => 'Description',
'rules' => [{
"protocol" => "ip_protocol",
"from" => "from_port",
"to" => "to_port",
"cidr" => "cidr"
}]
}
}
end
def flavors
[{
"id" => 'test_flavor',
"v_cpus" => 2,
"ram" => 256,
"disk" => 1000
}]
end
def images filters
[
{
"id" => 'test_image',
"name" => 'test image',
"status" => 'test status'
}
]
end
def networks
networks_detail
end
def networks_detail
[
{
'cidr' => '192.0.2.32/27',
'name' => 'test_network',
'id' => 'test_network_id'
}
]
end
end

View File

@ -23,6 +23,11 @@ module Provider
["ec2", "openstack", "static"].each do |p|
begin
require "providers/#{p}"
if File.exist?("providers/#{p}_stub.rb")
require "providers/#{p}_stub"
end
o = Provider.const_get(p.capitalize).new(conf)
if o.configured?
@@providers[p] = o

View File

@ -100,6 +100,13 @@ Then(/^response should be '(\d+)'$/) do |code|
assert(code.to_i == last_response.status, "Status is not #{code}, it is #{last_response.status}")
end
Then(/^response error should be "([^"]+)"$/) do |error_msg|
json = JSON.parse(last_response.body)
message = json['message']
stripped_message = message.sub(/Project '\w+'. Deploy environment '\w+'. /, '')
assert(error_msg == stripped_message, "Error message is not \n #{error_msg}\nit is \n #{stripped_message}")
end
Then(/^the Content\-Type header should include 'application\/json'$/) do
assert last_response.header.contenttype.include?("application/json"), "Response has no header 'Content-Type' with 'application/json'"
end

View File

@ -4,6 +4,7 @@ require "erb"
require "yaml"
require "ostruct"
require "fileutils"
require "./templates/fixtures/fixture_formatter"
class Generator < OpenStruct
@ -12,6 +13,7 @@ class Generator < OpenStruct
def initialize
@config = YAML.load_file(File.new(ENV["CONFIG"] || CONFIG))
load_fixtures()
super(:config => @config)
end
@ -52,6 +54,12 @@ class Generator < OpenStruct
def render(template)
ERB.new(template).result(binding)
end
def load_fixtures
@fixtures = {}
@fixtures['deploy_env'] = YAML.load_file('templates/fixtures/deploy_env.yml')
@formatter = FixtureFormatter.new(@fixtures)
end
end
templates = {

View File

@ -1,24 +1,217 @@
@project @deploy_env
Feature: Create deploy env
<% project_name = @config["static"]["project"]["name"] %>
@static
Scenario: Send deploy env with invalid runlist for project <%= project_name %>
When I send PUT '/v2.0/project/<%= project_name %>' query with JSON body
#---------------------
# OPENSTACK
#---------------------
<% openstack_project_name = @config["openstack"]["project"]["name"] %>
<% precreated_openstack_deploy_env = '{ "identifier": "test", "run_list": [], "expires": null, "provider": "openstack", "users": [ "test" ], "flavor": "test_flavor", "image": "test_image", "subnets": ["test_network"] }' %>
@openstack
Scenario: Send deploy env with invalid runlist for project <%= openstack_project_name %>
When I send PUT '/v2.0/project/<%= openstack_project_name %>' query with JSON body
"""
{
"deploy_envs": [
// precreated deploy env
<%= @formatter.json('deploy_env/openstack/valid', spaces: 8) %>,
{
"identifier": "test",
"identifier": "test2",
"run_list": [ "wrong_role"],
"expires": null,
"provider": "openstack",
"users": [ "test" ],
"flavor": "test_flavor",
"image": "test_image",
"subnets": ["test_network"]
}
],
"name": "<%= openstack_project_name %>"
}
"""
Then response should be '400'
And response error should be "Invalid run list elements: 'wrong_role'. Each element should be role or recipe."
@openstack
Scenario: Send deploy env with invalid expiration for project <%= openstack_project_name %>
When I send PUT '/v2.0/project/<%= openstack_project_name %>' query with JSON body
"""
{
"deploy_envs": [
<%= precreated_openstack_deploy_env %>,
{
"identifier": "test2",
"run_list": [],
"expires": "10_wrong",
"provider": "openstack",
"users": [ "test" ],
"flavor": "test_flavor",
"image": "test_image",
"subnets": ["test_network"]
}
],
"name": "<%= openstack_project_name %>"
}
"""
Then response should be '400'
And response error should be "Parameter 'expires' is invalid. Valid format: [0-9]+[smhdw] or null."
@openstack
Scenario: Send deploy env with invalid user (missing in mongo) for project <%= openstack_project_name %>
When I send PUT '/v2.0/project/<%= openstack_project_name %>' query with JSON body
"""
{
"deploy_envs": [
<%= precreated_openstack_deploy_env %>,
{
"identifier": "test2",
"run_list": [],
"expires": null,
"provider": "static",
"users": [
"test"
]
},
// new deploy env
"provider": "openstack",
"users": [ "non_existing_user" ],
"flavor": "test_flavor",
"image": "test_image",
"subnets": ["test_network"]
}
],
"name": "<%= openstack_project_name %>"
}
"""
Then response should be '400'
And response error should be "These users are missing in mongo: 'non_existing_user'."
@openstack
Scenario: Send deploy env with invalid flavor for project <%= openstack_project_name %>
When I send PUT '/v2.0/project/<%= openstack_project_name %>' query with JSON body
"""
{
"deploy_envs": [
<%= precreated_openstack_deploy_env %>,
{
"identifier": "test2",
"run_list": [ "role[test2_t2]" ],
"expires": null,
"provider": "openstack",
"users": [ "test" ],
"flavor": "wrong_flavor",
"image": "test_image",
"subnets": ["test_network"]
}
],
"name": "<%= openstack_project_name %>"
}
"""
Then response should be '400'
And response error should be "Invalid flavor 'wrong_flavor'."
@openstack
Scenario: Send deploy env with invalid image for project <%= openstack_project_name %>
When I send PUT '/v2.0/project/<%= openstack_project_name %>' query with JSON body
"""
{
"deploy_envs": [
<%= precreated_openstack_deploy_env %>,
{
"identifier": "test2",
"run_list": [ "role[test2_t2]" ],
"expires": null,
"provider": "openstack",
"users": [ "test" ],
"flavor": "test_flavor",
"image": "wrong_image",
"subnets": ["test_network"]
}
],
"name": "<%= openstack_project_name %>"
}
"""
Then response should be '400'
And response error should be "Invalid image 'wrong_image'."
@openstack
Scenario: Send deploy env with empty subnets for project <%= openstack_project_name %>
When I send PUT '/v2.0/project/<%= openstack_project_name %>' query with JSON body
"""
{
"deploy_envs": [
<%= precreated_openstack_deploy_env %>,
{
"identifier": "test2",
"run_list": [ "role[test2_t2]" ],
"expires": null,
"provider": "openstack",
"users": [ "test" ],
"flavor": "test_flavor",
"image": "test_image",
"subnets": null
}
],
"name": "<%= openstack_project_name %>"
}
"""
Then response should be '400'
And response error should be "Subnets array can not be empty"
@openstack
Scenario: Send deploy env with invalid subnets for project <%= openstack_project_name %>
When I send PUT '/v2.0/project/<%= openstack_project_name %>' query with JSON body
"""
{
"deploy_envs": [
<%= precreated_openstack_deploy_env %>,
{
"identifier": "test2",
"run_list": [ "role[test2_t2]" ],
"expires": null,
"provider": "openstack",
"users": [ "test" ],
"flavor": "test_flavor",
"image": "test_image",
"subnets": ["wrong_subnet"]
}
],
"name": "<%= openstack_project_name %>"
}
"""
Then response should be '400'
And response error should be "Invalid subnets 'wrong_subnet'."
@openstack
Scenario: Create deploy env for project <%= openstack_project_name %>
When I send PUT '/v2.0/project/<%= openstack_project_name %>' query with JSON body
"""
{
"deploy_envs": [
<%= precreated_openstack_deploy_env %>,
{
"identifier": "test2",
"run_list": [],
"expires": null,
"provider": "openstack",
"users": [ "test" ],
"flavor": "test_flavor",
"image": "test_image",
"subnets": ["test_network"]
}
],
"name": "<%= openstack_project_name %>"
}
"""
Then response should be '200'
#---------------------
# STATIC
#---------------------
<% static_project_name = @config["static"]["project"]["name"] %>
<% precreated_static_deploy_env = '{ "identifier": "test", "run_list": [], "expires": null, "provider": "static", "users": [ "test" ] }' %>
@static
Scenario: Send deploy env with invalid runlist for project <%= static_project_name %>
When I send PUT '/v2.0/project/<%= static_project_name %>' query with JSON body
"""
{
"deploy_envs": [
<%= precreated_static_deploy_env %>,
{
"identifier": "test2",
"run_list": [
@ -26,141 +219,71 @@ Feature: Create deploy env
],
"expires": null,
"provider": "static",
"users": [
"test"
]
"users": [ "test" ]
}
],
"name": "<%= project_name %>"
"name": "<%= static_project_name %>"
}
"""
Then response should be '400'
@static
Scenario: Send deploy env with invalid expiration for project <%= project_name %>
When I send PUT '/v2.0/project/<%= project_name %>' query with JSON body
Scenario: Send deploy env with invalid expiration for project <%= static_project_name %>
When I send PUT '/v2.0/project/<%= static_project_name %>' query with JSON body
"""
{
"deploy_envs": [
// precreated deploy env
{
"identifier": "test",
"run_list": [],
"expires": null,
"provider": "static",
"users": [
"test"
]
},
// new deploy env
<%= precreated_static_deploy_env %>,
{
"identifier": "test2",
"run_list": [],
"expires": "10asd",
"provider": "static",
"users": [
"test"
]
"users": [ "test" ]
}
],
"name": "<%= project_name %>"
"name": "<%= static_project_name %>"
}
"""
Then response should be '400'
@static
Scenario: Send deploy env with invalid expiration for project <%= project_name %>
When I send PUT '/v2.0/project/<%= project_name %>' query with JSON body
Scenario: Send deploy env with invalid user (missing in mongo) for project <%= static_project_name %>
When I send PUT '/v2.0/project/<%= static_project_name %>' query with JSON body
"""
{
"deploy_envs": [
// precreated deploy env
{
"identifier": "test",
"run_list": [],
"expires": null,
"provider": "static",
"users": [
"test"
]
},
// new deploy env
{
"identifier": "test2",
"run_list": [],
"expires": "10asd",
"provider": "static",
"users": [
"test"
]
}
],
"name": "<%= project_name %>"
}
"""
Then response should be '400'
@static
Scenario: Send deploy env with invalid user (missing in mongo) for project <%= project_name %>
When I send PUT '/v2.0/project/<%= project_name %>' query with JSON body
"""
{
"deploy_envs": [
// precreated deploy env
{
"identifier": "test",
"run_list": [],
"expires": null,
"provider": "static",
"users": [
"test"
]
},
// new deploy env
<%= precreated_static_deploy_env %>,
{
"identifier": "test2",
"run_list": [],
"expires": null,
"provider": "static",
"users": [
"non_existing_user"
]
"users": [ "non_existing_user" ]
}
],
"name": "<%= project_name %>"
"name": "<%= static_project_name %>"
}
"""
Then response should be '400'
@static
Scenario: Create deploy env for project <%= project_name %>
When I send PUT '/v2.0/project/<%= project_name %>' query with JSON body
Scenario: Create deploy env for project <%= static_project_name %>
When I send PUT '/v2.0/project/<%= static_project_name %>' query with JSON body
"""
{
"deploy_envs": [
// precreated deploy env
{
"identifier": "test",
"run_list": [],
"expires": null,
"provider": "static",
"users": [
"test"
]
},
// new deploy env
<%= precreated_static_deploy_env %>,
{
"identifier": "test2",
"run_list": [],
"expires": null,
"provider": "static",
"users": [
"test"
]
"users": [ "test" ]
}
],
"name": "<%= project_name %>"
"name": "<%= static_project_name %>"
}
"""
Then response should be '200'

View File

@ -8,6 +8,7 @@ Feature: Delete deploy env
"""
{
"deploy_envs": [
// Remove created deploy_envs, leave only the first one (precreated).
{
"identifier": "test",
"run_list": [],

View File

@ -0,0 +1,14 @@
openstack:
valid: &valid
"identifier": "test"
"run_list": []
"expires": "10d"
"provider": "openstack"
"users": [ "test" ]
"flavor": "test_flavor"
"image": "test_image"
"subnets": ["test_network"]
invalid:
run_list:
<<: *valid
"run_list": [ "wrong_role"]

View File

@ -0,0 +1,41 @@
require 'json'
class FixtureFormatter
def initialize(fixtures)
@fixtures = fixtures
end
def json(path, options={})
result = JSON.pretty_generate(get_fixture(path))
if options[:spaces]
result = shift_to_right(result, options[:spaces])
end
result
end
private
def get_fixture(path)
keys = path.split('/')
hash = @fixtures
keys.each do |key|
hash = hash[key]
end
hash
end
def shift_to_right(text, spaces_count)
buffer = ''
first_line = true
text.each_line do |line|
if first_line
first_line = false
buffer += line
next
end
buffer += (' ' * spaces_count) + line
end
buffer
end
end