vagrant-libvirt 0.0.30 → 0.0.31

Sign up to get free protection for your applications and to get access to all the features.
Files changed (51) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +20 -0
  3. data/Gemfile +6 -1
  4. data/README.md +146 -6
  5. data/example_box/Vagrantfile +1 -1
  6. data/example_box/metadata.json +1 -1
  7. data/lib/vagrant-libvirt.rb +3 -15
  8. data/lib/vagrant-libvirt/action.rb +59 -73
  9. data/lib/vagrant-libvirt/action/create_domain.rb +47 -19
  10. data/lib/vagrant-libvirt/action/create_domain_volume.rb +5 -5
  11. data/lib/vagrant-libvirt/action/create_network_interfaces.rb +82 -36
  12. data/lib/vagrant-libvirt/action/create_networks.rb +99 -54
  13. data/lib/vagrant-libvirt/action/destroy_domain.rb +4 -4
  14. data/lib/vagrant-libvirt/action/destroy_networks.rb +2 -2
  15. data/lib/vagrant-libvirt/action/halt_domain.rb +1 -1
  16. data/lib/vagrant-libvirt/action/handle_box_image.rb +25 -5
  17. data/lib/vagrant-libvirt/action/handle_storage_pool.rb +9 -7
  18. data/lib/vagrant-libvirt/action/is_running.rb +1 -1
  19. data/lib/vagrant-libvirt/action/is_suspended.rb +1 -1
  20. data/lib/vagrant-libvirt/action/package_domain.rb +3 -3
  21. data/lib/vagrant-libvirt/action/prepare_nfs_settings.rb +8 -5
  22. data/lib/vagrant-libvirt/action/prepare_nfs_valid_ids.rb +1 -1
  23. data/lib/vagrant-libvirt/action/prune_nfs_exports.rb +1 -1
  24. data/lib/vagrant-libvirt/action/read_mac_addresses.rb +1 -1
  25. data/lib/vagrant-libvirt/action/remove_libvirt_image.rb +1 -1
  26. data/lib/vagrant-libvirt/action/remove_stale_volume.rb +2 -2
  27. data/lib/vagrant-libvirt/action/resume_domain.rb +1 -1
  28. data/lib/vagrant-libvirt/action/set_boot_order.rb +66 -0
  29. data/lib/vagrant-libvirt/action/set_name_of_domain.rb +3 -2
  30. data/lib/vagrant-libvirt/action/start_domain.rb +1 -1
  31. data/lib/vagrant-libvirt/action/suspend_domain.rb +1 -1
  32. data/lib/vagrant-libvirt/action/wait_till_up.rb +1 -1
  33. data/lib/vagrant-libvirt/cap/mount_p9.rb +2 -1
  34. data/lib/vagrant-libvirt/cap/synced_folder.rb +11 -5
  35. data/lib/vagrant-libvirt/config.rb +44 -5
  36. data/lib/vagrant-libvirt/driver.rb +121 -0
  37. data/lib/vagrant-libvirt/errors.rb +4 -0
  38. data/lib/vagrant-libvirt/plugin.rb +7 -5
  39. data/lib/vagrant-libvirt/provider.rb +54 -12
  40. data/lib/vagrant-libvirt/templates/domain.xml.erb +18 -12
  41. data/lib/vagrant-libvirt/templates/filesystem.xml.erb +1 -1
  42. data/lib/vagrant-libvirt/templates/tunnel_interface.xml.erb +11 -0
  43. data/lib/vagrant-libvirt/util/network_util.rb +11 -1
  44. data/lib/vagrant-libvirt/version.rb +1 -1
  45. data/locales/en.yml +24 -15
  46. data/spec/support/environment_helper.rb +1 -1
  47. data/tools/prepare_redhat_for_box.sh +1 -2
  48. metadata +6 -5
  49. data/lib/vagrant-libvirt/action/connect_libvirt.rb +0 -51
  50. data/lib/vagrant-libvirt/action/read_ssh_info.rb +0 -68
  51. data/lib/vagrant-libvirt/action/read_state.rb +0 -60
@@ -47,6 +47,7 @@ module VagrantPlugins
47
47
  attr_accessor :management_network_name
48
48
  attr_accessor :management_network_address
49
49
  attr_accessor :management_network_mode
50
+ attr_accessor :management_network_mac
50
51
 
51
52
  # Default host prefix (alternative to use project folder name)
52
53
  attr_accessor :default_prefix
@@ -55,9 +56,11 @@ module VagrantPlugins
55
56
  attr_accessor :memory
56
57
  attr_accessor :cpus
57
58
  attr_accessor :cpu_mode
59
+ attr_accessor :loader
58
60
  attr_accessor :boot_order
59
61
  attr_accessor :machine_type
60
62
  attr_accessor :machine_arch
63
+ attr_accessor :machine_virtual_size
61
64
  attr_accessor :disk_bus
62
65
  attr_accessor :nic_model_type
63
66
  attr_accessor :nested
@@ -74,9 +77,17 @@ module VagrantPlugins
74
77
  attr_accessor :video_vram
75
78
  attr_accessor :keymap
76
79
 
80
+ # Sets the max number of NICs that can be created
81
+ # Default set to 8. Don't change the default unless you know
82
+ # what are doing
83
+ attr_accessor :nic_adapter_count
84
+
77
85
  # Storage
78
86
  attr_accessor :disks
79
- attr_accessor :cdroms
87
+ attr_accessor :cdroms
88
+
89
+ # Inputs
90
+ attr_accessor :inputs
80
91
 
81
92
  def initialize
82
93
  @uri = UNSET_VALUE
@@ -91,13 +102,16 @@ module VagrantPlugins
91
102
  @management_network_name = UNSET_VALUE
92
103
  @management_network_address = UNSET_VALUE
93
104
  @management_network_mode = UNSET_VALUE
105
+ @management_network_mac = UNSET_VALUE
94
106
 
95
107
  # Domain specific settings.
96
108
  @memory = UNSET_VALUE
97
109
  @cpus = UNSET_VALUE
98
110
  @cpu_mode = UNSET_VALUE
111
+ @loader = UNSET_VALUE
99
112
  @machine_type = UNSET_VALUE
100
113
  @machine_arch = UNSET_VALUE
114
+ @machine_virtual_size = UNSET_VALUE
101
115
  @disk_bus = UNSET_VALUE
102
116
  @nic_model_type = UNSET_VALUE
103
117
  @nested = UNSET_VALUE
@@ -114,13 +128,18 @@ module VagrantPlugins
114
128
  @video_vram = UNSET_VALUE
115
129
  @keymap = UNSET_VALUE
116
130
 
131
+ @nic_adapter_count = UNSET_VALUE
132
+
117
133
  # Boot order
118
134
  @boot_order = []
119
135
  # Storage
120
136
  @disks = []
121
- @cdroms = []
137
+ @cdroms = []
138
+
139
+ # Inputs
140
+ @inputs = UNSET_VALUE
122
141
  end
123
-
142
+
124
143
  def boot(device)
125
144
  @boot_order << device # append
126
145
  end
@@ -153,7 +172,22 @@ module VagrantPlugins
153
172
  end
154
173
 
155
174
  # is it better to raise our own error, or let libvirt cause the exception?
156
- raise "Only four cdroms may be attached at a time"
175
+ raise 'Only four cdroms may be attached at a time'
176
+ end
177
+
178
+ def input(options={})
179
+ if options[:type].nil? || options[:bus].nil?
180
+ raise 'Input type AND bus must be specified'
181
+ end
182
+
183
+ if @inputs == UNSET_VALUE
184
+ @inputs = []
185
+ end
186
+
187
+ @inputs.push({
188
+ type: options[:type],
189
+ bus: options[:bus]
190
+ })
157
191
  end
158
192
 
159
193
  # NOTE: this will run twice for each time it's needed- keep it idempotent
@@ -277,6 +311,7 @@ module VagrantPlugins
277
311
  @management_network_name = 'vagrant-libvirt' if @management_network_name == UNSET_VALUE
278
312
  @management_network_address = '192.168.121.0/24' if @management_network_address == UNSET_VALUE
279
313
  @management_network_mode = 'nat' if @management_network_mode == UNSET_VALUE
314
+ @management_network_mac = nil if @management_network_mac == UNSET_VALUE
280
315
 
281
316
  # generate a URI if none is supplied
282
317
  @uri = _generate_uri() if @uri == UNSET_VALUE
@@ -285,8 +320,10 @@ module VagrantPlugins
285
320
  @memory = 512 if @memory == UNSET_VALUE
286
321
  @cpus = 1 if @cpus == UNSET_VALUE
287
322
  @cpu_mode = 'host-model' if @cpu_mode == UNSET_VALUE
323
+ @loader = nil if @loader == UNSET_VALUE
288
324
  @machine_type = nil if @machine_type == UNSET_VALUE
289
325
  @machine_arch = nil if @machine_arch == UNSET_VALUE
326
+ @machine_virtual_size = nil if @machine_virtual_size == UNSET_VALUE
290
327
  @disk_bus = 'virtio' if @disk_bus == UNSET_VALUE
291
328
  @nic_model_type = 'virtio' if @nic_model_type == UNSET_VALUE
292
329
  @nested = false if @nested == UNSET_VALUE
@@ -306,13 +343,15 @@ module VagrantPlugins
306
343
  @video_type = 'cirrus' if @video_type == UNSET_VALUE
307
344
  @video_vram = 9216 if @video_vram == UNSET_VALUE
308
345
  @keymap = 'en-us' if @keymap == UNSET_VALUE
309
-
346
+ @nic_adapter_count = 8 if @nic_adapter_count == UNSET_VALUE
347
+
310
348
  # Boot order
311
349
  @boot_order = [] if @boot_order == UNSET_VALUE
312
350
 
313
351
  # Storage
314
352
  @disks = [] if @disks == UNSET_VALUE
315
353
  @cdroms = [] if @cdroms == UNSET_VALUE
354
+ @inputs = [{:type => "mouse", :bus => "ps2"}] if @inputs == UNSET_VALUE
316
355
  end
317
356
 
318
357
  def validate(machine)
@@ -0,0 +1,121 @@
1
+ require 'fog/libvirt'
2
+ require 'log4r'
3
+
4
+ module VagrantPlugins
5
+ module ProviderLibvirt
6
+ class Driver
7
+
8
+ # store the connection at the process level
9
+ #
10
+ # possibly this should be a connection pool using the connection
11
+ # settings as a key to allow per machine connection attributes
12
+ # to be used.
13
+ @@connection = nil
14
+
15
+ def initialize(machine)
16
+ @logger = Log4r::Logger.new('vagrant_libvirt::driver')
17
+ @machine = machine
18
+ end
19
+
20
+ def connection
21
+ # If already connected to libvirt, just use it and don't connect
22
+ # again.
23
+ return @@connection if @@connection
24
+
25
+ # Get config options for libvirt provider.
26
+ config = @machine.provider_config
27
+ uri = config.uri
28
+
29
+ conn_attr = {}
30
+ conn_attr[:provider] = 'libvirt'
31
+ conn_attr[:libvirt_uri] = uri
32
+ conn_attr[:libvirt_username] = config.username if config.username
33
+ conn_attr[:libvirt_password] = config.password if config.password
34
+
35
+ # Setup command for retrieving IP address for newly created machine
36
+ # with some MAC address. Get it from dnsmasq leases table
37
+ ip_command = %q[ awk "/$mac/ {print \$1}" /proc/net/arp ]
38
+ conn_attr[:libvirt_ip_command] = ip_command
39
+
40
+ @logger.info("Connecting to Libvirt (#{uri}) ...")
41
+ begin
42
+ @@connection = Fog::Compute.new(conn_attr)
43
+ rescue Fog::Errors::Error => e
44
+ raise Errors::FogLibvirtConnectionError,
45
+ :error_message => e.message
46
+ end
47
+
48
+ @@connection
49
+ end
50
+
51
+ def get_domain(mid)
52
+ begin
53
+ domain = connection.servers.get(mid)
54
+ rescue Libvirt::RetrieveError => e
55
+ if e.libvirt_code == ProviderLibvirt::Util::ErrorCodes::VIR_ERR_NO_DOMAIN
56
+ @logger.debug("machine #{mid} not found #{e}.")
57
+ return nil
58
+ else
59
+ raise e
60
+ end
61
+ end
62
+
63
+ domain
64
+ end
65
+
66
+ def created?(mid)
67
+ domain = get_domain(mid)
68
+ !domain.nil?
69
+ end
70
+
71
+ def get_ipaddress(machine)
72
+ # Find the machine
73
+ domain = get_domain(machine.id)
74
+
75
+ if domain.nil?
76
+ # The machine can't be found
77
+ return nil
78
+ end
79
+
80
+ # Get IP address from arp table
81
+ ip_address = nil
82
+ begin
83
+ domain.wait_for(2) do
84
+ addresses.each_pair do |type, ip|
85
+ # Multiple leases are separated with a newline, return only
86
+ # the most recent address
87
+ ip_address = ip[0].split("\n").first if ip[0] != nil
88
+ end
89
+ ip_address != nil
90
+ end
91
+ rescue Fog::Errors::TimeoutError
92
+ @logger.info("Timeout at waiting for an ip address for machine %s" % machine.name)
93
+ end
94
+
95
+ if not ip_address
96
+ @logger.info("No arp table entry found for machine %s" % machine.name)
97
+ return nil
98
+ end
99
+
100
+ ip_address
101
+ end
102
+
103
+ def state(machine)
104
+ # may be other error states with initial retreival we can't handle
105
+ begin
106
+ domain = get_domain(machine.id)
107
+ rescue Libvirt::RetrieveError => e
108
+ @logger.debug("Machine #{machine.id} not found #{e}.")
109
+ return :not_created
110
+ end
111
+
112
+ # TODO: terminated no longer appears to be a valid fog state, remove?
113
+ if domain.nil? || domain.state.to_sym == :terminated
114
+ return :not_created
115
+ end
116
+
117
+ return domain.state.gsub("-", "_").to_sym
118
+ end
119
+ end
120
+ end
121
+ end
@@ -106,6 +106,10 @@ module VagrantPlugins
106
106
  error_key(:activate_network_error)
107
107
  end
108
108
 
109
+ class TunnelPortNotDefined < VagrantLibvirtError
110
+ error_key(:tunnel_port_not_defined)
111
+ end
112
+
109
113
  # Other exceptions
110
114
  class InterfaceSlotNotAvailable < VagrantLibvirtError
111
115
  error_key(:interface_slot_not_available)
@@ -23,11 +23,7 @@ module VagrantPlugins
23
23
  Config
24
24
  end
25
25
 
26
- provider('libvirt', parallel: true) do
27
- # Setup logging and i18n
28
- setup_logging
29
- setup_i18n
30
-
26
+ provider('libvirt', parallel: true, box_optional: true) do
31
27
  require_relative 'provider'
32
28
  Provider
33
29
  end
@@ -90,6 +86,12 @@ module VagrantPlugins
90
86
  end
91
87
  end
92
88
 
89
+ # Setup logging and i18n before any autoloading loads other classes
90
+ # with logging configured as this prevents inheritance of the log level
91
+ # from the parent logger.
92
+ setup_logging
93
+ setup_i18n
94
+
93
95
  end
94
96
  end
95
97
  end
@@ -2,6 +2,7 @@ require 'vagrant'
2
2
 
3
3
  module VagrantPlugins
4
4
  module ProviderLibvirt
5
+ autoload :Driver, 'vagrant-libvirt/driver'
5
6
 
6
7
  # This is the base class for a provider for the V2 API. A provider
7
8
  # is responsible for creating compute resources to match the
@@ -22,6 +23,12 @@ module VagrantPlugins
22
23
  nil
23
24
  end
24
25
 
26
+ def driver
27
+ return @driver if @driver
28
+
29
+ @driver = Driver.new(@machine)
30
+ end
31
+
25
32
  # This method is called if the underying machine ID changes. Providers
26
33
  # can use this method to load in new data for the actual backing
27
34
  # machine or to realize that the machine is now gone (the ID can
@@ -33,9 +40,8 @@ module VagrantPlugins
33
40
  # SSH into the machine. If the machine is not at a point where
34
41
  # SSH is even possible, then `nil` should be returned.
35
42
  def ssh_info
36
- # Run a custom action called "read_ssh_info" which does what it says
37
- # and puts the resulting SSH info into the `:machine_ssh_info` key in
38
- # the environment.
43
+ # Return the ssh_info if already retrieved otherwise call the driver
44
+ # and save the result.
39
45
  #
40
46
  # Ssh info has following format..
41
47
  #
@@ -45,8 +51,32 @@ module VagrantPlugins
45
51
  # :username => "mitchellh",
46
52
  # :private_key_path => "/path/to/my/key"
47
53
  #}
48
- env = @machine.action('read_ssh_info')
49
- env[:machine_ssh_info]
54
+ # note that modifing @machine.id or accessing @machine.state is not
55
+ # thread safe, so be careful to avoid these here as this method may
56
+ # be called from other threads of execution.
57
+ return nil if state.id != :running
58
+
59
+ ip = driver.get_ipaddress(@machine)
60
+
61
+ # if can't determine the IP, just return nil and let the core
62
+ # deal with it, similar to the docker provider
63
+ return nil if !ip
64
+
65
+ ssh_info = {
66
+ :host => ip,
67
+ :port => @machine.config.ssh.guest_port,
68
+ :forward_agent => @machine.config.ssh.forward_agent,
69
+ :forward_x11 => @machine.config.ssh.forward_x11,
70
+ }
71
+
72
+ ssh_info[:proxy_command] = (
73
+ "ssh '#{@machine.provider_config.host}' " +
74
+ "-l '#{@machine.provider_config.username}' " +
75
+ "-i '#{@machine.provider_config.id_ssh_key_file}' " +
76
+ "nc %h %p"
77
+ ) if @machine.provider_config.connect_via_ssh
78
+
79
+ ssh_info
50
80
  end
51
81
 
52
82
  def mac_addresses
@@ -64,16 +94,28 @@ module VagrantPlugins
64
94
  # This should return the state of the machine within this provider.
65
95
  # The state must be an instance of {MachineState}.
66
96
  def state
67
- # Run a custom action we define called "read_state" which does
68
- # what it says. It puts the state in the `:machine_state_id`
69
- # key in the environment.
70
- env = @machine.action('read_state')
71
97
 
72
- state_id = env[:machine_state_id]
98
+ state_id = nil
99
+ state_id = :not_created if !@machine.id
100
+ state_id = :not_created if (
101
+ !state_id && (!@machine.id || !driver.created?(@machine.id)))
102
+ # Query the driver for the current state of the machine
103
+ state_id = driver.state(@machine) if @machine.id && !state_id
104
+ state_id = :unknown if !state_id
105
+
106
+ # This is a special pseudo-state so that we don't set the
107
+ # NOT_CREATED_ID while we're setting up the machine. This avoids
108
+ # clearing the data dir.
109
+ state_id = :preparing if @machine.id == "preparing"
73
110
 
74
111
  # Get the short and long description
75
- short = I18n.t("vagrant_libvirt.states.short_#{state_id}")
76
- long = I18n.t("vagrant_libvirt.states.long_#{state_id}")
112
+ short = state_id.to_s.gsub("_", " ")
113
+ long = I18n.t("vagrant_libvirt.states.#{state_id}")
114
+
115
+ # If we're not created, then specify the special ID flag
116
+ if state_id == :not_created
117
+ state_id = Vagrant::MachineState::NOT_CREATED_ID
118
+ end
77
119
 
78
120
  # Return the MachineState object
79
121
  Vagrant::MachineState.new(state_id, short, long)
@@ -3,15 +3,17 @@
3
3
  <memory><%= @memory_size %></memory>
4
4
  <vcpu><%= @cpus %></vcpu>
5
5
 
6
- <% if @nested %>
7
- <cpu mode='<%= @cpu_mode %>'>
8
- <% if @cpu_mode != 'host-passthrough' %>
9
- <model fallback='allow'>qemu64</model>
6
+
7
+ <cpu mode='<%= @cpu_mode %>'>
8
+ <% if @cpu_mode != 'host-passthrough' %>
9
+ <model fallback='allow'>qemu64</model>
10
+ <% if @nested %>
10
11
  <feature policy='optional' name='vmx'/>
11
12
  <feature policy='optional' name='svm'/>
12
13
  <% end %>
13
- </cpu>
14
- <% end %>
14
+ <% end %>
15
+ </cpu>
16
+
15
17
 
16
18
  <os>
17
19
  <% if @machine_type %>
@@ -27,13 +29,11 @@
27
29
  <type>hvm</type>
28
30
  <% end %>
29
31
  <% end %>
32
+ <% if @loader %>
33
+ <loader readonly='yes' type='rom'><%= @loader %></loader>
34
+ <% end %>
30
35
  <% if @boot_order.count >= 1 %>
31
- <% @boot_order.each do |b| %>
32
- <boot dev='<%= b %>'/>
33
- <% end %>
34
36
  <bootmenu enable='yes'/>
35
- <% else %>
36
- <boot dev='hd' />
37
37
  <% end %>
38
38
  <kernel><%= @kernel %></kernel>
39
39
  <initrd><%= @initrd %></initrd>
@@ -46,12 +46,14 @@
46
46
  </features>
47
47
  <clock offset='utc'/>
48
48
  <devices>
49
+ <% if @domain_volume_path %>
49
50
  <disk type='file' device='disk'>
50
51
  <driver name='qemu' type='qcow2' cache='<%= @domain_volume_cache %>'/>
51
52
  <source file='<%= @domain_volume_path %>'/>
52
53
  <%# we need to ensure a unique target dev -%>
53
54
  <target dev='vda' bus='<%= @disk_bus %>'/>
54
55
  </disk>
56
+ <% end %>
55
57
  <%# additional disks -%>
56
58
  <% @disks.each do |d| -%>
57
59
  <disk type='file' device='disk'>
@@ -78,7 +80,11 @@
78
80
  <console type='pty'>
79
81
  <target port='0'/>
80
82
  </console>
81
- <input type='mouse' bus='ps2'/>
83
+
84
+ <% @inputs.each do |input| %>
85
+ <input type='<%= input[:type] %>' bus='<%= input[:bus] %>'/>
86
+ <% end %>
87
+
82
88
  <%# Video device -%>
83
89
  <graphics type='<%= @graphics_type %>' port='<%= @graphics_port %>' autoport='<%= @graphics_autoport %>' listen='<%= @graphics_ip %>' keymap='<%= @keymap %>' <%= @graphics_passwd%> />
84
90
  <video>