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.
- checksums.yaml +4 -4
- data/.coveralls.yml +1 -0
- data/.github/issue_template.md +37 -0
- data/.gitignore +21 -0
- data/.travis.yml +24 -0
- data/Gemfile +26 -0
- data/LICENSE +22 -0
- data/README.md +1380 -0
- data/Rakefile +8 -0
- data/example_box/README.md +29 -0
- data/example_box/Vagrantfile +60 -0
- data/example_box/metadata.json +5 -0
- data/lib/vagrant-libvirt.rb +29 -0
- data/lib/vagrant-libvirt/action.rb +370 -0
- data/lib/vagrant-libvirt/action/create_domain.rb +322 -0
- data/lib/vagrant-libvirt/action/create_domain_volume.rb +87 -0
- data/lib/vagrant-libvirt/action/create_network_interfaces.rb +302 -0
- data/lib/vagrant-libvirt/action/create_networks.rb +361 -0
- data/lib/vagrant-libvirt/action/destroy_domain.rb +83 -0
- data/lib/vagrant-libvirt/action/destroy_networks.rb +95 -0
- data/lib/vagrant-libvirt/action/forward_ports.rb +227 -0
- data/lib/vagrant-libvirt/action/halt_domain.rb +41 -0
- data/lib/vagrant-libvirt/action/handle_box_image.rb +156 -0
- data/lib/vagrant-libvirt/action/handle_storage_pool.rb +57 -0
- data/lib/vagrant-libvirt/action/is_created.rb +18 -0
- data/lib/vagrant-libvirt/action/is_running.rb +21 -0
- data/lib/vagrant-libvirt/action/is_suspended.rb +42 -0
- data/lib/vagrant-libvirt/action/message_already_created.rb +16 -0
- data/lib/vagrant-libvirt/action/message_not_created.rb +16 -0
- data/lib/vagrant-libvirt/action/message_not_running.rb +16 -0
- data/lib/vagrant-libvirt/action/message_not_suspended.rb +16 -0
- data/lib/vagrant-libvirt/action/message_will_not_destroy.rb +17 -0
- data/lib/vagrant-libvirt/action/package_domain.rb +105 -0
- data/lib/vagrant-libvirt/action/prepare_nfs_settings.rb +94 -0
- data/lib/vagrant-libvirt/action/prepare_nfs_valid_ids.rb +17 -0
- data/lib/vagrant-libvirt/action/prune_nfs_exports.rb +27 -0
- data/lib/vagrant-libvirt/action/read_mac_addresses.rb +40 -0
- data/lib/vagrant-libvirt/action/remove_libvirt_image.rb +20 -0
- data/lib/vagrant-libvirt/action/remove_stale_volume.rb +50 -0
- data/lib/vagrant-libvirt/action/resume_domain.rb +34 -0
- data/lib/vagrant-libvirt/action/set_boot_order.rb +109 -0
- data/lib/vagrant-libvirt/action/set_name_of_domain.rb +64 -0
- data/lib/vagrant-libvirt/action/share_folders.rb +71 -0
- data/lib/vagrant-libvirt/action/start_domain.rb +307 -0
- data/lib/vagrant-libvirt/action/suspend_domain.rb +40 -0
- data/lib/vagrant-libvirt/action/wait_till_up.rb +109 -0
- data/lib/vagrant-libvirt/cap/mount_p9.rb +42 -0
- data/lib/vagrant-libvirt/cap/nic_mac_addresses.rb +17 -0
- data/lib/vagrant-libvirt/cap/synced_folder.rb +113 -0
- data/lib/vagrant-libvirt/config.rb +746 -0
- data/lib/vagrant-libvirt/driver.rb +118 -0
- data/lib/vagrant-libvirt/errors.rb +153 -0
- data/lib/vagrant-libvirt/plugin.rb +92 -0
- data/lib/vagrant-libvirt/provider.rb +130 -0
- data/lib/vagrant-libvirt/templates/default_storage_pool.xml.erb +13 -0
- data/lib/vagrant-libvirt/templates/domain.xml.erb +244 -0
- data/lib/vagrant-libvirt/templates/private_network.xml.erb +42 -0
- data/lib/vagrant-libvirt/templates/public_interface.xml.erb +26 -0
- data/lib/vagrant-libvirt/util.rb +11 -0
- data/lib/vagrant-libvirt/util/collection.rb +19 -0
- data/lib/vagrant-libvirt/util/erb_template.rb +22 -0
- data/lib/vagrant-libvirt/util/error_codes.rb +100 -0
- data/lib/vagrant-libvirt/util/network_util.rb +151 -0
- data/lib/vagrant-libvirt/util/timer.rb +17 -0
- data/lib/vagrant-libvirt/version.rb +5 -0
- data/locales/en.yml +162 -0
- data/spec/spec_helper.rb +9 -0
- data/spec/support/environment_helper.rb +46 -0
- data/spec/support/libvirt_context.rb +30 -0
- data/spec/support/sharedcontext.rb +34 -0
- data/spec/unit/action/destroy_domain_spec.rb +97 -0
- data/spec/unit/action/set_name_of_domain_spec.rb +21 -0
- data/spec/unit/action/wait_till_up_spec.rb +127 -0
- data/spec/unit/config_spec.rb +113 -0
- data/spec/unit/templates/domain_all_settings.xml +137 -0
- data/spec/unit/templates/domain_defaults.xml +46 -0
- data/spec/unit/templates/domain_spec.rb +84 -0
- data/tools/create_box.sh +130 -0
- data/tools/prepare_redhat_for_box.sh +119 -0
- data/vagrant-libvirt.gemspec +54 -0
- 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
|