diff --git a/features/controller_node.feature b/features/controller_node.feature index acd6da6..d4cc9ba 100644 --- a/features/controller_node.feature +++ b/features/controller_node.feature @@ -14,4 +14,3 @@ Feature: Controller node @system Scenario: Essential system requirements - diff --git a/features/migration.feature b/features/migration.feature new file mode 100644 index 0000000..c25cd9b --- /dev/null +++ b/features/migration.feature @@ -0,0 +1,28 @@ +@migration +Feature: Instance migration + As administrator + I want to make sure that Instance migration is working correctly + + Background: + Given At least 2 Compute nodes must be enabled + And Image is available + + @kvm + Scenario: Test KVM migration + Given At least 2 KVM Hypervisors are available + When I create an KVM instance + And Instance is running + And I migrate KVM instance + Then I expect the instance will run on different host + And will be in state "ACTIVE" + And I turn off the instance(so it will not use resources) + + @xen + Scenario: Test Xen migrationnd I turn off the instance(so it will not use resources) + Given At least 2 Xen Hypervisors are available + When I create an Xen instance + And Instance is running + And I migrate Xen instance + Then I expect the instance will run on different host + And will be in state "ACTIVE" + And I turn off the instance(so it will not use resources) diff --git a/features/step_definitions/migration/background_steps.rb b/features/step_definitions/migration/background_steps.rb new file mode 100644 index 0000000..0c18973 --- /dev/null +++ b/features/step_definitions/migration/background_steps.rb @@ -0,0 +1,15 @@ +Given(/^At least (\d+) Compute nodes must be enabled$/) do |arg1| + # get hypervisors and count Xen's ones - for migration we need 2 + enabled_host_list = control_node.exec!("openstack host list -f value --zone nova").output + expect(enabled_host_list.each_line(separator=$/).to_a.count).to be >= arg1.to_i +end + +Given(/^Image is available$/) do + # check image + image_name = "jeos" + images = control_node.openstack.image.list + images.each do |i| + @image_id = i.id if i.name == image_name + end + expect(@image_id).not_to be_empty +end diff --git a/features/step_definitions/migration/migration_steps.rb b/features/step_definitions/migration/migration_steps.rb new file mode 100644 index 0000000..562aa1c --- /dev/null +++ b/features/step_definitions/migration/migration_steps.rb @@ -0,0 +1,128 @@ +Given(/^At least (\d+) Xen Hypervisors are available$/) do |arg1| + # get hypervisors and count Xen's ones - for migration at least 2 + hashypervisor_xen = 0 + @hypervisors = control_node.openstack.hypervisor.list + expect(@hypervisors).not_to be_empty + + @hypervisors.each do |h| + hypervisor = control_node.openstack.hypervisor.show(h.id) + hashypervisor_xen = (hashypervisor_xen + 1) if hypervisor.hypervisor_type == "Xen" + end + expect(hashypervisor_xen).to be >= arg1.to_i +end + +Given(/^At least (\d+) KVM Hypervisors are available$/) do |arg1| + # get hypervisors and count KVM's ones - for migration at least 2 + hashypervisor_kvm = 0 + @hypervisors = control_node.openstack.hypervisor.list + expect(@hypervisors).not_to be_empty + + @hypervisors.each do |h| + hypervisor = control_node.openstack.hypervisor.show(h.id) + hashypervisor_kvm = (hashypervisor_kvm + 1) if hypervisor.hypervisor_type == "QEMU" + end + expect(hashypervisor_kvm).to be >= arg1.to_i +end + +When(/^I create an KVM instance$/) do + def delete_old_instances(server_id) + puts("old instance #{server_id } found - deleting") + control_node.exec!("openstack server delete #{server_id}") + end + ## TODO add --key-name zkubala + # clean old instances + @servers = control_node.openstack.server.list + @instance_name = "kvm_mig_instance" + @servers.each do |s| + s.name == @instance_name and delete_old_instances(s.id) + end + # create a new instance + new_instance = control_node.exec!("openstack server create -f shell --flavor m1.smaller --image jeos --security-group default -c id #{@instance_name}") + @new_instance_id = new_instance.output[4, 36] + puts ("New instance id: #{@new_instance_id}") +end + +When(/^I create an Xen instance$/) do + def delete_old_instances(server_id) + puts("old instance #{server_id } found - deleting") + control_node.exec!("openstack server delete #{server_id}") + end + ## TODO add --key-name zkubala + # clean old instances + @servers = control_node.openstack.server.list + @instance_name = "xen_mig_instance" + @servers.each do |s| + s.name == @instance_name and delete_old_instances(s.id) + end + # create a new instance + new_instance = control_node.exec!("openstack server create -f shell --flavor m1.smaller --image jeos --security-group default -c id #{@instance_name}") + @new_instance_id = new_instance.output[4, 36] + puts ("New instance id: #{@new_instance_id}") +end + +When(/^Instance is running$/) do + ## TODO Raise an expection if in ERROR state + # it may take some time before the instance turns active + wait_for "Checking that instance status is active", max: "120 seconds", sleep: "4 seconds" do + @instance_show = control_node.openstack.server.show(@new_instance_id) + break if @instance_show.status == "ACTIVE" + end +end + +When(/^I migrate Xen instance$/) do + # get actual host of the instance and migrate it + @instance_host = @instance_show.send("os-ext-srv-attr:host") + puts "Instance running on: #{@instance_host}" + instance_migrate = control_node.exec!("openstack server migrate --shared-migration #{@new_instance_id}") + + # it may take some time before the instance turns verify_resize + wait_for "Checking that instance status is verify_resize", max: "300 seconds", sleep: "10 seconds" do + instance_show = control_node.openstack.server.show(@new_instance_id) + if instance_show.status == "VERIFY_RESIZE" + puts "Migration finished, confirming..." + control_node.exec!("openstack server resize --confirm #{@new_instance_id}") + break + end + end +end + +When(/^I migrate KVM instance$/) do + # get actual host of the instance and migrate it + @instance_host = @instance_show.send("os-ext-srv-attr:host") + puts "Instance running on: #{@instance_host}" + instance_migrate = control_node.exec!("openstack server migrate #{@new_instance_id}") + + # it may take some time before the instance turns verify_resize + wait_for "Checking that instance status is verify_resize", max: "300 seconds", sleep: "10 seconds" do + instance_show = control_node.openstack.server.show(@new_instance_id) + if instance_show.status == "VERIFY_RESIZE" + puts "Migration finished, confirming..." + control_node.exec!("openstack server resize --confirm #{@new_instance_id}") + break + end + end +end + +Then(/^I expect the instance will run on different host$/) do + instance_show = control_node.openstack.server.show(@new_instance_id) + instance_host = instance_show.send("os-ext-srv-attr:host") + puts "Instance running on: #{instance_host}" + expect(@instance_host).not_to eq(instance_host) + +end + +Then(/^will be in state "([^"]*)"$/) do |arg1| + wait_for "Checking that instance status is ACTIVE", max: "40 seconds", sleep: "10 seconds" do + instance_show = control_node.openstack.server.show(@new_instance_id) + break if instance_show.status == "ACTIVE" + end +end + +Then(/^I turn off the instance\(so it will not use resources\)$/) do + control_node.exec!("openstack server stop #{@new_instance_id}") + wait_for "Checking that instance status is SHUTOFF", max: "120 seconds", sleep: "10 seconds" do + instance_show = control_node.openstack.server.show(@new_instance_id) + break if instance_show.status == "SHUTOFF" + end +end + diff --git a/lib/cct/commands/openstack.rb b/lib/cct/commands/openstack.rb index ef7002d..48aba73 100644 --- a/lib/cct/commands/openstack.rb +++ b/lib/cct/commands/openstack.rb @@ -22,6 +22,8 @@ class Client attr_reader :project attr_reader :network attr_reader :role + attr_reader :hypervisor + attr_reader :server # @param [Cct::Node] as the receiver for the openstack client def initialize node @@ -30,6 +32,8 @@ def initialize node @project = Openstack::Project.new(node) @network = Openstack::Network.new(node) @role = Openstack::Role.new(node) + @hypervisor = Openstack::Hypervisor.new(node) + @server= Openstack::Server.new(node) end def actions @@ -112,9 +116,9 @@ def list *options end end - def show id_or_name + def show id_or_name, *options params.clear - OpenStruct.new(shell_parse(exec!("show", id_or_name, "--format=shell").output)) + OpenStruct.new(shell_parse(exec!("show", id_or_name, options, "--format=shell").output)) end def exist? id_or_name @@ -222,4 +226,6 @@ def filter_params type require 'cct/commands/openstack/project' require 'cct/commands/openstack/network' require 'cct/commands/openstack/role' +require 'cct/commands/openstack/hypervisor' +require 'cct/commands/openstack/server' diff --git a/lib/cct/commands/openstack/hypervisor.rb b/lib/cct/commands/openstack/hypervisor.rb new file mode 100644 index 0000000..57e421d --- /dev/null +++ b/lib/cct/commands/openstack/hypervisor.rb @@ -0,0 +1,12 @@ +module Cct + module Commands + module Openstack + class Hypervisor < Command + self.command = ["hypervisor"] + def list *options + super(*(options << {row: Struct.new(:id, :"Hypervisor Hostname")})) + end + end + end + end +end diff --git a/lib/cct/commands/openstack/server.rb b/lib/cct/commands/openstack/server.rb new file mode 100644 index 0000000..6b960f4 --- /dev/null +++ b/lib/cct/commands/openstack/server.rb @@ -0,0 +1,9 @@ +module Cct + module Commands + module Openstack + class Server < Command + self.command = ["server"] + end + end + end +end diff --git a/tasks/features.rake b/tasks/features.rake index f4eb67b..307213b 100644 --- a/tasks/features.rake +++ b/tasks/features.rake @@ -6,8 +6,18 @@ namespace :features do invoke_task "feature:users" invoke_task "feature:images" invoke_task "features:barclamps" + invoke_task "feature:migration:kvm" end + desc "Run basic tests for cloud with xen computes" + task :base_xen do + invoke_task "feature:admin" + invoke_task "feature:controller" + invoke_task "feature:users" + invoke_task "feature:images" + invoke_task "features:barclamps" + invoke_task "feature:migration:xen" + end desc "Run functional client tests" task :functional do invoke_task "test:func:all" diff --git a/tasks/features/migration.rake b/tasks/features/migration.rake new file mode 100644 index 0000000..6766acf --- /dev/null +++ b/tasks/features/migration.rake @@ -0,0 +1,14 @@ +namespace :feature do + feature_name "Instance migration" + + namespace :migration do + desc "Test KVM migration" + feature_task :kvm, tags: :@kvm + + desc "Test Xen migration" + feature_task :xen, tags: :@xen + end + + desc "Complete verification of 'Instance migration' feature" + task :migration => "migration:kvm" +end