Merge pull request #436 from electrofelix/parallel-ssh_info

allow query of ssh_info in parallel from other machines or user
This commit is contained in:
Dmitry Vasilets 2015-08-05 21:48:13 +02:00
commit 0c1c94bf36
30 changed files with 228 additions and 294 deletions

View File

@ -7,20 +7,6 @@ module VagrantPlugins
autoload :Errors, lib_path.join('errors')
autoload :Util, lib_path.join('util')
# Hold connection handler so there is no need to connect more times than
# one. This can be annoying when there are more machines to create, or when
# doing state action first and then some other.
#
# TODO Don't sure if this is the best solution
@@libvirt_connection = nil
def self.libvirt_connection
@@libvirt_connection
end
def self.libvirt_connection=(conn)
@@libvirt_connection = conn
end
def self.source_root
@source_root ||= Pathname.new(File.expand_path('../../', __FILE__))
end

View File

@ -19,7 +19,6 @@ module VagrantPlugins
def self.action_up
Vagrant::Action::Builder.new.tap do |b|
b.use ConfigValidate
b.use ConnectLibvirt
b.use Call, IsCreated do |env, b2|
# Create VM if not yet created.
if !env[:result]
@ -58,7 +57,6 @@ module VagrantPlugins
def self.action_start
Vagrant::Action::Builder.new.tap do |b|
b.use ConfigValidate
b.use ConnectLibvirt
b.use Call, IsRunning do |env, b2|
# If the VM is running, then our work here is done, exit
next if env[:result]
@ -101,7 +99,6 @@ module VagrantPlugins
def self.action_halt
Vagrant::Action::Builder.new.tap do |b|
b.use ConfigValidate
b.use ConnectLibvirt
b.use ClearForwardedPorts
b.use Call, IsCreated do |env, b2|
if !env[:result]
@ -144,7 +141,6 @@ module VagrantPlugins
def self.action_package
Vagrant::Action::Builder.new.tap do |b|
b.use ConfigValidate
b.use ConnectLibvirt
b.use PackageDomain
end
end
@ -157,7 +153,6 @@ module VagrantPlugins
b.use Call, IsCreated do |env, b2|
if !env[:result]
# Try to remove stale volumes anyway
b2.use ConnectLibvirt
b2.use SetNameOfDomain
b2.use RemoveStaleVolume
if !env[:result]
@ -167,7 +162,6 @@ module VagrantPlugins
next
end
b2.use ConnectLibvirt
b2.use ClearForwardedPorts
# b2.use PruneNFSExports
b2.use DestroyDomain
@ -187,7 +181,6 @@ module VagrantPlugins
next
end
b2.use ConnectLibvirt
b2.use Call, IsRunning do |env2, b3|
if !env2[:result]
b3.use MessageNotRunning
@ -210,7 +203,6 @@ module VagrantPlugins
next
end
b2.use ConnectLibvirt
b2.use Call, IsRunning do |env2, b3|
if !env2[:result]
b3.use MessageNotRunning
@ -235,7 +227,6 @@ module VagrantPlugins
next
end
b2.use ConnectLibvirt
b2.use Call, IsRunning do |env2, b3|
if !env2[:result]
b3.use MessageNotRunning
@ -258,7 +249,6 @@ module VagrantPlugins
next
end
b2.use ConnectLibvirt
b2.use Call, IsSuspended do |env2, b3|
if !env2[:result]
b3.use MessageNotSuspended
@ -270,31 +260,9 @@ module VagrantPlugins
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
Vagrant::Action::Builder.new.tap do |b|
b.use ConfigValidate
b.use ConnectLibvirt
b.use ReadState
end
end
# This action is called to read the SSH info of the machine. The
# resulting state is expected to be put into the `:machine_ssh_info`
# key.
def self.action_read_ssh_info
Vagrant::Action::Builder.new.tap do |b|
b.use ConfigValidate
b.use ConnectLibvirt
b.use ReadSSHInfo
end
end
def self.action_read_mac_addresses
Vagrant::Action::Builder.new.tap do |b|
b.use ConfigValidate
b.use ConnectLibvirt
b.use ReadMacAddresses
end
end
@ -309,7 +277,6 @@ module VagrantPlugins
next
end
b2.use ConnectLibvirt
b2.use Call, IsRunning do |env2, b3|
if !env2[:result]
b3.use MessageNotRunning
@ -324,7 +291,6 @@ module VagrantPlugins
end
action_root = Pathname.new(File.expand_path('../action', __FILE__))
autoload :ConnectLibvirt, action_root.join('connect_libvirt')
autoload :PackageDomain, action_root.join('package_domain')
autoload :CreateDomain, action_root.join('create_domain')
autoload :CreateDomainVolume, action_root.join('create_domain_volume')
@ -352,9 +318,7 @@ module VagrantPlugins
autoload :PrepareNFSValidIds, action_root.join('prepare_nfs_valid_ids')
autoload :PruneNFSExports, action_root.join('prune_nfs_exports')
autoload :ReadSSHInfo, action_root.join('read_ssh_info')
autoload :ReadMacAddresses, action_root.join('read_mac_addresses')
autoload :ReadState, action_root.join('read_state')
autoload :ResumeDomain, action_root.join('resume_domain')
autoload :SetNameOfDomain, action_root.join('set_name_of_domain')

View File

@ -1,51 +0,0 @@
require 'fog/libvirt'
require 'log4r'
module VagrantPlugins
module ProviderLibvirt
module Action
class ConnectLibvirt
def initialize(app, env)
@logger = Log4r::Logger.new('vagrant_libvirt::action::connect_libvirt')
@app = app
end
def call(env)
# If already connected to libvirt, just use it and don't connect
# again.
if ProviderLibvirt.libvirt_connection
env[:libvirt_compute] = ProviderLibvirt.libvirt_connection
return @app.call(env)
end
# Get config options for libvirt provider.
config = env[:machine].provider_config
uri = config.uri
conn_attr = {}
conn_attr[:provider] = 'libvirt'
conn_attr[:libvirt_uri] = uri
conn_attr[:libvirt_username] = config.username if config.username
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 from dnsmasq leases table
ip_command = %q[ awk "/$mac/ {print \$1}" /proc/net/arp ]
conn_attr[:libvirt_ip_command] = ip_command
@logger.info("Connecting to Libvirt (#{uri}) ...")
begin
env[:libvirt_compute] = Fog::Compute.new(conn_attr)
rescue Fog::Errors::Error => e
raise Errors::FogLibvirtConnectionError,
:error_message => e.message
end
ProviderLibvirt.libvirt_connection = env[:libvirt_compute]
@app.call(env)
end
end
end
end
end

View File

@ -72,7 +72,7 @@ module VagrantPlugins
@os_type = 'hvm'
# Get path to domain image from the storage pool selected.
actual_volumes = env[:libvirt_compute].volumes.all.select do |x|
actual_volumes = env[:machine].provider.driver.connection.volumes.all.select do |x|
x.pool_name == @storage_pool_name
end
domain_volume = ProviderLibvirt::Util::Collection.find_matching(
@ -94,12 +94,12 @@ module VagrantPlugins
disk[:absolute_path] = storage_prefix + disk[:path]
if env[:libvirt_compute].volumes.select {
if env[:machine].provider.driver.connection.volumes.select {
|x| x.name == disk[:name] and x.pool_name == @storage_pool_name}.empty?
# make the disk. equivalent to:
# qemu-img create -f qcow2 <path> 5g
begin
env[:libvirt_compute].volumes.create(
env[:machine].provider.driver.connection.volumes.create(
name: disk[:name],
format_type: disk[:type],
path: disk[:absolute_path],
@ -166,7 +166,7 @@ module VagrantPlugins
# Is there a way to tell fog to create new domain with already
# existing volume? Use domain creation from template..
begin
server = env[:libvirt_compute].servers.create(
server = env[:machine].provider.driver.connection.servers.create(
xml: to_xml('domain'))
rescue Fog::Errors::Error => e
raise Errors::FogCreateServerError, error_message: e.message

View File

@ -26,12 +26,12 @@ module VagrantPlugins
# Verify the volume doesn't exist already.
domain_volume = ProviderLibvirt::Util::Collection.find_matching(
env[:libvirt_compute].volumes.all, @name)
env[:machine].provider.driver.connection.volumes.all, @name)
raise Errors::DomainVolumeExists if domain_volume
# Get path to backing image - box volume.
box_volume = ProviderLibvirt::Util::Collection.find_matching(
env[:libvirt_compute].volumes.all, env[:box_volume_name])
env[:machine].provider.driver.connection.volumes.all, env[:box_volume_name])
@backing_file = box_volume.path
# Virtual size of image. Take value worked out by HandleBoxImage
@ -40,7 +40,7 @@ module VagrantPlugins
# Create new volume from xml template. Fog currently doesn't support
# volume snapshots directly.
begin
domain_volume = env[:libvirt_compute].volumes.create(
domain_volume = env[:machine].provider.driver.connection.volumes.create(
:xml => to_xml('volume_snapshot'),
:pool_name => config.storage_pool_name)
rescue Fog::Errors::Error => e

View File

@ -27,7 +27,7 @@ module VagrantPlugins
def call(env)
# Get domain first.
begin
domain = env[:libvirt_compute].client.lookup_domain_by_uuid(
domain = env[:machine].provider.driver.connection.client.lookup_domain_by_uuid(
env[:machine].id.to_s)
rescue => e
raise Errors::NoDomainError,
@ -61,7 +61,7 @@ module VagrantPlugins
# We have slot for interface, fill it with interface configuration.
adapters[free_slot] = options
adapters[free_slot][:network_name] = interface_network(
env[:libvirt_compute].client, adapters[free_slot])
env[:machine].provider.driver.connection.client, adapters[free_slot])
end
# Create each interface as new domain device.

View File

@ -23,7 +23,7 @@ module VagrantPlugins
@available_networks = []
@options = {}
@libvirt_client = env[:libvirt_compute].client
@libvirt_client = env[:machine].provider.driver.connection.client
end
def call(env)
@ -46,7 +46,7 @@ module VagrantPlugins
# list is used throughout this class and should be easier to
# process than libvirt API calls.
@available_networks = libvirt_networks(
env[:libvirt_compute].client)
env[:machine].provider.driver.connection.client)
# Prepare a hash describing network for this specific interface.
@interface_network = {

View File

@ -17,7 +17,7 @@ module VagrantPlugins
# Fog libvirt currently doesn't support snapshots. Use
# ruby-libvirt client directly. Note this is racy, see
# http://www.libvirt.org/html/libvirt-libvirt.html#virDomainSnapshotListNames
libvirt_domain = env[:libvirt_compute].client.lookup_domain_by_uuid(
libvirt_domain = env[:machine].provider.driver.connection.client.lookup_domain_by_uuid(
env[:machine].id)
libvirt_domain.list_snapshots.each do |name|
@logger.info("Deleting snapshot '#{name}'")
@ -28,7 +28,7 @@ module VagrantPlugins
end
end
domain = env[:libvirt_compute].servers.get(env[:machine].id.to_s)
domain = env[:machine].provider.driver.connection.servers.get(env[:machine].id.to_s)
if env[:machine].provider_config.disks.empty?
# if using default configuration of disks

View File

@ -36,7 +36,7 @@ module VagrantPlugins
# lookup_network_by_uuid throws same exception
# if there is an error or if the network just doesn't exist
begin
libvirt_network = env[:libvirt_compute].client.lookup_network_by_uuid(
libvirt_network = env[:machine].provider.driver.connection.client.lookup_network_by_uuid(
network_uuid)
rescue Libvirt::RetrieveError => e
# this network is already destroyed, so move on

View File

@ -13,7 +13,7 @@ module VagrantPlugins
def call(env)
env[:ui].info(I18n.t("vagrant_libvirt.halt_domain"))
domain = env[:libvirt_compute].servers.get(env[:machine].id.to_s)
domain = env[:machine].provider.driver.connection.servers.get(env[:machine].id.to_s)
raise Errors::NoDomainError if domain == nil
@logger.info("Trying gracefull shutdown.")

View File

@ -60,7 +60,7 @@ module VagrantPlugins
@@lock.synchronize do
# Don't continue if image already exists in storage pool.
break if ProviderLibvirt::Util::Collection.find_matching(
env[:libvirt_compute].volumes.all, env[:box_volume_name])
env[:machine].provider.driver.connection.volumes.all, env[:box_volume_name])
# Box is not available as a storage pool volume. Create and upload
# it as a copy of local box image.
@ -73,7 +73,7 @@ module VagrantPlugins
message << " in storage pool #{config.storage_pool_name}."
@logger.info(message)
begin
fog_volume = env[:libvirt_compute].volumes.create(
fog_volume = env[:machine].provider.driver.connection.volumes.create(
name: env[:box_volume_name],
allocation: "#{box_image_size/1024/1024}M",
capacity: "#{box_virtual_size}G",
@ -117,10 +117,10 @@ module VagrantPlugins
image_size = File.size(image_file) # B
begin
pool = env[:libvirt_compute].client.lookup_storage_pool_by_name(
pool = env[:machine].provider.driver.connection.client.lookup_storage_pool_by_name(
pool_name)
volume = pool.lookup_volume_by_name(volume_name)
stream = env[:libvirt_compute].client.stream
stream = env[:machine].provider.driver.connection.client.stream
volume.upload(stream, offset=0, length=image_size)
# Exception ProviderLibvirt::RetrieveError can be raised if buffer is

View File

@ -23,7 +23,7 @@ module VagrantPlugins
@@lock.synchronize do
# Check for storage pool, where box image should be created
break if ProviderLibvirt::Util::Collection.find_matching(
env[:libvirt_compute].pools.all, config.storage_pool_name)
env[:machine].provider.driver.connection.pools.all, config.storage_pool_name)
@logger.info("No storage pool '#{config.storage_pool_name}' is available.")
@ -36,7 +36,7 @@ module VagrantPlugins
# Fog libvirt currently doesn't support creating pools. Use
# ruby-libvirt client directly.
begin
libvirt_pool = env[:libvirt_compute].client.define_storage_pool_xml(
libvirt_pool = env[:machine].provider.driver.connection.client.define_storage_pool_xml(
to_xml('default_storage_pool'))
libvirt_pool.build
libvirt_pool.create

View File

@ -9,7 +9,7 @@ module VagrantPlugins
end
def call(env)
domain = env[:libvirt_compute].servers.get(env[:machine].id.to_s)
domain = env[:machine].provider.driver.connection.servers.get(env[:machine].id.to_s)
raise Errors::NoDomainError if domain == nil
env[:result] = domain.state.to_s == 'running'

View File

@ -9,7 +9,7 @@ module VagrantPlugins
end
def call(env)
domain = env[:libvirt_compute].servers.get(env[:machine].id.to_s)
domain = env[:machine].provider.driver.connection.servers.get(env[:machine].id.to_s)
raise Errors::NoDomainError if domain == nil
env[:result] = domain.state.to_s == 'paused'

View File

@ -14,9 +14,9 @@ module VagrantPlugins
def call(env)
env[:ui].info(I18n.t('vagrant_libvirt.package_domain'))
libvirt_domain = env[:libvirt_compute].client.lookup_domain_by_uuid(
libvirt_domain = env[:machine].provider.driver.connection.client.lookup_domain_by_uuid(
env[:machine].id)
domain = env[:libvirt_compute].servers.get(env[:machine].id.to_s)
domain = env[:machine].provider.driver.connection.servers.get(env[:machine].id.to_s)
root_disk = domain.volumes.select do |x|
x.name == libvirt_domain.name + '.img'
end.first

View File

@ -8,7 +8,7 @@ module VagrantPlugins
end
def call(env)
env[:nfs_valid_ids] = env[:libvirt_compute].servers.all.map(&:id)
env[:nfs_valid_ids] = env[:machine].provider.driver.connection.servers.all.map(&:id)
@app.call(env)
end
end

View File

@ -12,7 +12,7 @@ module VagrantPlugins
if env[:host]
uuid = env[:machine].id
# get all uuids
uuids = env[:libvirt_compute].servers.all.map(&:id)
uuids = env[:machine].provider.driver.connection.servers.all.map(&:id)
# not exiisted in array will removed from nfs
uuids.delete(uuid)
env[:host].capability(

View File

@ -10,7 +10,7 @@ module VagrantPlugins
end
def call(env)
env[:machine_mac_addresses] = read_mac_addresses(env[:libvirt_compute], env[:machine])
env[:machine_mac_addresses] = read_mac_addresses(env[:machine].provider.driver.connection, env[:machine])
end
def read_mac_addresses(libvirt, machine)

View File

@ -1,68 +0,0 @@
require "log4r"
module VagrantPlugins
module ProviderLibvirt
module Action
# This action reads the SSH info for the machine and puts it into the
# `:machine_ssh_info` key in the environment.
class ReadSSHInfo
def initialize(app, env)
@app = app
@logger = Log4r::Logger.new("vagrant_libvirt::action::read_ssh_info")
end
def call(env)
env[:machine_ssh_info] = read_ssh_info(env[:libvirt_compute],
env[:machine])
@app.call(env)
end
def read_ssh_info(libvirt, machine)
return nil if machine.id.nil?
return nil if machine.state.id != :running
# Find the machine
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 from dnsmasq lease file.
ip_address = nil
begin
domain.wait_for(2) do
addresses.each_pair do |type, ip|
# Multiple leases are separated with a newline, return only
# the most recent address
ip_address = ip[0].split("\n").first if ip[0] != nil
end
ip_address != nil
end
rescue Fog::Errors::TimeoutError
@logger.info("Timeout at waiting for an ip address for machine %s" % machine.name)
end
if not ip_address
@logger.info("No lease found for machine %s" % machine.name)
return nil
end
ssh_info = {
:host => ip_address,
:port => machine.config.ssh.guest_port,
:forward_agent => machine.config.ssh.forward_agent,
:forward_x11 => machine.config.ssh.forward_x11,
}
ssh_info[:proxy_command] = "ssh '#{machine.provider_config.host}' -l '#{machine.provider_config.username}' -i '#{machine.provider_config.id_ssh_key_file}' nc %h %p" if machine.provider_config.connect_via_ssh
ssh_info
end
end
end
end
end

View File

@ -1,60 +0,0 @@
require 'log4r'
module VagrantPlugins
module ProviderLibvirt
module Action
# This action reads the state of the machine and puts it in the
# `:machine_state_id` key in the environment.
class ReadState
def initialize(app, env)
@app = app
@logger = Log4r::Logger.new('vagrant_libvirt::action::read_state')
end
def call(env)
env[:machine_state_id] = read_state(env[:libvirt_compute], env[:machine])
@app.call(env)
end
def read_state(libvirt, machine)
return :not_created if machine.id.nil?
begin
server = libvirt.servers.get(machine.id)
rescue Libvirt::RetrieveError => e
server = nil
@logger.debug('Machine not found #{e}.')
end
# Find the machine
begin
# Wait for libvirt to shutdown the domain
while libvirt.servers.get(machine.id).state.to_sym == :'shutting-down' do
@logger.info('Waiting on the machine to shut down...')
sleep 1
end
server = libvirt.servers.get(machine.id)
if server.nil? || server.state.to_sym == :terminated
# The machine can't be found
@logger.info('Machine terminated, assuming it got destroyed.')
machine.id = nil
return :not_created
end
rescue Libvirt::RetrieveError => e
if e.libvirt_code == ProviderLibvirt::Util::ErrorCodes::VIR_ERR_NO_DOMAIN
@logger.info("Machine #{machine.id} not found.")
machine.id = nil
return :not_created
else
raise e
end
end
# Return the state
return server.state.to_sym
end
end
end
end
end

View File

@ -22,7 +22,7 @@ module VagrantPlugins
config = env[:machine].provider_config
# Check for storage pool, where box image should be created
fog_pool = ProviderLibvirt::Util::Collection.find_matching(
env[:libvirt_compute].pools.all, config.storage_pool_name)
env[:machine].provider.driver.connection.pools.all, config.storage_pool_name)
@logger.debug("**** Pool #{fog_pool.name}")
# This is name of newly created image for vm.
@ -31,7 +31,7 @@ module VagrantPlugins
# remove root storage
box_volume = ProviderLibvirt::Util::Collection.find_matching(
env[:libvirt_compute].volumes.all, name)
env[:machine].provider.driver.connection.volumes.all, name)
if box_volume && box_volume.pool_name == fog_pool.name
@logger.info("Deleting volume #{box_volume.key}")
box_volume.destroy

View File

@ -13,7 +13,7 @@ module VagrantPlugins
def call(env)
env[:ui].info(I18n.t("vagrant_libvirt.resuming_domain"))
domain = env[:libvirt_compute].servers.get(env[:machine].id.to_s)
domain = env[:machine].provider.driver.connection.servers.get(env[:machine].id.to_s)
raise Errors::NoDomainError if domain == nil
domain.resume

View File

@ -14,11 +14,12 @@ module VagrantPlugins
env[:domain_name] = build_domain_name(env)
begin
@logger.info("Looking for domain #{env[:domain_name]} through list #{env[:libvirt_compute].servers.all}")
@logger.info("Looking for domain #{env[:domain_name]} through list " +
"#{env[:machine].provider.driver.connection.servers.all}")
# Check if the domain name is not already taken
domain = ProviderLibvirt::Util::Collection.find_matching(
env[:libvirt_compute].servers.all, env[:domain_name])
env[:machine].provider.driver.connection.servers.all, env[:domain_name])
rescue Fog::Errors::Error => e
@logger.info("#{e}")
domain = nil

View File

@ -14,7 +14,7 @@ module VagrantPlugins
def call(env)
env[:ui].info(I18n.t("vagrant_libvirt.starting_domain"))
domain = env[:libvirt_compute].servers.get(env[:machine].id.to_s)
domain = env[:machine].provider.driver.connection.servers.get(env[:machine].id.to_s)
raise Errors::NoDomainError if domain == nil
begin

View File

@ -14,7 +14,7 @@ module VagrantPlugins
def call(env)
env[:ui].info(I18n.t("vagrant_libvirt.suspending_domain"))
domain = env[:libvirt_compute].servers.get(env[:machine].id.to_s)
domain = env[:machine].provider.driver.connection.servers.get(env[:machine].id.to_s)
raise Errors::NoDomainError if domain == nil
domain.suspend

View File

@ -21,7 +21,7 @@ module VagrantPlugins
env[:metrics] ||= {}
# Get domain object
domain = env[:libvirt_compute].servers.get(env[:machine].id.to_s)
domain = env[:machine].provider.driver.connection.servers.get(env[:machine].id.to_s)
raise NoDomainError if domain == nil
# Wait for domain to obtain an ip address. Ip address is searched

View File

@ -25,13 +25,13 @@ module VagrantPlugins
# <filesystem/> support in device attach/detach introduced in 1.2.2
# version number format is major * 1,000,000 + minor * 1,000 + release
libvirt_version = ProviderLibvirt.libvirt_connection.client.libversion
libvirt_version = machine.provider.driver.connection.client.libversion
libvirt_version >= 1_002_002
end
def prepare(machine, folders, _opts)
raise Vagrant::Errors::Error('No libvirt connection') if ProviderLibvirt.libvirt_connection.nil?
@conn = ProviderLibvirt.libvirt_connection.client
raise Vagrant::Errors::Error('No libvirt connection') if machine.provider.driver.connection.nil?
@conn = machine.provider.driver.connection.client
begin
# loop through folders
@ -73,10 +73,10 @@ module VagrantPlugins
end
def cleanup(machine, _opts)
if ProviderLibvirt.libvirt_connection.nil?
if machine.provider.driver.connection.nil?
raise Vagrant::Errors::Error('No libvirt connection')
end
@conn = ProviderLibvirt.libvirt_connection.client
@conn = machine.provider.driver.connection.client
begin
if machine.id && machine.id != ''
dom = @conn.lookup_domain_by_uuid(machine.id)

View File

@ -0,0 +1,121 @@
require 'fog/libvirt'
require 'log4r'
module VagrantPlugins
module ProviderLibvirt
class Driver
# store the connection at the process level
#
# possibly this should be a connection pool using the connection
# settings as a key to allow per machine connection attributes
# to be used.
@@connection = nil
def initialize(machine)
@logger = Log4r::Logger.new('vagrant_libvirt::driver')
@machine = machine
end
def connection
# If already connected to libvirt, just use it and don't connect
# again.
return @@connection if @@connection
# Get config options for libvirt provider.
config = @machine.provider_config
uri = config.uri
conn_attr = {}
conn_attr[:provider] = 'libvirt'
conn_attr[:libvirt_uri] = uri
conn_attr[:libvirt_username] = config.username if config.username
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 from dnsmasq leases table
ip_command = %q[ awk "/$mac/ {print \$1}" /proc/net/arp ]
conn_attr[:libvirt_ip_command] = ip_command
@logger.info("Connecting to Libvirt (#{uri}) ...")
begin
@@connection = Fog::Compute.new(conn_attr)
rescue Fog::Errors::Error => e
raise Errors::FogLibvirtConnectionError,
:error_message => e.message
end
@@connection
end
def get_domain(mid)
begin
domain = connection.servers.get(mid)
rescue Libvirt::RetrieveError => e
if e.libvirt_code == ProviderLibvirt::Util::ErrorCodes::VIR_ERR_NO_DOMAIN
@logger.debug("machine #{mid} not found #{e}.")
return nil
else
raise e
end
end
domain
end
def created?(mid)
domain = get_domain(mid)
!domain.nil?
end
def get_ipaddress(machine)
# Find the machine
domain = get_domain(machine.id)
if domain.nil?
# The machine can't be found
return nil
end
# Get IP address from arp table
ip_address = nil
begin
domain.wait_for(2) do
addresses.each_pair do |type, ip|
# Multiple leases are separated with a newline, return only
# the most recent address
ip_address = ip[0].split("\n").first if ip[0] != nil
end
ip_address != nil
end
rescue Fog::Errors::TimeoutError
@logger.info("Timeout at waiting for an ip address for machine %s" % machine.name)
end
if not ip_address
@logger.info("No arp table entry found for machine %s" % machine.name)
return nil
end
ip_address
end
def state(machine)
# may be other error states with initial retreival we can't handle
begin
domain = get_domain(machine.id)
rescue Libvirt::RetrieveError => e
@logger.debug("Machine #{machine.id} not found #{e}.")
return :not_created
end
# TODO: terminated no longer appears to be a valid fog state, remove?
if domain.nil? || domain.state.to_sym == :terminated
return :not_created
end
return domain.state.gsub("-", "_").to_sym
end
end
end
end

View File

@ -2,6 +2,7 @@ require 'vagrant'
module VagrantPlugins
module ProviderLibvirt
autoload :Driver, 'vagrant-libvirt/driver'
# This is the base class for a provider for the V2 API. A provider
# is responsible for creating compute resources to match the
@ -22,6 +23,12 @@ module VagrantPlugins
nil
end
def driver
return @driver if @driver
@driver = Driver.new(@machine)
end
# This method is called if the underying machine ID changes. Providers
# can use this method to load in new data for the actual backing
# machine or to realize that the machine is now gone (the ID can
@ -33,9 +40,8 @@ module VagrantPlugins
# SSH into the machine. If the machine is not at a point where
# SSH is even possible, then `nil` should be returned.
def ssh_info
# Run a custom action called "read_ssh_info" which does what it says
# and puts the resulting SSH info into the `:machine_ssh_info` key in
# the environment.
# Return the ssh_info if already retrieved otherwise call the driver
# and save the result.
#
# Ssh info has following format..
#
@ -45,8 +51,32 @@ module VagrantPlugins
# :username => "mitchellh",
# :private_key_path => "/path/to/my/key"
#}
env = @machine.action('read_ssh_info', :lock => false)
env[:machine_ssh_info]
# note that modifing @machine.id or accessing @machine.state is not
# thread safe, so be careful to avoid these here as this method may
# be called from other threads of execution.
return nil if state.id != :running
ip = driver.get_ipaddress(@machine)
# if can't determine the IP, just return nil and let the core
# deal with it, similar to the docker provider
return nil if !ip
ssh_info = {
:host => ip,
:port => @machine.config.ssh.guest_port,
:forward_agent => @machine.config.ssh.forward_agent,
:forward_x11 => @machine.config.ssh.forward_x11,
}
ssh_info[:proxy_command] = (
"ssh '#{@machine.provider_config.host}' " +
"-l '#{@machine.provider_config.username}' " +
"-i '#{@machine.provider_config.id_ssh_key_file}' " +
"nc %h %p"
) if @machine.provider_config.connect_via_ssh
ssh_info
end
def mac_addresses
@ -64,16 +94,28 @@ module VagrantPlugins
# This should return the state of the machine within this provider.
# The state must be an instance of {MachineState}.
def state
# Run a custom action we define called "read_state" which does
# what it says. It puts the state in the `:machine_state_id`
# key in the environment.
env = @machine.action('read_state', :lock => false)
state_id = env[:machine_state_id]
state_id = nil
state_id = :not_created if !@machine.id
state_id = :not_created if (
!state_id && (!@machine.id || !driver.created?(@machine.id)))
# Query the driver for the current state of the machine
state_id = driver.state(@machine) if @machine.id && !state_id
state_id = :unknown if !state_id
# This is a special pseudo-state so that we don't set the
# NOT_CREATED_ID while we're setting up the machine. This avoids
# clearing the data dir.
state_id = :preparing if @machine.id == "preparing"
# Get the short and long description
short = I18n.t("vagrant_libvirt.states.short_#{state_id}")
long = I18n.t("vagrant_libvirt.states.long_#{state_id}")
short = state_id.to_s.gsub("_", " ")
long = I18n.t("vagrant_libvirt.states.#{state_id}")
# If we're not created, then specify the special ID flag
if state_id == :not_created
state_id = Vagrant::MachineState::NOT_CREATED_ID
end
# Return the MachineState object
Vagrant::MachineState.new(state_id, short, long)

View File

@ -139,19 +139,18 @@ en:
TCP tunnel port not defined.
states:
short_paused: |-
pause
short_shutoff: |-
shutoff
long_shutoff: |-
paused: |-
The Libvirt domain is suspended. Run `vagrant resume` to resume it.
shutting_down: |-
The Libvirt domain is shutting down. Wait for it to complete and
then run `vagrant up` to start it or `vagrant destroy` to remove.
shutoff: |-
The Libvirt domain is not running. Run `vagrant up` to start it.
short_not_created: |-
not created
long_not_created: |-
not_created: |-
The Libvirt domain is not created. Run `vagrant up` to create it.
short_running: |-
running
long_running: |-
running: |-
The Libvirt domain is running. To stop this machine, you can run
`vagrant halt`. To destroy the machine, you can run `vagrant destroy`.
preparing: |-
The vagrant machine is being prepared for creation, please wait for
it to reach a steady state before issuing commands on it.