Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add VM scalling tests with cirros image #49

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 44 additions & 0 deletions features/scaling_vms.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# You need to set the environment variable $cct_vm_number before running this feature
# If your cloud doesn't have the same number of floating IPs as VMs available, set
# the variable $cct_fip_number; floating IPs will be assigned to VMs picked randomly
# from the created pool of VMs. Additionally you can set the way how the VMs are
# going to be spawned, you either can rely on openstack managing the VMs' spawning
# processt_vm_delay to delay the VMs' booting process by number of seconds.
#
# Configuration:
# ===================================================================================
# $cct_vm_number => number of VMs to spawn, default is 10
# $cct_fip_number => number of floating IPs to be assigned to the created VMs, optional
# $cct_wait_for_vm => optional, default is 1;
# $cct_vm_reserve => optional, default is 3; increases the quotas due to VMs leftovers

@scaling_vms
Feature: Scaling VMs
As a cloud administrator
I want to verify the cloud can scale to VMs count defined by VM_COUNT env variable
In order to make sure the cloud components work properly

Background:
Given the environment variable "cct_vm_number" is set
And the variable "cct_vm_number" has value greater than zero
And necessary rules for "default" security group on port "22" are present
And necessary rules for "default" security group on "ipmc" protocol are present
And "default" quotas for cores and instances in project "openstack" have been updated
And respective quotas for nova in project "openstack" have been updated
And respective quotas for neutron in project "openstack" have been updated

@cirros
Scenario: Scaling with cirros image
Given the image named "cirros-.*x86_64.*-machine" is available
And the flavor "cirros-test" is defined
And the key pair "cirros-test" has been created
And there are no VMs with the name "cirros-test-vm" present
When I request creating VMs with name "cirros-test-vm"
Then I get all the VMs listed as "ACTIVE"
And there are enough floating IPs available
And I assign floating IPs to the VMs
And I can ping running VMs
And I ssh to VMs successfully as "cirros" user
And I remove the floating IPs from all VMs
And I delete floating IPs from the pool
And I delete all the VMs used for testing
196 changes: 196 additions & 0 deletions features/step_definitions/scaling_vms/scaling_steps.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,196 @@
Given(/^the environment variable "([^"]*)" is set$/) do |vm_count|
ENV["cct_vm_number"] = "10" if ENV["cct_vm_number"].nil?
expect(ENV[vm_count]).not_to be_nil
end

Given(/^the variable "([^"]*)" has value greater than zero$/) do |vm_count|
@vm_count = ENV[vm_count].to_i
expect(@vm_count).to be > 0
# Let's expect there is some number of VMs already in place (e.g. testsetup leftovers),
# they must be considered when setting the quotas for neutron and nova later
@vm_reserve = ENV["cct_vm_reserve"] || 3
end

Given(/^necessary rules for "([^"]*)" security group on port "([^"]*)" are present$/) do |sec_group, port_number|
rule_found = openstack.security_group.rule.list(sec_group).find do |rule|
rule.port_range.match("#{port_number}:#{port_number}")
end

if !rule_found
openstack.security_group.rule.create(
sec_group,
dst_port: port_number.to_i
)
end
end

Given(/^necessary rules for "([^"]*)" security group on "([^"]*)" protocol are present$/) do |sec_group, protocol|
rule_found = openstack.security_group.rule.list(sec_group).find do |rule|
rule.protocol == "icmp"
end

if !rule_found
openstack.security_group.rule.create(
sec_group,
proto: "icmp"
)
end
end

Given(/^"([^"]*)" quotas for cores and instances in project "([^"]*)" have been updated$/) do |default, project|
quota_class_update(
"default",
instances: @vm_count + @vm_reserve,
cores: @vm_count + @vm_reserve,
floating_ips: @vm_count + @vm_reserve
)

quota_class_update(
project,
instances: @vm_count + @vm_reserve,
cores: @vm_count + @vm_reserve,
floating_ips: @vm_count + @vm_reserve
)
end

Given(/^respective quotas for nova in project "([^"]*)" have been updated$/) do |project|
quota_update(
:nova,
floating_ips: @vm_count + @vm_reserve,
instances: @vm_count + @vm_reserve,
tenant: project
)
end

Given(/^respective quotas for neutron in project "([^"]*)" have been updated$/) do |project|
quota_update(
:neutron,
port: @vm_count + @vm_reserve,
vip: @vm_count + @vm_reserve,
tenant: project
)

quota_update(
:neutron,
port: @vm_count + @vm_reserve,
vip: @vm_count + @vm_reserve,
)
end

Given(/^the image named "([^"]*)" is available$/) do |image_name|
image = openstack.image.list.find {|i| i.name.match(/#{image_name}$/) }
@image = openstack.image.show(image.name)
end

Given(/^the flavor "([^"]*)" is defined$/) do |flavor|
@flavor = openstack.flavor.list.find {|f| f.name == flavor }
@flavor = openstack.flavor.create(flavor) if @flavor.nil?
end

Given(/^the key pair "([^"]*)" has been created$/) do |keypair_name|
@key_path = "/tmp/#{keypair_name}"
control_node.exec!("rm -rf #@key_path*")
control_node.exec!(
"ssh-keygen -t dsa -f #{@key_path} -N ''"
)
control_node.exec!(
"chmod 600 #{@key_path}*"
)

if openstack.keypair.list.find {|k| k.name.match(keypair_name) }
control_node.openstack.keypair.delete(keypair_name)
end

control_node.openstack.keypair.create(keypair_name, public_key: "#{@key_path}.pub")
@keypair_name = keypair_name
end

Given(/^there are no VMs with the name "([^"]*)" present$/) do |vm_name|
@vm_name = vm_name
@wait = ENV["cct_wait_for_vm"].nil? ? true : (ENV["cct_wait_for_vm"].to_i.zero? ? false : true)
delete_vms(name: @vm_name)
end

When(/^I request creating VMs with name "([^"]*)"$/) do |vm_name|

options = {
image: @image.name,
flavor: @flavor.name,
key_name: @keypair_name,
}

if @wait
options.merge!(wait: true, max: @vm_count)
openstack.server.create(vm_name, options)
else
1.upto(@vm_count).each do |num|
openstack.server.create("#{vm_name}-#{num}", options)
end
end
end

Then(/^I get all the VMs listed as "([^"]*)"$/) do |status_active|
@all_vms = []
wait_for("VMs being up and running successfully", max: "#{@vm_count*5} seconds", sleep: "2 seconds") do
@all_vms = openstack.server.list.select {|vm| vm.name.match(@vm_name)}
statuses = @all_vms.map(&:status)
active = statuses.select {|status| status == "ACTIVE"} || []
break if active.count == @all_vms.count
end
expect(@all_vms.count).to eq(@vm_count)
end

Then(/^there are enough floating IPs available$/) do
fip_limit = ENV["cct_fip_number"].to_i
ips = openstack.ip_floating.list.select {|ip| ip.instance_id.empty? }

if fip_limit.nonzero?
needed = fip_limit > ips.size ? fip_limit - ips.size : fip_limit
else
needed = @all_vms.size - ips.size
end

1.upto(needed).each do
openstack.ip_floating.create("floating")
end
@floating_ips = openstack.ip_floating.list.select {|ip| ip.instance_id.empty? }
@all_vms = @all_vms.sample(fip_limit) if fip_limit.nonzero?
end

When(/^I assign floating IPs to the VMs$/) do
Ip = Struct.new(:id, :ip)
@vm_ips = {}
@all_vms.each_with_index do |vm, index|
floating = @floating_ips[index]
openstack.ip_floating.add(floating.ip, vm.id)
@vm_ips[vm.id] = Ip.new(floating.id, floating.ip)
end
end

Then(/^I can ping running VMs$/) do
@all_vms.each {|vm| ping_vm(@vm_ips[vm.id].ip) }
end

Then(/^I ssh to VMs successfully as "([^"]*)" user$/) do |user|
@all_vms.each do |vm|
control_node.exec!("ssh #{user}@#{@vm_ips[vm.id].ip} -i #{@key_path} 'echo test'")
end
end

Then(/^I remove the floating IPs from all VMs$/) do
@all_vms.each do |vm|
openstack.ip_floating.remove(@vm_ips[vm.id].ip, vm.id)
end
end

Then(/^I delete floating IPs from the pool$/) do
@all_vms.each do |vm|
openstack.ip_floating.delete(@vm_ips[vm.id].id)
end
end

Then(/^I delete all the VMs used for testing$/) do
delete_vms(name: @vm_name)
end


4 changes: 3 additions & 1 deletion features/support/env.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
require_relative "step_helpers"
require_relative "feature_helpers"
require_relative "custom_matchers"
require_relative "openstack_helpers"

# Guess verbosity from the cli params
verbose = ARGV.grep(/(--verbose|-v)/).empty? ? false : true
Expand All @@ -27,7 +28,8 @@

World(
StepHelpers,
FeatureHelpers
FeatureHelpers,
OpenstackHelpers
)


Expand Down
1 change: 0 additions & 1 deletion features/support/feature_helpers.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
module FeatureHelpers
attr_reader :scenario_tag, :feature_tag

def proposal barclamp, name: "default"
JSON.parse(admin_node.exec!("crowbar #{barclamp} show #{name}").output)
end
Expand Down
64 changes: 64 additions & 0 deletions features/support/openstack_helpers.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
module OpenstackHelpers

def ping_vm ip
control_node.exec!("ping", "-q -c 2 -w 3 #{ip}")
end

def delete_vms name: nil, wait: true, all: false, ids: []
options = wait ? {wait: true} : {}

if !ids.empty?
openstack.server.delete(ids, options)
return
end

if all
openstack.server.list.each {|s| openstack.server.delete(s.id, options) }
return
end

vms = openstack.server.list
ids = vms.select {|vm| vm.name.match(/#{name}/)}.map(&:id)
openstack.server.delete(ids, options) unless ids.empty?
end

def openstack
control_node.openstack
end

def quota_update component, options={}
case component
when :nova then nova_quota_update(options)
when :neutron then neutron_quota_update(options)
end
end

def quota_class_update classname, options
command = "nova --insecure quota-class-update "
command << "--instances #{options[:instances]} " if options[:instances]
command << "--cores #{options[:cores]} " if options[:cores]
command << "--floating #{options[:floating_ips]} " if options[:floating_ips]
command << classname
control_node.exec!(command)
end

private

def nova_quota_update options
command = "nova --insecure quota-update "
command << "--floating-ips #{options[:floating_ips]} "
command << "--instances #{options[:instances]} "
command << options[:tenant]
control_node.exec!(command)
end

def neutron_quota_update options
command = "neutron --insecure quota-update "
command << "--port #{options[:port]} "
command << "--vip #{options[:vip]} "
command << "--tenant-id #{options[:tenant]}" if options[:tenant]
control_node.exec!(command)
end

end

Loading