vm_shepherd 1.10.1 → 1.11.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 4c28ff60aceef4bca731813761ce712123b7f941
4
- data.tar.gz: 055d66480ba8775dab95bd80554556654da54c55
3
+ metadata.gz: 763cd128f7302c5fb7250c56c5fb6f2902659a7b
4
+ data.tar.gz: aac10b49759fcb9b8c5b385e8f9a3bb4fc6b32d6
5
5
  SHA512:
6
- metadata.gz: 930db4b3aba4201353764122080c6badbc9ba2021c5ada38018738647bdbcfb14f65a647113abebb80b3d1a9bb9f04fe1cf051ebcf13ffcc3ccf002f7146310a
7
- data.tar.gz: f9fa8ea157d70fb41454e44716616b1b682d868d9c23cfab097e8e8d895c5302e5f65422552bccdc7e52338d42c731c1d42059a9050d9d0153d8037bcfe708cf
6
+ metadata.gz: b67e18537b886374536aaf33ec441b389c81ffeb283fcaff7ddff1c53899db708f9fceebc9b22ea90a70d29b810b56f04f6486d7689d17721cea9a8304247075
7
+ data.tar.gz: 7e0e37f43205234107f6350dde7dcbf3d6c409b4b25357fd486710b95504563cd7e3d825f7e5ab6365a8981b0913d9a99d21c1a5e4748b8c19a0ae72377ac1b1
@@ -1,7 +1,11 @@
1
1
  require 'vm_shepherd/shepherd'
2
+ require 'vm_shepherd/data_object'
2
3
  require 'vm_shepherd/aws_manager'
3
4
  require 'vm_shepherd/openstack_manager'
4
5
  require 'vm_shepherd/vcloud_manager'
6
+ require 'vm_shepherd/vcloud/deployer'
7
+ require 'vm_shepherd/vcloud/destroyer'
8
+ require 'vm_shepherd/vcloud/vapp_config'
5
9
  require 'vm_shepherd/vsphere_manager'
6
10
 
7
11
  module VmShepherd
@@ -0,0 +1,11 @@
1
+ module VmShepherd
2
+ module DataObject
3
+ def ==(other_obj)
4
+ return false unless self.class === other_obj
5
+
6
+ instance_variables.all? do |ivar_name|
7
+ self.instance_variable_get(ivar_name) == other_obj.instance_variable_get(ivar_name)
8
+ end
9
+ end
10
+ end
11
+ end
@@ -184,7 +184,7 @@ module VmShepherd
184
184
 
185
185
  def vcloud_deploy_options(vm_shepherd_config)
186
186
  vm = vm_shepherd_config.vapp
187
- {
187
+ VmShepherd::Vcloud::VappConfig.new(
188
188
  name: vm.ops_manager_name,
189
189
  ip: vm.ip,
190
190
  gateway: vm.gateway,
@@ -193,7 +193,7 @@ module VmShepherd
193
193
  ntp: vm.ntp,
194
194
  catalog: vm_shepherd_config.vdc.catalog,
195
195
  network: vm_shepherd_config.vdc.network,
196
- }
196
+ )
197
197
  end
198
198
 
199
199
  def ami_manager
@@ -0,0 +1,23 @@
1
+ module VmShepherd
2
+ module Vcloud
3
+ class Deployer
4
+ def self.deploy_and_power_on_vapp(client:, ovf_dir:, vapp_config:, vdc_name:)
5
+ catalog = client.create_catalog(vapp_config.catalog)
6
+
7
+ # upload template and instantiate vapp
8
+ catalog.upload_vapp_template(vdc_name, vapp_config.name, ovf_dir)
9
+
10
+ # instantiate template
11
+ network_config = VCloudSdk::NetworkConfig.new(vapp_config.network, 'Network 1')
12
+ vapp = catalog.instantiate_vapp_template(vapp_config.name, vdc_name, vapp_config.name, nil, nil, network_config)
13
+
14
+ # reconfigure vm
15
+ vm = vapp.find_vm_by_name(vapp_config.name)
16
+ vm.product_section_properties = vapp_config.build_properties
17
+
18
+ # power on vapp
19
+ vapp.power_on
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,47 @@
1
+ module VmShepherd
2
+ module Vcloud
3
+ class Destroyer
4
+ def initialize(client:, vdc_name:)
5
+ @client = client
6
+ @vdc_name = vdc_name
7
+ end
8
+
9
+ def delete_catalog_and_vapps(catalog, vapp_names, logger)
10
+ delete_vapps(vapp_names, logger)
11
+ delete_catalog(catalog)
12
+ end
13
+
14
+ private
15
+
16
+ def vdc
17
+ @vdc ||= @client.find_vdc_by_name(@vdc_name)
18
+ end
19
+
20
+ def delete_vapps(vapp_names, logger)
21
+ vapp_names.each do |vapp_name|
22
+ begin
23
+ delete_vapp(vapp_name)
24
+ rescue VCloudSdk::ObjectNotFoundError => e
25
+ logger.debug "Could not delete vapp '#{vapp_name}': #{e.inspect}"
26
+ end
27
+ end
28
+ end
29
+
30
+ def delete_catalog(catalog)
31
+ @client.delete_catalog_by_name(catalog) if @client.catalog_exists?(catalog)
32
+ end
33
+
34
+ def delete_vapp(vapp_name)
35
+ vapp = vdc.find_vapp_by_name(vapp_name)
36
+ vapp.vms.map do |vm|
37
+ vm.independent_disks.map do |disk|
38
+ vm.detach_disk(disk)
39
+ vdc.delete_disk_by_name(disk.name)
40
+ end
41
+ end
42
+ vapp.power_off
43
+ vapp.delete
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,78 @@
1
+ module VmShepherd
2
+ module Vcloud
3
+ class VappConfig
4
+ include VmShepherd::DataObject
5
+ attr_reader :name, :gateway, :dns, :ntp, :ip, :netmask, :catalog, :network
6
+
7
+ def initialize(name:, ip:, gateway:, netmask:, dns:, ntp:, catalog:, network:)
8
+ @name = name
9
+ @ip = ip
10
+ @gateway = gateway
11
+ @netmask = netmask
12
+ @dns = dns
13
+ @ntp = ntp
14
+ @catalog = catalog
15
+ @network = network
16
+ end
17
+
18
+ def build_properties
19
+ [
20
+ {
21
+ 'type' => 'string',
22
+ 'key' => 'gateway',
23
+ 'value' => gateway,
24
+ 'password' => 'false',
25
+ 'userConfigurable' => 'true',
26
+ 'Label' => 'Default Gateway',
27
+ 'Description' => 'The default gateway address for the VM network. Leave blank if DHCP is desired.'
28
+ },
29
+ {
30
+ 'type' => 'string',
31
+ 'key' => 'DNS',
32
+ 'value' => dns,
33
+ 'password' => 'false',
34
+ 'userConfigurable' => 'true',
35
+ 'Label' => 'DNS',
36
+ 'Description' => 'The domain name servers for the VM (comma separated). Leave blank if DHCP is desired.',
37
+ },
38
+ {
39
+ 'type' => 'string',
40
+ 'key' => 'ntp_servers',
41
+ 'value' => ntp,
42
+ 'password' => 'false',
43
+ 'userConfigurable' => 'true',
44
+ 'Label' => 'NTP Servers',
45
+ 'Description' => 'Comma-delimited list of NTP servers'
46
+ },
47
+ {
48
+ 'type' => 'string',
49
+ 'key' => 'admin_password',
50
+ 'value' => 'tempest',
51
+ 'password' => 'true',
52
+ 'userConfigurable' => 'true',
53
+ 'Label' => 'Admin Password',
54
+ 'Description' => 'This password is used to SSH into the VM. The username is "tempest".',
55
+ },
56
+ {
57
+ 'type' => 'string',
58
+ 'key' => 'ip0',
59
+ 'value' => ip,
60
+ 'password' => 'false',
61
+ 'userConfigurable' => 'true',
62
+ 'Label' => 'IP Address',
63
+ 'Description' => 'The IP address for the VM. Leave blank if DHCP is desired.',
64
+ },
65
+ {
66
+ 'type' => 'string',
67
+ 'key' => 'netmask0',
68
+ 'value' => netmask,
69
+ 'password' => 'false',
70
+ 'userConfigurable' => 'true',
71
+ 'Label' => 'Netmask',
72
+ 'Description' => 'The netmask for the VM network. Leave blank if DHCP is desired.'
73
+ }
74
+ ]
75
+ end
76
+ end
77
+ end
78
+ end
@@ -17,9 +17,15 @@ module VmShepherd
17
17
 
18
18
  untar_vapp_template_tar(File.expand_path(vapp_template_tar_path), tmpdir)
19
19
 
20
- vapp = deploy_vapp(tmpdir, vapp_config)
21
- reconfigure_vm(vapp, vapp_config)
22
- vapp.power_on
20
+ VmShepherd::Vcloud::Deployer.deploy_and_power_on_vapp(
21
+ client: client,
22
+ ovf_dir: tmpdir,
23
+ vapp_config: vapp_config,
24
+ vdc_name: @vdc_name,
25
+ )
26
+ rescue => e
27
+ logger.error(e.http_body) if e.respond_to?(:http_body)
28
+ raise e
23
29
  ensure
24
30
  FileUtils.remove_entry_secure(tmpdir, force: true)
25
31
  end
@@ -28,8 +34,8 @@ module VmShepherd
28
34
  end
29
35
 
30
36
  def destroy(vapp_names, catalog)
31
- delete_vapps(vapp_names)
32
- delete_catalog(catalog)
37
+ VmShepherd::Vcloud::Destroyer.new(client: client, vdc_name: @vdc_name).
38
+ delete_catalog_and_vapps(catalog, vapp_names, @logger)
33
39
  end
34
40
 
35
41
  def clean_environment(vapp_names, catalog)
@@ -40,14 +46,15 @@ module VmShepherd
40
46
 
41
47
  def check_vapp_status(vapp_config)
42
48
  log('Checking for existing VM') do
43
- ip = vapp_config[:ip]
44
- raise "VM exists at #{ip}" if system("ping -c 5 #{ip}")
49
+ ip = vapp_config.ip
50
+ system("ping -c 5 #{ip}") and raise "VM exists at #{ip}"
45
51
  end
46
52
  end
47
53
 
48
54
  def untar_vapp_template_tar(vapp_template_tar_path, dir)
49
55
  log("Untarring #{vapp_template_tar_path}") do
50
- system_or_exit("cd #{dir} && tar xfv '#{vapp_template_tar_path}'")
56
+ cmd = "cd #{dir} && tar xfv '#{vapp_template_tar_path}'"
57
+ system(cmd) or raise("Error executing: #{cmd}")
51
58
  end
52
59
  end
53
60
 
@@ -61,127 +68,10 @@ module VmShepherd
61
68
  )
62
69
  end
63
70
 
64
- def deploy_vapp(ovf_dir, vapp_config)
65
- vapp_name = vapp_config.fetch(:name)
66
- catalog_name = vapp_config.fetch(:catalog)
67
- network = vapp_config.fetch(:network)
68
- # setup the catalog
69
- client.delete_catalog_by_name(catalog_name) if client.catalog_exists?(catalog_name)
70
- catalog = client.create_catalog(catalog_name)
71
-
72
- # upload template and instantiate vapp
73
- catalog.upload_vapp_template(@vdc_name, vapp_name, ovf_dir)
74
-
75
- # instantiate template
76
- network_config = VCloudSdk::NetworkConfig.new(network, 'Network 1')
77
- catalog.instantiate_vapp_template(vapp_name, @vdc_name, vapp_name, nil, nil, network_config)
78
- rescue => e
79
- @logger.error(e.http_body) if e.respond_to?(:http_body)
80
- raise e
81
- end
82
-
83
- def reconfigure_vm(vapp, vapp_config)
84
- vapp_name = vapp_config.fetch(:name)
85
- gateway = vapp_config.fetch(:gateway)
86
- dns = vapp_config.fetch(:dns)
87
- ntp = vapp_config.fetch(:ntp)
88
- ip = vapp_config.fetch(:ip)
89
- netmask = vapp_config.fetch(:netmask)
90
-
91
- vm = vapp.find_vm_by_name(vapp_name)
92
- vm.product_section_properties = build_properties(gateway: gateway, dns: dns, ntp: ntp, ip: ip, netmask: netmask)
93
- vm
94
- end
95
-
96
- def build_properties(gateway:, dns:, ntp:, ip:, netmask:)
97
- [
98
- {
99
- 'type' => 'string',
100
- 'key' => 'gateway',
101
- 'value' => gateway,
102
- 'password' => 'false',
103
- 'userConfigurable' => 'true',
104
- 'Label' => 'Default Gateway',
105
- 'Description' => 'The default gateway address for the VM network. Leave blank if DHCP is desired.'
106
- },
107
- {
108
- 'type' => 'string',
109
- 'key' => 'DNS',
110
- 'value' => dns,
111
- 'password' => 'false',
112
- 'userConfigurable' => 'true',
113
- 'Label' => 'DNS',
114
- 'Description' => 'The domain name servers for the VM (comma separated). Leave blank if DHCP is desired.',
115
- },
116
- {
117
- 'type' => 'string',
118
- 'key' => 'ntp_servers',
119
- 'value' => ntp,
120
- 'password' => 'false',
121
- 'userConfigurable' => 'true',
122
- 'Label' => 'NTP Servers',
123
- 'Description' => 'Comma-delimited list of NTP servers'
124
- },
125
- {
126
- 'type' => 'string',
127
- 'key' => 'admin_password',
128
- 'value' => 'tempest',
129
- 'password' => 'true',
130
- 'userConfigurable' => 'true',
131
- 'Label' => 'Admin Password',
132
- 'Description' => 'This password is used to SSH into the VM. The username is "tempest".',
133
- },
134
- {
135
- 'type' => 'string',
136
- 'key' => 'ip0',
137
- 'value' => ip,
138
- 'password' => 'false',
139
- 'userConfigurable' => 'true',
140
- 'Label' => 'IP Address',
141
- 'Description' => 'The IP address for the VM. Leave blank if DHCP is desired.',
142
- },
143
- {
144
- 'type' => 'string',
145
- 'key' => 'netmask0',
146
- 'value' => netmask,
147
- 'password' => 'false',
148
- 'userConfigurable' => 'true',
149
- 'Label' => 'Netmask',
150
- 'Description' => 'The netmask for the VM network. Leave blank if DHCP is desired.'
151
- }
152
- ]
153
- end
154
-
155
71
  def log(title, &blk)
156
72
  @logger.debug "--- Begin: #{title.inspect} @ #{DateTime.now}"
157
73
  blk.call
158
74
  @logger.debug "--- End: #{title.inspect} @ #{DateTime.now}"
159
75
  end
160
-
161
- def system_or_exit(command)
162
- log(command) do
163
- system(command) || raise("Error executing: #{command.inspect}")
164
- end
165
- end
166
-
167
- def vdc
168
- @vdc ||= client.find_vdc_by_name(@vdc_name)
169
- end
170
-
171
- def delete_vapps(vapp_names)
172
- vapp_names.each do |vapp_name|
173
- begin
174
- vapp = vdc.find_vapp_by_name(vapp_name)
175
- vapp.power_off
176
- vapp.delete
177
- rescue VCloudSdk::ObjectNotFoundError => e
178
- @logger.debug "Could not delete vapp '#{vapp_name}': #{e.inspect}"
179
- end
180
- end
181
- end
182
-
183
- def delete_catalog(catalog)
184
- client.delete_catalog_by_name(catalog) if client.catalog_exists?(catalog)
185
- end
186
76
  end
187
77
  end
@@ -1,3 +1,3 @@
1
1
  module VmShepherd
2
- VERSION = '1.10.1'.freeze
2
+ VERSION = '1.11.0'.freeze
3
3
  end
@@ -0,0 +1,49 @@
1
+ require 'vm_shepherd/data_object'
2
+
3
+ module VmShepherd
4
+ class TestDataObject
5
+ include DataObject
6
+
7
+ attr_accessor :name
8
+ end
9
+
10
+ RSpec.describe(DataObject) do
11
+ describe '#==' do
12
+ it 'returns false for objects of a different class' do
13
+ class DifferentDataObject
14
+ include DataObject
15
+ end
16
+
17
+ expect(TestDataObject.new == DifferentDataObject.new).to be_falsey
18
+ end
19
+
20
+ it 'returns true for objects of a descendent class' do
21
+ class DescendentDataObject < TestDataObject
22
+ include DataObject
23
+ end
24
+
25
+ expect(TestDataObject.new == DescendentDataObject.new).to be_truthy
26
+ end
27
+
28
+ it 'returns false when any attribute is unequal' do
29
+ a = TestDataObject.new
30
+ b = TestDataObject.new
31
+
32
+ a.name = 'a'
33
+ b.name = 'b'
34
+
35
+ expect(a == b).to be_falsey
36
+ end
37
+
38
+ it 'returns true when all attributes are equal' do
39
+ eleventy_one = TestDataObject.new
40
+ hundred_and_eleven = TestDataObject.new
41
+
42
+ eleventy_one.name = '111'
43
+ hundred_and_eleven.name = '111'
44
+
45
+ expect(eleventy_one == hundred_and_eleven).to be_truthy
46
+ end
47
+ end
48
+ end
49
+ end
@@ -84,7 +84,7 @@ module VmShepherd
84
84
 
85
85
  expect(first_vcloud_manager).to receive(:deploy).with(
86
86
  'FIRST_FAKE_PATH',
87
- {
87
+ Vcloud::VappConfig.new(
88
88
  name: first_config.vapp.ops_manager_name,
89
89
  ip: first_config.vapp.ip,
90
90
  gateway: first_config.vapp.gateway,
@@ -93,12 +93,12 @@ module VmShepherd
93
93
  ntp: first_config.vapp.ntp,
94
94
  catalog: first_config.vdc.catalog,
95
95
  network: first_config.vdc.network,
96
- }
96
+ )
97
97
  )
98
98
 
99
99
  expect(last_vcloud_manager).to receive(:deploy).with(
100
100
  'LAST_FAKE_PATH',
101
- {
101
+ Vcloud::VappConfig.new(
102
102
  name: last_config.vapp.ops_manager_name,
103
103
  ip: last_config.vapp.ip,
104
104
  gateway: last_config.vapp.gateway,
@@ -107,7 +107,7 @@ module VmShepherd
107
107
  ntp: last_config.vapp.ntp,
108
108
  catalog: last_config.vdc.catalog,
109
109
  network: last_config.vdc.network,
110
- }
110
+ )
111
111
  )
112
112
 
113
113
  manager.deploy(paths: ['FIRST_FAKE_PATH', 'LAST_FAKE_PATH'])
@@ -0,0 +1,83 @@
1
+ require 'vm_shepherd/data_object'
2
+ require 'vm_shepherd/vcloud/vapp_config'
3
+ require 'vm_shepherd/vcloud/deployer'
4
+ require 'ruby_vcloud_sdk'
5
+
6
+ module VmShepherd
7
+ module Vcloud
8
+ RSpec.describe Deployer do
9
+ describe '.deploy_and_power_on_vapp' do
10
+ let(:vapp_config) do
11
+ VappConfig.new(
12
+ name: 'NAME',
13
+ ip: 'IP',
14
+ gateway: 'GATEWAY',
15
+ netmask: 'NETMASK',
16
+ dns: 'DNS',
17
+ ntp: 'NTP',
18
+ catalog: 'CATALOG',
19
+ network: 'NETWORK',
20
+ )
21
+ end
22
+
23
+ let(:client) { instance_double(VCloudSdk::Client) }
24
+ let(:catalog) { instance_double(VCloudSdk::Catalog) }
25
+ let(:vapp) { instance_double(VCloudSdk::VApp) }
26
+ let(:vm) { instance_double(VCloudSdk::VM) }
27
+ let(:network_config) { instance_double(VCloudSdk::NetworkConfig) }
28
+
29
+ before do
30
+ allow(client).to receive(:create_catalog).and_return(catalog)
31
+ allow(catalog).to receive(:upload_vapp_template)
32
+ allow(catalog).to receive(:instantiate_vapp_template).and_return(vapp)
33
+ allow(vapp).to receive(:find_vm_by_name).and_return(vm)
34
+ allow(vm).to receive(:product_section_properties=)
35
+ allow(vapp).to receive(:power_on)
36
+
37
+ allow(VCloudSdk::NetworkConfig).to receive(:new).with('NETWORK', 'Network 1').and_return(network_config)
38
+ end
39
+
40
+ it 'creates a catalog' do
41
+ expect(client).to receive(:create_catalog).with('CATALOG')
42
+
43
+ Deployer.deploy_and_power_on_vapp(client: client, ovf_dir: nil, vapp_config: vapp_config, vdc_name: nil)
44
+ end
45
+
46
+ it 'uploads a vapp template' do
47
+ expect(catalog).to receive(:upload_vapp_template).with('VDC_NAME', 'NAME', 'OVF_DIR')
48
+
49
+ Deployer.deploy_and_power_on_vapp(client: client, ovf_dir: 'OVF_DIR', vapp_config: vapp_config, vdc_name: 'VDC_NAME')
50
+ end
51
+
52
+ it 'instantiates the template' do
53
+ expect(catalog).to receive(:upload_vapp_template).with('VDC_NAME', 'NAME', 'OVF_DIR')
54
+ expect(catalog).to receive(:instantiate_vapp_template).with('NAME', 'VDC_NAME', 'NAME', nil, nil, network_config)
55
+
56
+ Deployer.deploy_and_power_on_vapp(client: client, ovf_dir: 'OVF_DIR', vapp_config: vapp_config, vdc_name: 'VDC_NAME')
57
+ end
58
+
59
+ it 'reconfigures the vm' do
60
+ expect(vm).to receive(:product_section_properties=).with(vapp_config.build_properties)
61
+
62
+ Deployer.deploy_and_power_on_vapp(client: client, ovf_dir: 'OVF_DIR', vapp_config: vapp_config, vdc_name: 'VDC_NAME')
63
+ end
64
+
65
+ it 'powers on the vapp' do
66
+ expect(vapp).to receive(:power_on)
67
+
68
+ Deployer.deploy_and_power_on_vapp(client: client, ovf_dir: 'OVF_DIR', vapp_config: vapp_config, vdc_name: 'VDC_NAME')
69
+ end
70
+
71
+ it 'does things in order' do
72
+ Deployer.deploy_and_power_on_vapp(client: client, ovf_dir: 'OVF_DIR', vapp_config: vapp_config, vdc_name: 'VDC_NAME')
73
+
74
+ expect(client).to have_received(:create_catalog).ordered
75
+ expect(catalog).to have_received(:upload_vapp_template).ordered
76
+ expect(catalog).to have_received(:instantiate_vapp_template).ordered
77
+ expect(vm).to have_received(:product_section_properties=).ordered
78
+ expect(vapp).to have_received(:power_on).ordered
79
+ end
80
+ end
81
+ end
82
+ end
83
+ end
@@ -0,0 +1,72 @@
1
+ require 'vm_shepherd/data_object'
2
+ require 'vm_shepherd/vcloud/vapp_config'
3
+ require 'vm_shepherd/vcloud/destroyer'
4
+ require 'ruby_vcloud_sdk'
5
+
6
+ module VmShepherd
7
+ module Vcloud
8
+ RSpec.describe Destroyer do
9
+ subject(:destroyer) { Destroyer.new(client: client, vdc_name: vdc_name) }
10
+ let(:client) { instance_double(VCloudSdk::Client) }
11
+ let(:vdc_name) { 'VDC_NAME' }
12
+ let(:fake_logger) { double(:logger, debug: nil) }
13
+ let(:vm) { instance_double(VCloudSdk::VM) }
14
+ let(:vdc) { instance_double(VCloudSdk::VDC) }
15
+ let(:vapp) { instance_double(VCloudSdk::VApp) }
16
+ let(:disk) { instance_double(VCloudSdk::InternalDisk, name: 'DISK_NAME') }
17
+
18
+ before do
19
+ allow(client).to receive(:delete_catalog_by_name)
20
+ allow(client).to receive(:catalog_exists?)
21
+ allow(client).to receive(:find_vdc_by_name).with(vdc_name).and_return(vdc)
22
+ allow(vdc).to receive(:find_vapp_by_name).with('VAPP_NAME').and_return(vapp)
23
+ allow(vdc).to receive(:delete_disk_by_name)
24
+ allow(vapp).to receive(:vms).and_return([vm])
25
+ allow(vapp).to receive(:power_off)
26
+ allow(vapp).to receive(:delete)
27
+ allow(vm).to receive(:independent_disks).and_return([disk])
28
+ allow(vm).to receive(:detach_disk)
29
+ end
30
+
31
+ describe '#delete_catalog_and_vapps' do
32
+ context 'when the catalog exists' do
33
+ before do
34
+ allow(client).to receive(:catalog_exists?).with('CATALOG_NAME').and_return(true)
35
+ end
36
+
37
+ it 'deletes the catalog' do
38
+ destroyer.delete_catalog_and_vapps('CATALOG_NAME', [], fake_logger)
39
+
40
+ expect(client).to have_received(:delete_catalog_by_name).with('CATALOG_NAME')
41
+ end
42
+ end
43
+
44
+ context 'when the catalog does not exist' do
45
+ before do
46
+ allow(client).to receive(:catalog_exists?).with('CATALOG_NAME').and_return(false)
47
+ end
48
+
49
+ it 'skips deleting the catalog' do
50
+ destroyer.delete_catalog_and_vapps('CATALOG_NAME', [], fake_logger)
51
+
52
+ expect(client).not_to have_received(:delete_catalog_by_name).with('CATALOG_NAME')
53
+ end
54
+ end
55
+
56
+ it 'detaches and deletes persistent disks' do
57
+ destroyer.delete_catalog_and_vapps('CATALOG_NAME', ['VAPP_NAME'], fake_logger)
58
+
59
+ expect(vm).to have_received(:detach_disk).with(disk)
60
+ expect(vdc).to have_received(:delete_disk_by_name).with('DISK_NAME')
61
+ end
62
+
63
+ it 'powers off and deletes vapps' do
64
+ destroyer.delete_catalog_and_vapps('CATALOG_NAME', ['VAPP_NAME'], fake_logger)
65
+
66
+ expect(vapp).to have_received(:power_off)
67
+ expect(vapp).to have_received(:delete)
68
+ end
69
+ end
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,25 @@
1
+ require 'vm_shepherd/data_object'
2
+ require 'vm_shepherd/vcloud/vapp_config'
3
+
4
+ module VmShepherd
5
+ module Vcloud
6
+ RSpec.describe(VappConfig) do
7
+ subject(:vapp_config) do
8
+ VappConfig.new(
9
+ name: 'NAME',
10
+ ip: 'IP',
11
+ gateway: 'GATEWAY',
12
+ netmask: 'NETMASK',
13
+ dns: 'DNS',
14
+ ntp: 'NTP',
15
+ catalog: 'CATALOG',
16
+ network: 'NETWORK',
17
+ )
18
+ end
19
+
20
+ it 'is a DataObject' do
21
+ expect(vapp_config).to be_a(DataObject)
22
+ end
23
+ end
24
+ end
25
+ end
@@ -1,4 +1,8 @@
1
+ require 'vm_shepherd/data_object'
1
2
  require 'vm_shepherd/vcloud_manager'
3
+ require 'vm_shepherd/vcloud/deployer'
4
+ require 'vm_shepherd/vcloud/destroyer'
5
+ require 'vm_shepherd/vcloud/vapp_config'
2
6
 
3
7
  module VmShepherd
4
8
  RSpec.describe VcloudManager do
@@ -18,7 +22,7 @@ module VmShepherd
18
22
 
19
23
  describe '#deploy' do
20
24
  let(:vapp_config) do
21
- {
25
+ Vcloud::VappConfig.new(
22
26
  ip: 'FAKE_IP',
23
27
  name: 'FAKE_NAME',
24
28
  gateway: 'FAKE_GATEWAY',
@@ -27,7 +31,7 @@ module VmShepherd
27
31
  netmask: 'FAKE_NETMASK',
28
32
  catalog: 'FAKE_VAPP_CATALOG',
29
33
  network: 'FAKE_NETWORK',
30
- }
34
+ )
31
35
  end
32
36
 
33
37
  let(:vapp_template_path) { 'FAKE_VAPP_TEMPLATE_PATH' }
@@ -39,7 +43,7 @@ module VmShepherd
39
43
  let(:expanded_vapp_template_path) { 'FAKE_EXPANDED_VAPP_TEMPLATE_PATH' }
40
44
 
41
45
  before do
42
- allow(vcloud_manager).to receive(:system).with("ping -c 5 #{vapp_config.fetch(:ip)}").and_return(false)
46
+ allow(vcloud_manager).to receive(:system).with("ping -c 5 #{vapp_config.ip}").and_return(false)
43
47
 
44
48
  allow(File).to receive(:expand_path).with(vapp_template_path).and_return(expanded_vapp_template_path)
45
49
 
@@ -71,7 +75,7 @@ module VmShepherd
71
75
  {
72
76
  'type' => 'string',
73
77
  'key' => 'gateway',
74
- 'value' => vapp_config.fetch(:gateway),
78
+ 'value' => vapp_config.gateway,
75
79
  'password' => 'false',
76
80
  'userConfigurable' => 'true',
77
81
  'Label' => 'Default Gateway',
@@ -80,7 +84,7 @@ module VmShepherd
80
84
  {
81
85
  'type' => 'string',
82
86
  'key' => 'DNS',
83
- 'value' => vapp_config.fetch(:dns),
87
+ 'value' => vapp_config.dns,
84
88
  'password' => 'false',
85
89
  'userConfigurable' => 'true',
86
90
  'Label' => 'DNS',
@@ -89,7 +93,7 @@ module VmShepherd
89
93
  {
90
94
  'type' => 'string',
91
95
  'key' => 'ntp_servers',
92
- 'value' => vapp_config.fetch(:ntp),
96
+ 'value' => vapp_config.ntp,
93
97
  'password' => 'false',
94
98
  'userConfigurable' => 'true',
95
99
  'Label' => 'NTP Servers',
@@ -107,7 +111,7 @@ module VmShepherd
107
111
  {
108
112
  'type' => 'string',
109
113
  'key' => 'ip0',
110
- 'value' => vapp_config.fetch(:ip),
114
+ 'value' => vapp_config.ip,
111
115
  'password' => 'false',
112
116
  'userConfigurable' => 'true',
113
117
  'Label' => 'IP Address',
@@ -116,7 +120,7 @@ module VmShepherd
116
120
  {
117
121
  'type' => 'string',
118
122
  'key' => 'netmask0',
119
- 'value' => vapp_config.fetch(:netmask),
123
+ 'value' => vapp_config.netmask,
120
124
  'password' => 'false',
121
125
  'userConfigurable' => 'true',
122
126
  'Label' => 'Netmask',
@@ -153,34 +157,8 @@ module VmShepherd
153
157
  vcloud_manager.deploy(vapp_template_path, vapp_config)
154
158
  end
155
159
 
156
- describe 'catalog deletion' do
157
- before do
158
- allow(client).to receive(:catalog_exists?).and_return(catalog_exists)
159
- end
160
-
161
- context 'when the catalog exists' do
162
- let(:catalog_exists) { true }
163
-
164
- it 'deletes the catalog' do
165
- expect(client).to receive(:delete_catalog_by_name).with(vapp_config.fetch(:catalog))
166
-
167
- vcloud_manager.deploy(vapp_template_path, vapp_config)
168
- end
169
- end
170
-
171
- context 'when the catalog does not exist' do
172
- let(:catalog_exists) { false }
173
-
174
- it 'does not delete the catalog' do
175
- expect(client).not_to receive(:delete_catalog_by_name).with(vapp_config.fetch(:catalog))
176
-
177
- vcloud_manager.deploy(vapp_template_path, vapp_config)
178
- end
179
- end
180
- end
181
-
182
160
  it 'creates the catalog' do
183
- expect(client).to receive(:create_catalog).with(vapp_config.fetch(:catalog)).and_return(catalog)
161
+ expect(client).to receive(:create_catalog).with(vapp_config.catalog).and_return(catalog)
184
162
 
185
163
  vcloud_manager.deploy(vapp_template_path, vapp_config)
186
164
  end
@@ -188,7 +166,7 @@ module VmShepherd
188
166
  it 'uploads the vApp template' do
189
167
  expect(catalog).to receive(:upload_vapp_template).with(
190
168
  vdc_name,
191
- vapp_config.fetch(:name),
169
+ vapp_config.name,
192
170
  tmpdir,
193
171
  ).and_return(catalog)
194
172
 
@@ -197,7 +175,7 @@ module VmShepherd
197
175
 
198
176
  it 'creates a VCloudSdk::NetworkConfig' do
199
177
  expect(VCloudSdk::NetworkConfig).to receive(:new).with(
200
- vapp_config.fetch(:network),
178
+ vapp_config.network,
201
179
  'Network 1',
202
180
  ).and_return(network_config)
203
181
 
@@ -206,9 +184,9 @@ module VmShepherd
206
184
 
207
185
  it 'instantiates the vApp template' do
208
186
  expect(catalog).to receive(:instantiate_vapp_template).with(
209
- vapp_config.fetch(:name),
187
+ vapp_config.name,
210
188
  vdc_name,
211
- vapp_config.fetch(:name),
189
+ vapp_config.name,
212
190
  nil,
213
191
  nil,
214
192
  network_config
@@ -256,7 +234,7 @@ module VmShepherd
256
234
  end
257
235
 
258
236
  it 'raises an error' do
259
- expect { vcloud_manager.deploy(vapp_template_path, vapp_config) }.to raise_error("Error executing: #{tar_expand_cmd.inspect}")
237
+ expect { vcloud_manager.deploy(vapp_template_path, vapp_config) }.to raise_error("Error executing: #{tar_expand_cmd}")
260
238
  end
261
239
 
262
240
  it 'removes the expanded vApp template' do
@@ -269,11 +247,11 @@ module VmShepherd
269
247
 
270
248
  context 'when a host exists at the specified IP' do
271
249
  before do
272
- allow(vcloud_manager).to receive(:system).with("ping -c 5 #{vapp_config.fetch(:ip)}").and_return(true)
250
+ allow(vcloud_manager).to receive(:system).with("ping -c 5 #{vapp_config.ip}").and_return(true)
273
251
  end
274
252
 
275
253
  it 'raises an error' do
276
- expect { vcloud_manager.deploy(vapp_template_path, vapp_config) }.to raise_error("VM exists at #{vapp_config.fetch(:ip)}")
254
+ expect { vcloud_manager.deploy(vapp_template_path, vapp_config) }.to raise_error("VM exists at #{vapp_config.ip}")
277
255
  end
278
256
 
279
257
  it 'removes the expanded vApp template' do
@@ -290,6 +268,13 @@ module VmShepherd
290
268
  let(:vapp) { instance_double(VCloudSdk::VApp) }
291
269
  let(:vapp_name) { 'FAKE_VAPP_NAME' }
292
270
  let(:vapp_catalog) { 'FAKE_VAPP_CATALOG' }
271
+ let(:vm) { instance_double(VCloudSdk::VM) }
272
+ let(:disk) { instance_double(VCloudSdk::InternalDisk, name: 'disk name') }
273
+
274
+ before do
275
+ allow(vapp).to receive(:vms).and_return([vm])
276
+ allow(vm).to receive(:independent_disks).and_return([disk])
277
+ end
293
278
 
294
279
  context 'when the catalog exists' do
295
280
  before do
@@ -299,6 +284,8 @@ module VmShepherd
299
284
  it 'uses VCloudSdk::Client to delete the vApp' do
300
285
  expect(client).to receive(:find_vdc_by_name).with(vdc_name).and_return(vdc)
301
286
  expect(vdc).to receive(:find_vapp_by_name).with(vapp_name).and_return(vapp)
287
+ expect(vm).to receive(:detach_disk).with(disk)
288
+ expect(vdc).to receive(:delete_disk_by_name).with('disk name')
302
289
  expect(vapp).to receive(:power_off)
303
290
  expect(vapp).to receive(:delete)
304
291
  expect(client).to receive(:delete_catalog_by_name).with(vapp_catalog)
@@ -319,6 +306,8 @@ module VmShepherd
319
306
  allow(VCloudSdk::Client).to receive(:new).and_return(client)
320
307
  allow(client).to receive(:find_vdc_by_name).and_return(vdc)
321
308
  allow(vdc).to receive(:find_vapp_by_name).and_return(vapp)
309
+ allow(vm).to receive(:detach_disk)
310
+ allow(vdc).to receive(:delete_disk_by_name)
322
311
  allow(vapp).to receive(:power_off)
323
312
  allow(vapp).to receive(:delete)
324
313
 
@@ -326,7 +315,7 @@ module VmShepherd
326
315
  end
327
316
 
328
317
  it 'catches the error' do
329
- allow(client).to receive(:find_vdc_by_name).and_raise(VCloudSdk::ObjectNotFoundError)
318
+ allow(vdc).to receive(:find_vapp_by_name).and_raise(VCloudSdk::ObjectNotFoundError)
330
319
 
331
320
  expect { vcloud_manager.destroy([vapp_name], vapp_catalog) }.not_to raise_error
332
321
  end
@@ -347,6 +336,8 @@ module VmShepherd
347
336
  it 'uses VCloudSdk::Client to delete the vApp' do
348
337
  expect(client).to receive(:find_vdc_by_name).with(vdc_name).and_return(vdc)
349
338
  expect(vdc).to receive(:find_vapp_by_name).with(vapp_name).and_return(vapp)
339
+ expect(vm).to receive(:detach_disk).with(disk)
340
+ expect(vdc).to receive(:delete_disk_by_name).with('disk name')
350
341
  expect(vapp).to receive(:power_off)
351
342
  expect(vapp).to receive(:delete)
352
343
  expect(client).not_to receive(:delete_catalog_by_name).with(vapp_catalog)
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: vm_shepherd
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.10.1
4
+ version: 1.11.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ops Manager Team
@@ -168,9 +168,13 @@ files:
168
168
  - ci/run_specs.sh
169
169
  - lib/vm_shepherd.rb
170
170
  - lib/vm_shepherd/aws_manager.rb
171
+ - lib/vm_shepherd/data_object.rb
171
172
  - lib/vm_shepherd/openstack_manager.rb
172
173
  - lib/vm_shepherd/retry_helper.rb
173
174
  - lib/vm_shepherd/shepherd.rb
175
+ - lib/vm_shepherd/vcloud/deployer.rb
176
+ - lib/vm_shepherd/vcloud/destroyer.rb
177
+ - lib/vm_shepherd/vcloud/vapp_config.rb
174
178
  - lib/vm_shepherd/vcloud_manager.rb
175
179
  - lib/vm_shepherd/version.rb
176
180
  - lib/vm_shepherd/vsphere_manager.rb
@@ -184,9 +188,13 @@ files:
184
188
  - spec/spec_helper.rb
185
189
  - spec/support/patched_fog.rb
186
190
  - spec/vm_shepherd/aws_manager_spec.rb
191
+ - spec/vm_shepherd/data_object_spec.rb
187
192
  - spec/vm_shepherd/openstack_manager_spec.rb
188
193
  - spec/vm_shepherd/retry_helper_spec.rb
189
194
  - spec/vm_shepherd/shepherd_spec.rb
195
+ - spec/vm_shepherd/vcloud/deployer_spec.rb
196
+ - spec/vm_shepherd/vcloud/destroyer_spec.rb
197
+ - spec/vm_shepherd/vcloud/vapp_config_spec.rb
190
198
  - spec/vm_shepherd/vcloud_manager_spec.rb
191
199
  - spec/vm_shepherd/vsphere_manager_spec.rb
192
200
  - vm_shepherd.gemspec
@@ -209,7 +217,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
209
217
  version: '0'
210
218
  requirements: []
211
219
  rubyforge_project:
212
- rubygems_version: 2.4.6
220
+ rubygems_version: 2.4.7
213
221
  signing_key:
214
222
  specification_version: 4
215
223
  summary: A tool for booting and tearing down Ops Manager VMs on various Infrastructures.
@@ -224,8 +232,12 @@ test_files:
224
232
  - spec/spec_helper.rb
225
233
  - spec/support/patched_fog.rb
226
234
  - spec/vm_shepherd/aws_manager_spec.rb
235
+ - spec/vm_shepherd/data_object_spec.rb
227
236
  - spec/vm_shepherd/openstack_manager_spec.rb
228
237
  - spec/vm_shepherd/retry_helper_spec.rb
229
238
  - spec/vm_shepherd/shepherd_spec.rb
239
+ - spec/vm_shepherd/vcloud/deployer_spec.rb
240
+ - spec/vm_shepherd/vcloud/destroyer_spec.rb
241
+ - spec/vm_shepherd/vcloud/vapp_config_spec.rb
230
242
  - spec/vm_shepherd/vcloud_manager_spec.rb
231
243
  - spec/vm_shepherd/vsphere_manager_spec.rb