vm_shepherd 0.0.1 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile +0 -2
- data/LICENSE.txt +22 -0
- data/README.md +15 -2
- data/ci/run_specs.sh +6 -1
- data/lib/vm_shepherd.rb +12 -0
- data/lib/vm_shepherd/{ami_manager.rb → aws_manager.rb} +1 -3
- data/lib/vm_shepherd/openstack_manager.rb +102 -0
- data/lib/vm_shepherd/shepherd.rb +74 -81
- data/lib/vm_shepherd/vcloud_manager.rb +170 -0
- data/lib/vm_shepherd/version.rb +1 -1
- data/lib/vm_shepherd/vsphere_manager.rb +293 -0
- data/spec/fixtures/shepherd/openstack.yml +19 -0
- data/spec/support/patched_fog.rb +20 -0
- data/spec/vm_shepherd/{ami_manager_spec.rb → aws_manager_spec.rb} +9 -10
- data/spec/vm_shepherd/openstack_manager_spec.rb +237 -0
- data/spec/vm_shepherd/shepherd_spec.rb +115 -50
- data/spec/vm_shepherd/vcloud_manager_spec.rb +364 -0
- data/spec/vm_shepherd/vsphere_manager_spec.rb +16 -0
- data/vm_shepherd.gemspec +1 -1
- metadata +31 -32
- data/lib/vm_shepherd/ova_manager/base.rb +0 -31
- data/lib/vm_shepherd/ova_manager/deployer.rb +0 -202
- data/lib/vm_shepherd/ova_manager/destroyer.rb +0 -29
- data/lib/vm_shepherd/ova_manager/open_monkey_patch.rb +0 -14
- data/lib/vm_shepherd/vapp_manager/deployer.rb +0 -151
- data/lib/vm_shepherd/vapp_manager/destroyer.rb +0 -46
- data/spec/vm_shepherd/ova_manager/base_spec.rb +0 -56
- data/spec/vm_shepherd/ova_manager/deployer_spec.rb +0 -134
- data/spec/vm_shepherd/ova_manager/destroyer_spec.rb +0 -42
- data/spec/vm_shepherd/vapp_manager/deployer_spec.rb +0 -287
- data/spec/vm_shepherd/vapp_manager/destroyer_spec.rb +0 -104
@@ -1,46 +0,0 @@
|
|
1
|
-
require 'ruby_vcloud_sdk'
|
2
|
-
|
3
|
-
module VmShepherd
|
4
|
-
module VappManager
|
5
|
-
class Destroyer
|
6
|
-
def initialize(login_info, location, logger)
|
7
|
-
@login_info = login_info
|
8
|
-
@location = location
|
9
|
-
@logger = logger
|
10
|
-
end
|
11
|
-
|
12
|
-
def destroy(vapp_name)
|
13
|
-
delete_vapp(vapp_name)
|
14
|
-
delete_catalog
|
15
|
-
end
|
16
|
-
|
17
|
-
private
|
18
|
-
|
19
|
-
def client
|
20
|
-
@client ||= VCloudSdk::Client.new(
|
21
|
-
@login_info[:url],
|
22
|
-
"#{@login_info[:user]}@#{@login_info[:organization]}",
|
23
|
-
@login_info[:password],
|
24
|
-
{},
|
25
|
-
@logger,
|
26
|
-
)
|
27
|
-
end
|
28
|
-
|
29
|
-
def vdc
|
30
|
-
@vdc ||= client.find_vdc_by_name(@location[:vdc])
|
31
|
-
end
|
32
|
-
|
33
|
-
def delete_vapp(vapp_name)
|
34
|
-
vapp = vdc.find_vapp_by_name(vapp_name)
|
35
|
-
vapp.power_off
|
36
|
-
vapp.delete
|
37
|
-
rescue VCloudSdk::ObjectNotFoundError => e
|
38
|
-
@logger.debug "Could not delete vapp '#{vapp_name}': #{e.inspect}"
|
39
|
-
end
|
40
|
-
|
41
|
-
def delete_catalog
|
42
|
-
client.delete_catalog_by_name(@location[:catalog]) if client.catalog_exists?(@location[:catalog])
|
43
|
-
end
|
44
|
-
end
|
45
|
-
end
|
46
|
-
end
|
@@ -1,56 +0,0 @@
|
|
1
|
-
require 'vm_shepherd/ova_manager/base'
|
2
|
-
|
3
|
-
module VmShepherd
|
4
|
-
module OvaManager
|
5
|
-
RSpec.describe Base do
|
6
|
-
subject(:base) { Base.new(vcenter) }
|
7
|
-
|
8
|
-
let(:vcenter) { { host: 'host', user: 'user', password: 'password' } }
|
9
|
-
let(:search_index) { double('searchIndex') }
|
10
|
-
let(:connection) { double('RbVmomi::VIM', searchIndex: search_index) }
|
11
|
-
let(:datacenter) { FakeDatacenter.new }
|
12
|
-
|
13
|
-
class FakeDatacenter < RbVmomi::VIM::Datacenter
|
14
|
-
def initialize
|
15
|
-
end
|
16
|
-
end
|
17
|
-
|
18
|
-
before { allow(RbVmomi::VIM).to receive(:connect).and_return(connection) }
|
19
|
-
|
20
|
-
def stub_search(find_result)
|
21
|
-
allow(search_index).to receive(:FindByInventoryPath).and_return(find_result)
|
22
|
-
end
|
23
|
-
|
24
|
-
describe '#find_datacenter' do
|
25
|
-
it 'should return datacenter with valid name' do
|
26
|
-
stub_search(datacenter)
|
27
|
-
expect(base.find_datacenter('valid_datacenter')).to be(datacenter)
|
28
|
-
end
|
29
|
-
|
30
|
-
it 'should return nil with invalid name' do
|
31
|
-
stub_search(nil)
|
32
|
-
expect(base.find_datacenter('does_not_exist')).to be_nil
|
33
|
-
end
|
34
|
-
|
35
|
-
it 'should return nil when find returns non-datacenter' do
|
36
|
-
stub_search(double)
|
37
|
-
expect(base.find_datacenter('non_a_datacenter')).to be_nil
|
38
|
-
end
|
39
|
-
end
|
40
|
-
|
41
|
-
describe '#connection' do
|
42
|
-
it 'should return a connection' do
|
43
|
-
conn = base.send(:connection)
|
44
|
-
expect(conn).to be(connection)
|
45
|
-
end
|
46
|
-
|
47
|
-
it 'should return the same connection on subsequent invocations' do
|
48
|
-
conn = base.send(:connection)
|
49
|
-
conn_again = base.send(:connection)
|
50
|
-
expect(conn).to be(conn_again)
|
51
|
-
expect(RbVmomi::VIM).to have_received(:connect).once
|
52
|
-
end
|
53
|
-
end
|
54
|
-
end
|
55
|
-
end
|
56
|
-
end
|
@@ -1,134 +0,0 @@
|
|
1
|
-
require 'tempfile'
|
2
|
-
require 'vm_shepherd/ova_manager/deployer'
|
3
|
-
|
4
|
-
module VmShepherd
|
5
|
-
module OvaManager
|
6
|
-
RSpec.describe Deployer do
|
7
|
-
let(:connection) { double('connection') }
|
8
|
-
let(:cluster) { double('cluster', resourcePool: cluster_resource_pool) }
|
9
|
-
let(:cluster_resource_pool) { double(:cluster_resource_pool, resourcePool: [a_resource_pool, another_resource_pool]) }
|
10
|
-
|
11
|
-
let(:a_resource_pool) { double('resource_pool', name: 'resource_pool_name') }
|
12
|
-
let(:another_resource_pool) { double('another_resource_pool', name: 'another_resource_pool_name') }
|
13
|
-
|
14
|
-
let(:target_folder) { double('target_folder') }
|
15
|
-
let(:datastore) { double('datastore') }
|
16
|
-
let(:network) { double('network', name: 'network') }
|
17
|
-
let(:datacenter) { double('datacenter', network: [network]) }
|
18
|
-
let(:cached_ova_deployer) {
|
19
|
-
double('CachedOvaDeployer', upload_ovf_as_template: template, linked_clone: linked_clone)
|
20
|
-
}
|
21
|
-
let(:template) { double('template', name: 'template name') }
|
22
|
-
let(:ova_path) { File.join(SPEC_ROOT, 'fixtures', 'ova_manager', 'foo.ova') }
|
23
|
-
let(:linked_clone) { double('linked clone', guest_ip: '1.1.1.1') }
|
24
|
-
let(:vcenter_config) {
|
25
|
-
{
|
26
|
-
host: 'foo',
|
27
|
-
user: 'bar',
|
28
|
-
password: 'secret'
|
29
|
-
}
|
30
|
-
}
|
31
|
-
|
32
|
-
subject(:deployer) { Deployer.new(vcenter_config, location) }
|
33
|
-
|
34
|
-
before do
|
35
|
-
allow(deployer).to receive(:system).with(/cd .* && tar xfv .*/).and_call_original
|
36
|
-
allow(deployer).to receive(:system).with(/nc -z -w 5 .* 443/).and_return(false)
|
37
|
-
|
38
|
-
allow(datacenter).to receive(:find_compute_resource).with('cluster').and_return(cluster)
|
39
|
-
|
40
|
-
allow(datacenter).to receive(:find_datastore).with('datastore').and_return(datastore)
|
41
|
-
|
42
|
-
allow(linked_clone).to receive_message_chain(:ReconfigVM_Task, :wait_for_completion)
|
43
|
-
allow(linked_clone).to receive_message_chain(:PowerOnVM_Task, :wait_for_completion)
|
44
|
-
|
45
|
-
allow(RbVmomi::VIM).to receive(:connect).with({
|
46
|
-
host: vcenter_config[:host],
|
47
|
-
user: vcenter_config[:user],
|
48
|
-
password: vcenter_config[:password],
|
49
|
-
ssl: true,
|
50
|
-
insecure: true
|
51
|
-
}).and_return connection
|
52
|
-
|
53
|
-
allow(deployer).to receive(:find_datacenter).and_return(datacenter)
|
54
|
-
|
55
|
-
allow(datacenter).to receive_message_chain(:vmFolder, :traverse).
|
56
|
-
with('target_folder', RbVmomi::VIM::Folder, true).and_return(target_folder)
|
57
|
-
allow(datacenter).to receive(:networkFolder).and_return(
|
58
|
-
double(:networkFolder).tap do |network_folder|
|
59
|
-
allow(network_folder).to receive(:traverse).with('network').and_return(network)
|
60
|
-
end
|
61
|
-
)
|
62
|
-
end
|
63
|
-
|
64
|
-
context 'resource pool is a parameter' do
|
65
|
-
let(:location) {
|
66
|
-
{
|
67
|
-
connection: connection,
|
68
|
-
network: 'network',
|
69
|
-
cluster: 'cluster',
|
70
|
-
folder: 'target_folder',
|
71
|
-
datastore: 'datastore',
|
72
|
-
datacenter: 'datacenter',
|
73
|
-
resource_pool: resource_pool_name
|
74
|
-
}
|
75
|
-
}
|
76
|
-
|
77
|
-
context 'resource pool can be found' do
|
78
|
-
let(:resource_pool_name) { a_resource_pool.name }
|
79
|
-
|
80
|
-
it 'uses VsphereClient::CachedOvfDeployer to deploy an OVA within a resource pool' do
|
81
|
-
expect(VsphereClients::CachedOvfDeployer).to receive(:new).with(
|
82
|
-
connection,
|
83
|
-
network,
|
84
|
-
cluster,
|
85
|
-
a_resource_pool,
|
86
|
-
target_folder,
|
87
|
-
target_folder,
|
88
|
-
datastore
|
89
|
-
).and_return(cached_ova_deployer)
|
90
|
-
|
91
|
-
deployer.deploy('foo', ova_path, { ip: '1.1.1.1' })
|
92
|
-
end
|
93
|
-
end
|
94
|
-
|
95
|
-
context 'resource pool cannot be found' do
|
96
|
-
let(:resource_pool_name) { 'i am no body' }
|
97
|
-
|
98
|
-
it 'uses VsphereClient::CachedOvfDeployer to deploy an OVA within a resource pool' do
|
99
|
-
expect {
|
100
|
-
deployer.deploy('foo', ova_path, { ip: '1.1.1.1' })
|
101
|
-
}.to raise_error(/Failed to find resource pool '#{resource_pool_name}'/)
|
102
|
-
end
|
103
|
-
end
|
104
|
-
end
|
105
|
-
|
106
|
-
context 'when there is no resource pool in location' do
|
107
|
-
let(:location) {
|
108
|
-
{
|
109
|
-
connection: connection,
|
110
|
-
network: 'network',
|
111
|
-
cluster: 'cluster',
|
112
|
-
folder: 'target_folder',
|
113
|
-
datastore: 'datastore',
|
114
|
-
datacenter: 'datacenter',
|
115
|
-
}
|
116
|
-
}
|
117
|
-
|
118
|
-
it 'uses the cluster resource pool' do
|
119
|
-
expect(VsphereClients::CachedOvfDeployer).to receive(:new).with(
|
120
|
-
connection,
|
121
|
-
network,
|
122
|
-
cluster,
|
123
|
-
cluster_resource_pool,
|
124
|
-
target_folder,
|
125
|
-
target_folder,
|
126
|
-
datastore
|
127
|
-
).and_return(cached_ova_deployer)
|
128
|
-
|
129
|
-
deployer.deploy('foo', ova_path, { ip: '1.1.1.1' })
|
130
|
-
end
|
131
|
-
end
|
132
|
-
end
|
133
|
-
end
|
134
|
-
end
|
@@ -1,42 +0,0 @@
|
|
1
|
-
require 'vm_shepherd/ova_manager/destroyer'
|
2
|
-
|
3
|
-
module VmShepherd
|
4
|
-
module OvaManager
|
5
|
-
RSpec.describe Destroyer do
|
6
|
-
subject(:destroyer) { Destroyer.new('datacenter_name', vcenter_config) }
|
7
|
-
let(:vcenter_config) { { host: 'host', user: 'user', password: 'password' } }
|
8
|
-
|
9
|
-
describe '#clean_folder' do
|
10
|
-
# Crappy temporary test to at least ensure that Destroyer requires the appropriate files
|
11
|
-
it 'is wired up correctly' do
|
12
|
-
connection = double('connection', serviceInstance: double('serviceInstance'))
|
13
|
-
datacenter = double('datacenter')
|
14
|
-
allow(datacenter).to receive(:is_a?).with(RbVmomi::VIM::Datacenter).and_return(true)
|
15
|
-
vm_folder_client = double('vm_folder_client')
|
16
|
-
|
17
|
-
expect(RbVmomi::VIM).to receive(:connect).with(
|
18
|
-
host: 'host',
|
19
|
-
user: 'user',
|
20
|
-
password: 'password',
|
21
|
-
ssl: true,
|
22
|
-
insecure: true,
|
23
|
-
).and_return(connection)
|
24
|
-
expect(connection).to receive(:searchIndex).and_return(
|
25
|
-
double(:searchIndex).tap do |search_index|
|
26
|
-
expect(search_index).to receive(:FindByInventoryPath).
|
27
|
-
with(inventoryPath: 'datacenter_name').
|
28
|
-
and_return(datacenter)
|
29
|
-
end
|
30
|
-
)
|
31
|
-
expect(VsphereClients::VmFolderClient).to receive(:new).
|
32
|
-
with(datacenter, instance_of(Logger)).
|
33
|
-
and_return(vm_folder_client)
|
34
|
-
expect(vm_folder_client).to receive(:delete_folder).with('folder_name')
|
35
|
-
expect(vm_folder_client).to receive(:create_folder).with('folder_name')
|
36
|
-
|
37
|
-
destroyer.clean_folder('folder_name')
|
38
|
-
end
|
39
|
-
end
|
40
|
-
end
|
41
|
-
end
|
42
|
-
end
|
@@ -1,287 +0,0 @@
|
|
1
|
-
require 'vm_shepherd/vapp_manager/deployer'
|
2
|
-
|
3
|
-
module VmShepherd
|
4
|
-
module VappManager
|
5
|
-
RSpec.describe Deployer do
|
6
|
-
let(:login_info) do
|
7
|
-
{
|
8
|
-
url: 'FAKE_URL',
|
9
|
-
organization: 'FAKE_ORGANIZATION',
|
10
|
-
user: 'FAKE_USER',
|
11
|
-
password: 'FAKE_PASSWORD',
|
12
|
-
}
|
13
|
-
end
|
14
|
-
let(:location) do
|
15
|
-
{
|
16
|
-
catalog: 'FAKE_CATALOG',
|
17
|
-
network: 'FAKE_NETWORK',
|
18
|
-
vdc: 'FAKE_VDC',
|
19
|
-
}
|
20
|
-
end
|
21
|
-
let(:logger) { instance_double(Logger).as_null_object }
|
22
|
-
|
23
|
-
let(:deployer) { Deployer.new(login_info, location, logger) }
|
24
|
-
|
25
|
-
describe '#deploy' do
|
26
|
-
let(:vapp_config) do
|
27
|
-
{
|
28
|
-
ip: 'FAKE_IP',
|
29
|
-
name: 'FAKE_NAME',
|
30
|
-
gateway: 'FAKE_GATEWAY',
|
31
|
-
dns: 'FAKE_DNS',
|
32
|
-
ntp: 'FAKE_NTP',
|
33
|
-
ip: 'FAKE_IP',
|
34
|
-
netmask: 'FAKE_NETMASK',
|
35
|
-
}
|
36
|
-
end
|
37
|
-
let(:vapp_template_path) { 'FAKE_VAPP_TEMPLATE_PATH' }
|
38
|
-
let(:tmpdir) { 'FAKE_TMP_DIR' }
|
39
|
-
|
40
|
-
before { allow(Dir).to receive(:mktmpdir).and_return(tmpdir) }
|
41
|
-
|
42
|
-
context 'when NO host exists at the specified IP' do
|
43
|
-
let(:expanded_vapp_template_path) { 'FAKE_EXPANDED_VAPP_TEMPLATE_PATH' }
|
44
|
-
|
45
|
-
before do
|
46
|
-
allow(deployer).to receive(:system).with("ping -c 5 #{vapp_config.fetch(:ip)}").and_return(false)
|
47
|
-
|
48
|
-
allow(File).to receive(:expand_path).with(vapp_template_path).and_return(expanded_vapp_template_path)
|
49
|
-
|
50
|
-
allow(FileUtils).to receive(:remove_entry_secure)
|
51
|
-
end
|
52
|
-
|
53
|
-
it 'expands the vapp_template into a TMP dir' do
|
54
|
-
expect(deployer).to receive(:system).with("cd #{tmpdir} && tar xfv '#{expanded_vapp_template_path}'")
|
55
|
-
|
56
|
-
expect { deployer.deploy(vapp_template_path, vapp_config) }.to raise_error
|
57
|
-
end
|
58
|
-
|
59
|
-
context 'when the template can be expanded' do
|
60
|
-
let(:client) { instance_double(VCloudSdk::Client) }
|
61
|
-
let(:catalog) { instance_double(VCloudSdk::Catalog) }
|
62
|
-
let(:network_config) { instance_double(VCloudSdk::NetworkConfig) }
|
63
|
-
let(:vapp) { instance_double(VCloudSdk::VApp) }
|
64
|
-
let(:vm) { instance_double(VCloudSdk::VM) }
|
65
|
-
|
66
|
-
before do
|
67
|
-
allow(deployer).to receive(:system).with("cd #{tmpdir} && tar xfv '#{expanded_vapp_template_path}'").
|
68
|
-
and_return(true)
|
69
|
-
end
|
70
|
-
|
71
|
-
context 'when the vApp can be deployed' do
|
72
|
-
let(:expected_properties) do
|
73
|
-
[
|
74
|
-
{
|
75
|
-
'type' => 'string',
|
76
|
-
'key' => 'gateway',
|
77
|
-
'value' => vapp_config.fetch(:gateway),
|
78
|
-
'password' => 'false',
|
79
|
-
'userConfigurable' => 'true',
|
80
|
-
'Label' => 'Default Gateway',
|
81
|
-
'Description' => 'The default gateway address for the VM network. Leave blank if DHCP is desired.'
|
82
|
-
},
|
83
|
-
{
|
84
|
-
'type' => 'string',
|
85
|
-
'key' => 'DNS',
|
86
|
-
'value' => vapp_config.fetch(:dns),
|
87
|
-
'password' => 'false',
|
88
|
-
'userConfigurable' => 'true',
|
89
|
-
'Label' => 'DNS',
|
90
|
-
'Description' => 'The domain name servers for the VM (comma separated). Leave blank if DHCP is desired.',
|
91
|
-
},
|
92
|
-
{
|
93
|
-
'type' => 'string',
|
94
|
-
'key' => 'ntp_servers',
|
95
|
-
'value' => vapp_config.fetch(:ntp),
|
96
|
-
'password' => 'false',
|
97
|
-
'userConfigurable' => 'true',
|
98
|
-
'Label' => 'NTP Servers',
|
99
|
-
'Description' => 'Comma-delimited list of NTP servers'
|
100
|
-
},
|
101
|
-
{
|
102
|
-
'type' => 'string',
|
103
|
-
'key' => 'admin_password',
|
104
|
-
'value' => 'tempest',
|
105
|
-
'password' => 'true',
|
106
|
-
'userConfigurable' => 'true',
|
107
|
-
'Label' => 'Admin Password',
|
108
|
-
'Description' => 'This password is used to SSH into the VM. The username is "tempest".',
|
109
|
-
},
|
110
|
-
{
|
111
|
-
'type' => 'string',
|
112
|
-
'key' => 'ip0',
|
113
|
-
'value' => vapp_config.fetch(:ip),
|
114
|
-
'password' => 'false',
|
115
|
-
'userConfigurable' => 'true',
|
116
|
-
'Label' => 'IP Address',
|
117
|
-
'Description' => 'The IP address for the VM. Leave blank if DHCP is desired.',
|
118
|
-
},
|
119
|
-
{
|
120
|
-
'type' => 'string',
|
121
|
-
'key' => 'netmask0',
|
122
|
-
'value' => vapp_config.fetch(:netmask),
|
123
|
-
'password' => 'false',
|
124
|
-
'userConfigurable' => 'true',
|
125
|
-
'Label' => 'Netmask',
|
126
|
-
'Description' => 'The netmask for the VM network. Leave blank if DHCP is desired.'
|
127
|
-
}
|
128
|
-
]
|
129
|
-
end
|
130
|
-
|
131
|
-
before do
|
132
|
-
allow(VCloudSdk::Client).to receive(:new).and_return(client)
|
133
|
-
allow(client).to receive(:catalog_exists?)
|
134
|
-
allow(client).to receive(:delete_catalog_by_name)
|
135
|
-
|
136
|
-
allow(client).to receive(:create_catalog).and_return(catalog)
|
137
|
-
allow(catalog).to receive(:upload_vapp_template)
|
138
|
-
allow(catalog).to receive(:instantiate_vapp_template).and_return(vapp)
|
139
|
-
|
140
|
-
allow(VCloudSdk::NetworkConfig).to receive(:new).and_return(network_config)
|
141
|
-
|
142
|
-
allow(vapp).to receive(:find_vm_by_name).and_return(vm)
|
143
|
-
allow(vm).to receive(:product_section_properties=)
|
144
|
-
allow(vapp).to receive(:power_on)
|
145
|
-
end
|
146
|
-
|
147
|
-
it 'uses VCloudSdk::Client' do
|
148
|
-
expect(VCloudSdk::Client).to receive(:new).with(
|
149
|
-
login_info.fetch(:url),
|
150
|
-
[login_info.fetch(:user), login_info.fetch(:organization)].join('@'),
|
151
|
-
login_info.fetch(:password),
|
152
|
-
{},
|
153
|
-
logger,
|
154
|
-
).and_return(client)
|
155
|
-
|
156
|
-
deployer.deploy(vapp_template_path, vapp_config)
|
157
|
-
end
|
158
|
-
|
159
|
-
describe 'catalog deletion' do
|
160
|
-
before do
|
161
|
-
allow(client).to receive(:catalog_exists?).and_return(catalog_exists)
|
162
|
-
end
|
163
|
-
|
164
|
-
context 'when the catalog exists' do
|
165
|
-
let(:catalog_exists) { true }
|
166
|
-
|
167
|
-
it 'deletes the catalog' do
|
168
|
-
expect(client).to receive(:delete_catalog_by_name).with(location.fetch(:catalog))
|
169
|
-
|
170
|
-
deployer.deploy(vapp_template_path, vapp_config)
|
171
|
-
end
|
172
|
-
end
|
173
|
-
|
174
|
-
context 'when the catalog does not exist' do
|
175
|
-
let(:catalog_exists) { false }
|
176
|
-
|
177
|
-
it 'does not delete the catalog' do
|
178
|
-
expect(client).not_to receive(:delete_catalog_by_name).with(location.fetch(:catalog))
|
179
|
-
|
180
|
-
deployer.deploy(vapp_template_path, vapp_config)
|
181
|
-
end
|
182
|
-
end
|
183
|
-
end
|
184
|
-
|
185
|
-
it 'creates the catalog' do
|
186
|
-
expect(client).to receive(:create_catalog).with(location.fetch(:catalog)).and_return(catalog)
|
187
|
-
|
188
|
-
deployer.deploy(vapp_template_path, vapp_config)
|
189
|
-
end
|
190
|
-
|
191
|
-
it 'uploads the vApp template' do
|
192
|
-
expect(catalog).to receive(:upload_vapp_template).with(
|
193
|
-
location.fetch(:vdc),
|
194
|
-
vapp_config.fetch(:name),
|
195
|
-
tmpdir,
|
196
|
-
).and_return(catalog)
|
197
|
-
|
198
|
-
deployer.deploy(vapp_template_path, vapp_config)
|
199
|
-
end
|
200
|
-
|
201
|
-
it 'creates a VCloudSdk::NetworkConfig' do
|
202
|
-
expect(VCloudSdk::NetworkConfig).to receive(:new).with(
|
203
|
-
location.fetch(:network),
|
204
|
-
'Network 1',
|
205
|
-
).and_return(network_config)
|
206
|
-
|
207
|
-
deployer.deploy(vapp_template_path, vapp_config)
|
208
|
-
end
|
209
|
-
|
210
|
-
it 'instantiates the vApp template' do
|
211
|
-
expect(catalog).to receive(:instantiate_vapp_template).with(
|
212
|
-
vapp_config.fetch(:name),
|
213
|
-
location.fetch(:vdc),
|
214
|
-
vapp_config.fetch(:name),
|
215
|
-
nil,
|
216
|
-
nil,
|
217
|
-
network_config
|
218
|
-
).and_return(vapp)
|
219
|
-
|
220
|
-
deployer.deploy(vapp_template_path, vapp_config)
|
221
|
-
end
|
222
|
-
|
223
|
-
it 'sets the product section properties' do
|
224
|
-
expect(vm).to receive(:product_section_properties=).with(expected_properties)
|
225
|
-
|
226
|
-
deployer.deploy(vapp_template_path, vapp_config)
|
227
|
-
end
|
228
|
-
|
229
|
-
it 'powers on the vApp' do
|
230
|
-
expect(vapp).to receive(:power_on)
|
231
|
-
|
232
|
-
deployer.deploy(vapp_template_path, vapp_config)
|
233
|
-
end
|
234
|
-
|
235
|
-
it 'removes the expanded vApp template' do
|
236
|
-
expect(FileUtils).to receive(:remove_entry_secure).with(tmpdir, force: true)
|
237
|
-
|
238
|
-
deployer.deploy(vapp_template_path, vapp_config)
|
239
|
-
end
|
240
|
-
end
|
241
|
-
|
242
|
-
context 'when the vApp can NOT be deployed' do
|
243
|
-
it 'removes the expanded vApp template' do
|
244
|
-
expect(FileUtils).to receive(:remove_entry_secure).with(tmpdir, force: true)
|
245
|
-
|
246
|
-
expect { deployer.deploy(vapp_template_path, vapp_config) }.to raise_error
|
247
|
-
end
|
248
|
-
end
|
249
|
-
end
|
250
|
-
|
251
|
-
context 'when the template can NOT be expanded' do
|
252
|
-
let(:tar_expand_cmd) { "cd #{tmpdir} && tar xfv '#{expanded_vapp_template_path}'" }
|
253
|
-
before do
|
254
|
-
allow(deployer).to receive(:system).with(tar_expand_cmd).and_return(false)
|
255
|
-
end
|
256
|
-
|
257
|
-
it 'raises an error' do
|
258
|
-
expect { deployer.deploy(vapp_template_path, vapp_config) }.to raise_error("Error executing: #{tar_expand_cmd.inspect}")
|
259
|
-
end
|
260
|
-
|
261
|
-
it 'removes the expanded vApp template' do
|
262
|
-
expect(FileUtils).to receive(:remove_entry_secure).with(tmpdir, force: true)
|
263
|
-
|
264
|
-
expect { deployer.deploy(vapp_template_path, vapp_config) }.to raise_error
|
265
|
-
end
|
266
|
-
end
|
267
|
-
end
|
268
|
-
|
269
|
-
context 'when a host exists at the specified IP' do
|
270
|
-
before do
|
271
|
-
allow(deployer).to receive(:system).with("ping -c 5 #{vapp_config.fetch(:ip)}").and_return(true)
|
272
|
-
end
|
273
|
-
|
274
|
-
it 'raises an error' do
|
275
|
-
expect { deployer.deploy(vapp_template_path, vapp_config) }.to raise_error("VM exists at #{vapp_config.fetch(:ip)}")
|
276
|
-
end
|
277
|
-
|
278
|
-
it 'removes the expanded vApp template' do
|
279
|
-
expect(FileUtils).to receive(:remove_entry_secure).with(tmpdir, force: true)
|
280
|
-
|
281
|
-
expect { deployer.deploy(vapp_template_path, vapp_config) }.to raise_error
|
282
|
-
end
|
283
|
-
end
|
284
|
-
end
|
285
|
-
end
|
286
|
-
end
|
287
|
-
end
|