mirror of
				https://github.com/vagrant-libvirt/vagrant-libvirt.git
				synced 2025-02-25 18:55:27 -06:00 
			
		
		
		
	- Changed way how to get IP address of new VM - checks
/var/lib/libvirt/dnsmasq/*.leases files. - IP address is saved in $data_dir/ip file for future. This IP is then checked if it match with VMs MAC address. - Added ssh, provision and resume subcommand
This commit is contained in:
		
							
								
								
									
										6
									
								
								Rakefile
									
									
									
									
									
								
							
							
						
						
									
										6
									
								
								Rakefile
									
									
									
									
									
								
							| @@ -1,7 +1,7 @@ | ||||
| #!/usr/bin/env rake | ||||
|  | ||||
| require 'rubygems' | ||||
| require 'bundler/setup' | ||||
| #require 'bundler/gem_tasks' | ||||
| #require 'rubygems' | ||||
| #require 'bundler/setup' | ||||
| require 'bundler/gem_tasks' | ||||
| Bundler::GemHelper.install_tasks | ||||
|  | ||||
|   | ||||
| @@ -29,12 +29,12 @@ module VagrantPlugins | ||||
|             b2.use CreateDomainVolume | ||||
|             b2.use CreateDomain | ||||
|             b2.use CreateNetworkInterfaces | ||||
|           end | ||||
|  | ||||
|           b.use TimedProvision | ||||
|           b.use StartDomain | ||||
|           b.use WaitTillUp | ||||
|           b.use SyncFolders | ||||
|             b2.use TimedProvision | ||||
|             b2.use StartDomain | ||||
|             b2.use WaitTillUp | ||||
|             b2.use SyncFolders | ||||
|           end | ||||
|         end | ||||
|       end | ||||
|  | ||||
| @@ -55,6 +55,71 @@ module VagrantPlugins | ||||
|         end | ||||
|       end | ||||
|  | ||||
|       # This action is called to SSH into the machine. | ||||
|       def self.action_ssh | ||||
|         Vagrant::Action::Builder.new.tap do |b| | ||||
|           b.use ConfigValidate | ||||
|           b.use Call, IsCreated do |env, b2| | ||||
|             if !env[:result] | ||||
|               b2.use MessageNotCreated | ||||
|               next | ||||
|             end | ||||
|  | ||||
|             b2.use SSHExec | ||||
|           end | ||||
|         end | ||||
|       end | ||||
|  | ||||
|       # This action is called when `vagrant provision` is called. | ||||
|       def self.action_provision | ||||
|         Vagrant::Action::Builder.new.tap do |b| | ||||
|           b.use ConfigValidate | ||||
|           b.use Call, IsCreated do |env, b2| | ||||
|             if !env[:result] | ||||
|               b2.use MessageNotCreated | ||||
|               next | ||||
|             end | ||||
|  | ||||
|             b2.use Provision | ||||
|             b2.use SyncFolders | ||||
|           end | ||||
|         end | ||||
|       end | ||||
|  | ||||
|       # This is the action that is primarily responsible for suspending | ||||
|       # the virtual machine. | ||||
|       def self.action_suspend | ||||
|         Vagrant::Action::Builder.new.tap do |b| | ||||
|           b.use ConfigValidate | ||||
|           b.use Call, IsCreated do |env, b2| | ||||
|             if !env[:result] | ||||
|               b2.use MessageNotCreated | ||||
|               next | ||||
|             end | ||||
|  | ||||
|             b2.use ConnectLibvirt | ||||
|             b2.use SuspendDomain | ||||
|           end | ||||
|         end | ||||
|       end | ||||
|  | ||||
|       # This is the action that is primarily responsible for resuming | ||||
|       # suspended machines. | ||||
|       def self.action_resume | ||||
|         Vagrant::Action::Builder.new.tap do |b| | ||||
|           b.use ConfigValidate | ||||
|           b.use Call, IsCreated do |env, b2| | ||||
|             if !env[:result] | ||||
|               b2.use MessageNotCreated | ||||
|               next | ||||
|             end | ||||
|  | ||||
|             b2.use ConnectLibvirt | ||||
|             b2.use ResumeDomain | ||||
|           end | ||||
|         end | ||||
|       end | ||||
|  | ||||
|       # This action is called to read the state of the machine. The resulting | ||||
|       # state is expected to be put into the `:machine_state_id` key. | ||||
|       def self.action_read_state | ||||
| @@ -76,18 +141,7 @@ module VagrantPlugins | ||||
|         end | ||||
|       end | ||||
|  | ||||
|       # suspend | ||||
|       # save vm to file | ||||
|       def self.action_suspend | ||||
|         Vagrant::Action::Builder.new.tap do |b| | ||||
|           b.use ConfigValidate | ||||
|           b.use ConnectLibvirt | ||||
|           b.use Suspend | ||||
|         end | ||||
|       end | ||||
|  | ||||
|       action_root = Pathname.new(File.expand_path("../action", __FILE__)) | ||||
|       autoload :Suspend, action_root.join("suspend") | ||||
|       autoload :ConnectLibvirt, action_root.join("connect_libvirt") | ||||
|       autoload :IsCreated, action_root.join("is_created") | ||||
|       autoload :MessageAlreadyCreated, action_root.join("message_already_created") | ||||
| @@ -100,6 +154,8 @@ module VagrantPlugins | ||||
|       autoload :CreateNetworkInterfaces, action_root.join("create_network_interfaces") | ||||
|       autoload :DestroyDomain, action_root.join("destroy_domain") | ||||
|       autoload :StartDomain, action_root.join("start_domain") | ||||
|       autoload :SuspendDomain, action_root.join("suspend_domain") | ||||
|       autoload :ResumeDomain, action_root.join("resume_domain") | ||||
|       autoload :ReadState, action_root.join("read_state") | ||||
|       autoload :ReadSSHInfo, action_root.join("read_ssh_info") | ||||
|       autoload :TimedProvision, action_root.join("timed_provision") | ||||
|   | ||||
| @@ -48,11 +48,9 @@ module VagrantPlugins | ||||
|           conn_attr[:libvirt_password] = config.password if config.password | ||||
|            | ||||
|           # Setup command for retrieving IP address for newly created machine | ||||
|           # with some MAC address. Get it via arp table. This solution doesn't | ||||
|           # require arpwatch to be installed. | ||||
|           conn_attr[:libvirt_ip_command] = "arp -an | grep $mac | sed '" | ||||
|           conn_attr[:libvirt_ip_command] << 's/.*(\([0-9\.]*\)).*/\1/' | ||||
|           conn_attr[:libvirt_ip_command] << "'" | ||||
|           # with some MAC address. Get it from dnsmasq leases table. | ||||
|           conn_attr[:libvirt_ip_command] =  "cat /var/lib/libvirt/dnsmasq/*.leases" | ||||
|           conn_attr[:libvirt_ip_command] << " | grep $mac | awk ' { print $3 }'" | ||||
|  | ||||
|           @logger.info("Connecting to Libvirt (#{uri}) ...") | ||||
|           begin | ||||
|   | ||||
| @@ -37,6 +37,7 @@ module VagrantPlugins | ||||
|           env[:ui].info(" -- Cpus:          #{@cpus}") | ||||
|           env[:ui].info(" -- Memory:        #{@memory_size/1024}M") | ||||
|           env[:ui].info(" -- Base box:      #{env[:machine].box.name}") | ||||
|           env[:ui].info(" -- Storage pool:  #{env[:machine].provider_config.storage_pool_name}") | ||||
|           env[:ui].info(" -- Image:         #{@domain_volume_path}") | ||||
|  | ||||
|           # Create libvirt domain. | ||||
|   | ||||
| @@ -4,24 +4,26 @@ module VagrantPlugins | ||||
|   module Libvirt | ||||
|     module Action | ||||
|       class DestroyDomain | ||||
|  | ||||
|         def initialize(app, env) | ||||
|           @logger = Log4r::Logger.new("vagrant_libvirt::action::destroy_domain") | ||||
|           @app = app | ||||
|         end | ||||
|  | ||||
|         def call(env) | ||||
|  | ||||
|           # Destroy the server and remove the tracking ID | ||||
|           # Destroy the server, remove the tracking ID and file holding IP | ||||
|           # address. | ||||
|           env[:ui].info(I18n.t("vagrant_libvirt.destroy_domain")) | ||||
|  | ||||
|           domain = env[:libvirt_compute].servers.get(env[:machine].id.to_s) | ||||
|           domain.destroy(:destroy_volumes => true) | ||||
|           env[:machine].id = nil | ||||
|  | ||||
|           # Remove file holding IP address | ||||
|           ip_file_path = env[:machine].data_dir + 'ip' | ||||
|           File.delete(ip_file_path) if File.exists?(ip_file_path) | ||||
|  | ||||
|           @app.call(env) | ||||
|         end | ||||
|  | ||||
|       end | ||||
|     end | ||||
|   end | ||||
|   | ||||
| @@ -18,23 +18,58 @@ module VagrantPlugins | ||||
|           @app.call(env) | ||||
|         end | ||||
|  | ||||
|  | ||||
|         def read_ssh_info(libvirt, machine) | ||||
|         def read_ssh_info(libvirt,machine) | ||||
|           return nil if machine.id.nil? | ||||
|  | ||||
|           # Find the machine | ||||
|           server = libvirt.servers.get(machine.id) | ||||
|           if server.nil? | ||||
|           domain = libvirt.servers.get(machine.id) | ||||
|           if domain.nil? | ||||
|             # The machine can't be found | ||||
|             @logger.info("Machine couldn't be found, assuming it got destroyed.") | ||||
|             machine.id = nil | ||||
|             return nil | ||||
|           end | ||||
|  | ||||
|           # Get ip address of machine | ||||
|           ip_address = server.public_ip_address | ||||
|           ip_address = server.private_ip_address if ip_address == nil | ||||
|           return nil if ip_address == nil | ||||
|           # IP address of machine is stored in $data_dir/ip file. Why? Commands | ||||
|           # like ssh or provision need to get IP of VM long time after it was | ||||
|           # started and gathered IP. Record in arp table is lost, and this is | ||||
|           # the way how to store this info. Not an ideal solution, but libvirt | ||||
|           # doesn't provide way how to get IP of some domain.  | ||||
|           ip_file = machine.data_dir + 'ip' | ||||
|           raise Errors::NoIpAddressError if not File.exists?(ip_file) | ||||
|           ip_address = File.open(ip_file, 'r') do |file| | ||||
|             file.read | ||||
|           end | ||||
|  | ||||
|           # Check if stored IP address matches with MAC address of machine. | ||||
|           # Command is executed either localy, or on remote libvirt hypervisor, | ||||
|           # depends on establised fog libvirt connection. | ||||
|           ip_match = false | ||||
|           ip_command = "ping -c1 #{ip_address} > /dev/null && " | ||||
|           ip_command << "arp -an | grep $mac | sed '" | ||||
|           ip_command << 's/.*(\([0-9\.]*\)).*/\1/' + "'" | ||||
|           options_hash = { :ip_command => ip_command } | ||||
|           3.times do |x| | ||||
|             break if ip_match | ||||
|             domain.wait_for(1) { | ||||
|               begin | ||||
|                 addresses(service, options_hash).each_pair do |type, ip| | ||||
|                   if ip[0] != nil | ||||
|                     ip_match = true | ||||
|                     break | ||||
|                   end | ||||
|                 end | ||||
|               rescue Fog::Errors::Error | ||||
|                 # Sometimes, if pinging happen too quickly after after IP | ||||
|                 # assignment, machine is not responding yet. Give it a little | ||||
|                 # time.. | ||||
|                 sleep 1 | ||||
|               end | ||||
|  | ||||
|               break if ip_match | ||||
|             } | ||||
|           end | ||||
|           raise Errors::IpAddressMismatchError if not ip_match | ||||
|  | ||||
|           # Return the info | ||||
|           # TODO: Some info should be configurable in Vagrantfile | ||||
| @@ -43,8 +78,7 @@ module VagrantPlugins | ||||
|             :port => 22, | ||||
|             :username => 'root', | ||||
|           } | ||||
|         end | ||||
|   | ||||
|         end  | ||||
|       end | ||||
|     end | ||||
|   end | ||||
|   | ||||
							
								
								
									
										27
									
								
								lib/vagrant-libvirt/action/resume_domain.rb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								lib/vagrant-libvirt/action/resume_domain.rb
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,27 @@ | ||||
| require 'log4r' | ||||
|  | ||||
| module VagrantPlugins | ||||
|   module Libvirt | ||||
|     module Action | ||||
|       # Resume suspended domain. | ||||
|       class ResumeDomain | ||||
|         def initialize(app, env) | ||||
|           @logger = Log4r::Logger.new("vagrant_libvirt::action::resume_domain") | ||||
|           @app = app | ||||
|         end | ||||
|  | ||||
|         def call(env) | ||||
|           env[:ui].info(I18n.t("vagrant_libvirt.resuming_domain")) | ||||
|  | ||||
|           domain = env[:libvirt_compute].servers.get(env[:machine].id.to_s) | ||||
|           raise Errors::NoDomainError if domain == nil | ||||
|  | ||||
|           domain.resume | ||||
|           @logger.info("Machine #{env[:machine].id} is resumed.") | ||||
|  | ||||
|           @app.call(env) | ||||
|         end | ||||
|       end | ||||
|     end | ||||
|   end | ||||
| end | ||||
| @@ -3,23 +3,26 @@ require 'log4r' | ||||
| module VagrantPlugins | ||||
|   module Libvirt | ||||
|     module Action | ||||
| 
 | ||||
|       class Suspend | ||||
|       # Suspend domain. | ||||
|       class SuspendDomain | ||||
|         def initialize(app, env) | ||||
|           @logger = Log4r::Logger.new("vagrant_libvirt::action::create_domain") | ||||
|           @logger = Log4r::Logger.new("vagrant_libvirt::action::suspend_domain") | ||||
|           @app = app | ||||
|         end | ||||
| 
 | ||||
|         # make pause | ||||
|         def call(env) | ||||
|           vmid = env[:machine].id.to_s.chomp | ||||
|           domain = env[:libvirt_compute].servers.get(vmid) | ||||
|           env[:ui].info(I18n.t("vagrant_libvirt.suspending_domain")) | ||||
| 
 | ||||
|           domain = env[:libvirt_compute].servers.get(env[:machine].id.to_s) | ||||
|           raise Errors::NoDomainError if domain == nil | ||||
| 
 | ||||
|           domain.suspend | ||||
|           @logger.info("Machine #{vmid} is suspended ") | ||||
|           @logger.info("Machine #{env[:machine].id} is suspended ") | ||||
| 
 | ||||
|           @app.call(env) | ||||
|         end | ||||
|       end | ||||
| 
 | ||||
|     end | ||||
|   end | ||||
| end | ||||
| @@ -47,6 +47,13 @@ module VagrantPlugins | ||||
|           @logger.info("Got IP address #{env[:ip_address]}") | ||||
|           @logger.info("Time for getting IP: #{env[:metrics]["instance_ip_time"]}") | ||||
|  | ||||
|           # Save newly assigned IP address to machines data_dir | ||||
|           ip_file_path = env[:machine].data_dir + 'ip' | ||||
|           @logger.info("Saving IP address to #{ip_file_path} file.") | ||||
|           File.open(ip_file_path, 'w') do |file| | ||||
|             file.write(env[:ip_address]) | ||||
|           end | ||||
|  | ||||
|           # Machine has ip address assigned, now wait till we are able to | ||||
|           # connect via ssh. | ||||
|           env[:metrics]["instance_ssh_time"] = Util::Timer.time do | ||||
|   | ||||
| @@ -85,6 +85,15 @@ module VagrantPlugins | ||||
|       class AttachDeviceError < VagrantLibvirtError | ||||
|         error_key(:attach_device_error) | ||||
|       end | ||||
|  | ||||
|       class NoIpAddressError < VagrantLibvirtError | ||||
|         error_key(:no_ip_address_error) | ||||
|       end | ||||
|  | ||||
|       class IpAddressMismatchError < VagrantLibvirtError | ||||
|         error_key(:ip_address_mismatch_error) | ||||
|       end | ||||
|  | ||||
|     end | ||||
|   end | ||||
| end | ||||
|   | ||||
| @@ -1,13 +1,13 @@ | ||||
| en: | ||||
|   vagrant_libvirt: | ||||
|     already_created: |- | ||||
|       The machine is already created. | ||||
|       The domain is already created. | ||||
|     not_created: |- | ||||
|       Machine is not created. Please run `vagrant up` first. | ||||
|       Domain is not created. Please run `vagrant up` first. | ||||
|     finding_volume: |- | ||||
|       Checking if volume is available. | ||||
|     creating_domain: |- | ||||
|       Creating machine with the following settings... | ||||
|       Creating domain with the following settings... | ||||
|     uploading_volume: |- | ||||
|       Uploading base box image as volume into libvirt storage... | ||||
|     creating_domain_volume: |- | ||||
| @@ -15,17 +15,21 @@ en: | ||||
|     removing_domain_volume: |- | ||||
|       Removing image (snapshot of base box volume). | ||||
|     starting_domain: |- | ||||
|       Starting machine. | ||||
|       Starting domain. | ||||
|     terminating: |- | ||||
|       Removing machine... | ||||
|       Removing domain... | ||||
|     poweroff_domain: |- | ||||
|       Poweroff machine. | ||||
|       Poweroff domain. | ||||
|     destroy_domain: |- | ||||
|       Removing machine... | ||||
|       Removing domain... | ||||
|     resuming_domain: |- | ||||
|       Resuming domain... | ||||
|     suspending_domain: |- | ||||
|       Suspending domain... | ||||
|     waiting_for_ready: |- | ||||
|       Waiting for machine to become "ready"... | ||||
|       Waiting for domain to become "ready"... | ||||
|     waiting_for_ip: |- | ||||
|       Waiting for machine to get an IP address... | ||||
|       Waiting for domain to get an IP address... | ||||
|     waiting_for_ssh: |- | ||||
|       Waiting for SSH to become available... | ||||
|     booted: |- | ||||
| @@ -89,6 +93,12 @@ en: | ||||
|         No domain found. %{error_message} | ||||
|       attach_device_error: |- | ||||
|         Error while attaching new device to domain. %{error_message} | ||||
|       no_ip_address_error: |- | ||||
|         No IP address found. | ||||
|       ip_address_mismatch_error: |- | ||||
|         IP address mismatch. Possible reason is that domain IP address changed. | ||||
|         You can run `vagrant destroy` and then `vagrant up` to rebuild your | ||||
|         project. | ||||
|  | ||||
|     states: | ||||
|       short_paused: |- | ||||
|   | ||||
		Reference in New Issue
	
	Block a user