vagrant-libvirt 0.0.41 → 0.0.42

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.
Files changed (81) hide show
  1. checksums.yaml +4 -4
  2. data/.coveralls.yml +1 -0
  3. data/.github/issue_template.md +37 -0
  4. data/.gitignore +21 -0
  5. data/.travis.yml +24 -0
  6. data/Gemfile +26 -0
  7. data/LICENSE +22 -0
  8. data/README.md +1380 -0
  9. data/Rakefile +8 -0
  10. data/example_box/README.md +29 -0
  11. data/example_box/Vagrantfile +60 -0
  12. data/example_box/metadata.json +5 -0
  13. data/lib/vagrant-libvirt.rb +29 -0
  14. data/lib/vagrant-libvirt/action.rb +370 -0
  15. data/lib/vagrant-libvirt/action/create_domain.rb +322 -0
  16. data/lib/vagrant-libvirt/action/create_domain_volume.rb +87 -0
  17. data/lib/vagrant-libvirt/action/create_network_interfaces.rb +302 -0
  18. data/lib/vagrant-libvirt/action/create_networks.rb +361 -0
  19. data/lib/vagrant-libvirt/action/destroy_domain.rb +83 -0
  20. data/lib/vagrant-libvirt/action/destroy_networks.rb +95 -0
  21. data/lib/vagrant-libvirt/action/forward_ports.rb +227 -0
  22. data/lib/vagrant-libvirt/action/halt_domain.rb +41 -0
  23. data/lib/vagrant-libvirt/action/handle_box_image.rb +156 -0
  24. data/lib/vagrant-libvirt/action/handle_storage_pool.rb +57 -0
  25. data/lib/vagrant-libvirt/action/is_created.rb +18 -0
  26. data/lib/vagrant-libvirt/action/is_running.rb +21 -0
  27. data/lib/vagrant-libvirt/action/is_suspended.rb +42 -0
  28. data/lib/vagrant-libvirt/action/message_already_created.rb +16 -0
  29. data/lib/vagrant-libvirt/action/message_not_created.rb +16 -0
  30. data/lib/vagrant-libvirt/action/message_not_running.rb +16 -0
  31. data/lib/vagrant-libvirt/action/message_not_suspended.rb +16 -0
  32. data/lib/vagrant-libvirt/action/message_will_not_destroy.rb +17 -0
  33. data/lib/vagrant-libvirt/action/package_domain.rb +105 -0
  34. data/lib/vagrant-libvirt/action/prepare_nfs_settings.rb +94 -0
  35. data/lib/vagrant-libvirt/action/prepare_nfs_valid_ids.rb +17 -0
  36. data/lib/vagrant-libvirt/action/prune_nfs_exports.rb +27 -0
  37. data/lib/vagrant-libvirt/action/read_mac_addresses.rb +40 -0
  38. data/lib/vagrant-libvirt/action/remove_libvirt_image.rb +20 -0
  39. data/lib/vagrant-libvirt/action/remove_stale_volume.rb +50 -0
  40. data/lib/vagrant-libvirt/action/resume_domain.rb +34 -0
  41. data/lib/vagrant-libvirt/action/set_boot_order.rb +109 -0
  42. data/lib/vagrant-libvirt/action/set_name_of_domain.rb +64 -0
  43. data/lib/vagrant-libvirt/action/share_folders.rb +71 -0
  44. data/lib/vagrant-libvirt/action/start_domain.rb +307 -0
  45. data/lib/vagrant-libvirt/action/suspend_domain.rb +40 -0
  46. data/lib/vagrant-libvirt/action/wait_till_up.rb +109 -0
  47. data/lib/vagrant-libvirt/cap/mount_p9.rb +42 -0
  48. data/lib/vagrant-libvirt/cap/nic_mac_addresses.rb +17 -0
  49. data/lib/vagrant-libvirt/cap/synced_folder.rb +113 -0
  50. data/lib/vagrant-libvirt/config.rb +746 -0
  51. data/lib/vagrant-libvirt/driver.rb +118 -0
  52. data/lib/vagrant-libvirt/errors.rb +153 -0
  53. data/lib/vagrant-libvirt/plugin.rb +92 -0
  54. data/lib/vagrant-libvirt/provider.rb +130 -0
  55. data/lib/vagrant-libvirt/templates/default_storage_pool.xml.erb +13 -0
  56. data/lib/vagrant-libvirt/templates/domain.xml.erb +244 -0
  57. data/lib/vagrant-libvirt/templates/private_network.xml.erb +42 -0
  58. data/lib/vagrant-libvirt/templates/public_interface.xml.erb +26 -0
  59. data/lib/vagrant-libvirt/util.rb +11 -0
  60. data/lib/vagrant-libvirt/util/collection.rb +19 -0
  61. data/lib/vagrant-libvirt/util/erb_template.rb +22 -0
  62. data/lib/vagrant-libvirt/util/error_codes.rb +100 -0
  63. data/lib/vagrant-libvirt/util/network_util.rb +151 -0
  64. data/lib/vagrant-libvirt/util/timer.rb +17 -0
  65. data/lib/vagrant-libvirt/version.rb +5 -0
  66. data/locales/en.yml +162 -0
  67. data/spec/spec_helper.rb +9 -0
  68. data/spec/support/environment_helper.rb +46 -0
  69. data/spec/support/libvirt_context.rb +30 -0
  70. data/spec/support/sharedcontext.rb +34 -0
  71. data/spec/unit/action/destroy_domain_spec.rb +97 -0
  72. data/spec/unit/action/set_name_of_domain_spec.rb +21 -0
  73. data/spec/unit/action/wait_till_up_spec.rb +127 -0
  74. data/spec/unit/config_spec.rb +113 -0
  75. data/spec/unit/templates/domain_all_settings.xml +137 -0
  76. data/spec/unit/templates/domain_defaults.xml +46 -0
  77. data/spec/unit/templates/domain_spec.rb +84 -0
  78. data/tools/create_box.sh +130 -0
  79. data/tools/prepare_redhat_for_box.sh +119 -0
  80. data/vagrant-libvirt.gemspec +54 -0
  81. metadata +93 -3
@@ -0,0 +1,361 @@
1
+ require 'log4r'
2
+ require 'vagrant/util/network_ip'
3
+ require 'vagrant/util/scoped_hash_override'
4
+ require 'ipaddr'
5
+ require 'thread'
6
+
7
+ module VagrantPlugins
8
+ module ProviderLibvirt
9
+ module Action
10
+ # Prepare all networks needed for domain connections.
11
+ class CreateNetworks
12
+ include Vagrant::Util::NetworkIP
13
+ include Vagrant::Util::ScopedHashOverride
14
+ include VagrantPlugins::ProviderLibvirt::Util::ErbTemplate
15
+ include VagrantPlugins::ProviderLibvirt::Util::NetworkUtil
16
+
17
+ @@lock = Mutex.new
18
+
19
+ def initialize(app, env)
20
+ mess = 'vagrant_libvirt::action::create_networks'
21
+ @logger = Log4r::Logger.new(mess)
22
+ @app = app
23
+
24
+ @available_networks = []
25
+ @options = {}
26
+ @libvirt_client = env[:machine].provider.driver.connection.client
27
+ end
28
+
29
+ def call(env)
30
+ # only one vm at a time should try to set up networks
31
+ # otherwise they'll have inconsitent views of current state
32
+ # and conduct redundant operations that cause errors
33
+ @@lock.synchronize do
34
+ # Iterate over networks If some network is not
35
+ # available, create it if possible. Otherwise raise an error.
36
+ configured_networks(env, @logger).each do |options|
37
+ # Only need to create private networks
38
+ next if options[:iface_type] != :private_network ||
39
+ options.fetch(:tunnel_type, nil)
40
+ @logger.debug "Searching for network with options #{options}"
41
+
42
+ # should fix other methods so this doesn't have to be instance var
43
+ @options = options
44
+
45
+ # Get a list of all (active and inactive) libvirt networks. This
46
+ # list is used throughout this class and should be easier to
47
+ # process than libvirt API calls.
48
+ @available_networks = libvirt_networks(
49
+ env[:machine].provider.driver.connection.client
50
+ )
51
+
52
+ # Prepare a hash describing network for this specific interface.
53
+ @interface_network = {
54
+ name: nil,
55
+ ip_address: nil,
56
+ netmask: @options[:netmask],
57
+ network_address: nil,
58
+ bridge_name: nil,
59
+ domain_name: nil,
60
+ ipv6_address: options[:ipv6_address] || nil,
61
+ ipv6_prefix: options[:ipv6_prefix] || nil,
62
+ created: false,
63
+ active: false,
64
+ autostart: options[:autostart] || false,
65
+ guest_ipv6: @options[:guest_ipv6] || 'yes',
66
+ libvirt_network: nil
67
+ }
68
+
69
+ if @options[:ip]
70
+ handle_ip_option(env)
71
+ elsif @options[:type].to_s == 'dhcp'
72
+ handle_dhcp_private_network(env)
73
+ elsif @options[:network_name]
74
+ handle_network_name_option(env)
75
+ else
76
+ raise Errors::CreateNetworkError, error_message: @options
77
+ end
78
+
79
+ autostart_network if @interface_network[:autostart]
80
+ activate_network unless @interface_network[:active]
81
+ end
82
+ end
83
+
84
+ @app.call(env)
85
+ end
86
+
87
+ private
88
+
89
+ def lookup_network_by_ip(ip)
90
+ @logger.debug "looking up network with ip == #{ip}"
91
+ @available_networks.find { |network| network[:network_address] == ip }
92
+ end
93
+
94
+ # Return hash of network for specified name, or nil if not found.
95
+ def lookup_network_by_name(network_name)
96
+ @logger.debug "looking up network named #{network_name}"
97
+ @available_networks.find { |network| network[:name] == network_name }
98
+ end
99
+
100
+ # Return hash of network for specified bridge, or nil if not found.
101
+ def lookup_bridge_by_name(bridge_name)
102
+ @logger.debug "looking up bridge named #{bridge_name}"
103
+ @available_networks.find { |network| network[:bridge_name] == bridge_name }
104
+ end
105
+
106
+ # Throw an error if dhcp setting for an existing network does not
107
+ # match what was configured in the vagrantfile
108
+ # since we always enable dhcp for the management network
109
+ # this ensures we wont start a vm vagrant cant reach
110
+ # Allow the situation where DHCP is not requested (:libvirt__dhcp_enabled == false)
111
+ # but where it is enabled on the virtual network
112
+ def verify_dhcp
113
+ if @interface_network[:dhcp_enabled] == true && @options[:dhcp_enabled] == false
114
+ raise Errors::DHCPMismatch,
115
+ network_name: @interface_network[:name],
116
+ requested: @options[:dhcp_enabled] ? 'enabled' : 'disabled'
117
+ end
118
+ end
119
+
120
+ # Handle only situations, when ip is specified. Variables @options and
121
+ # @available_networks should be filled before calling this function.
122
+ def handle_ip_option(env)
123
+ return unless @options[:ip]
124
+ net_address = nil
125
+
126
+ unless @options[:forward_mode] == 'veryisolated'
127
+ net_address = network_address(@options[:ip], @options[:netmask])
128
+
129
+ # Set IP address of network (actually bridge). It will be used as
130
+ # gateway address for machines connected to this network.
131
+ @interface_network[:ip_address] = get_host_ip_addr(net_address)
132
+ end
133
+
134
+ @interface_network[:network_address] = net_address
135
+
136
+ # if network is veryisolated, search by name
137
+ network = if @options[:libvirt__forward_mode] == 'veryisolated'
138
+ lookup_network_by_name(@options[:network_name])
139
+ elsif net_address
140
+ # otherwise, search by ip (if set)
141
+ lookup_network_by_ip(net_address)
142
+ else
143
+ # leaving this here to mimic prior behavior. If we get
144
+ # here, something's probably broken.
145
+ lookup_network_by_name(@options[:network_name])
146
+ end
147
+ @interface_network = network if network
148
+
149
+ verify_dhcp if @interface_network[:created]
150
+
151
+ if @options[:network_name]
152
+ @logger.debug 'Checking that network name does not clash with ip'
153
+ if @interface_network[:created]
154
+ # Just check for mismatch error here - if name and ip from
155
+ # config match together.
156
+ if @options[:network_name] != @interface_network[:name]
157
+ raise Errors::NetworkNameAndAddressMismatch,
158
+ ip_address: @options[:ip],
159
+ network_name: @options[:network_name]
160
+ end
161
+ else
162
+ # Network is not created, but name is set. We need to check,
163
+ # whether network name from config doesn't already exist.
164
+ if lookup_network_by_name @options[:network_name]
165
+ raise Errors::NetworkNameAndAddressMismatch,
166
+ ip_address: @options[:ip],
167
+ network_name: @options[:network_name]
168
+ end
169
+
170
+ # Network with 'name' doesn't exist. Set it as name for new
171
+ # network.
172
+ @interface_network[:name] = @options[:network_name]
173
+ end
174
+ end
175
+
176
+ # Do we need to create new network?
177
+ unless @interface_network[:created]
178
+
179
+ # TODO: stop after some loops. Don't create infinite loops.
180
+
181
+ # Is name for new network set? If not, generate a unique one.
182
+ count = 0
183
+ while @interface_network[:name].nil?
184
+ @logger.debug 'generating name for network'
185
+
186
+ # Generate a network name.
187
+ network_name = env[:root_path].basename.to_s.dup
188
+ network_name << count.to_s
189
+ count += 1
190
+
191
+ # Check if network name is unique.
192
+ next if lookup_network_by_name(network_name)
193
+
194
+ @interface_network[:name] = network_name
195
+ end
196
+
197
+ # Generate a unique name for network bridge.
198
+ @interface_network[:bridge_name] = generate_bridge_name
199
+
200
+ # Create a private network.
201
+ create_private_network(env)
202
+ end
203
+ end
204
+
205
+ # Handle network_name option, if ip was not specified. Variables
206
+ # @options and @available_networks should be filled before calling this
207
+ # function.
208
+ def handle_network_name_option(env)
209
+ return if @options[:ip] || \
210
+ !@options[:network_name] || \
211
+ !@options[:libvirt__forward_mode] == 'veryisolated'
212
+
213
+ network = lookup_network_by_name(@options[:network_name])
214
+ @interface_network = network if network
215
+
216
+ if @options[:libvirt__forward_mode] == 'veryisolated'
217
+ # if this interface has a network address, something's wrong.
218
+ if @interface_network[:network_address]
219
+ raise Errors::NetworkNotAvailableError,
220
+ network_name: @options[:network_name]
221
+ end
222
+ else
223
+ if !@interface_network
224
+ raise Errors::NetworkNotAvailableError,
225
+ network_name: @options[:network_name]
226
+ else
227
+ verify_dhcp
228
+ end
229
+ end
230
+
231
+ # Do we need to create new network?
232
+ unless @interface_network[:created]
233
+ @interface_network[:name] = @options[:network_name]
234
+ @interface_network[:ip_address] ||= @options[:host_ip]
235
+
236
+ # Generate a unique name for network bridge.
237
+ @interface_network[:bridge_name] = generate_bridge_name
238
+
239
+ # Create a private network.
240
+ create_private_network(env)
241
+ end
242
+ end
243
+
244
+ def handle_dhcp_private_network(env)
245
+ net_address = @options[:libvirt__network_address]
246
+ net_address = '172.28.128.0' unless net_address
247
+ network = lookup_network_by_ip(net_address)
248
+
249
+ @interface_network = network if network
250
+
251
+ # Do we need to create new network?
252
+ unless @interface_network[:created]
253
+ @interface_network[:name] = 'vagrant-private-dhcp'
254
+ @interface_network[:network_address] = net_address
255
+
256
+ # Set IP address of network (actually bridge). It will be used as
257
+ # gateway address for machines connected to this network.
258
+ @interface_network[:ip_address] = get_host_ip_addr(net_address)
259
+
260
+ # Generate a unique name for network bridge.
261
+ @interface_network[:bridge_name] = generate_bridge_name
262
+
263
+ # Create a private network.
264
+ create_private_network(env)
265
+ end
266
+ end
267
+
268
+ # Return provided address or first address of network otherwise
269
+ def get_host_ip_addr(network)
270
+ @options[:host_ip] ? IPAddr.new(@options[:host_ip]) : IPAddr.new(network).succ
271
+ end
272
+
273
+ # Return the first available virbr interface name
274
+ def generate_bridge_name
275
+ @logger.debug 'generating name for bridge'
276
+ count = 0
277
+ while lookup_bridge_by_name(bridge_name = "virbr#{count}")
278
+ count += 1
279
+ end
280
+ @logger.debug "found available bridge name #{bridge_name}"
281
+ bridge_name
282
+ end
283
+
284
+ def create_private_network(env)
285
+ @network_name = @interface_network[:name]
286
+ @network_bridge_name = @interface_network[:bridge_name]
287
+ @network_address = @interface_network[:ip_address]
288
+ @network_netmask = @interface_network[:netmask]
289
+ @network_mtu = Integer(@options[:mtu]) if @options[:mtu]
290
+
291
+ @guest_ipv6 = @interface_network[:guest_ipv6]
292
+
293
+ @network_ipv6_address = @interface_network[:ipv6_address]
294
+ @network_ipv6_prefix = @interface_network[:ipv6_prefix]
295
+
296
+ @network_forward_mode = @options[:forward_mode]
297
+ if @options[:forward_device]
298
+ @network_forward_device = @options[:forward_device]
299
+ end
300
+
301
+ if @options[:dhcp_enabled]
302
+ # Find out DHCP addresses pool range.
303
+ network_address = "#{@interface_network[:network_address]}/"
304
+ network_address << (@interface_network[:netmask]).to_s
305
+ net = @interface_network[:network_address] ? IPAddr.new(network_address) : nil
306
+
307
+ # First is address of network, second is gateway (by default).
308
+ # So start the range two addresses after network address by default.
309
+ # TODO: Detect if this IP is not set on the interface.
310
+ start_address = @options[:dhcp_start] || net.to_range.begin.succ
311
+
312
+ # Default to last possible address. (Stop address must not be broadcast address.)
313
+ stop_address = @options[:dhcp_stop] || (net.to_range.end & IPAddr.new('255.255.255.254'))
314
+
315
+ @network_dhcp_enabled = true
316
+ @network_dhcp_bootp_file = @options[:dhcp_bootp_file]
317
+ @network_dhcp_bootp_server = @options[:dhcp_bootp_server]
318
+ @network_range_start = start_address
319
+ @network_range_stop = stop_address
320
+ else
321
+ @network_dhcp_enabled = false
322
+ end
323
+
324
+ @network_domain_name = @options[:domain_name]
325
+
326
+ begin
327
+ @interface_network[:libvirt_network] = \
328
+ @libvirt_client.define_network_xml(to_xml('private_network'))
329
+ @logger.debug 'created network'
330
+ rescue => e
331
+ raise Errors::CreateNetworkError, error_message: e.message
332
+ end
333
+
334
+ created_networks_file = env[:machine].data_dir + 'created_networks'
335
+
336
+ message = 'Saving information about created network '
337
+ message << "#{@interface_network[:name]}, "
338
+ message << "UUID=#{@interface_network[:libvirt_network].uuid} "
339
+ message << "to file #{created_networks_file}."
340
+ @logger.info(message)
341
+
342
+ File.open(created_networks_file, 'a') do |file|
343
+ file.puts @interface_network[:libvirt_network].uuid
344
+ end
345
+ end
346
+
347
+ def autostart_network
348
+ @interface_network[:libvirt_network].autostart = true
349
+ rescue => e
350
+ raise Errors::AutostartNetworkError, error_message: e.message
351
+ end
352
+
353
+ def activate_network
354
+ @interface_network[:libvirt_network].create
355
+ rescue => e
356
+ raise Errors::ActivateNetworkError, error_message: e.message
357
+ end
358
+ end
359
+ end
360
+ end
361
+ end
@@ -0,0 +1,83 @@
1
+ require 'log4r'
2
+
3
+ module VagrantPlugins
4
+ module ProviderLibvirt
5
+ module Action
6
+ class DestroyDomain
7
+ def initialize(app, _env)
8
+ @logger = Log4r::Logger.new('vagrant_libvirt::action::destroy_domain')
9
+ @app = app
10
+ end
11
+
12
+ def call(env)
13
+ # Destroy the server, remove the tracking ID
14
+ env[:ui].info(I18n.t('vagrant_libvirt.destroy_domain'))
15
+
16
+ # Must delete any snapshots before domain can be destroyed
17
+ # Fog libvirt currently doesn't support snapshots. Use
18
+ # ruby-libvirt client directly. Note this is racy, see
19
+ # http://www.libvirt.org/html/libvirt-libvirt.html#virDomainSnapshotListNames
20
+ libvirt_domain = env[:machine].provider.driver.connection.client.lookup_domain_by_uuid(
21
+ env[:machine].id
22
+ )
23
+ begin
24
+ libvirt_domain.list_snapshots.each do |name|
25
+ @logger.info("Deleting snapshot '#{name}'")
26
+ begin
27
+ libvirt_domain.lookup_snapshot_by_name(name).delete
28
+ rescue => e
29
+ raise Errors::DeleteSnapshotError, error_message: e.message
30
+ end
31
+ end
32
+ rescue
33
+ # Some drivers (xen) don't support getting list of snapshots,
34
+ # not much can be done here about it
35
+ @logger.warn("Failed to get list of snapshots")
36
+ end
37
+
38
+ # must remove managed saves
39
+ libvirt_domain.managed_save_remove if libvirt_domain.has_managed_save?
40
+
41
+ domain = env[:machine].provider.driver.connection.servers.get(env[:machine].id.to_s)
42
+
43
+ if env[:machine].provider_config.disks.empty? &&
44
+ env[:machine].provider_config.cdroms.empty?
45
+ # if using default configuration of disks and cdroms
46
+ # cdroms are consider volumes, but cannot be destroyed
47
+ domain.destroy(destroy_volumes: true)
48
+ else
49
+ domain.destroy(destroy_volumes: false)
50
+
51
+ env[:machine].provider_config.disks.each do |disk|
52
+ # shared disks remove only manually or ???
53
+ next if disk[:allow_existing]
54
+ diskname = libvirt_domain.name + '-' + disk[:device] + '.' + disk[:type].to_s
55
+ # diskname is unique
56
+ libvirt_disk = domain.volumes.select do |x|
57
+ x.name == diskname
58
+ end.first
59
+ if libvirt_disk
60
+ libvirt_disk.destroy
61
+ elsif disk[:path]
62
+ poolname = env[:machine].provider_config.storage_pool_name
63
+ libvirt_disk = domain.volumes.select do |x|
64
+ # FIXME: can remove pool/target.img and pool/123/target.img
65
+ x.path =~ /\/#{disk[:path]}$/ && x.pool_name == poolname
66
+ end.first
67
+ libvirt_disk.destroy if libvirt_disk
68
+ end
69
+ end
70
+
71
+ # remove root storage
72
+ root_disk = domain.volumes.select do |x|
73
+ x.name == libvirt_domain.name + '.img'
74
+ end.first
75
+ root_disk.destroy if root_disk
76
+ end
77
+
78
+ @app.call(env)
79
+ end
80
+ end
81
+ end
82
+ end
83
+ end
@@ -0,0 +1,95 @@
1
+ require 'log4r'
2
+ require 'nokogiri'
3
+
4
+ module VagrantPlugins
5
+ module ProviderLibvirt
6
+ module Action
7
+ # Destroy all networks created for this specific domain. Skip
8
+ # removing if network has still active connections.
9
+ class DestroyNetworks
10
+ def initialize(app, _env)
11
+ @logger = Log4r::Logger.new('vagrant_libvirt::action::destroy_networks')
12
+ @app = app
13
+ end
14
+
15
+ def call(env)
16
+ # If there were some networks created for this machine, in machines
17
+ # data directory, created_networks file holds UUIDs of each network.
18
+ created_networks_file = env[:machine].data_dir + 'created_networks'
19
+
20
+ @logger.info 'Checking if any networks were created'
21
+ # If created_networks file doesn't exist, there are no networks we
22
+ # need to remove.
23
+ unless File.exist?(created_networks_file)
24
+ env[:machine].id = nil
25
+ return @app.call(env)
26
+ end
27
+
28
+ @logger.info 'File with created networks exists'
29
+
30
+ # Iterate over each created network UUID and try to remove it.
31
+ created_networks = []
32
+ file = File.open(created_networks_file, 'r')
33
+ file.readlines.each do |network_uuid|
34
+ @logger.info "Checking for #{network_uuid}"
35
+ # lookup_network_by_uuid throws same exception
36
+ # if there is an error or if the network just doesn't exist
37
+ begin
38
+ libvirt_network = env[:machine].provider.driver.connection.client.lookup_network_by_uuid(
39
+ network_uuid
40
+ )
41
+ rescue Libvirt::RetrieveError => e
42
+ # this network is already destroyed, so move on
43
+ if e.message =~ /Network not found/
44
+ @logger.info 'It is already undefined'
45
+ next
46
+ # some other error occured, so raise it again
47
+ else
48
+ raise e
49
+ end
50
+ end
51
+
52
+ # Skip removing if network has still active connections.
53
+ xml = Nokogiri::XML(libvirt_network.xml_desc)
54
+ connections = xml.xpath('/network/@connections').first
55
+ unless connections.nil?
56
+ @logger.info 'Still has connections so will not undefine'
57
+ created_networks << network_uuid
58
+ next
59
+ end
60
+
61
+ # Shutdown network first.
62
+ # Undefine network.
63
+ begin
64
+ libvirt_network.destroy
65
+ libvirt_network.undefine
66
+ @logger.info 'Undefined it'
67
+ rescue => e
68
+ raise Errors::DestroyNetworkError,
69
+ network_name: libvirt_network.name,
70
+ error_message: e.message
71
+ end
72
+ end
73
+ file.close
74
+
75
+ # Update status of created networks after removing some/all of them.
76
+ # Not sure why we are doing this, something else seems to always delete the file
77
+ if !created_networks.empty?
78
+ File.open(created_networks_file, 'w') do |file|
79
+ @logger.info 'Writing new created_networks file'
80
+ created_networks.each do |network_uuid|
81
+ file.puts network_uuid
82
+ end
83
+ end
84
+ else
85
+ @logger.info 'Deleting created_networks file'
86
+ File.delete(created_networks_file)
87
+ end
88
+
89
+ env[:machine].id = nil
90
+ @app.call(env)
91
+ end
92
+ end
93
+ end
94
+ end
95
+ end