vmpooler-provider-ec2/spec/unit/providers/ec2_spec.rb
Samuel Beaulieu 0bff2df079
Change the way we load secrets so that we do not have to pass them as ENV vars.
they will be pulled from the provider config, similarily to the other providers
2022-07-11 10:55:03 -05:00

333 lines
9.4 KiB
Ruby

require 'spec_helper'
require 'mock_redis'
require 'ec2_helper'
require 'vmpooler/providers/ec2'
RSpec::Matchers.define :relocation_spec_with_host do |value|
match { |actual| actual[:spec].host == value }
end
describe 'Vmpooler::PoolManager::Provider::Ec2' do
let(:logger) { MockLogger.new }
let(:metrics) { Vmpooler::Metrics::DummyStatsd.new }
let(:poolname) { 'debian-9' }
let(:provider_options) { { 'param' => 'value' } }
let(:zone) { 'us-west-2b' }
let(:region) { 'us-west-2'}
let(:config) { YAML.load(<<~EOT
---
:config:
max_tries: 3
retry_factor: 10
:providers:
:ec2:
connection_pool_timeout: 1
zone: '#{zone}'
region: '#{region}'
:pools:
- name: '#{poolname}'
alias: [ 'mockpool' ]
amisize: 'a1.large'
template: 'ami-03c1b544a7566b3e5'
size: 5
timeout: 10
ready_ttl: 1440
provider: 'ec2'
EOT
)
}
let(:vmname) { 'vm17' }
let(:connection) { MockComputeServiceConnection.new }
let(:redis_connection_pool) do
Vmpooler::PoolManager::GenericConnectionPool.new(
metrics: metrics,
connpool_type: 'redis_connection_pool',
connpool_provider: 'testprovider',
size: 1,
timeout: 5
) { MockRedis.new }
end
subject { Vmpooler::PoolManager::Provider::Ec2.new(config, logger, metrics, redis_connection_pool, 'ec2', provider_options) }
describe '#manual tests live' do
context 'in itsysops' do
let(:vmname) { "instance-50" }
let(:poolname) { "ubuntu-2004-arm64" }
let(:config) { YAML.load(<<~EOT
---
:config:
max_tries: 3
retry_factor: 10
:providers:
:ec2:
connection_pool_timeout: 1
zone: '#{zone}'
region: '#{region}'
:pools:
- name: '#{poolname}'
alias: [ 'mockpool' ]
amisize: 'a1.large'
template: 'ami-03c1b544a7566b3e5'
size: 5
timeout: 10
ready_ttl: 1440
provider: 'ec2'
provision: 'true'
EOT
)
}
before(:each) {
allow(subject).to receive(:dns).and_call_original
}
skip 'gets a vm' do
result = subject.create_vm(poolname, vmname)
#subject.vms_in_pool("amazon-6-x86_64-ec2")
#subject.provision_node_aws("ip-10-227-4-97.amz-dev.puppet.net", poolname)
# subject.create_snapshot(poolname, vmname, "foo")
#subject.create_disk(poolname, vmname, 10)
# a = subject.destroy_vm(poolname, vmname)
# b = subject.get_vm(poolname, vmname)
puts "done"
# subject.dns_teardown({'name' => vmname})
# subject.dns_setup({'name' => vmname, 'ip' => '1.2.3.5'})
end
end
end
describe '#vms_in_pool' do
let(:pool_config) { config[:pools][0] }
before(:each) do
allow(subject).to receive(:connect_to_aws).and_return(connection)
end
context 'Given an empty pool folder' do
it 'should return an empty array' do
allow(connection).to receive(:instances).and_return([nil])
result = subject.vms_in_pool(poolname)
expect(result).to eq([])
end
end
context 'Given a pool with many VMs' do
let(:expected_vm_list) do
[
{ 'name' => 'vm1' },
{ 'name' => 'vm2' },
{ 'name' => 'vm3' }
]
end
before(:each) do
instance_list = []
expected_vm_list.each do |vm_hash|
tags = [MockTag.new(key: "vm_name", value: vm_hash['name'])]
mock_vm = MockInstance.new(tags: tags)
instance_list << mock_vm
end
expect(connection).to receive(:instances).and_return(instance_list)
end
it 'should list all VMs in the VM folder for the pool' do
result = subject.vms_in_pool(poolname)
expect(result).to eq(expected_vm_list)
end
end
end
describe '#get_vm' do
before(:each) do
allow(subject).to receive(:connect_to_aws).and_return(connection)
end
context 'when VM does not exist' do
it 'should return nil' do
allow(connection).to receive(:instances).and_return([nil])
expect(subject.get_vm(poolname, vmname)).to be_nil
end
end
context 'when VM exists but is missing information' do
before(:each) do
tags = [MockTag.new(key: "vm_name", value: vmname)]
allow(connection).to receive(:instances).and_return([MockInstance.new(tags: tags)])
end
it 'should return a hash' do
expect(subject.get_vm(poolname, vmname)).to be_kind_of(Hash)
end
it 'should return the VM name' do
result = subject.get_vm(poolname, vmname)
expect(result['name']).to eq(vmname)
end
%w[boottime image_size status private_ip_address].each do |testcase|
it "should return nil for #{testcase}" do
result = subject.get_vm(poolname, vmname)
expect(result[testcase]).to be_nil
end
end
end
context 'when VM exists and contains all information' do
let(:vm_hostname) { "#{vmname}.demo.local" }
let(:boot_time) { Time.now }
let(:vm_object) do
state = Struct.new(:name)
runningstate = state.new "running"
MockInstance.new(
launch_time: boot_time,
state: runningstate,
instance_type: "a1.large",
private_ip_address: "1.1.1.1",
tags: [
MockTag.new(key: "vm_name", value: vmname),
MockTag.new(key: "pool", value: poolname)
]
)
end
let(:pool_info) { config[:pools][0] }
before(:each) do
allow(connection).to receive(:instances).and_return([vm_object])
end
it 'should return a hash' do
expect(subject.get_vm(poolname, vmname)).to be_kind_of(Hash)
end
it 'should return the VM name' do
result = subject.get_vm(poolname, vmname)
expect(result['name']).to eq(vmname)
end
it 'should return the template name' do
result = subject.get_vm(poolname, vmname)
expect(result['template']).to eq(pool_info['template'])
end
it 'should return the pool name' do
result = subject.get_vm(poolname, vmname)
expect(result['poolname']).to eq(pool_info['name'])
end
it 'should return the boot time' do
result = subject.get_vm(poolname, vmname)
expect(result['boottime']).to eq(boot_time)
end
it 'should return the status' do
result = subject.get_vm(poolname, vmname)
expect(result['status']).to eq("running")
end
it 'should return the status' do
result = subject.get_vm(poolname, vmname)
expect(result['image_size']).to eq("a1.large")
end
end
end
describe '#create_vm' do
before(:each) do
allow(subject).to receive(:connect_to_aws).and_return(connection)
end
context 'Given an invalid pool name' do
it 'should raise an error' do
expect { subject.create_vm('missing_pool', vmname) }.to raise_error(/missing_pool does not exist/)
end
end
context 'Given a vmname that already exists' do
before(:each) do
allow(subject).to receive(:get_vm).and_return({
'name' => "foobar",
'template' => "abc",
'status' => "running"
})
end
it 'should raise an error' do
expect { subject.create_vm(poolname, vmname) }.to raise_error(/Instance creation not attempted, .* already exists/)
end
end
context 'Given a successful creation' do
let(:client) { double }
before(:each) do
allow(subject).to receive(:get_vm).and_return(nil,{
'name' => vmname,
'template' => "abc",
'status' => "running"
})
result = Struct.new(:instance_id)
batch_instance = result.new(instance_id: "abcfoo")
allow(connection).to receive(:create_instances).and_return([batch_instance])
allow(connection).to receive(:client).and_return(client)
allow(client).to receive(:wait_until)
end
it 'should return a hash' do
result = subject.create_vm(poolname, vmname)
expect(result.is_a?(Hash)).to be true
end
it 'should have the new VM name' do
result = subject.create_vm(poolname, vmname)
expect(result['name']).to eq(vmname)
end
end
end
describe '#destroy_vm' do
before(:each) do
allow(subject).to receive(:connect_to_aws).and_return(connection)
end
context 'Given a missing VM name' do
let(:client) { double }
before(:each) do
allow(connection).to receive(:instances).and_return([nil])
allow(connection).to receive(:client).and_return(client)
allow(client).to receive(:wait_until)
end
it 'should return true' do
expect(subject.destroy_vm(poolname, 'missing_vm')).to be true
end
end
context 'Given a running VM' do
let(:instance) { double("instance") }
let(:client) { double }
before(:each) do
allow(connection).to receive(:instances).and_return([instance])
expect(instance).to receive(:terminate)
allow(connection).to receive(:client).and_return(client)
allow(client).to receive(:wait_until)
allow(instance).to receive(:id)
end
it 'should return true' do
expect(subject.destroy_vm(poolname, vmname)).to be true
end
end
end
end