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