fuel-astute/astute/spec/unit/orchestrator_spec.rb

182 lines
7.7 KiB
Ruby

#!/usr/bin/env rspec
require File.join(File.dirname(__FILE__), "..", "spec_helper")
describe Astute::Orchestrator do
include SpecHelpers
before(:each) do
@orchestrator = Astute::Orchestrator.new
@reporter = mock('reporter')
@reporter.stub_everything
end
it "must be able to return node type" do
nodes = [{'uid' => '1'}]
res = {:data => {:node_type => 'target'},
:sender=>"1"}
mc_res = mock_mc_result(res)
mc_timeout = 5
rpcclient = mock_rpcclient(nodes, mc_timeout)
rpcclient.expects(:get_type).once.returns([mc_res])
types = @orchestrator.node_type(@reporter, 'task_uuid', nodes, mc_timeout)
types.should eql([{"node_type"=>"target", "uid"=>"1"}])
end
it "must be able to complete verify_networks" do
nodes = [{'uid' => '1'}, {'uid' => '2'}]
networks = [{'id' => 1, 'vlan_id' => 100, 'cidr' => '10.0.0.0/24'},
{'id' => 2, 'vlan_id' => 101, 'cidr' => '192.168.0.0/24'}]
res1 = {:data => {:uid=>"1",
:neighbours => {"eth0" => {"100" => {"1" => ["eth0"], "2" => ["eth0"]},
"101" => {"1" => ["eth0"]}
}
}
},
:sender=>"1"
}
res2 = {:data => {:uid=>"2",
:neighbours => {"eth0" => {"100" => {"1" => ["eth0"], "2" => ["eth0"]},
"101" => {"1" => ["eth0"], "2" => ["eth0"]}
}
}
},
:sender=>"2"
}
valid_res = {:statuscode => 0, :sender => '1'}
mc_res1 = mock_mc_result(res1)
mc_res2 = mock_mc_result(res2)
mc_valid_res = mock_mc_result
rpcclient = mock_rpcclient(nodes)
rpcclient.expects(:start_frame_listeners).once.returns([mc_valid_res]*2)
rpcclient.expects(:send_probing_frames).once.returns([mc_valid_res]*2)
rpcclient.expects(:get_probing_info).once.returns([mc_res1, mc_res2])
Astute::MClient.any_instance.stubs(:rpcclient).returns(rpcclient)
res = @orchestrator.verify_networks(@reporter, 'task_uuid', nodes, networks)
expected = {"nodes" => [{"networks" => [{"iface"=>"eth0", "vlans"=>[100]}], "uid"=>"1"},
{"networks"=>[{"iface"=>"eth0", "vlans"=>[100, 101]}], "uid"=>"2"}]}
res.should eql(expected)
end
it "verify_network returns error if nodes list is empty" do
res = @orchestrator.verify_networks(@reporter, 'task_uuid', [], [])
res.should eql({'status' => 'error', 'error' => "Nodes list is empty. Nothing to check."})
end
it "verify_network returns all vlans passed if only one node provided" do
nodes = [{'uid' => '1'}]
networks = [{'id' => 1, 'vlan_id' => 100, 'cidr' => '10.0.0.0/24'},
{'id' => 2, 'vlan_id' => 101, 'cidr' => '192.168.0.0/24'}]
res = @orchestrator.verify_networks(@reporter, 'task_uuid', nodes, networks)
expected = {"nodes" => [{"networks" => [{"iface"=>"eth0", "vlans"=>[100,101]}], "uid"=>"1"}]}
res.should eql(expected)
end
it "in remove_nodes, it returns empty list if nodes are not provided" do
res = @orchestrator.remove_nodes(@reporter, 'task_uuid', [])
res.should eql({'nodes' => []})
end
it "remove_nodes cleans nodes and reboots them" do
removed_hash = {:sender => '1',
:data => {:rebooted => true}}
error_hash = {:sender => '2',
:data => {:rebooted => false, :error_msg => 'Could not reboot'}}
nodes = [{'uid' => 1}, {'uid' => 2}]
rpcclient = mock_rpcclient
mc_removed_res = mock_mc_result(removed_hash)
mc_error_res = mock_mc_result(error_hash)
rpcclient.expects(:erase_node).at_least_once.with(:reboot => true).returns([mc_removed_res, mc_error_res])
res = @orchestrator.remove_nodes(@reporter, 'task_uuid', nodes)
res.should eql({'nodes' => [{'uid' => '1'}], 'status' => 'error',
'error_nodes' => [{"uid"=>"2", "error"=>"RPC method 'erase_node' failed "\
"with message: Could not reboot"}]})
end
it "it calls deploy method with valid arguments" do
nodes = [{'uid' => 1}]
attrs = {'a' => 'b'}
Astute::DeploymentEngine::NailyFact.any_instance.expects(:deploy).
with([{'uid' => '1'}], attrs)
@orchestrator.deploy(@reporter, 'task_uuid', nodes, attrs)
end
it "deploy method raises error if nodes list is empty" do
expect {@orchestrator.deploy(@reporter, 'task_uuid', [], {})}.
to raise_error(/Nodes to deploy are not provided!/)
end
it "remove_nodes try to call MCAgent multiple times on error" do
removed_hash = {:sender => '1',
:data => {:rebooted => true}}
error_hash = {:sender => '2',
:data => {:rebooted => false, :error_msg => 'Could not reboot'}}
nodes = [{'uid' => 1}, {'uid' => 2}]
rpcclient = mock_rpcclient(nodes)
mc_removed_res = mock_mc_result(removed_hash)
mc_error_res = mock_mc_result(error_hash)
retries = Astute.config[:MC_RETRIES]
retries.should == 5
rpcclient.expects(:discover).with(:nodes => ['2']).times(retries)
rpcclient.expects(:erase_node).times(retries + 1).with(:reboot => true).returns([mc_removed_res, mc_error_res]).then.returns([mc_error_res])
res = @orchestrator.remove_nodes(@reporter, 'task_uuid', nodes)
res.should eql({'nodes' => [{'uid' => '1'}], 'status' => 'error',
'error_nodes' => [{"uid"=>"2", "error"=>"RPC method 'erase_node' failed "\
"with message: Could not reboot"}]})
end
it "remove_nodes try to call MCAgent multiple times on no response" do
removed_hash = {:sender => '2', :data => {:rebooted => true}}
then_removed_hash = {:sender => '3', :data => {:rebooted => true}}
nodes = [{'uid' => 1}, {'uid' => 2}, {'uid' => 3}]
rpcclient = mock_rpcclient(nodes)
mc_removed_res = mock_mc_result(removed_hash)
mc_then_removed_res = mock_mc_result(then_removed_hash)
retries = Astute.config[:MC_RETRIES]
rpcclient.expects(:discover).with(:nodes => %w(1 3)).times(1)
rpcclient.expects(:discover).with(:nodes => %w(1)).times(retries - 1)
rpcclient.expects(:erase_node).times(retries + 1).with(:reboot => true).
returns([mc_removed_res]).then.returns([mc_then_removed_res]).then.returns([])
res = @orchestrator.remove_nodes(@reporter, 'task_uuid', nodes)
res['nodes'] = res['nodes'].sort_by{|n| n['uid'] }
res.should eql({'nodes' => [{'uid' => '2'}, {'uid' => '3'}], 'status' => 'error',
'error_nodes' => [{'uid'=>'1', 'error'=>'Node not answered by RPC.'}]})
end
it "remove_nodes and returns early if retries were successful" do
removed_hash = {:sender => '1', :data => {:rebooted => true}}
then_removed_hash = {:sender => '2', :data => {:rebooted => true}}
nodes = [{'uid' => 1}, {'uid' => 2}]
rpcclient = mock_rpcclient(nodes)
mc_removed_res = mock_mc_result(removed_hash)
mc_then_removed_res = mock_mc_result(then_removed_hash)
retries = Astute.config[:MC_RETRIES]
retries.should_not == 2
rpcclient.expects(:discover).with(:nodes => %w(2)).times(1)
rpcclient.expects(:erase_node).times(2).with(:reboot => true).
returns([mc_removed_res]).then.returns([mc_then_removed_res])
res = @orchestrator.remove_nodes(@reporter, 'task_uuid', nodes)
res['nodes'] = res['nodes'].sort_by{|n| n['uid'] }
res.should eql({'nodes' => [{'uid' => '1'}, {'uid' => '2'}]})
end
it "remove_nodes do not fail if any of nodes failed"
end