vagrant-libvirt 0.0.1
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.
- checksums.yaml +7 -0
- data/.gitignore +17 -0
- data/Gemfile +12 -0
- data/LICENSE +22 -0
- data/README.md +33 -0
- data/Rakefile +7 -0
- data/example_box/README.md +14 -0
- data/example_box/Vagrantfile +45 -0
- data/example_box/metadata.json +5 -0
- data/lib/vagrant-libvirt/action/connect_libvirt.rb +72 -0
- data/lib/vagrant-libvirt/action/create_domain.rb +62 -0
- data/lib/vagrant-libvirt/action/create_domain_volume.rb +58 -0
- data/lib/vagrant-libvirt/action/create_network_interfaces.rb +85 -0
- data/lib/vagrant-libvirt/action/destroy_domain.rb +28 -0
- data/lib/vagrant-libvirt/action/handle_box_image.rb +121 -0
- data/lib/vagrant-libvirt/action/handle_storage_pool.rb +49 -0
- data/lib/vagrant-libvirt/action/is_created.rb +18 -0
- data/lib/vagrant-libvirt/action/message_already_created.rb +16 -0
- data/lib/vagrant-libvirt/action/message_not_created.rb +16 -0
- data/lib/vagrant-libvirt/action/read_ssh_info.rb +51 -0
- data/lib/vagrant-libvirt/action/read_state.rb +38 -0
- data/lib/vagrant-libvirt/action/set_name_of_domain.rb +31 -0
- data/lib/vagrant-libvirt/action/start_domain.rb +27 -0
- data/lib/vagrant-libvirt/action/sync_folders.rb +58 -0
- data/lib/vagrant-libvirt/action/timed_provision.rb +21 -0
- data/lib/vagrant-libvirt/action/wait_till_up.rb +96 -0
- data/lib/vagrant-libvirt/action.rb +94 -0
- data/lib/vagrant-libvirt/config.rb +48 -0
- data/lib/vagrant-libvirt/errors.rb +90 -0
- data/lib/vagrant-libvirt/plugin.rb +77 -0
- data/lib/vagrant-libvirt/provider.rb +76 -0
- data/lib/vagrant-libvirt/templates/default_storage_pool.xml.erb +13 -0
- data/lib/vagrant-libvirt/templates/domain.xml.erb +34 -0
- data/lib/vagrant-libvirt/templates/interface.xml.erb +7 -0
- data/lib/vagrant-libvirt/templates/volume_snapshot.xml.erb +26 -0
- data/lib/vagrant-libvirt/util/collection.rb +22 -0
- data/lib/vagrant-libvirt/util/erb_template.rb +21 -0
- data/lib/vagrant-libvirt/util/timer.rb +17 -0
- data/lib/vagrant-libvirt/util.rb +10 -0
- data/lib/vagrant-libvirt/version.rb +5 -0
- data/lib/vagrant-libvirt.rb +30 -0
- data/locales/en.yml +103 -0
- data/vagrant-libvirt.gemspec +23 -0
- metadata +127 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 857a7572e2968583b54a002899aeb4ed206ce1a9
|
4
|
+
data.tar.gz: b2272a7a10779ccbaef6f5c8aa1eda3d7cc77d9f
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 1eb41e05a79497bd68f8b8616d75b61ed8a4e7d4a9787ea90ec5ef0a061847f8ca12e2b6f80e3d95b941a6483cd2ef21df48ffd020cdda1949e4ea5d30784c2e
|
7
|
+
data.tar.gz: cb6363c8c70efaac9b3ed73cdace2ef42c658b946571a5d5bc8693144273af6612b0afdcc79ca8de69b685380fc33c7b009ca46bcae8b1de0cf9d5ce37125e91
|
data/.gitignore
ADDED
data/Gemfile
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
source 'https://rubygems.org'
|
2
|
+
|
3
|
+
# Specify your gem's dependencies in vagrant-libvirt.gemspec
|
4
|
+
gemspec
|
5
|
+
|
6
|
+
group :development do
|
7
|
+
# We depend on Vagrant for development, but we don't add it as a
|
8
|
+
# gem dependency because we expect to be installed within the
|
9
|
+
# Vagrant environment itself using `vagrant plugin`.
|
10
|
+
gem "vagrant", :git => "git://github.com/mitchellh/vagrant.git"
|
11
|
+
end
|
12
|
+
|
data/LICENSE
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2013 Lukas Stanek
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
# Vagrant Libvirt Provider
|
2
|
+
|
3
|
+
This is a [Vagrant](http://www.vagrantup.com) 1.1+ plugin that adds an
|
4
|
+
[Libvirt](http://libvirt.org) provider to Vagrant, allowing Vagrant to
|
5
|
+
control and provision machines via Libvirt toolkit.
|
6
|
+
|
7
|
+
**Note:** This plugin requires Vagrant 1.1+.
|
8
|
+
|
9
|
+
## Features
|
10
|
+
|
11
|
+
* Upload of box image (qcow2 format) to Libvirt storage pool.
|
12
|
+
* Volume creation as COW diff image for each new domain.
|
13
|
+
* Create and boot Libvirt domains.
|
14
|
+
* SSH into domains.
|
15
|
+
* Provision domains with any built-in Vagrant provisioner.
|
16
|
+
* Minimal synced folder support via `rsync`.
|
17
|
+
|
18
|
+
## Usage
|
19
|
+
|
20
|
+
Install using standard Vagrant 1.1+ plugin installation methods. After
|
21
|
+
installing, `vagrant up` and specify the `libvirt` provider. An example is
|
22
|
+
shown below.
|
23
|
+
|
24
|
+
```
|
25
|
+
$ vagrant plugin install vagrant-libvirt
|
26
|
+
...
|
27
|
+
$ vagrant up --provider=libvirt
|
28
|
+
...
|
29
|
+
```
|
30
|
+
|
31
|
+
Of course prior to doing this, you'll need to obtain an Libvirt-compatible
|
32
|
+
box file for Vagrant.
|
33
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
# Vagrant Libvirt Example Box
|
2
|
+
|
3
|
+
Vagrant providers each require a custom provider-specific box format.
|
4
|
+
This folder shows the example contents of a box for the `libvirt` provider.
|
5
|
+
To turn this into a box create a vagrant image according documentation (don't
|
6
|
+
forget to install rsync command) and create box with following command:
|
7
|
+
|
8
|
+
```
|
9
|
+
$ tar cvzf custom_box.box ./metadata.json ./Vagrantfile ./box.img
|
10
|
+
```
|
11
|
+
|
12
|
+
This box works by using Vagrant's built-in Vagrantfile merging to setup
|
13
|
+
defaults for Libvirt. These defaults can easily be overwritten by higher-level
|
14
|
+
Vagrantfiles (such as project root Vagrantfiles).
|
@@ -0,0 +1,45 @@
|
|
1
|
+
# -*- mode: ruby -*-
|
2
|
+
# vi: set ft=ruby :
|
3
|
+
|
4
|
+
Vagrant.configure("2") do |config|
|
5
|
+
|
6
|
+
# Example configuration of new VM..
|
7
|
+
#
|
8
|
+
#config.vm.define :test_vm do |test_vm|
|
9
|
+
# Box name
|
10
|
+
#test_vm.vm.box = "centos64"
|
11
|
+
|
12
|
+
# Interfaces for VM
|
13
|
+
#
|
14
|
+
# Hostonly network is not supported in this version of provider. Bridged
|
15
|
+
# interface with network id specified can be created.
|
16
|
+
#test_vm.vm.network :bridged, :bridge => "default", :adapter => 1
|
17
|
+
#end
|
18
|
+
|
19
|
+
# Options for libvirt vagrant provider.
|
20
|
+
config.vm.provider :libvirt do |libvirt|
|
21
|
+
|
22
|
+
# A hypervisor name to access. Different drivers can be specified, but
|
23
|
+
# this version of provider creates KVM machines only. Some examples of
|
24
|
+
# drivers are qemu (KVM/qemu), xen (Xen hypervisor), lxc (Linux Containers),
|
25
|
+
# esx (VMware ESX), vmwarews (VMware Workstation) and more. Refer to
|
26
|
+
# documentation for available drivers (http://libvirt.org/drivers.html).
|
27
|
+
libvirt.driver = "qemu"
|
28
|
+
|
29
|
+
# The name of the server, where libvirtd is running.
|
30
|
+
libvirt.host = "localhost"
|
31
|
+
|
32
|
+
# If use ssh tunnel to connect to Libvirt.
|
33
|
+
libvirt.connect_via_ssh = false
|
34
|
+
|
35
|
+
# The username and password to access Libvirt. Password is not used when
|
36
|
+
# connecting via ssh.
|
37
|
+
libvirt.username = "root"
|
38
|
+
#libvirt.password = "secret"
|
39
|
+
|
40
|
+
# Libvirt storage pool name, where box image and instance snapshots will
|
41
|
+
# be stored.
|
42
|
+
libvirt.storage_pool_name = "default"
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
@@ -0,0 +1,72 @@
|
|
1
|
+
require 'fog'
|
2
|
+
require 'log4r'
|
3
|
+
|
4
|
+
module VagrantPlugins
|
5
|
+
module Libvirt
|
6
|
+
module Action
|
7
|
+
class ConnectLibvirt
|
8
|
+
def initialize(app, env)
|
9
|
+
@logger = Log4r::Logger.new("vagrant_libvirt::action::connect_libvirt")
|
10
|
+
@app = app
|
11
|
+
end
|
12
|
+
|
13
|
+
def call(env)
|
14
|
+
|
15
|
+
# If already connected to libvirt, just use it and don't connect
|
16
|
+
# again.
|
17
|
+
if Libvirt.libvirt_connection
|
18
|
+
env[:libvirt_compute] = Libvirt.libvirt_connection
|
19
|
+
return @app.call(env)
|
20
|
+
end
|
21
|
+
|
22
|
+
# Get config options for libvirt provider.
|
23
|
+
config = env[:machine].provider_config
|
24
|
+
|
25
|
+
# Setup connection uri.
|
26
|
+
uri = config.driver
|
27
|
+
if config.connect_via_ssh
|
28
|
+
uri << '+ssh://'
|
29
|
+
if config.username
|
30
|
+
uri << config.username + '@'
|
31
|
+
end
|
32
|
+
|
33
|
+
if config.host
|
34
|
+
uri << config.host
|
35
|
+
else
|
36
|
+
uri << 'localhost'
|
37
|
+
end
|
38
|
+
else
|
39
|
+
uri << '://'
|
40
|
+
uri << config.host if config.host
|
41
|
+
end
|
42
|
+
uri << '/system?no_verify=1'
|
43
|
+
|
44
|
+
conn_attr = {}
|
45
|
+
conn_attr[:provider] = 'libvirt'
|
46
|
+
conn_attr[:libvirt_uri] = uri
|
47
|
+
conn_attr[:libvirt_username] = config.username if config.username
|
48
|
+
conn_attr[:libvirt_password] = config.password if config.password
|
49
|
+
|
50
|
+
# Setup command for retrieving IP address for newly created machine
|
51
|
+
# with some MAC address. Get it via arp table. This solution doesn't
|
52
|
+
# require arpwatch to be installed.
|
53
|
+
conn_attr[:libvirt_ip_command] = "arp -an | grep $mac | sed '"
|
54
|
+
conn_attr[:libvirt_ip_command] << 's/.*(\([0-9\.]*\)).*/\1/'
|
55
|
+
conn_attr[:libvirt_ip_command] << "'"
|
56
|
+
|
57
|
+
@logger.info("Connecting to Libvirt (#{uri}) ...")
|
58
|
+
begin
|
59
|
+
env[:libvirt_compute] = Fog::Compute.new(conn_attr)
|
60
|
+
rescue Fog::Errors::Error => e
|
61
|
+
raise Errors::FogLibvirtConnectionError,
|
62
|
+
:error_message => e.message
|
63
|
+
end
|
64
|
+
Libvirt.libvirt_connection = env[:libvirt_compute]
|
65
|
+
|
66
|
+
@app.call(env)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
@@ -0,0 +1,62 @@
|
|
1
|
+
require 'log4r'
|
2
|
+
|
3
|
+
module VagrantPlugins
|
4
|
+
module Libvirt
|
5
|
+
module Action
|
6
|
+
|
7
|
+
class CreateDomain
|
8
|
+
include VagrantPlugins::Libvirt::Util::ErbTemplate
|
9
|
+
|
10
|
+
def initialize(app, env)
|
11
|
+
@logger = Log4r::Logger.new("vagrant_libvirt::action::create_domain")
|
12
|
+
@app = app
|
13
|
+
end
|
14
|
+
|
15
|
+
def call(env)
|
16
|
+
# Gather some info about domain
|
17
|
+
# TODO from Vagrantfile
|
18
|
+
@name = env[:domain_name]
|
19
|
+
@cpus = 1
|
20
|
+
@memory_size = 512*1024
|
21
|
+
|
22
|
+
# TODO get type from driver config option
|
23
|
+
@domain_type = 'kvm'
|
24
|
+
|
25
|
+
@os_type = 'hvm'
|
26
|
+
|
27
|
+
# Get path to domain image.
|
28
|
+
domain_volume = Libvirt::Util::Collection.find_matching(
|
29
|
+
env[:libvirt_compute].volumes.all, "#{@name}.img")
|
30
|
+
raise Errors::DomainVolumeExists if domain_volume == nil
|
31
|
+
@domain_volume_path = domain_volume.path
|
32
|
+
|
33
|
+
# Output the settings we're going to use to the user
|
34
|
+
env[:ui].info(I18n.t("vagrant_libvirt.creating_domain"))
|
35
|
+
env[:ui].info(" -- Name: #{@name}")
|
36
|
+
env[:ui].info(" -- Domain type: #{@domain_type}")
|
37
|
+
env[:ui].info(" -- Cpus: #{@cpus}")
|
38
|
+
env[:ui].info(" -- Memory: #{@memory_size/1024}M")
|
39
|
+
env[:ui].info(" -- Base box: #{env[:machine].box.name}")
|
40
|
+
env[:ui].info(" -- Image: #{@domain_volume_path}")
|
41
|
+
|
42
|
+
# Create libvirt domain.
|
43
|
+
# Is there a way to tell fog to create new domain with already
|
44
|
+
# existing volume? Use domain creation from template..
|
45
|
+
begin
|
46
|
+
server = env[:libvirt_compute].servers.create(
|
47
|
+
:xml => to_xml('domain'))
|
48
|
+
rescue Fog::Errors::Error => e
|
49
|
+
raise Errors::FogCreateServerError,
|
50
|
+
:error_message => e.message
|
51
|
+
end
|
52
|
+
|
53
|
+
# Immediately save the ID since it is created at this point.
|
54
|
+
env[:machine].id = server.id
|
55
|
+
|
56
|
+
@app.call(env)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
require 'log4r'
|
2
|
+
|
3
|
+
module VagrantPlugins
|
4
|
+
module Libvirt
|
5
|
+
module Action
|
6
|
+
|
7
|
+
# Create a snapshot of base box image. This new snapshot is just new
|
8
|
+
# cow image with backing storage pointing to base box image. Use this
|
9
|
+
# image as new domain volume.
|
10
|
+
class CreateDomainVolume
|
11
|
+
include VagrantPlugins::Libvirt::Util::ErbTemplate
|
12
|
+
|
13
|
+
def initialize(app, env)
|
14
|
+
@logger = Log4r::Logger.new("vagrant_libvirt::action::create_domain_volume")
|
15
|
+
@app = app
|
16
|
+
end
|
17
|
+
|
18
|
+
def call(env)
|
19
|
+
env[:ui].info(I18n.t("vagrant_libvirt.creating_domain_volume"))
|
20
|
+
|
21
|
+
# Get config options.
|
22
|
+
config = env[:machine].provider_config
|
23
|
+
|
24
|
+
# This is name of newly created image for vm.
|
25
|
+
@name = "#{env[:domain_name]}.img"
|
26
|
+
|
27
|
+
# Verify the volume doesn't exist already.
|
28
|
+
domain_volume = Libvirt::Util::Collection.find_matching(
|
29
|
+
env[:libvirt_compute].volumes.all, @name)
|
30
|
+
raise Errors::DomainVolumeExists if domain_volume
|
31
|
+
|
32
|
+
# Get path to backing image - box volume.
|
33
|
+
box_volume = Libvirt::Util::Collection.find_matching(
|
34
|
+
env[:libvirt_compute].volumes.all, env[:box_volume_name])
|
35
|
+
@backing_file = box_volume.path
|
36
|
+
|
37
|
+
# Virtual size of image. Same as box image size.
|
38
|
+
@capacity = env[:machine].box.metadata['virtual_size'] #G
|
39
|
+
|
40
|
+
# Create new volume from xml template. Fog currently doesn't support
|
41
|
+
# volume snapshots directly.
|
42
|
+
begin
|
43
|
+
domain_volume = env[:libvirt_compute].volumes.create(
|
44
|
+
:xml => to_xml('volume_snapshot'),
|
45
|
+
:pool_name => config.storage_pool_name)
|
46
|
+
rescue Fog::Errors::Error => e
|
47
|
+
raise Errors::FogDomainVolumeCreateError,
|
48
|
+
:error_message => e.message
|
49
|
+
end
|
50
|
+
|
51
|
+
@app.call(env)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
@@ -0,0 +1,85 @@
|
|
1
|
+
require 'log4r'
|
2
|
+
|
3
|
+
module VagrantPlugins
|
4
|
+
module Libvirt
|
5
|
+
module Action
|
6
|
+
|
7
|
+
# Create network interfaces for domain, before domain is running.
|
8
|
+
class CreateNetworkInterfaces
|
9
|
+
include VagrantPlugins::Libvirt::Util::ErbTemplate
|
10
|
+
|
11
|
+
def initialize(app, env)
|
12
|
+
@logger = Log4r::Logger.new("vagrant_libvirt::action::create_network_interfaces")
|
13
|
+
@app = app
|
14
|
+
end
|
15
|
+
|
16
|
+
def call(env)
|
17
|
+
# Get domain first.
|
18
|
+
begin
|
19
|
+
domain = env[:libvirt_compute].client.lookup_domain_by_uuid(
|
20
|
+
env[:machine].id.to_s)
|
21
|
+
rescue => e
|
22
|
+
raise Errors::NoDomainError,
|
23
|
+
:error_message => e.message
|
24
|
+
end
|
25
|
+
|
26
|
+
# Setup list of interfaces before creating them
|
27
|
+
adapters = []
|
28
|
+
|
29
|
+
# Assign main interface for provisioning to first slot.
|
30
|
+
# Use network 'default' as network for ssh connecting and
|
31
|
+
# machine provisioning. This should be maybe configurable in
|
32
|
+
# Vagrantfile in future.
|
33
|
+
adapters[0] = 'default'
|
34
|
+
|
35
|
+
env[:machine].config.vm.networks.each do |type, options|
|
36
|
+
# Other types than bridged are not supported for now.
|
37
|
+
next if type != :bridged
|
38
|
+
|
39
|
+
network_name = 'default'
|
40
|
+
network_name = options[:bridge] if options[:bridge]
|
41
|
+
|
42
|
+
if options[:adapter]
|
43
|
+
if adapters[options[:adapter]]
|
44
|
+
raise Errors::InterfaceSlotNotAvailable
|
45
|
+
end
|
46
|
+
|
47
|
+
adapters[options[:adapter].to_i] = network_name
|
48
|
+
else
|
49
|
+
empty_slot = find_empty(adapters, start=1)
|
50
|
+
raise Errors::InterfaceSlotNotAvailable if empty_slot == nil
|
51
|
+
|
52
|
+
adapters[empty_slot] = network_name
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
# Create each interface as new domain device
|
57
|
+
adapters.each_with_index do |network_name, slot_number|
|
58
|
+
@iface_number = slot_number
|
59
|
+
@network_name = network_name
|
60
|
+
@logger.info("Creating network interface eth#{@iface_number}")
|
61
|
+
begin
|
62
|
+
domain.attach_device(to_xml('interface'))
|
63
|
+
rescue => e
|
64
|
+
raise Errors::AttachDeviceError,
|
65
|
+
:error_message => e.message
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
@app.call(env)
|
70
|
+
end
|
71
|
+
|
72
|
+
private
|
73
|
+
|
74
|
+
def find_empty(array, start=0, stop=8)
|
75
|
+
for i in start..stop
|
76
|
+
return i if !array[i]
|
77
|
+
end
|
78
|
+
return nil
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'log4r'
|
2
|
+
|
3
|
+
module VagrantPlugins
|
4
|
+
module Libvirt
|
5
|
+
module Action
|
6
|
+
class DestroyDomain
|
7
|
+
|
8
|
+
def initialize(app, env)
|
9
|
+
@logger = Log4r::Logger.new("vagrant_libvirt::action::destroy_domain")
|
10
|
+
@app = app
|
11
|
+
end
|
12
|
+
|
13
|
+
def call(env)
|
14
|
+
|
15
|
+
# Destroy the server and remove the tracking ID
|
16
|
+
env[:ui].info(I18n.t("vagrant_libvirt.destroy_domain"))
|
17
|
+
|
18
|
+
domain = env[:libvirt_compute].servers.get(env[:machine].id.to_s)
|
19
|
+
domain.destroy(:destroy_volumes => true)
|
20
|
+
env[:machine].id = nil
|
21
|
+
|
22
|
+
@app.call(env)
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,121 @@
|
|
1
|
+
require 'log4r'
|
2
|
+
|
3
|
+
module VagrantPlugins
|
4
|
+
module Libvirt
|
5
|
+
module Action
|
6
|
+
class HandleBoxImage
|
7
|
+
def initialize(app, env)
|
8
|
+
@logger = Log4r::Logger.new("vagrant_libvirt::action::handle_box_image")
|
9
|
+
@app = app
|
10
|
+
end
|
11
|
+
|
12
|
+
def call(env)
|
13
|
+
|
14
|
+
# Verify box metadata for mandatory values.
|
15
|
+
#
|
16
|
+
# Virtual size has to be set for allocating space in storage pool.
|
17
|
+
box_virtual_size = env[:machine].box.metadata['virtual_size']
|
18
|
+
if box_virtual_size == nil
|
19
|
+
raise Errors::NoBoxVirtualSizeSet
|
20
|
+
end
|
21
|
+
|
22
|
+
# Support qcow2 format only for now, but other formats with backing
|
23
|
+
# store capability should be usable.
|
24
|
+
box_format = env[:machine].box.metadata['format']
|
25
|
+
if box_format == nil
|
26
|
+
raise Errors::NoBoxFormatSet
|
27
|
+
elsif box_format != 'qcow2'
|
28
|
+
raise Errors::WrongBoxFormatSet
|
29
|
+
end
|
30
|
+
|
31
|
+
# Get config options
|
32
|
+
config = env[:machine].provider_config
|
33
|
+
box_image_file = env[:machine].box.directory.join("box.img").to_s
|
34
|
+
env[:box_volume_name] = env[:machine].box.name.to_s.dup
|
35
|
+
env[:box_volume_name] << '_vagrant_box_image.img'
|
36
|
+
|
37
|
+
# Don't continue if image already exists in storage pool.
|
38
|
+
return @app.call(env) if Libvirt::Util::Collection.find_matching(
|
39
|
+
env[:libvirt_compute].volumes.all, env[:box_volume_name])
|
40
|
+
|
41
|
+
# Box is not available as a storage pool volume. Create and upload
|
42
|
+
# it as a copy of local box image.
|
43
|
+
env[:ui].info(I18n.t("vagrant_libvirt.uploading_volume"))
|
44
|
+
|
45
|
+
# Create new volume in storage pool
|
46
|
+
box_image_size = File.size(box_image_file) # B
|
47
|
+
message = "Creating volume #{env[:box_volume_name]}"
|
48
|
+
message << " in storage pool #{config.storage_pool_name}."
|
49
|
+
@logger.info(message)
|
50
|
+
begin
|
51
|
+
fog_volume = env[:libvirt_compute].volumes.create(
|
52
|
+
:name => env[:box_volume_name],
|
53
|
+
:allocation => "#{box_image_size/1024/1024}M",
|
54
|
+
:capacity => "#{box_virtual_size}G",
|
55
|
+
:format_type => box_format,
|
56
|
+
:pool_name => config.storage_pool_name)
|
57
|
+
rescue Fog::Errors::Error => e
|
58
|
+
raise Errors::FogCreateVolumeError,
|
59
|
+
:error_message => e.message
|
60
|
+
end
|
61
|
+
|
62
|
+
# Upload box image to storage pool
|
63
|
+
ret = upload_image(box_image_file, config.storage_pool_name,
|
64
|
+
env[:box_volume_name], env) do |progress|
|
65
|
+
env[:ui].clear_line
|
66
|
+
env[:ui].report_progress(progress, box_image_size, false)
|
67
|
+
end
|
68
|
+
|
69
|
+
# Clear the line one last time since the progress meter doesn't
|
70
|
+
# disappear immediately.
|
71
|
+
env[:ui].clear_line
|
72
|
+
|
73
|
+
# If upload failed or was interrupted, remove created volume from
|
74
|
+
# storage pool.
|
75
|
+
if env[:interrupted] or !ret
|
76
|
+
begin
|
77
|
+
fog_volume.destroy
|
78
|
+
rescue
|
79
|
+
nil
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
@app.call(env)
|
84
|
+
end
|
85
|
+
|
86
|
+
protected
|
87
|
+
|
88
|
+
# Fog libvirt currently doesn't support uploading images to storage
|
89
|
+
# pool volumes. Use ruby-libvirt client instead.
|
90
|
+
def upload_image(image_file, pool_name, volume_name, env)
|
91
|
+
image_size = File.size(image_file) # B
|
92
|
+
|
93
|
+
begin
|
94
|
+
pool = env[:libvirt_compute].client.lookup_storage_pool_by_name(
|
95
|
+
pool_name)
|
96
|
+
volume = pool.lookup_volume_by_name(volume_name)
|
97
|
+
stream = env[:libvirt_compute].client.stream
|
98
|
+
volume.upload(stream, offset=0, length=image_size)
|
99
|
+
buf_size = 1024*1024 # 1M
|
100
|
+
progress = 0
|
101
|
+
open(image_file, 'rb') do |io|
|
102
|
+
while (buff = io.read(buf_size)) do
|
103
|
+
sent = stream.send buff
|
104
|
+
progress += sent
|
105
|
+
yield progress
|
106
|
+
end
|
107
|
+
end
|
108
|
+
rescue => e
|
109
|
+
raise Errors::ImageUploadError,
|
110
|
+
:error_message => e.message
|
111
|
+
end
|
112
|
+
|
113
|
+
return true if progress == image_size
|
114
|
+
false
|
115
|
+
end
|
116
|
+
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require 'log4r'
|
2
|
+
|
3
|
+
module VagrantPlugins
|
4
|
+
module Libvirt
|
5
|
+
module Action
|
6
|
+
class HandleStoragePool
|
7
|
+
include VagrantPlugins::Libvirt::Util::ErbTemplate
|
8
|
+
|
9
|
+
def initialize(app, env)
|
10
|
+
@logger = Log4r::Logger.new("vagrant_libvirt::action::handle_storage_pool")
|
11
|
+
@app = app
|
12
|
+
end
|
13
|
+
|
14
|
+
def call(env)
|
15
|
+
# Get config options.
|
16
|
+
config = env[:machine].provider_config
|
17
|
+
|
18
|
+
# Check for storage pool, where box image should be created
|
19
|
+
fog_pool = Libvirt::Util::Collection.find_matching(
|
20
|
+
env[:libvirt_compute].pools.all, config.storage_pool_name)
|
21
|
+
return @app.call(env) if fog_pool
|
22
|
+
|
23
|
+
@logger.info("No storage pool '#{config.storage_pool_name}' is available.")
|
24
|
+
|
25
|
+
# If user specified other pool than default, don't create default
|
26
|
+
# storage pool, just write error message.
|
27
|
+
raise Errors::NoStoragePool if config.storage_pool_name != 'default'
|
28
|
+
|
29
|
+
@logger.info("Creating storage pool 'default'")
|
30
|
+
|
31
|
+
# Fog libvirt currently doesn't support creating pools. Use
|
32
|
+
# ruby-libvirt client directly.
|
33
|
+
begin
|
34
|
+
libvirt_pool = env[:libvirt_compute].client.create_storage_pool_xml(
|
35
|
+
to_xml('default_storage_pool'))
|
36
|
+
rescue => e
|
37
|
+
raise Errors::CreatingStoragePoolError,
|
38
|
+
:error_message => e.message
|
39
|
+
end
|
40
|
+
raise Errors::NoStoragePool if !libvirt_pool
|
41
|
+
|
42
|
+
@app.call(env)
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module VagrantPlugins
|
2
|
+
module Libvirt
|
3
|
+
module Action
|
4
|
+
# This can be used with "Call" built-in to check if the machine
|
5
|
+
# is created and branch in the middleware.
|
6
|
+
class IsCreated
|
7
|
+
def initialize(app, env)
|
8
|
+
@app = app
|
9
|
+
end
|
10
|
+
|
11
|
+
def call(env)
|
12
|
+
env[:result] = env[:machine].state.id != :not_created
|
13
|
+
@app.call(env)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|