vm_shepherd 0.0.1 → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|