313 lines
9.3 KiB
Ruby
313 lines
9.3 KiB
Ruby
# Copyright 2014 Mirantis, Inc.
|
|
#
|
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
|
# not use this file except in compliance with the License. You may obtain
|
|
# a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
# License for the specific language governing permissions and limitations
|
|
# under the License.
|
|
|
|
require File.join(File.dirname(__FILE__), '../spec_helper')
|
|
|
|
describe Astute::CobblerManager do
|
|
include SpecHelpers
|
|
|
|
let(:data) do
|
|
{
|
|
"engine"=>{
|
|
"url"=>"http://localhost/cobbler_api",
|
|
"username"=>"cobbler",
|
|
"password"=>"cobbler",
|
|
"master_ip"=>"127.0.0.1",
|
|
},
|
|
"task_uuid"=>"a5c44b9a-285a-4a0c-ae65-2ed6b3d250f4",
|
|
"nodes" => [
|
|
{
|
|
'uid' => '1',
|
|
'profile' => 'centos-x86_64',
|
|
"slave_name"=>"controller-1",
|
|
"admin_ip" =>'1.2.3.5',
|
|
'power_type' => 'ssh',
|
|
'power_user' => 'root',
|
|
'power_pass' => '/root/.ssh/bootstrap.rsa',
|
|
'power-address' => '1.2.3.5',
|
|
'hostname' => 'name.domain.tld',
|
|
'name_servers' => '1.2.3.4 1.2.3.100',
|
|
'name_servers_search' => 'some.domain.tld domain.tld',
|
|
'netboot_enabled' => '1',
|
|
'ks_meta' => {
|
|
'repo_setup' => {
|
|
'repos' => [
|
|
{
|
|
"type" => "deb",
|
|
"name" => "repo1",
|
|
"uri" => "ip_address:port/patch",
|
|
"suite" => "param1",
|
|
"section" => "param2",
|
|
"priority" => 1001
|
|
},
|
|
{
|
|
"type" => "rpm",
|
|
"name" => "repo2",
|
|
"uri" => "ip_address:port/patch",
|
|
"priority" => 1
|
|
}
|
|
]
|
|
}
|
|
},
|
|
'interfaces' => {
|
|
'eth0' => {
|
|
'mac_address' => '00:00:00:00:00:00',
|
|
'static' => '1',
|
|
'netmask' => '255.255.255.0',
|
|
'ip_address' => '1.2.3.5',
|
|
'dns_name' => 'node.mirantis.net',
|
|
},
|
|
'eth1' => {
|
|
'mac_address' => '00:00:00:00:00:01',
|
|
'static' => '0',
|
|
'netmask' => '255.255.255.0',
|
|
'ip_address' => '1.2.3.6',
|
|
}
|
|
},
|
|
'interfaces_extra' => {
|
|
'eth0' => {
|
|
'peerdns' => 'no',
|
|
'onboot' => 'yes',
|
|
},
|
|
'eth1' => {
|
|
'peerdns' => 'no',
|
|
'onboot' => 'yes',
|
|
}
|
|
}
|
|
}
|
|
]
|
|
}
|
|
end
|
|
|
|
let(:reporter) do
|
|
reporter = mock('reporter')
|
|
reporter.stub_everything
|
|
reporter
|
|
end
|
|
|
|
let(:engine) do
|
|
cobbler = mock('cobbler')
|
|
cobbler.stub_everything
|
|
cobbler
|
|
end
|
|
|
|
before(:each) do
|
|
Astute::Provision::Cobbler.stubs(:new).returns(engine)
|
|
end
|
|
|
|
let(:cobbler_manager) { Astute::CobblerManager.new(data['engine'], reporter) }
|
|
|
|
describe '#add_nodes' do
|
|
before(:each) do
|
|
cobbler_manager.stubs(:sleep)
|
|
end
|
|
|
|
it 'should sync engine status after end' do
|
|
engine.stubs(:item_from_hash)
|
|
cobbler_manager.expects(:sync).once
|
|
|
|
cobbler_manager.add_nodes(data['nodes'])
|
|
end
|
|
|
|
end #'add_nodes'
|
|
|
|
describe '#edit_nodes' do
|
|
before(:each) do
|
|
cobbler_manager.stubs(:sleep)
|
|
end
|
|
|
|
it 'should edit nodes' do
|
|
cobbler_manager.stubs(:sync)
|
|
engine.expects(:item_from_hash).with(
|
|
'system',
|
|
'controller-1',
|
|
{'profile' => Astute.config.bootstrap_profile},
|
|
:item_preremove => false)
|
|
|
|
cobbler_manager.edit_nodes(
|
|
data['nodes'],
|
|
{'profile' => Astute.config.bootstrap_profile}
|
|
)
|
|
end
|
|
|
|
it 'should sync at the end of the call' do
|
|
engine.stubs(:item_from_hash)
|
|
cobbler_manager.expects(:sync)
|
|
|
|
cobbler_manager.edit_nodes(
|
|
data['nodes'],
|
|
{'profile' => Astute.config.bootstrap_profile}
|
|
)
|
|
end
|
|
|
|
it 'should sync after an error' do
|
|
engine.stubs(:item_from_hash).raises(RuntimeError)
|
|
cobbler_manager.expects(:sync)
|
|
|
|
expect{ cobbler_manager.edit_nodes(
|
|
data['nodes'],
|
|
{'profile' => Astute.config.bootstrap_profile}
|
|
)}.to raise_error(RuntimeError)
|
|
end
|
|
|
|
end #'edit_nodes'
|
|
|
|
describe '#remove_nodes' do
|
|
nodes = [
|
|
{"slave_name" => "node-1"},
|
|
{"slave_name" => "node-2"},
|
|
{"slave_name" => "node-3"},
|
|
]
|
|
system_exists_return_seq = [true, false, true, false, true, false]
|
|
system_remove_with_seq = ["node-1", "node-2", "node-3"]
|
|
before(:each) do
|
|
cobbler_manager.stubs(:sleep)
|
|
end
|
|
it 'should try to remove nodes using cobbler engine' do
|
|
engine.stubs(:system_exists?).returns(*system_exists_return_seq)
|
|
engine.expects(:remove_system).returns(true).times(3)
|
|
engine.expects(:sync).once
|
|
cobbler_manager.remove_nodes(nodes)
|
|
end
|
|
it 'should try to remove nodes three times before giving up' do
|
|
engine.stubs(:system_exists?).returns(true)
|
|
engine.expects(:remove_system).times(9)
|
|
engine.expects(:sync).once
|
|
cobbler_manager.remove_nodes(nodes)
|
|
end
|
|
it 'should not try to remove nodes if they do not exist' do
|
|
engine.stubs(:system_exists?).returns(false)
|
|
engine.expects(:remove_system).never
|
|
engine.expects(:sync).once
|
|
cobbler_manager.remove_nodes(nodes)
|
|
end
|
|
it 'should try to remove uniq list of nodes' do
|
|
nodes << {"slave_name" => "node-1"}
|
|
engine.stubs(:system_exists?).returns(*system_exists_return_seq)
|
|
engine.expects(:remove_system).times(3)
|
|
engine.expects(:sync).once
|
|
cobbler_manager.remove_nodes(nodes)
|
|
end
|
|
end
|
|
|
|
describe '#reboot_nodes' do
|
|
before(:each) do
|
|
cobbler_manager.stubs(:sleep)
|
|
end
|
|
|
|
it 'should reboot nodes' do
|
|
engine.expects(:power_reboot)
|
|
|
|
cobbler_manager.reboot_nodes(data['nodes'])
|
|
end
|
|
|
|
context 'splay' do
|
|
around(:each) do |example|
|
|
old_iops_value = Astute.config.iops
|
|
old_splay_factor_value = Astute.config.splay_factor
|
|
example.run
|
|
Astute.config.iops = old_iops_value
|
|
Astute.config.splay_factor = old_splay_factor_value
|
|
end
|
|
|
|
it 'should delay between nodes reboot' do
|
|
engine.stubs(:power_reboot)
|
|
|
|
cobbler_manager.expects(:calculate_splay_between_nodes).returns(5).once
|
|
cobbler_manager.expects(:sleep).with(5).once
|
|
|
|
cobbler_manager.reboot_nodes(data['nodes'])
|
|
end
|
|
|
|
it 'use formula (node + 1) / iops * splay_factor / node' do
|
|
Astute.config.iops = 100
|
|
Astute.config.splay_factor = 100
|
|
|
|
engine.stubs(:power_reboot)
|
|
cobbler_manager.expects(:sleep).with(2.0).once
|
|
|
|
cobbler_manager.reboot_nodes(data['nodes'])
|
|
end
|
|
end #'splay'
|
|
|
|
end #'reboot_nodes'
|
|
|
|
describe '#netboot_nodes' do
|
|
it 'should netboot nodes' do
|
|
cobbler_manager.stubs(:sync)
|
|
engine.expects(:netboot).with('controller-1', false)
|
|
|
|
cobbler_manager.netboot_nodes(data['nodes'], false)
|
|
end
|
|
|
|
it 'should sync at the end of the call' do
|
|
engine.stubs(:netboot)
|
|
cobbler_manager.expects(:sync)
|
|
|
|
cobbler_manager.netboot_nodes(data['nodes'], false)
|
|
end
|
|
|
|
it 'should sync after an error' do
|
|
engine.stubs(:netboot).raises(RuntimeError)
|
|
cobbler_manager.expects(:sync)
|
|
|
|
expect{cobbler_manager.netboot_nodes(data['nodes'], false)}
|
|
.to raise_error(RuntimeError)
|
|
end
|
|
end #'edit_nodes'
|
|
|
|
describe '#get_existent_nodes' do
|
|
it 'should return existent nodes' do
|
|
engine.expects(:system_exists?).with('controller-1').returns(true)
|
|
|
|
expect(cobbler_manager.get_existent_nodes(data['nodes']))
|
|
.to eql(data['nodes'])
|
|
end
|
|
|
|
it 'should not return non existent nodes' do
|
|
engine.expects(:system_exists?).with('controller-1').returns(false)
|
|
|
|
expect(cobbler_manager.get_existent_nodes(data['nodes']))
|
|
.to eql([])
|
|
end
|
|
end #'get_existent_nodes'
|
|
|
|
describe '#get_mac_duplicate_names' do
|
|
it 'should return cobbler names of those systems that have at least one matching mac address' do
|
|
engine.expects(:system_by_mac).with('00:00:00:00:00:00').returns({'name' => 'node-XXX'})
|
|
engine.expects(:system_by_mac).with('00:00:00:00:00:01').returns(nil)
|
|
|
|
expect(cobbler_manager.get_mac_duplicate_names(data['nodes']))
|
|
.to eql(['node-XXX'])
|
|
end
|
|
|
|
it 'should return uniq list of cobbler names of those systems that have matching mac addresses' do
|
|
engine.expects(:system_by_mac).with('00:00:00:00:00:00').returns({'name' => 'node-XXX'})
|
|
engine.expects(:system_by_mac).with('00:00:00:00:00:01').returns({'name' => 'node-XXX'})
|
|
|
|
expect(cobbler_manager.get_mac_duplicate_names(data['nodes']))
|
|
.to eql(['node-XXX'])
|
|
end
|
|
|
|
it 'should not return nodes that have not matching mac addresses' do
|
|
engine.expects(:system_by_mac).with('00:00:00:00:00:00').returns(nil)
|
|
engine.expects(:system_by_mac).with('00:00:00:00:00:01').returns(nil)
|
|
|
|
expect(cobbler_manager.get_mac_duplicate_names(data['nodes']))
|
|
.to eql([])
|
|
end
|
|
end #'get_existent_nodes'
|
|
|
|
end
|