vmpooler 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ %w[base dummy vsphere].each do |lib|
2
+ begin
3
+ require "vmpooler/providers/#{lib}"
4
+ rescue LoadError
5
+ require File.expand_path(File.join(File.dirname(__FILE__), 'providers', lib))
6
+ end
7
+ end
@@ -0,0 +1,231 @@
1
+ module Vmpooler
2
+ class PoolManager
3
+ class Provider
4
+ class Base
5
+ # These defs must be overidden in child classes
6
+
7
+ # Helper Methods
8
+ # Global Logger object
9
+ attr_reader :logger
10
+ # Global Metrics object
11
+ attr_reader :metrics
12
+ # Provider options passed in during initialization
13
+ attr_reader :provider_options
14
+
15
+ def initialize(config, logger, metrics, name, options)
16
+ @config = config
17
+ @logger = logger
18
+ @metrics = metrics
19
+ @provider_name = name
20
+
21
+ # Ensure that there is not a nil provider configuration
22
+ @config[:providers] = {} if @config[:providers].nil?
23
+ @config[:providers][@provider_name] = {} if provider_config.nil?
24
+
25
+ # Ensure that there is not a nil pool configuration
26
+ @config[:pools] = {} if @config[:pools].nil?
27
+
28
+ @provider_options = options
29
+ logger.log('s', "[!] Creating provider '#{name}'")
30
+ end
31
+
32
+ # Helper Methods
33
+
34
+ # inputs
35
+ # [String] pool_name : Name of the pool to get the configuration
36
+ # returns
37
+ # [Hashtable] : The pools configuration from the config file. Returns nil if the pool does not exist
38
+ def pool_config(pool_name)
39
+ # Get the configuration of a specific pool
40
+ @config[:pools].each do |pool|
41
+ return pool if pool['name'] == pool_name
42
+ end
43
+
44
+ nil
45
+ end
46
+
47
+ # returns
48
+ # [Hashtable] : This provider's configuration from the config file. Returns nil if the provider does not exist
49
+ def provider_config
50
+ @config[:providers].each do |provider|
51
+ # Convert the symbol from the config into a string for comparison
52
+ return (provider[1].nil? ? {} : provider[1]) if provider[0].to_s == @provider_name
53
+ end
54
+
55
+ nil
56
+ end
57
+
58
+ # returns
59
+ # [Hashtable] : The entire VMPooler configuration
60
+ def global_config
61
+ # This entire VM Pooler config
62
+ @config
63
+ end
64
+
65
+ # returns
66
+ # [String] : Name of the provider service
67
+ def name
68
+ @provider_name
69
+ end
70
+
71
+ # returns
72
+ # Array[String] : Array of pool names this provider services
73
+ def provided_pools
74
+ list = []
75
+ @config[:pools].each do |pool|
76
+ list << pool['name'] if pool['provider'] == name
77
+ end
78
+ list
79
+ end
80
+
81
+ # Pool Manager Methods
82
+
83
+ # inputs
84
+ # [String] pool_name : Name of the pool
85
+ # returns
86
+ # Array[Hashtable]
87
+ # Hash contains:
88
+ # 'name' => [String] Name of VM
89
+ def vms_in_pool(_pool_name)
90
+ raise("#{self.class.name} does not implement vms_in_pool")
91
+ end
92
+
93
+ # inputs
94
+ # [String]pool_name : Name of the pool
95
+ # [String] vm_name : Name of the VM
96
+ # returns
97
+ # [String] : Name of the host computer running the vm. If this is not a Virtual Machine, it returns the vm_name
98
+ def get_vm_host(_pool_name, _vm_name)
99
+ raise("#{self.class.name} does not implement get_vm_host")
100
+ end
101
+
102
+ # inputs
103
+ # [String] pool_name : Name of the pool
104
+ # [String] vm_name : Name of the VM
105
+ # returns
106
+ # [String] : Name of the most appropriate host computer to run this VM. Useful for load balancing VMs in a cluster
107
+ # If this is not a Virtual Machine, it returns the vm_name
108
+ def find_least_used_compatible_host(_pool_name, _vm_name)
109
+ raise("#{self.class.name} does not implement find_least_used_compatible_host")
110
+ end
111
+
112
+ # inputs
113
+ # [String] pool_name : Name of the pool
114
+ # [String] vm_name : Name of the VM to migrate
115
+ # [String] dest_host_name : Name of the host to migrate `vm_name` to
116
+ # returns
117
+ # [Boolean] : true on success or false on failure
118
+ def migrate_vm_to_host(_pool_name, _vm_name, _dest_host_name)
119
+ raise("#{self.class.name} does not implement migrate_vm_to_host")
120
+ end
121
+
122
+ # inputs
123
+ # [String] pool_name : Name of the pool
124
+ # [String] vm_name : Name of the VM to migrate
125
+ # [Class] redis : Redis object
126
+ def migrate_vm(_pool_name, _vm_name, _redis)
127
+ raise("#{self.class.name} does not implement migrate_vm")
128
+ end
129
+
130
+ # inputs
131
+ # [String] pool_name : Name of the pool
132
+ # [String] vm_name : Name of the VM to find
133
+ # returns
134
+ # nil if VM doesn't exist
135
+ # [Hastable] of the VM
136
+ # [String] name : Name of the VM
137
+ # [String] hostname : Name reported by Vmware tools (host.summary.guest.hostName)
138
+ # [String] template : This is the name of template exposed by the API. It must _match_ the poolname
139
+ # [String] poolname : Name of the pool the VM is located
140
+ # [Time] boottime : Time when the VM was created/booted
141
+ # [String] powerstate : Current power state of a VM. Valid values (as per vCenter API)
142
+ # - 'PoweredOn','PoweredOff'
143
+ def get_vm(_pool_name, _vm_name)
144
+ raise("#{self.class.name} does not implement get_vm")
145
+ end
146
+
147
+ # inputs
148
+ # [String] pool : Name of the pool
149
+ # [String] new_vmname : Name to give the new VM
150
+ # returns
151
+ # [Hashtable] of the VM as per get_vm
152
+ # Raises RuntimeError if the pool_name is not supported by the Provider
153
+ def create_vm(_pool_name, _new_vmname)
154
+ raise("#{self.class.name} does not implement create_vm")
155
+ end
156
+
157
+ # inputs
158
+ # [String] pool_name : Name of the pool
159
+ # [String] vm_name : Name of the VM to create the disk on
160
+ # [Integer] disk_size : Size of the disk to create in Gigabytes (GB)
161
+ # returns
162
+ # [Boolean] : true if success, false if disk could not be created
163
+ # Raises RuntimeError if the Pool does not exist
164
+ # Raises RuntimeError if the VM does not exist
165
+ def create_disk(_pool_name, _vm_name, _disk_size)
166
+ raise("#{self.class.name} does not implement create_disk")
167
+ end
168
+
169
+ # inputs
170
+ # [String] pool_name : Name of the pool
171
+ # [String] new_vmname : Name of the VM to create the snapshot on
172
+ # [String] new_snapshot_name : Name of the new snapshot to create
173
+ # returns
174
+ # [Boolean] : true if success, false if snapshot could not be created
175
+ # Raises RuntimeError if the Pool does not exist
176
+ # Raises RuntimeError if the VM does not exist
177
+ def create_snapshot(_pool_name, _vm_name, _new_snapshot_name)
178
+ raise("#{self.class.name} does not implement create_snapshot")
179
+ end
180
+
181
+ # inputs
182
+ # [String] pool_name : Name of the pool
183
+ # [String] new_vmname : Name of the VM to restore
184
+ # [String] snapshot_name : Name of the snapshot to restore to
185
+ # returns
186
+ # [Boolean] : true if success, false if snapshot could not be revertted
187
+ # Raises RuntimeError if the Pool does not exist
188
+ # Raises RuntimeError if the VM does not exist
189
+ # Raises RuntimeError if the snapshot does not exist
190
+ def revert_snapshot(_pool_name, _vm_name, _snapshot_name)
191
+ raise("#{self.class.name} does not implement revert_snapshot")
192
+ end
193
+
194
+ # inputs
195
+ # [String] pool_name : Name of the pool
196
+ # [String] vm_name : Name of the VM to destroy
197
+ # returns
198
+ # [Boolean] : true if success, false on error. Should returns true if the VM is missing
199
+ def destroy_vm(_pool_name, _vm_name)
200
+ raise("#{self.class.name} does not implement destroy_vm")
201
+ end
202
+
203
+ # inputs
204
+ # [String] pool_name : Name of the pool
205
+ # [String] vm_name : Name of the VM to check if ready
206
+ # returns
207
+ # [Boolean] : true if ready, false if not
208
+ def vm_ready?(_pool_name, _vm_name)
209
+ raise("#{self.class.name} does not implement vm_ready?")
210
+ end
211
+
212
+ # inputs
213
+ # [String] pool_name : Name of the pool
214
+ # [String] vm_name : Name of the VM to check if it exists
215
+ # returns
216
+ # [Boolean] : true if it exists, false if not
217
+ def vm_exists?(pool_name, vm_name)
218
+ !get_vm(pool_name, vm_name).nil?
219
+ end
220
+
221
+ # inputs
222
+ # [Hash] pool : Configuration for the pool
223
+ # returns
224
+ # nil when successful. Raises error when encountered
225
+ def create_template_delta_disks(pool)
226
+ raise("#{self.class.name} does not implement create_template_delta_disks")
227
+ end
228
+ end
229
+ end
230
+ end
231
+ end
@@ -0,0 +1,402 @@
1
+ require 'yaml'
2
+
3
+ module Vmpooler
4
+ class PoolManager
5
+ class Provider
6
+ class Dummy < Vmpooler::PoolManager::Provider::Base
7
+ # Fake VM Provider for testing
8
+
9
+ def initialize(config, logger, metrics, name, options)
10
+ super(config, logger, metrics, name, options)
11
+ dummyfilename = provider_config['filename']
12
+
13
+ # This initial_state option is only intended to be used by spec tests
14
+ @dummylist = provider_options['initial_state'].nil? ? {} : provider_options['initial_state']
15
+
16
+ @dummylist = YAML.load_file(dummyfilename) if !dummyfilename.nil? && File.exist?(dummyfilename)
17
+
18
+ # Even though this code is using Mutexes, it's still no 100% atomic i.e. it's still possible for
19
+ # duplicate actions to put the @dummylist hashtable into a bad state, for example;
20
+ # Deleting a VM while it's in the middle of adding a disk.
21
+ @write_lock = Mutex.new
22
+
23
+ # Create a dummy connection pool
24
+ connpool_size = provider_config['connection_pool_size'].nil? ? 1 : provider_config['connection_pool_size'].to_i
25
+ connpool_timeout = provider_config['connection_pool_timeout'].nil? ? 10 : provider_config['connection_pool_timeout'].to_i
26
+ logger.log('d', "[#{name}] ConnPool - Creating a connection pool of size #{connpool_size} with timeout #{connpool_timeout}")
27
+ @connection_pool = Vmpooler::PoolManager::GenericConnectionPool.new(
28
+ metrics: metrics,
29
+ metric_prefix: "#{name}_provider_connection_pool",
30
+ size: connpool_size,
31
+ timeout: connpool_timeout
32
+ ) do
33
+ # Create a mock connection object
34
+ new_conn = { create_timestamp: Time.now, conn_id: rand(2048).to_s }
35
+ logger.log('d', "[#{name}] ConnPool - Creating a connection object ID #{new_conn[:conn_id]}")
36
+ new_conn
37
+ end
38
+ end
39
+
40
+ def name
41
+ 'dummy'
42
+ end
43
+
44
+ def vms_in_pool(pool_name)
45
+ vmlist = []
46
+
47
+ @connection_pool.with_metrics do |_conn|
48
+ get_dummy_pool_object(pool_name).each do |vm|
49
+ vmlist << { 'name' => vm['name'] }
50
+ end
51
+ end
52
+
53
+ vmlist
54
+ end
55
+
56
+ def get_vm_host(pool_name, vm_name)
57
+ current_vm = nil
58
+ @connection_pool.with_metrics do |_conn|
59
+ current_vm = get_dummy_vm(pool_name, vm_name)
60
+ end
61
+
62
+ current_vm.nil? ? raise("VM #{vm_name} does not exist") : current_vm['vm_host']
63
+ end
64
+
65
+ def find_least_used_compatible_host(pool_name, vm_name)
66
+ current_vm = nil
67
+ @connection_pool.with_metrics do |_conn|
68
+ current_vm = get_dummy_vm(pool_name, vm_name)
69
+ end
70
+
71
+ # Unless migratevm_couldmove_percent is specified, don't migrate
72
+ return current_vm['vm_host'] if provider_config['migratevm_couldmove_percent'].nil?
73
+
74
+ # Only migrate if migratevm_couldmove_percent is met
75
+ return current_vm['vm_host'] if 1 + rand(100) > provider_config['migratevm_couldmove_percent']
76
+
77
+ # Simulate a 10 node cluster and randomly pick a different one
78
+ new_host = 'HOST' + (1 + rand(10)).to_s while new_host == current_vm['vm_host']
79
+
80
+ new_host
81
+ end
82
+
83
+ def migrate_vm_to_host(pool_name, vm_name, dest_host_name)
84
+ @connection_pool.with_metrics do |_conn|
85
+ current_vm = get_dummy_vm(pool_name, vm_name)
86
+
87
+ # Inject migration delay
88
+ unless provider_config['migratevm_max_time'].nil?
89
+ migrate_time = 1 + rand(provider_config['migratevm_max_time'])
90
+ sleep(migrate_time)
91
+ end
92
+
93
+ # Inject clone failure
94
+ unless provider_config['migratevm_fail_percent'].nil?
95
+ raise('Dummy Failure for migratevm_fail_percent') if 1 + rand(100) <= provider_config['migratevm_fail_percent']
96
+ end
97
+
98
+ @write_lock.synchronize do
99
+ current_vm = get_dummy_vm(pool_name, vm_name)
100
+ current_vm['vm_host'] = dest_host_name
101
+ write_backing_file
102
+ end
103
+ end
104
+
105
+ true
106
+ end
107
+
108
+ def get_vm(pool_name, vm_name)
109
+ obj = {}
110
+ @connection_pool.with_metrics do |_conn|
111
+ dummy = get_dummy_vm(pool_name, vm_name)
112
+ return nil if dummy.nil?
113
+
114
+ # Randomly power off the VM
115
+ unless dummy['powerstate'] != 'PoweredOn' || provider_config['getvm_poweroff_percent'].nil?
116
+ if 1 + rand(100) <= provider_config['getvm_poweroff_percent']
117
+ @write_lock.synchronize do
118
+ dummy = get_dummy_vm(pool_name, vm_name)
119
+ dummy['powerstate'] = 'PoweredOff'
120
+ write_backing_file
121
+ end
122
+ logger.log('d', "[ ] [#{dummy['poolname']}] '#{dummy['name']}' is being Dummy Powered Off")
123
+ end
124
+ end
125
+
126
+ # Randomly rename the host
127
+ unless dummy['hostname'] != dummy['name'] || provider_config['getvm_rename_percent'].nil?
128
+ if 1 + rand(100) <= provider_config['getvm_rename_percent']
129
+ @write_lock.synchronize do
130
+ dummy = get_dummy_vm(pool_name, vm_name)
131
+ dummy['hostname'] = 'DUMMY' + dummy['name']
132
+ write_backing_file
133
+ end
134
+ logger.log('d', "[ ] [#{dummy['poolname']}] '#{dummy['name']}' is being Dummy renamed")
135
+ end
136
+ end
137
+
138
+ obj['name'] = dummy['name']
139
+ obj['hostname'] = dummy['hostname']
140
+ obj['boottime'] = dummy['boottime']
141
+ obj['template'] = dummy['template']
142
+ obj['poolname'] = dummy['poolname']
143
+ obj['powerstate'] = dummy['powerstate']
144
+ obj['snapshots'] = dummy['snapshots']
145
+ end
146
+
147
+ obj
148
+ end
149
+
150
+ def create_vm(pool_name, dummy_hostname)
151
+ pool = pool_config(pool_name)
152
+ raise("Pool #{pool_name} does not exist for the provider #{name}") if pool.nil?
153
+
154
+ template_name = pool['template']
155
+
156
+ vm = {}
157
+ vm['name'] = dummy_hostname
158
+ vm['hostname'] = dummy_hostname
159
+ vm['domain'] = 'dummy.local'
160
+ # 'vm_template' is the name of the template to use to clone the VM from <----- Do we need this?!?!?
161
+ vm['vm_template'] = template_name
162
+ # 'template' is the Template name in VM Pooler API, in our case that's the poolname.
163
+ vm['template'] = pool_name
164
+ vm['poolname'] = pool_name
165
+ vm['ready'] = false
166
+ vm['boottime'] = Time.now
167
+ vm['powerstate'] = 'PoweredOn'
168
+ vm['vm_host'] = 'HOST1'
169
+ vm['dummy_state'] = 'UNKNOWN'
170
+ vm['snapshots'] = []
171
+ vm['disks'] = []
172
+
173
+ # Make sure the pool exists in the dummy list
174
+ @write_lock.synchronize do
175
+ get_dummy_pool_object(pool_name)
176
+ @dummylist['pool'][pool_name] << vm
177
+ write_backing_file
178
+ end
179
+
180
+ logger.log('d', "[ ] [#{pool_name}] '#{dummy_hostname}' is being cloned from '#{template_name}'")
181
+
182
+ @connection_pool.with_metrics do |_conn|
183
+ # Inject clone time delay
184
+ unless provider_config['createvm_max_time'].nil?
185
+ @write_lock.synchronize do
186
+ vm['dummy_state'] = 'CLONING'
187
+ write_backing_file
188
+ end
189
+ clone_time = 1 + rand(provider_config['createvm_max_time'])
190
+ sleep(clone_time)
191
+ end
192
+
193
+ begin
194
+ # Inject clone failure
195
+ unless provider_config['createvm_fail_percent'].nil?
196
+ raise('Dummy Failure for createvm_fail_percent') if 1 + rand(100) <= provider_config['createvm_fail_percent']
197
+ end
198
+
199
+ # Assert the VM is ready for use
200
+ @write_lock.synchronize do
201
+ vm['dummy_state'] = 'RUNNING'
202
+ write_backing_file
203
+ end
204
+ rescue => _err
205
+ @write_lock.synchronize do
206
+ remove_dummy_vm(pool_name, dummy_hostname)
207
+ write_backing_file
208
+ end
209
+ raise
210
+ end
211
+ end
212
+
213
+ get_vm(pool_name, dummy_hostname)
214
+ end
215
+
216
+ def create_disk(pool_name, vm_name, disk_size)
217
+ @connection_pool.with_metrics do |_conn|
218
+ vm_object = get_dummy_vm(pool_name, vm_name)
219
+ raise("VM #{vm_name} does not exist in Pool #{pool_name} for the provider #{name}") if vm_object.nil?
220
+
221
+ # Inject create time delay
222
+ unless provider_config['createdisk_max_time'].nil?
223
+ delay = 1 + rand(provider_config['createdisk_max_time'])
224
+ sleep(delay)
225
+ end
226
+
227
+ # Inject create failure
228
+ unless provider_config['createdisk_fail_percent'].nil?
229
+ raise('Dummy Failure for createdisk_fail_percent') if 1 + rand(100) <= provider_config['createdisk_fail_percent']
230
+ end
231
+
232
+ @write_lock.synchronize do
233
+ vm_object = get_dummy_vm(pool_name, vm_name)
234
+ vm_object['disks'] << disk_size
235
+ write_backing_file
236
+ end
237
+ end
238
+
239
+ true
240
+ end
241
+
242
+ def create_snapshot(pool_name, vm_name, snapshot_name)
243
+ @connection_pool.with_metrics do |_conn|
244
+ vm_object = get_dummy_vm(pool_name, vm_name)
245
+ raise("VM #{vm_name} does not exist in Pool #{pool_name} for the provider #{name}") if vm_object.nil?
246
+
247
+ # Inject create time delay
248
+ unless provider_config['createsnapshot_max_time'].nil?
249
+ delay = 1 + rand(provider_config['createsnapshot_max_time'])
250
+ sleep(delay)
251
+ end
252
+
253
+ # Inject create failure
254
+ unless provider_config['createsnapshot_fail_percent'].nil?
255
+ raise('Dummy Failure for createsnapshot_fail_percent') if 1 + rand(100) <= provider_config['createsnapshot_fail_percent']
256
+ end
257
+
258
+ @write_lock.synchronize do
259
+ vm_object = get_dummy_vm(pool_name, vm_name)
260
+ vm_object['snapshots'] << snapshot_name
261
+ write_backing_file
262
+ end
263
+ end
264
+
265
+ true
266
+ end
267
+
268
+ def revert_snapshot(pool_name, vm_name, snapshot_name)
269
+ vm_object = nil
270
+ @connection_pool.with_metrics do |_conn|
271
+ vm_object = get_dummy_vm(pool_name, vm_name)
272
+ raise("VM #{vm_name} does not exist in Pool #{pool_name} for the provider #{name}") if vm_object.nil?
273
+
274
+ # Inject create time delay
275
+ unless provider_config['revertsnapshot_max_time'].nil?
276
+ delay = 1 + rand(provider_config['revertsnapshot_max_time'])
277
+ sleep(delay)
278
+ end
279
+
280
+ # Inject create failure
281
+ unless provider_config['revertsnapshot_fail_percent'].nil?
282
+ raise('Dummy Failure for revertsnapshot_fail_percent') if 1 + rand(100) <= provider_config['revertsnapshot_fail_percent']
283
+ end
284
+ end
285
+
286
+ vm_object['snapshots'].include?(snapshot_name)
287
+ end
288
+
289
+ def destroy_vm(pool_name, vm_name)
290
+ @connection_pool.with_metrics do |_conn|
291
+ vm = get_dummy_vm(pool_name, vm_name)
292
+ return false if vm.nil?
293
+ return false if vm['poolname'] != pool_name
294
+
295
+ # Shutdown down the VM if it's poweredOn
296
+ if vm['powerstate'] == 'PoweredOn'
297
+ logger.log('d', "[ ] [#{pool_name}] '#{vm_name}' is being shut down")
298
+
299
+ # Inject shutdown delay time
300
+ unless provider_config['destroyvm_max_shutdown_time'].nil?
301
+ shutdown_time = 1 + rand(provider_config['destroyvm_max_shutdown_time'])
302
+ sleep(shutdown_time)
303
+ end
304
+
305
+ @write_lock.synchronize do
306
+ vm = get_dummy_vm(pool_name, vm_name)
307
+ vm['powerstate'] = 'PoweredOff'
308
+ write_backing_file
309
+ end
310
+ end
311
+
312
+ # Inject destroy VM delay
313
+ unless provider_config['destroyvm_max_time'].nil?
314
+ destroy_time = 1 + rand(provider_config['destroyvm_max_time'])
315
+ sleep(destroy_time)
316
+ end
317
+
318
+ # Inject destroy VM failure
319
+ unless provider_config['destroyvm_fail_percent'].nil?
320
+ raise('Dummy Failure for migratevm_fail_percent') if 1 + rand(100) <= provider_config['destroyvm_fail_percent']
321
+ end
322
+
323
+ # 'Destroy' the VM
324
+ @write_lock.synchronize do
325
+ remove_dummy_vm(pool_name, vm_name)
326
+ write_backing_file
327
+ end
328
+ end
329
+
330
+ true
331
+ end
332
+
333
+ def vm_ready?(pool_name, vm_name)
334
+ @connection_pool.with_metrics do |_conn|
335
+ vm_object = get_dummy_vm(pool_name, vm_name)
336
+ return false if vm_object.nil?
337
+ return false if vm_object['poolname'] != pool_name
338
+ return true if vm_object['ready']
339
+
340
+ timeout = provider_config['is_ready_timeout'] || 5
341
+
342
+ Timeout.timeout(timeout) do
343
+ while vm_object['dummy_state'] != 'RUNNING'
344
+ sleep(2)
345
+ vm_object = get_dummy_vm(pool_name, vm_name)
346
+ end
347
+ end
348
+
349
+ # Simulate how long it takes from a VM being powered on until
350
+ # it's ready to receive a connection
351
+ sleep(2)
352
+
353
+ unless provider_config['vmready_fail_percent'].nil?
354
+ raise('Dummy Failure for vmready_fail_percent') if 1 + rand(100) <= provider_config['vmready_fail_percent']
355
+ end
356
+
357
+ @write_lock.synchronize do
358
+ vm_object['ready'] = true
359
+ write_backing_file
360
+ end
361
+ end
362
+
363
+ true
364
+ end
365
+
366
+ private
367
+
368
+ # Note - NEVER EVER use the @write_lock object in the private methods!!!! Deadlocks will ensue
369
+
370
+ def remove_dummy_vm(pool_name, vm_name)
371
+ return if @dummylist['pool'][pool_name].nil?
372
+ new_poollist = @dummylist['pool'][pool_name].delete_if { |vm| vm['name'] == vm_name }
373
+ @dummylist['pool'][pool_name] = new_poollist
374
+ end
375
+
376
+ # Get's the pool config safely from the in-memory hashtable
377
+ def get_dummy_pool_object(pool_name)
378
+ @dummylist['pool'] = {} if @dummylist['pool'].nil?
379
+ @dummylist['pool'][pool_name] = [] if @dummylist['pool'][pool_name].nil?
380
+
381
+ @dummylist['pool'][pool_name]
382
+ end
383
+
384
+ def get_dummy_vm(pool_name, vm_name)
385
+ return nil if @dummylist['pool'][pool_name].nil?
386
+
387
+ @dummylist['pool'][pool_name].each do |poolvm|
388
+ return poolvm if poolvm['name'] == vm_name
389
+ end
390
+
391
+ nil
392
+ end
393
+
394
+ def write_backing_file
395
+ dummyfilename = provider_config['filename']
396
+ return if dummyfilename.nil?
397
+ File.open(dummyfilename, 'w') { |file| file.write(YAML.dump(@dummylist)) }
398
+ end
399
+ end
400
+ end
401
+ end
402
+ end