mirror of
https://github.com/vagrant-libvirt/vagrant-libvirt.git
synced 2026-07-29 23:58:20 -05: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:
@@ -1,7 +1,7 @@
|
|||||||
#!/usr/bin/env rake
|
#!/usr/bin/env rake
|
||||||
|
|
||||||
require 'rubygems'
|
#require 'rubygems'
|
||||||
require 'bundler/setup'
|
#require 'bundler/setup'
|
||||||
#require 'bundler/gem_tasks'
|
require 'bundler/gem_tasks'
|
||||||
Bundler::GemHelper.install_tasks
|
Bundler::GemHelper.install_tasks
|
||||||
|
|
||||||
|
|||||||
@@ -29,12 +29,12 @@ module VagrantPlugins
|
|||||||
b2.use CreateDomainVolume
|
b2.use CreateDomainVolume
|
||||||
b2.use CreateDomain
|
b2.use CreateDomain
|
||||||
b2.use CreateNetworkInterfaces
|
b2.use CreateNetworkInterfaces
|
||||||
end
|
|
||||||
|
|
||||||
b.use TimedProvision
|
b2.use TimedProvision
|
||||||
b.use StartDomain
|
b2.use StartDomain
|
||||||
b.use WaitTillUp
|
b2.use WaitTillUp
|
||||||
b.use SyncFolders
|
b2.use SyncFolders
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -55,6 +55,71 @@ module VagrantPlugins
|
|||||||
end
|
end
|
||||||
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
|
# 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.
|
# state is expected to be put into the `:machine_state_id` key.
|
||||||
def self.action_read_state
|
def self.action_read_state
|
||||||
@@ -76,18 +141,7 @@ module VagrantPlugins
|
|||||||
end
|
end
|
||||||
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__))
|
action_root = Pathname.new(File.expand_path("../action", __FILE__))
|
||||||
autoload :Suspend, action_root.join("suspend")
|
|
||||||
autoload :ConnectLibvirt, action_root.join("connect_libvirt")
|
autoload :ConnectLibvirt, action_root.join("connect_libvirt")
|
||||||
autoload :IsCreated, action_root.join("is_created")
|
autoload :IsCreated, action_root.join("is_created")
|
||||||
autoload :MessageAlreadyCreated, action_root.join("message_already_created")
|
autoload :MessageAlreadyCreated, action_root.join("message_already_created")
|
||||||
@@ -100,6 +154,8 @@ module VagrantPlugins
|
|||||||
autoload :CreateNetworkInterfaces, action_root.join("create_network_interfaces")
|
autoload :CreateNetworkInterfaces, action_root.join("create_network_interfaces")
|
||||||
autoload :DestroyDomain, action_root.join("destroy_domain")
|
autoload :DestroyDomain, action_root.join("destroy_domain")
|
||||||
autoload :StartDomain, action_root.join("start_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 :ReadState, action_root.join("read_state")
|
||||||
autoload :ReadSSHInfo, action_root.join("read_ssh_info")
|
autoload :ReadSSHInfo, action_root.join("read_ssh_info")
|
||||||
autoload :TimedProvision, action_root.join("timed_provision")
|
autoload :TimedProvision, action_root.join("timed_provision")
|
||||||
|
|||||||
@@ -48,11 +48,9 @@ module VagrantPlugins
|
|||||||
conn_attr[:libvirt_password] = config.password if config.password
|
conn_attr[:libvirt_password] = config.password if config.password
|
||||||
|
|
||||||
# Setup command for retrieving IP address for newly created machine
|
# Setup command for retrieving IP address for newly created machine
|
||||||
# with some MAC address. Get it via arp table. This solution doesn't
|
# with some MAC address. Get it from dnsmasq leases table.
|
||||||
# require arpwatch to be installed.
|
conn_attr[:libvirt_ip_command] = "cat /var/lib/libvirt/dnsmasq/*.leases"
|
||||||
conn_attr[:libvirt_ip_command] = "arp -an | grep $mac | sed '"
|
conn_attr[:libvirt_ip_command] << " | grep $mac | awk ' { print $3 }'"
|
||||||
conn_attr[:libvirt_ip_command] << 's/.*(\([0-9\.]*\)).*/\1/'
|
|
||||||
conn_attr[:libvirt_ip_command] << "'"
|
|
||||||
|
|
||||||
@logger.info("Connecting to Libvirt (#{uri}) ...")
|
@logger.info("Connecting to Libvirt (#{uri}) ...")
|
||||||
begin
|
begin
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ module VagrantPlugins
|
|||||||
env[:ui].info(" -- Cpus: #{@cpus}")
|
env[:ui].info(" -- Cpus: #{@cpus}")
|
||||||
env[:ui].info(" -- Memory: #{@memory_size/1024}M")
|
env[:ui].info(" -- Memory: #{@memory_size/1024}M")
|
||||||
env[:ui].info(" -- Base box: #{env[:machine].box.name}")
|
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}")
|
env[:ui].info(" -- Image: #{@domain_volume_path}")
|
||||||
|
|
||||||
# Create libvirt domain.
|
# Create libvirt domain.
|
||||||
|
|||||||
@@ -4,24 +4,26 @@ module VagrantPlugins
|
|||||||
module Libvirt
|
module Libvirt
|
||||||
module Action
|
module Action
|
||||||
class DestroyDomain
|
class DestroyDomain
|
||||||
|
|
||||||
def initialize(app, env)
|
def initialize(app, env)
|
||||||
@logger = Log4r::Logger.new("vagrant_libvirt::action::destroy_domain")
|
@logger = Log4r::Logger.new("vagrant_libvirt::action::destroy_domain")
|
||||||
@app = app
|
@app = app
|
||||||
end
|
end
|
||||||
|
|
||||||
def call(env)
|
def call(env)
|
||||||
|
# Destroy the server, remove the tracking ID and file holding IP
|
||||||
# Destroy the server and remove the tracking ID
|
# address.
|
||||||
env[:ui].info(I18n.t("vagrant_libvirt.destroy_domain"))
|
env[:ui].info(I18n.t("vagrant_libvirt.destroy_domain"))
|
||||||
|
|
||||||
domain = env[:libvirt_compute].servers.get(env[:machine].id.to_s)
|
domain = env[:libvirt_compute].servers.get(env[:machine].id.to_s)
|
||||||
domain.destroy(:destroy_volumes => true)
|
domain.destroy(:destroy_volumes => true)
|
||||||
env[:machine].id = nil
|
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)
|
@app.call(env)
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -18,23 +18,58 @@ module VagrantPlugins
|
|||||||
@app.call(env)
|
@app.call(env)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def read_ssh_info(libvirt,machine)
|
||||||
def read_ssh_info(libvirt, machine)
|
|
||||||
return nil if machine.id.nil?
|
return nil if machine.id.nil?
|
||||||
|
|
||||||
# Find the machine
|
# Find the machine
|
||||||
server = libvirt.servers.get(machine.id)
|
domain = libvirt.servers.get(machine.id)
|
||||||
if server.nil?
|
if domain.nil?
|
||||||
# The machine can't be found
|
# The machine can't be found
|
||||||
@logger.info("Machine couldn't be found, assuming it got destroyed.")
|
@logger.info("Machine couldn't be found, assuming it got destroyed.")
|
||||||
machine.id = nil
|
machine.id = nil
|
||||||
return nil
|
return nil
|
||||||
end
|
end
|
||||||
|
|
||||||
# Get ip address of machine
|
# IP address of machine is stored in $data_dir/ip file. Why? Commands
|
||||||
ip_address = server.public_ip_address
|
# like ssh or provision need to get IP of VM long time after it was
|
||||||
ip_address = server.private_ip_address if ip_address == nil
|
# started and gathered IP. Record in arp table is lost, and this is
|
||||||
return nil if ip_address == nil
|
# 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
|
# Return the info
|
||||||
# TODO: Some info should be configurable in Vagrantfile
|
# TODO: Some info should be configurable in Vagrantfile
|
||||||
@@ -43,8 +78,7 @@ module VagrantPlugins
|
|||||||
:port => 22,
|
:port => 22,
|
||||||
:username => 'root',
|
:username => 'root',
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -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
|
||||||
+10
-7
@@ -3,23 +3,26 @@ require 'log4r'
|
|||||||
module VagrantPlugins
|
module VagrantPlugins
|
||||||
module Libvirt
|
module Libvirt
|
||||||
module Action
|
module Action
|
||||||
|
# Suspend domain.
|
||||||
class Suspend
|
class SuspendDomain
|
||||||
def initialize(app, env)
|
def initialize(app, env)
|
||||||
@logger = Log4r::Logger.new("vagrant_libvirt::action::create_domain")
|
@logger = Log4r::Logger.new("vagrant_libvirt::action::suspend_domain")
|
||||||
@app = app
|
@app = app
|
||||||
end
|
end
|
||||||
|
|
||||||
# make pause
|
# make pause
|
||||||
def call(env)
|
def call(env)
|
||||||
vmid = env[:machine].id.to_s.chomp
|
env[:ui].info(I18n.t("vagrant_libvirt.suspending_domain"))
|
||||||
domain = env[:libvirt_compute].servers.get(vmid)
|
|
||||||
|
domain = env[:libvirt_compute].servers.get(env[:machine].id.to_s)
|
||||||
|
raise Errors::NoDomainError if domain == nil
|
||||||
|
|
||||||
domain.suspend
|
domain.suspend
|
||||||
@logger.info("Machine #{vmid} is suspended ")
|
@logger.info("Machine #{env[:machine].id} is suspended ")
|
||||||
|
|
||||||
@app.call(env)
|
@app.call(env)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -47,6 +47,13 @@ module VagrantPlugins
|
|||||||
@logger.info("Got IP address #{env[:ip_address]}")
|
@logger.info("Got IP address #{env[:ip_address]}")
|
||||||
@logger.info("Time for getting IP: #{env[:metrics]["instance_ip_time"]}")
|
@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
|
# Machine has ip address assigned, now wait till we are able to
|
||||||
# connect via ssh.
|
# connect via ssh.
|
||||||
env[:metrics]["instance_ssh_time"] = Util::Timer.time do
|
env[:metrics]["instance_ssh_time"] = Util::Timer.time do
|
||||||
|
|||||||
@@ -85,6 +85,15 @@ module VagrantPlugins
|
|||||||
class AttachDeviceError < VagrantLibvirtError
|
class AttachDeviceError < VagrantLibvirtError
|
||||||
error_key(:attach_device_error)
|
error_key(:attach_device_error)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
class NoIpAddressError < VagrantLibvirtError
|
||||||
|
error_key(:no_ip_address_error)
|
||||||
|
end
|
||||||
|
|
||||||
|
class IpAddressMismatchError < VagrantLibvirtError
|
||||||
|
error_key(:ip_address_mismatch_error)
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
+19
-9
@@ -1,13 +1,13 @@
|
|||||||
en:
|
en:
|
||||||
vagrant_libvirt:
|
vagrant_libvirt:
|
||||||
already_created: |-
|
already_created: |-
|
||||||
The machine is already created.
|
The domain is already created.
|
||||||
not_created: |-
|
not_created: |-
|
||||||
Machine is not created. Please run `vagrant up` first.
|
Domain is not created. Please run `vagrant up` first.
|
||||||
finding_volume: |-
|
finding_volume: |-
|
||||||
Checking if volume is available.
|
Checking if volume is available.
|
||||||
creating_domain: |-
|
creating_domain: |-
|
||||||
Creating machine with the following settings...
|
Creating domain with the following settings...
|
||||||
uploading_volume: |-
|
uploading_volume: |-
|
||||||
Uploading base box image as volume into libvirt storage...
|
Uploading base box image as volume into libvirt storage...
|
||||||
creating_domain_volume: |-
|
creating_domain_volume: |-
|
||||||
@@ -15,17 +15,21 @@ en:
|
|||||||
removing_domain_volume: |-
|
removing_domain_volume: |-
|
||||||
Removing image (snapshot of base box volume).
|
Removing image (snapshot of base box volume).
|
||||||
starting_domain: |-
|
starting_domain: |-
|
||||||
Starting machine.
|
Starting domain.
|
||||||
terminating: |-
|
terminating: |-
|
||||||
Removing machine...
|
Removing domain...
|
||||||
poweroff_domain: |-
|
poweroff_domain: |-
|
||||||
Poweroff machine.
|
Poweroff domain.
|
||||||
destroy_domain: |-
|
destroy_domain: |-
|
||||||
Removing machine...
|
Removing domain...
|
||||||
|
resuming_domain: |-
|
||||||
|
Resuming domain...
|
||||||
|
suspending_domain: |-
|
||||||
|
Suspending domain...
|
||||||
waiting_for_ready: |-
|
waiting_for_ready: |-
|
||||||
Waiting for machine to become "ready"...
|
Waiting for domain to become "ready"...
|
||||||
waiting_for_ip: |-
|
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: |-
|
||||||
Waiting for SSH to become available...
|
Waiting for SSH to become available...
|
||||||
booted: |-
|
booted: |-
|
||||||
@@ -89,6 +93,12 @@ en:
|
|||||||
No domain found. %{error_message}
|
No domain found. %{error_message}
|
||||||
attach_device_error: |-
|
attach_device_error: |-
|
||||||
Error while attaching new device to domain. %{error_message}
|
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:
|
states:
|
||||||
short_paused: |-
|
short_paused: |-
|
||||||
|
|||||||
Reference in New Issue
Block a user