vmpooler 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.
@@ -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