vagrant-libvirt 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|