vagrant-libvirt 0.0.41 → 0.0.42

Sign up to get free protection for your applications and to get access to all the features.
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