vagrant-libvirt 0.0.41 → 0.0.42

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (81) hide show
  1. checksums.yaml +4 -4
  2. data/.coveralls.yml +1 -0
  3. data/.github/issue_template.md +37 -0
  4. data/.gitignore +21 -0
  5. data/.travis.yml +24 -0
  6. data/Gemfile +26 -0
  7. data/LICENSE +22 -0
  8. data/README.md +1380 -0
  9. data/Rakefile +8 -0
  10. data/example_box/README.md +29 -0
  11. data/example_box/Vagrantfile +60 -0
  12. data/example_box/metadata.json +5 -0
  13. data/lib/vagrant-libvirt.rb +29 -0
  14. data/lib/vagrant-libvirt/action.rb +370 -0
  15. data/lib/vagrant-libvirt/action/create_domain.rb +322 -0
  16. data/lib/vagrant-libvirt/action/create_domain_volume.rb +87 -0
  17. data/lib/vagrant-libvirt/action/create_network_interfaces.rb +302 -0
  18. data/lib/vagrant-libvirt/action/create_networks.rb +361 -0
  19. data/lib/vagrant-libvirt/action/destroy_domain.rb +83 -0
  20. data/lib/vagrant-libvirt/action/destroy_networks.rb +95 -0
  21. data/lib/vagrant-libvirt/action/forward_ports.rb +227 -0
  22. data/lib/vagrant-libvirt/action/halt_domain.rb +41 -0
  23. data/lib/vagrant-libvirt/action/handle_box_image.rb +156 -0
  24. data/lib/vagrant-libvirt/action/handle_storage_pool.rb +57 -0
  25. data/lib/vagrant-libvirt/action/is_created.rb +18 -0
  26. data/lib/vagrant-libvirt/action/is_running.rb +21 -0
  27. data/lib/vagrant-libvirt/action/is_suspended.rb +42 -0
  28. data/lib/vagrant-libvirt/action/message_already_created.rb +16 -0
  29. data/lib/vagrant-libvirt/action/message_not_created.rb +16 -0
  30. data/lib/vagrant-libvirt/action/message_not_running.rb +16 -0
  31. data/lib/vagrant-libvirt/action/message_not_suspended.rb +16 -0
  32. data/lib/vagrant-libvirt/action/message_will_not_destroy.rb +17 -0
  33. data/lib/vagrant-libvirt/action/package_domain.rb +105 -0
  34. data/lib/vagrant-libvirt/action/prepare_nfs_settings.rb +94 -0
  35. data/lib/vagrant-libvirt/action/prepare_nfs_valid_ids.rb +17 -0
  36. data/lib/vagrant-libvirt/action/prune_nfs_exports.rb +27 -0
  37. data/lib/vagrant-libvirt/action/read_mac_addresses.rb +40 -0
  38. data/lib/vagrant-libvirt/action/remove_libvirt_image.rb +20 -0
  39. data/lib/vagrant-libvirt/action/remove_stale_volume.rb +50 -0
  40. data/lib/vagrant-libvirt/action/resume_domain.rb +34 -0
  41. data/lib/vagrant-libvirt/action/set_boot_order.rb +109 -0
  42. data/lib/vagrant-libvirt/action/set_name_of_domain.rb +64 -0
  43. data/lib/vagrant-libvirt/action/share_folders.rb +71 -0
  44. data/lib/vagrant-libvirt/action/start_domain.rb +307 -0
  45. data/lib/vagrant-libvirt/action/suspend_domain.rb +40 -0
  46. data/lib/vagrant-libvirt/action/wait_till_up.rb +109 -0
  47. data/lib/vagrant-libvirt/cap/mount_p9.rb +42 -0
  48. data/lib/vagrant-libvirt/cap/nic_mac_addresses.rb +17 -0
  49. data/lib/vagrant-libvirt/cap/synced_folder.rb +113 -0
  50. data/lib/vagrant-libvirt/config.rb +746 -0
  51. data/lib/vagrant-libvirt/driver.rb +118 -0
  52. data/lib/vagrant-libvirt/errors.rb +153 -0
  53. data/lib/vagrant-libvirt/plugin.rb +92 -0
  54. data/lib/vagrant-libvirt/provider.rb +130 -0
  55. data/lib/vagrant-libvirt/templates/default_storage_pool.xml.erb +13 -0
  56. data/lib/vagrant-libvirt/templates/domain.xml.erb +244 -0
  57. data/lib/vagrant-libvirt/templates/private_network.xml.erb +42 -0
  58. data/lib/vagrant-libvirt/templates/public_interface.xml.erb +26 -0
  59. data/lib/vagrant-libvirt/util.rb +11 -0
  60. data/lib/vagrant-libvirt/util/collection.rb +19 -0
  61. data/lib/vagrant-libvirt/util/erb_template.rb +22 -0
  62. data/lib/vagrant-libvirt/util/error_codes.rb +100 -0
  63. data/lib/vagrant-libvirt/util/network_util.rb +151 -0
  64. data/lib/vagrant-libvirt/util/timer.rb +17 -0
  65. data/lib/vagrant-libvirt/version.rb +5 -0
  66. data/locales/en.yml +162 -0
  67. data/spec/spec_helper.rb +9 -0
  68. data/spec/support/environment_helper.rb +46 -0
  69. data/spec/support/libvirt_context.rb +30 -0
  70. data/spec/support/sharedcontext.rb +34 -0
  71. data/spec/unit/action/destroy_domain_spec.rb +97 -0
  72. data/spec/unit/action/set_name_of_domain_spec.rb +21 -0
  73. data/spec/unit/action/wait_till_up_spec.rb +127 -0
  74. data/spec/unit/config_spec.rb +113 -0
  75. data/spec/unit/templates/domain_all_settings.xml +137 -0
  76. data/spec/unit/templates/domain_defaults.xml +46 -0
  77. data/spec/unit/templates/domain_spec.rb +84 -0
  78. data/tools/create_box.sh +130 -0
  79. data/tools/prepare_redhat_for_box.sh +119 -0
  80. data/vagrant-libvirt.gemspec +54 -0
  81. metadata +93 -3
@@ -0,0 +1,118 @@
1
+ require 'fog/libvirt'
2
+ require 'log4r'
3
+
4
+ module VagrantPlugins
5
+ module ProviderLibvirt
6
+ class Driver
7
+ # store the connection at the process level
8
+ #
9
+ # possibly this should be a connection pool using the connection
10
+ # settings as a key to allow per machine connection attributes
11
+ # to be used.
12
+ @@connection = nil
13
+
14
+ def initialize(machine)
15
+ @logger = Log4r::Logger.new('vagrant_libvirt::driver')
16
+ @machine = machine
17
+ end
18
+
19
+ def connection
20
+ # If already connected to libvirt, just use it and don't connect
21
+ # again.
22
+ return @@connection if @@connection
23
+
24
+ # Get config options for libvirt provider.
25
+ config = @machine.provider_config
26
+ uri = config.uri
27
+
28
+ conn_attr = {}
29
+ conn_attr[:provider] = 'libvirt'
30
+ conn_attr[:libvirt_uri] = uri
31
+ conn_attr[:libvirt_username] = config.username if config.username
32
+ conn_attr[:libvirt_password] = config.password if config.password
33
+
34
+ # Setup command for retrieving IP address for newly created machine
35
+ # with some MAC address. Get it from dnsmasq leases table
36
+ ip_command = %q( awk "/$mac/ {print \$1}" /proc/net/arp )
37
+ conn_attr[:libvirt_ip_command] = ip_command
38
+
39
+ @logger.info("Connecting to Libvirt (#{uri}) ...")
40
+ begin
41
+ @@connection = Fog::Compute.new(conn_attr)
42
+ rescue Fog::Errors::Error => e
43
+ raise Errors::FogLibvirtConnectionError,
44
+ error_message: e.message
45
+ end
46
+
47
+ @@connection
48
+ end
49
+
50
+ def get_domain(mid)
51
+ begin
52
+ domain = connection.servers.get(mid)
53
+ rescue Libvirt::RetrieveError => e
54
+ if e.libvirt_code == ProviderLibvirt::Util::ErrorCodes::VIR_ERR_NO_DOMAIN
55
+ @logger.debug("machine #{mid} not found #{e}.")
56
+ return nil
57
+ else
58
+ raise e
59
+ end
60
+ end
61
+
62
+ domain
63
+ end
64
+
65
+ def created?(mid)
66
+ domain = get_domain(mid)
67
+ !domain.nil?
68
+ end
69
+
70
+ def get_ipaddress(machine)
71
+ # Find the machine
72
+ domain = get_domain(machine.id)
73
+
74
+ if domain.nil?
75
+ # The machine can't be found
76
+ return nil
77
+ end
78
+
79
+ # Get IP address from arp table
80
+ ip_address = nil
81
+ begin
82
+ domain.wait_for(2) do
83
+ addresses.each_pair do |_type, ip|
84
+ # Multiple leases are separated with a newline, return only
85
+ # the most recent address
86
+ ip_address = ip[0].split("\n").first unless ip[0].nil?
87
+ end
88
+ !ip_address.nil?
89
+ end
90
+ rescue Fog::Errors::TimeoutError
91
+ @logger.info('Timeout at waiting for an ip address for machine %s' % machine.name)
92
+ end
93
+
94
+ unless ip_address
95
+ @logger.info('No arp table entry found for machine %s' % machine.name)
96
+ return nil
97
+ end
98
+
99
+ ip_address
100
+ end
101
+
102
+ def state(machine)
103
+ # may be other error states with initial retreival we can't handle
104
+ begin
105
+ domain = get_domain(machine.id)
106
+ rescue Libvirt::RetrieveError => e
107
+ @logger.debug("Machine #{machine.id} not found #{e}.")
108
+ return :not_created
109
+ end
110
+
111
+ # TODO: terminated no longer appears to be a valid fog state, remove?
112
+ return :not_created if domain.nil? || domain.state.to_sym == :terminated
113
+
114
+ domain.state.tr('-', '_').to_sym
115
+ end
116
+ end
117
+ end
118
+ end
@@ -0,0 +1,153 @@
1
+ require 'vagrant'
2
+
3
+ module VagrantPlugins
4
+ module ProviderLibvirt
5
+ module Errors
6
+ class VagrantLibvirtError < Vagrant::Errors::VagrantError
7
+ error_namespace('vagrant_libvirt.errors')
8
+ end
9
+
10
+ # package not supported
11
+ class PackageNotSupported < VagrantLibvirtError
12
+ error_key(:package_not_supported)
13
+ end
14
+
15
+ # Storage pools and volumes exceptions
16
+ class NoStoragePool < VagrantLibvirtError
17
+ error_key(:no_storage_pool)
18
+ end
19
+
20
+ class DomainVolumeExists < VagrantLibvirtError
21
+ error_key(:domain_volume_exists)
22
+ end
23
+
24
+ class NoDomainVolume < VagrantLibvirtError
25
+ error_key(:no_domain_volume)
26
+ end
27
+
28
+ class CreatingStoragePoolError < VagrantLibvirtError
29
+ error_key(:creating_storage_pool_error)
30
+ end
31
+
32
+ class ImageUploadError < VagrantLibvirtError
33
+ error_key(:image_upload_error)
34
+ end
35
+
36
+ # Box exceptions
37
+ class NoBoxVolume < VagrantLibvirtError
38
+ error_key(:no_box_volume)
39
+ end
40
+
41
+ class NoBoxVirtualSizeSet < VagrantLibvirtError
42
+ error_key(:no_box_virtual_size)
43
+ end
44
+
45
+ class NoBoxFormatSet < VagrantLibvirtError
46
+ error_key(:no_box_format)
47
+ end
48
+
49
+ class WrongBoxFormatSet < VagrantLibvirtError
50
+ error_key(:wrong_box_format)
51
+ end
52
+
53
+ # Fog libvirt exceptions
54
+ class FogError < VagrantLibvirtError
55
+ error_key(:fog_error)
56
+ end
57
+
58
+ class FogLibvirtConnectionError < VagrantLibvirtError
59
+ error_key(:fog_libvirt_connection_error)
60
+ end
61
+
62
+ class FogCreateVolumeError < VagrantLibvirtError
63
+ error_key(:fog_create_volume_error)
64
+ end
65
+
66
+ class FogCreateDomainVolumeError < VagrantLibvirtError
67
+ error_key(:fog_create_domain_volume_error)
68
+ end
69
+
70
+ class FogCreateServerError < VagrantLibvirtError
71
+ error_key(:fog_create_server_error)
72
+ end
73
+
74
+ # Network exceptions
75
+ class ManagementNetworkError < VagrantLibvirtError
76
+ error_key(:management_network_error)
77
+ end
78
+
79
+ class NetworkNameAndAddressMismatch < VagrantLibvirtError
80
+ error_key(:network_name_and_address_mismatch)
81
+ end
82
+
83
+ class DHCPMismatch < VagrantLibvirtError
84
+ error_key(:dhcp_mismatch)
85
+ end
86
+
87
+ class CreateNetworkError < VagrantLibvirtError
88
+ error_key(:create_network_error)
89
+ end
90
+
91
+ class DestroyNetworkError < VagrantLibvirtError
92
+ error_key(:destroy_network_error)
93
+ end
94
+
95
+ class NetworkNotAvailableError < VagrantLibvirtError
96
+ error_key(:network_not_available_error)
97
+ end
98
+
99
+ class AutostartNetworkError < VagrantLibvirtError
100
+ error_key(:autostart_network_error)
101
+ end
102
+
103
+ class ActivateNetworkError < VagrantLibvirtError
104
+ error_key(:activate_network_error)
105
+ end
106
+
107
+ class TunnelPortNotDefined < VagrantLibvirtError
108
+ error_key(:tunnel_port_not_defined)
109
+ end
110
+
111
+ class ManagementNetworkRequired < VagrantLibvirtError
112
+ error_key(:management_network_required)
113
+ end
114
+
115
+ # Other exceptions
116
+ class InterfaceSlotNotAvailable < VagrantLibvirtError
117
+ error_key(:interface_slot_not_available)
118
+ end
119
+
120
+ class InterfaceSlotExhausted < VagrantLibvirtError
121
+ error_key(:interface_slot_exhausted)
122
+ end
123
+
124
+ class RsyncError < VagrantLibvirtError
125
+ error_key(:rsync_error)
126
+ end
127
+
128
+ class DomainNameExists < VagrantLibvirtError
129
+ error_key(:domain_name_exists)
130
+ end
131
+
132
+ class NoDomainError < VagrantLibvirtError
133
+ error_key(:no_domain_error)
134
+ end
135
+
136
+ class AttachDeviceError < VagrantLibvirtError
137
+ error_key(:attach_device_error)
138
+ end
139
+
140
+ class DetachDeviceError < VagrantLibvirtError
141
+ error_key(:detach_device_error)
142
+ end
143
+
144
+ class NoIpAddressError < VagrantLibvirtError
145
+ error_key(:no_ip_address_error)
146
+ end
147
+
148
+ class DeleteSnapshotError < VagrantLibvirtError
149
+ error_key(:delete_snapshot_error)
150
+ end
151
+ end
152
+ end
153
+ end
@@ -0,0 +1,92 @@
1
+ begin
2
+ require 'vagrant'
3
+ rescue LoadError
4
+ raise 'The Vagrant Libvirt plugin must be run within Vagrant.'
5
+ end
6
+
7
+ # compatibility fix to define constant not available vagrant <1.6
8
+ ::Vagrant::MachineState::NOT_CREATED_ID ||= :not_created
9
+
10
+ module VagrantPlugins
11
+ module ProviderLibvirt
12
+ class Plugin < Vagrant.plugin('2')
13
+ name 'libvirt'
14
+ description <<-DESC
15
+ Vagrant plugin to manage VMs in libvirt.
16
+ DESC
17
+
18
+ config('libvirt', :provider) do
19
+ require_relative 'config'
20
+ Config
21
+ end
22
+
23
+ provider('libvirt', parallel: true, box_optional: true) do
24
+ require_relative 'provider'
25
+ Provider
26
+ end
27
+
28
+ action_hook(:remove_libvirt_image) do |hook|
29
+ hook.after Vagrant::Action::Builtin::BoxRemove, Action.remove_libvirt_image
30
+ end
31
+
32
+ guest_capability('linux', 'mount_p9_shared_folder') do
33
+ require_relative 'cap/mount_p9'
34
+ Cap::MountP9
35
+ end
36
+
37
+ provider_capability(:libvirt, :nic_mac_addresses) do
38
+ require_relative 'cap/nic_mac_addresses'
39
+ Cap::NicMacAddresses
40
+ end
41
+
42
+ # lower priority than nfs or rsync
43
+ # https://github.com/vagrant-libvirt/vagrant-libvirt/pull/170
44
+ synced_folder('9p', 4) do
45
+ require_relative 'cap/synced_folder'
46
+ VagrantPlugins::SyncedFolder9p::SyncedFolder
47
+ end
48
+
49
+ # This initializes the internationalization strings.
50
+ def self.setup_i18n
51
+ I18n.load_path << File.expand_path('locales/en.yml',
52
+ ProviderLibvirt.source_root)
53
+ I18n.reload!
54
+ end
55
+
56
+ # This sets up our log level to be whatever VAGRANT_LOG is.
57
+ def self.setup_logging
58
+ require 'log4r'
59
+
60
+ level = nil
61
+ begin
62
+ level = Log4r.const_get(ENV['VAGRANT_LOG'].upcase)
63
+ rescue NameError
64
+ # This means that the logging constant wasn't found,
65
+ # which is fine. We just keep `level` as `nil`. But
66
+ # we tell the user.
67
+ level = nil
68
+ end
69
+
70
+ # Some constants, such as "true" resolve to booleans, so the
71
+ # above error checking doesn't catch it. This will check to make
72
+ # sure that the log level is an integer, as Log4r requires.
73
+ level = nil unless level.is_a?(Integer)
74
+
75
+ # Set the logging level on all "vagrant" namespaced
76
+ # logs as long as we have a valid level.
77
+ if level
78
+ logger = Log4r::Logger.new('vagrant_libvirt')
79
+ logger.outputters = Log4r::Outputter.stderr
80
+ logger.level = level
81
+ logger = nil
82
+ end
83
+ end
84
+
85
+ # Setup logging and i18n before any autoloading loads other classes
86
+ # with logging configured as this prevents inheritance of the log level
87
+ # from the parent logger.
88
+ setup_logging
89
+ setup_i18n
90
+ end
91
+ end
92
+ end
@@ -0,0 +1,130 @@
1
+ require 'vagrant'
2
+
3
+ module VagrantPlugins
4
+ module ProviderLibvirt
5
+ autoload :Driver, 'vagrant-libvirt/driver'
6
+
7
+ # This is the base class for a provider for the V2 API. A provider
8
+ # is responsible for creating compute resources to match the
9
+ # needs of a Vagrant-configured system.
10
+ class Provider < Vagrant.plugin('2', :provider)
11
+ def initialize(machine)
12
+ @machine = machine
13
+ raise 'REQUIRE USE RUBY >= 1.9.3 VERSION' if RUBY_VERSION < '1.9.3'
14
+ end
15
+
16
+ # This should return an action callable for the given name.
17
+ def action(name)
18
+ # Attempt to get the action method from the Action class if it
19
+ # exists, otherwise return nil to show that we don't support the
20
+ # given action.
21
+ action_method = "action_#{name}"
22
+ return Action.send(action_method) if Action.respond_to?(action_method)
23
+ nil
24
+ end
25
+
26
+ def driver
27
+ return @driver if @driver
28
+
29
+ @driver = Driver.new(@machine)
30
+ end
31
+
32
+ # This method is called if the underying machine ID changes. Providers
33
+ # can use this method to load in new data for the actual backing
34
+ # machine or to realize that the machine is now gone (the ID can
35
+ # become `nil`).
36
+ def machine_id_changed; end
37
+
38
+ # This should return a hash of information that explains how to
39
+ # SSH into the machine. If the machine is not at a point where
40
+ # SSH is even possible, then `nil` should be returned.
41
+ def ssh_info
42
+ # Return the ssh_info if already retrieved otherwise call the driver
43
+ # and save the result.
44
+ #
45
+ # Ssh info has following format..
46
+ #
47
+ # {
48
+ # :host => "1.2.3.4",
49
+ # :port => "22",
50
+ # :username => "mitchellh",
51
+ # :private_key_path => "/path/to/my/key"
52
+ # }
53
+ # note that modifing @machine.id or accessing @machine.state is not
54
+ # thread safe, so be careful to avoid these here as this method may
55
+ # be called from other threads of execution.
56
+ return nil if state.id != :running
57
+
58
+ ip = driver.get_ipaddress(@machine)
59
+
60
+ # if can't determine the IP, just return nil and let the core
61
+ # deal with it, similar to the docker provider
62
+ return nil unless ip
63
+
64
+ ssh_info = {
65
+ host: ip,
66
+ port: @machine.config.ssh.guest_port,
67
+ forward_agent: @machine.config.ssh.forward_agent,
68
+ forward_x11: @machine.config.ssh.forward_x11
69
+ }
70
+
71
+ if @machine.provider_config.connect_via_ssh
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
+
78
+ end
79
+
80
+ ssh_info
81
+ end
82
+
83
+ def mac_addresses
84
+ # Run a custom action called "read_mac_addresses" which will return
85
+ # a list of mac addresses used by the machine. The returned data will
86
+ # be in the following format:
87
+ #
88
+ # {
89
+ # <ADAPTER_ID>: <MAC>
90
+ # }
91
+ env = @machine.action('read_mac_addresses')
92
+ env[:machine_mac_addresses]
93
+ end
94
+
95
+ # This should return the state of the machine within this provider.
96
+ # The state must be an instance of {MachineState}.
97
+ def state
98
+ state_id = nil
99
+ state_id = :not_created unless @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 unless 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'
110
+
111
+ # Get the short and long description
112
+ short = state_id.to_s.tr('_', ' ')
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
119
+
120
+ # Return the MachineState object
121
+ Vagrant::MachineState.new(state_id, short, long)
122
+ end
123
+
124
+ def to_s
125
+ id = @machine.id.nil? ? 'new' : @machine.id
126
+ "Libvirt (#{id})"
127
+ end
128
+ end
129
+ end
130
+ end