[DRE-commits] [vagrant-libvirt] 01/104: Initial commit

Antonio Terceiro terceiro at moszumanska.debian.org
Sun Apr 24 13:55:38 UTC 2016


This is an automated email from the git hooks/post-receive script.

terceiro pushed a commit to annotated tag 0.0.11
in repository vagrant-libvirt.

commit 810f0b31b973281bdf70e8b9810f02d2486e9eb8
Author: pradels <les.pradels at gmail.com>
Date:   Wed Mar 27 00:55:30 2013 +0100

    Initial commit
---
 .gitignore                                         |  19 +++
 Gemfile                                            |  12 ++
 LICENSE                                            |  22 +++
 README.md                                          | 178 +++++++++++++++++++++
 Rakefile                                           |   7 +
 example_box/README.md                              |  23 +++
 example_box/metadata.json                          |   5 +
 lib/vagrant-libvirt.rb                             |  30 ++++
 lib/vagrant-libvirt/action.rb                      |  94 +++++++++++
 lib/vagrant-libvirt/action/connect_libvirt.rb      |  72 +++++++++
 lib/vagrant-libvirt/action/create_domain.rb        |  62 +++++++
 lib/vagrant-libvirt/action/create_domain_volume.rb |  58 +++++++
 .../action/create_network_interfaces.rb            |  85 ++++++++++
 lib/vagrant-libvirt/action/destroy_domain.rb       |  28 ++++
 lib/vagrant-libvirt/action/handle_box_image.rb     | 121 ++++++++++++++
 lib/vagrant-libvirt/action/handle_storage_pool.rb  |  49 ++++++
 lib/vagrant-libvirt/action/is_created.rb           |  18 +++
 .../action/message_already_created.rb              |  16 ++
 lib/vagrant-libvirt/action/message_not_created.rb  |  16 ++
 lib/vagrant-libvirt/action/read_ssh_info.rb        |  51 ++++++
 lib/vagrant-libvirt/action/read_state.rb           |  38 +++++
 lib/vagrant-libvirt/action/set_name_of_domain.rb   |  31 ++++
 lib/vagrant-libvirt/action/start_domain.rb         |  27 ++++
 lib/vagrant-libvirt/action/sync_folders.rb         |  58 +++++++
 lib/vagrant-libvirt/action/timed_provision.rb      |  21 +++
 lib/vagrant-libvirt/action/wait_till_up.rb         |  96 +++++++++++
 lib/vagrant-libvirt/config.rb                      |  48 ++++++
 lib/vagrant-libvirt/errors.rb                      |  90 +++++++++++
 lib/vagrant-libvirt/plugin.rb                      |  77 +++++++++
 lib/vagrant-libvirt/provider.rb                    |  76 +++++++++
 .../templates/default_storage_pool.xml.erb         |  13 ++
 lib/vagrant-libvirt/templates/domain.xml.erb       |  34 ++++
 lib/vagrant-libvirt/templates/interface.xml.erb    |   7 +
 .../templates/volume_snapshot.xml.erb              |  26 +++
 lib/vagrant-libvirt/util.rb                        |  10 ++
 lib/vagrant-libvirt/util/collection.rb             |  22 +++
 lib/vagrant-libvirt/util/erb_template.rb           |  21 +++
 lib/vagrant-libvirt/util/timer.rb                  |  17 ++
 lib/vagrant-libvirt/version.rb                     |   5 +
 locales/en.yml                                     | 103 ++++++++++++
 vagrant-libvirt.gemspec                            |  23 +++
 41 files changed, 1809 insertions(+)

diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..d036c0f
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,19 @@
+*.gem
+*.rbc
+.bundle
+.config
+.yardoc
+Gemfile.lock
+InstalledFiles
+_yardoc
+coverage
+doc/
+lib/bundler/man
+pkg
+rdoc
+spec/reports
+test/tmp
+test/version_tmp
+tmp
+Vagrantfile
+.vagrant
diff --git a/Gemfile b/Gemfile
new file mode 100644
index 0000000..ebd9fc4
--- /dev/null
+++ b/Gemfile
@@ -0,0 +1,12 @@
+source 'https://rubygems.org'
+
+# Specify your gem's dependencies in vagrant-libvirt.gemspec
+gemspec
+
+group :development do
+  # We depend on Vagrant for development, but we don't add it as a
+  # gem dependency because we expect to be installed within the
+  # Vagrant environment itself using `vagrant plugin`.
+  gem "vagrant", :git => "git://github.com/mitchellh/vagrant.git"
+end
+
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..93920f0
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,22 @@
+Copyright (c) 2013 Lukas Stanek
+
+MIT License
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..6e883d8
--- /dev/null
+++ b/README.md
@@ -0,0 +1,178 @@
+# Vagrant Libvirt Provider
+
+This is a [Vagrant](http://www.vagrantup.com) 1.1+ plugin that adds an
+[Libvirt](http://libvirt.org) provider to Vagrant, allowing Vagrant to
+control and provision machines via Libvirt toolkit.
+
+This plugin is inspired by existing [vagrant-aws](https://github.com/mitchellh/vagrant-aws) provider.
+
+**Note:** This plugin requires Vagrant 1.1+.
+
+## Features
+
+* Upload box image (qcow2 format) to Libvirt storage pool.
+* Create volume as COW diff image for domains.
+* Create and boot Libvirt domains.
+* SSH into domains.
+* Provision domains with any built-in Vagrant provisioner.
+* Minimal synced folder support via `rsync`.
+
+## Usage
+
+Install using standard Vagrant 1.1+ plugin installation methods. After
+installing, `vagrant up` and specify the `libvirt` provider. An example is
+shown below.
+
+```
+$ vagrant plugin install vagrant-libvirt
+...
+$ vagrant up --provider=libvirt
+...
+```
+
+Of course prior to doing this, you'll need to obtain an Libvirt-compatible
+box file for Vagrant. 
+
+### Problems with plugin installation
+
+In case of problems with building nokogiri gem, install missing development
+libraries libxslt and libxml2.
+
+In Ubuntu, Debian, ...
+```
+$ sudo apt-get install libxslt-dev libxml2-dev
+```
+
+In RedHat, Centos, Fedora, ...
+```
+# yum install libxslt-devel libxml2-devel
+```
+
+## Quick Start
+
+After installing the plugin (instructions above), the quickest way to get
+started is to add Libvirt box and specify all the details manually within
+a `config.vm.provider` block. So first, add Libvirt box using any name you
+want. This is just an example of Libvirt CentOS 6.4 box available:
+
+```
+$ vagrant box add centos64 http://kwok.cz/centos64.box
+...
+```
+
+And then make a Vagrantfile that looks like the following, filling in
+your information where necessary.
+
+```
+Vagrant.configure("2") do |config|
+  config.vm.define :test_vm do |test_vm|
+    test_vm.vm.box = "centos64"
+  end
+
+  config.vm.provider :libvirt do |libvirt|
+    libvirt.driver = "qemu"
+    libvirt.host = "example.com"
+    libvirt.connect_via_ssh = true
+    libvirt.username = "root"
+    #libvirt.password = "secret"
+    libvirt.storage_pool_name = "default"
+  end
+end
+
+```
+
+And then run `vagrant up --provider=libvirt`.
+
+This will first upload box image to remote Libvirt storage pool as new volume.
+Then create and start a CentOS 6.4 domain on example.com Libvirt host. In this
+example configuration, connection to Libvirt is tunneled via SSH.
+
+## Box Format
+
+Every provider in Vagrant must introduce a custom box format. This
+provider introduces `Libvirt` boxes. You can view an example box in
+the [example_box/directory](https://github.com/pradels/vagrant-libvirt/tree/master/example_box). That directory also contains instructions on how to build a box.
+
+The box format is qcow2 image file `box.img`, the required `metadata.json` file
+along with a `Vagrantfile` that does default settings for the
+provider-specific configuration for this provider.
+
+## Configuration
+
+This provider exposes quite a few provider-specific configuration options:
+
+* `driver` - A hypervisor name to access. For now only qemu is supported.
+* `host` - The name of the server, where libvirtd is running.
+* `connect_via_ssh` - If use ssh tunnel to connect to Libvirt.
+* `username` - Username and password to access Libvirt.
+* `password` - Password to access Libvirt.
+* `storage_pool_name` - Libvirt storage pool name, where box image and
+  instance snapshots will be stored.
+
+## Networks
+
+Networking features in the form of `config.vm.network` are supported only
+in bridged format, no hostonly network is supported in current version of
+provider.
+
+Example of network interface definition:
+
+```
+  config.vm.define :test_vm do |test_vm|
+    test_vm.vm.network :bridged, :bridge => "default", :adapter => 1
+  end
+```
+
+Bridged network adapter connected to network `default` is defined.
+
+## Getting IP address
+
+There is a little problem to find out which IP address was assigned to remote
+domain. Fog library uses SSH connection to remote libvirt host and by default
+checks arpwatch entries there. Libvirt provider uses just arp table. There is no
+need to install and setup arpwatch, but information about MAC->IP address
+mapping is lost after short time. That is why there are no ssh or provision
+actions available yet.
+
+## Synced Folders
+
+There is minimal support for synced folders. Upon `vagrant up`, the Libvirt
+provider will use `rsync` (if available) to uni-directionally sync the folder
+to the remote machine over SSH.
+
+This is good enough for all built-in Vagrant provisioners (shell,
+chef, and puppet) to work!
+
+## Development
+
+To work on the `vagrant-libvirt` plugin, clone this repository out, and use
+[Bundler](http://gembundler.com) to get the dependencies:
+
+```
+$ bundle
+```
+
+Once you have the dependencies, verify the unit tests pass with `rake`:
+
+```
+$ bundle exec rake
+```
+
+If those pass, you're ready to start developing the plugin. You can test
+the plugin without installing it into your Vagrant environment by just
+creating a `Vagrantfile` in the top level of this directory (it is gitignored)
+that uses it, and uses bundler to execute Vagrant:
+
+```
+$ bundle exec vagrant up --provider=libvirt
+```
+
+## Future work
+
+* Read cpu and memory settings from config.
+* Hostonly networks.
+* Use Libvirt shared folder, not rsync if machine is local.
+* Test if arpwatch is available for getting MAC->IP mapping.
+* Provision, ssh, reload, halt, resume actions.
+* Support other domain types than KVM.
+
diff --git a/Rakefile b/Rakefile
new file mode 100644
index 0000000..b41e6e1
--- /dev/null
+++ b/Rakefile
@@ -0,0 +1,7 @@
+#!/usr/bin/env rake
+
+require 'rubygems'
+require 'bundler/setup'
+#require 'bundler/gem_tasks'
+Bundler::GemHelper.install_tasks
+
diff --git a/example_box/README.md b/example_box/README.md
new file mode 100644
index 0000000..50b519e
--- /dev/null
+++ b/example_box/README.md
@@ -0,0 +1,23 @@
+# Vagrant Libvirt Example Box
+
+Vagrant providers each require a custom provider-specific box format.
+This folder shows the example contents of a box for the `libvirt` provider.
+To turn this into a box create a vagrant image according documentation (don't
+forget to install rsync command) and create box with following command:
+
+```
+$ tar cvzf custom_box.box ./metadata.json ./Vagrantfile ./box.img
+```
+
+This box works by using Vagrant's built-in Vagrantfile merging to setup
+defaults for Libvirt. These defaults can easily be overwritten by higher-level
+Vagrantfiles (such as project root Vagrantfiles).
+
+## Box Metadata
+
+Libvirt box should define at least three data fields in `metadata.json` file.
+
+* provider - Provider name is libvirt.
+* format - Currently supported format is qcow2.
+* virtual_size - Virtual size of image in GBytes.
+
diff --git a/example_box/metadata.json b/example_box/metadata.json
new file mode 100644
index 0000000..b755f46
--- /dev/null
+++ b/example_box/metadata.json
@@ -0,0 +1,5 @@
+{
+  "provider"     : "libvirt"
+  "format"       : "qcow2"
+  "virtual_size" : "40"
+}
diff --git a/lib/vagrant-libvirt.rb b/lib/vagrant-libvirt.rb
new file mode 100644
index 0000000..ad69975
--- /dev/null
+++ b/lib/vagrant-libvirt.rb
@@ -0,0 +1,30 @@
+require 'pathname'
+require 'vagrant-libvirt/plugin'
+
+module VagrantPlugins
+  module Libvirt
+    lib_path = Pathname.new(File.expand_path("../vagrant-libvirt", __FILE__))
+    autoload :Action, lib_path.join("action")
+    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  
+  end
+end
+
diff --git a/lib/vagrant-libvirt/action.rb b/lib/vagrant-libvirt/action.rb
new file mode 100644
index 0000000..f1acc48
--- /dev/null
+++ b/lib/vagrant-libvirt/action.rb
@@ -0,0 +1,94 @@
+require 'vagrant/action/builder'
+
+module VagrantPlugins
+  module Libvirt
+    module Action
+      # Include the built-in modules so we can use them as top-level things.
+      include Vagrant::Action::Builtin
+
+      # This action is called to bring the box up from nothing.
+      def self.action_up
+        Vagrant::Action::Builder.new.tap do |b|
+          b.use ConfigValidate
+          b.use ConnectLibvirt
+          b.use Call, IsCreated do |env, b2|
+            if env[:result]
+              b2.use MessageAlreadyCreated
+              next
+            end
+
+            b2.use SetNameOfDomain
+            b2.use HandleStoragePool
+            b2.use HandleBoxImage
+            b2.use CreateDomainVolume
+            b2.use CreateDomain
+            b2.use CreateNetworkInterfaces
+          end
+
+          b.use TimedProvision
+          b.use StartDomain
+          b.use WaitTillUp
+          b.use SyncFolders
+        end
+      end
+
+      # This is the action that is primarily responsible for completely
+      # freeing the resources of the underlying virtual machine.
+      def self.action_destroy
+        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 DestroyDomain
+          end
+        end
+      end
+
+      # This action is called to read the state of the machine. The resulting
+      # state is expected to be put into the `:machine_state_id` key.
+      def self.action_read_state
+        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
+
+      action_root = Pathname.new(File.expand_path("../action", __FILE__))
+      autoload :ConnectLibvirt, action_root.join("connect_libvirt")
+      autoload :IsCreated, action_root.join("is_created")
+      autoload :MessageAlreadyCreated, action_root.join("message_already_created")
+      autoload :MessageNotCreated, action_root.join("message_not_created")
+      autoload :HandleStoragePool, action_root.join("handle_storage_pool")
+      autoload :HandleBoxImage, action_root.join("handle_box_image")
+      autoload :SetNameOfDomain, action_root.join("set_name_of_domain")
+      autoload :CreateDomainVolume, action_root.join("create_domain_volume")
+      autoload :CreateDomain, action_root.join("create_domain")
+      autoload :CreateNetworkInterfaces, action_root.join("create_network_interfaces")
+      autoload :DestroyDomain, action_root.join("destroy_domain")
+      autoload :StartDomain, action_root.join("start_domain")
+      autoload :ReadState, action_root.join("read_state")
+      autoload :ReadSSHInfo, action_root.join("read_ssh_info")
+      autoload :TimedProvision, action_root.join("timed_provision")
+      autoload :WaitTillUp, action_root.join("wait_till_up")
+      autoload :SyncFolders, action_root.join("sync_folders")
+    end
+  end
+end
+
diff --git a/lib/vagrant-libvirt/action/connect_libvirt.rb b/lib/vagrant-libvirt/action/connect_libvirt.rb
new file mode 100644
index 0000000..04a0f82
--- /dev/null
+++ b/lib/vagrant-libvirt/action/connect_libvirt.rb
@@ -0,0 +1,72 @@
+require 'fog'
+require 'log4r'
+
+module VagrantPlugins
+  module Libvirt
+    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 Libvirt.libvirt_connection
+            env[:libvirt_compute] = Libvirt.libvirt_connection
+            return @app.call(env)
+          end
+          
+          # Get config options for libvirt provider.
+          config = env[:machine].provider_config
+
+          # Setup connection uri.
+          uri = config.driver
+          if config.connect_via_ssh
+            uri << '+ssh://'
+            if config.username
+              uri << config.username + '@'
+            end
+
+            if config.host
+              uri << config.host
+            else
+              uri << 'localhost'
+            end
+          else
+            uri << '://'
+            uri << config.host if config.host
+          end                
+          uri << '/system?no_verify=1'
+
+          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 via arp table. This solution doesn't
+          # require arpwatch to be installed.
+          conn_attr[:libvirt_ip_command] = "arp -an | grep $mac | sed '"
+          conn_attr[:libvirt_ip_command] << 's/.*(\([0-9\.]*\)).*/\1/'
+          conn_attr[:libvirt_ip_command] << "'"
+
+          @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
+          Libvirt.libvirt_connection = env[:libvirt_compute]
+
+          @app.call(env)
+        end
+      end
+    end
+  end
+end
+
diff --git a/lib/vagrant-libvirt/action/create_domain.rb b/lib/vagrant-libvirt/action/create_domain.rb
new file mode 100644
index 0000000..db58ec2
--- /dev/null
+++ b/lib/vagrant-libvirt/action/create_domain.rb
@@ -0,0 +1,62 @@
+require 'log4r'
+
+module VagrantPlugins
+  module Libvirt
+    module Action
+
+      class CreateDomain
+        include VagrantPlugins::Libvirt::Util::ErbTemplate
+
+        def initialize(app, env)
+          @logger = Log4r::Logger.new("vagrant_libvirt::action::create_domain")
+          @app = app
+        end
+
+        def call(env)
+          # Gather some info about domain
+          # TODO from Vagrantfile
+          @name = env[:domain_name]
+          @cpus = 1
+          @memory_size = 512*1024
+
+          # TODO get type from driver config option
+          @domain_type = 'kvm'
+
+          @os_type = 'hvm'
+
+          # Get path to domain image.
+          domain_volume = Libvirt::Util::Collection.find_matching(
+            env[:libvirt_compute].volumes.all, "#{@name}.img")
+          raise Errors::DomainVolumeExists if domain_volume == nil
+          @domain_volume_path = domain_volume.path
+
+          # Output the settings we're going to use to the user
+          env[:ui].info(I18n.t("vagrant_libvirt.creating_domain"))
+          env[:ui].info(" -- Name:          #{@name}")
+          env[:ui].info(" -- Domain type:   #{@domain_type}")
+          env[:ui].info(" -- Cpus:          #{@cpus}")
+          env[:ui].info(" -- Memory:        #{@memory_size/1024}M")
+          env[:ui].info(" -- Base box:      #{env[:machine].box.name}")
+          env[:ui].info(" -- Image:         #{@domain_volume_path}")
+
+          # Create libvirt domain.
+          # 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(
+              :xml => to_xml('domain'))
+          rescue Fog::Errors::Error => e
+            raise Errors::FogCreateServerError,
+              :error_message => e.message
+          end
+
+          # Immediately save the ID since it is created at this point.
+          env[:machine].id = server.id
+
+          @app.call(env)
+        end
+      end
+
+    end
+  end
+end
diff --git a/lib/vagrant-libvirt/action/create_domain_volume.rb b/lib/vagrant-libvirt/action/create_domain_volume.rb
new file mode 100644
index 0000000..021b47b
--- /dev/null
+++ b/lib/vagrant-libvirt/action/create_domain_volume.rb
@@ -0,0 +1,58 @@
+require 'log4r'
+
+module VagrantPlugins
+  module Libvirt
+    module Action
+
+      # Create a snapshot of base box image. This new snapshot is just new
+      # cow image with backing storage pointing to base box image. Use this
+      # image as new domain volume.
+      class CreateDomainVolume
+        include VagrantPlugins::Libvirt::Util::ErbTemplate
+
+        def initialize(app, env)
+          @logger = Log4r::Logger.new("vagrant_libvirt::action::create_domain_volume")
+          @app = app
+        end
+
+        def call(env)
+          env[:ui].info(I18n.t("vagrant_libvirt.creating_domain_volume"))
+
+          # Get config options.
+          config = env[:machine].provider_config
+
+          # This is name of newly created image for vm.
+          @name = "#{env[:domain_name]}.img"
+
+          # Verify the volume doesn't exist already.
+          domain_volume = Libvirt::Util::Collection.find_matching(
+            env[:libvirt_compute].volumes.all, @name)
+          raise Errors::DomainVolumeExists if domain_volume
+
+          # Get path to backing image - box volume.
+          box_volume = Libvirt::Util::Collection.find_matching(
+            env[:libvirt_compute].volumes.all, env[:box_volume_name])
+          @backing_file = box_volume.path
+
+          # Virtual size of image. Same as box image size.
+          @capacity = env[:machine].box.metadata['virtual_size'] #G
+
+          # Create new volume from xml template. Fog currently doesn't support
+          # volume snapshots directly.
+          begin
+            domain_volume = env[:libvirt_compute].volumes.create(
+              :xml       => to_xml('volume_snapshot'),
+              :pool_name => config.storage_pool_name)
+          rescue Fog::Errors::Error => e
+            raise Errors::FogDomainVolumeCreateError,
+              :error_message => e.message
+          end
+
+          @app.call(env)
+        end
+      end
+
+    end
+  end
+end
+
diff --git a/lib/vagrant-libvirt/action/create_network_interfaces.rb b/lib/vagrant-libvirt/action/create_network_interfaces.rb
new file mode 100644
index 0000000..d8b7f24
--- /dev/null
+++ b/lib/vagrant-libvirt/action/create_network_interfaces.rb
@@ -0,0 +1,85 @@
+require 'log4r'
+
+module VagrantPlugins
+  module Libvirt
+    module Action
+
+      # Create network interfaces for domain, before domain is running.
+      class CreateNetworkInterfaces
+        include VagrantPlugins::Libvirt::Util::ErbTemplate
+
+        def initialize(app, env)
+          @logger = Log4r::Logger.new("vagrant_libvirt::action::create_network_interfaces")
+          @app = app
+        end
+
+        def call(env)
+          # Get domain first.
+          begin
+            domain = env[:libvirt_compute].client.lookup_domain_by_uuid(
+              env[:machine].id.to_s)
+          rescue => e
+            raise Errors::NoDomainError,
+              :error_message => e.message
+          end
+
+          # Setup list of interfaces before creating them
+          adapters = []
+
+          # Assign main interface for provisioning to first slot.
+          # Use network 'default' as network for ssh connecting and
+          # machine provisioning. This should be maybe configurable in
+          # Vagrantfile in future.
+          adapters[0] = 'default'
+
+          env[:machine].config.vm.networks.each do |type, options|
+            # Other types than bridged are not supported for now.
+            next if type != :bridged
+
+            network_name = 'default'
+            network_name = options[:bridge] if options[:bridge]
+
+            if options[:adapter]
+              if adapters[options[:adapter]]
+                raise Errors::InterfaceSlotNotAvailable
+              end
+
+              adapters[options[:adapter].to_i] = network_name
+            else
+              empty_slot = find_empty(adapters, start=1)
+              raise Errors::InterfaceSlotNotAvailable if empty_slot == nil
+
+              adapters[empty_slot] = network_name
+            end           
+          end
+
+          # Create each interface as new domain device
+          adapters.each_with_index do |network_name, slot_number|
+            @iface_number = slot_number
+            @network_name = network_name
+            @logger.info("Creating network interface eth#{@iface_number}")
+            begin
+              domain.attach_device(to_xml('interface'))
+            rescue => e
+              raise Errors::AttachDeviceError,
+                :error_message => e.message
+            end
+          end
+
+          @app.call(env)
+        end
+
+        private
+
+        def find_empty(array, start=0, stop=8)
+          for i in start..stop
+            return i if !array[i]
+          end
+          return nil
+        end
+      end
+
+    end
+  end
+end
+
diff --git a/lib/vagrant-libvirt/action/destroy_domain.rb b/lib/vagrant-libvirt/action/destroy_domain.rb
new file mode 100644
index 0000000..e722d85
--- /dev/null
+++ b/lib/vagrant-libvirt/action/destroy_domain.rb
@@ -0,0 +1,28 @@
+require 'log4r'
+
+module VagrantPlugins
+  module Libvirt
+    module Action
+      class DestroyDomain
+
+        def initialize(app, env)
+          @logger = Log4r::Logger.new("vagrant_libvirt::action::destroy_domain")
+          @app = app
+        end
+
+        def call(env)
+
+          # Destroy the server and remove the tracking ID          
+          env[:ui].info(I18n.t("vagrant_libvirt.destroy_domain"))
+
+          domain = env[:libvirt_compute].servers.get(env[:machine].id.to_s)
+          domain.destroy(:destroy_volumes => true)
+          env[:machine].id = nil
+
+          @app.call(env)
+        end
+
+      end
+    end
+  end
+end
diff --git a/lib/vagrant-libvirt/action/handle_box_image.rb b/lib/vagrant-libvirt/action/handle_box_image.rb
new file mode 100644
index 0000000..a329560
--- /dev/null
+++ b/lib/vagrant-libvirt/action/handle_box_image.rb
@@ -0,0 +1,121 @@
+require 'log4r'
+
+module VagrantPlugins
+  module Libvirt
+    module Action
+      class HandleBoxImage
+        def initialize(app, env)
+          @logger = Log4r::Logger.new("vagrant_libvirt::action::handle_box_image")
+          @app = app
+        end
+
+        def call(env)
+
+          # Verify box metadata for mandatory values.
+          # 
+          # Virtual size has to be set for allocating space in storage pool.
+          box_virtual_size = env[:machine].box.metadata['virtual_size']
+          if box_virtual_size == nil
+            raise Errors::NoBoxVirtualSizeSet
+          end
+
+          # Support qcow2 format only for now, but other formats with backing
+          # store capability should be usable.
+          box_format = env[:machine].box.metadata['format']
+          if box_format == nil
+            raise Errors::NoBoxFormatSet
+          elsif box_format != 'qcow2'
+            raise Errors::WrongBoxFormatSet
+          end
+
+          # Get config options
+          config   = env[:machine].provider_config
+          box_image_file = env[:machine].box.directory.join("box.img").to_s
+          env[:box_volume_name] = env[:machine].box.name.to_s.dup
+          env[:box_volume_name] << '_vagrant_box_image.img'
+
+          # Don't continue if image already exists in storage pool.
+          return @app.call(env) if Libvirt::Util::Collection.find_matching(
+            env[:libvirt_compute].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.
+          env[:ui].info(I18n.t("vagrant_libvirt.uploading_volume"))
+
+          # Create new volume in storage pool
+          box_image_size = File.size(box_image_file) # B
+          message = "Creating volume #{env[:box_volume_name]}"
+          message << " in storage pool #{config.storage_pool_name}."
+          @logger.info(message)
+          begin
+            fog_volume = env[:libvirt_compute].volumes.create(
+              :name        => env[:box_volume_name],
+              :allocation  => "#{box_image_size/1024/1024}M",
+              :capacity    => "#{box_virtual_size}G",
+              :format_type => box_format,
+              :pool_name   => config.storage_pool_name)
+          rescue Fog::Errors::Error => e
+            raise Errors::FogCreateVolumeError,
+              :error_message => e.message
+          end
+
+          # Upload box image to storage pool
+          ret = upload_image(box_image_file, config.storage_pool_name,
+            env[:box_volume_name], env) do |progress|
+              env[:ui].clear_line
+              env[:ui].report_progress(progress, box_image_size, false)
+          end
+
+          # Clear the line one last time since the progress meter doesn't
+          # disappear immediately.
+          env[:ui].clear_line
+
+          # If upload failed or was interrupted, remove created volume from
+          # storage pool.
+          if env[:interrupted] or !ret
+            begin
+              fog_volume.destroy
+            rescue
+              nil
+            end
+          end
+
+          @app.call(env)
+        end
+
+        protected
+
+        # Fog libvirt currently doesn't support uploading images to storage
+        # pool volumes. Use ruby-libvirt client instead.
+        def upload_image(image_file, pool_name, volume_name, env)
+          image_size = File.size(image_file) # B
+
+          begin
+            pool = env[:libvirt_compute].client.lookup_storage_pool_by_name(
+              pool_name)
+            volume = pool.lookup_volume_by_name(volume_name)
+            stream = env[:libvirt_compute].client.stream
+            volume.upload(stream, offset=0, length=image_size)
+            buf_size = 1024*1024 # 1M
+            progress = 0
+            open(image_file, 'rb') do |io|
+              while (buff = io.read(buf_size)) do
+                sent = stream.send buff
+                progress += sent
+                yield progress
+              end 
+            end
+          rescue => e
+            raise Errors::ImageUploadError,
+              :error_message => e.message
+          end
+
+          return true if progress == image_size
+          false
+        end
+
+      end
+    end
+  end
+end
+
diff --git a/lib/vagrant-libvirt/action/handle_storage_pool.rb b/lib/vagrant-libvirt/action/handle_storage_pool.rb
new file mode 100644
index 0000000..b088d31
--- /dev/null
+++ b/lib/vagrant-libvirt/action/handle_storage_pool.rb
@@ -0,0 +1,49 @@
+require 'log4r'
+
+module VagrantPlugins
+  module Libvirt
+    module Action
+      class HandleStoragePool
+        include VagrantPlugins::Libvirt::Util::ErbTemplate
+
+        def initialize(app, env)
+          @logger = Log4r::Logger.new("vagrant_libvirt::action::handle_storage_pool")
+          @app = app
+        end
+
+        def call(env)
+          # Get config options.
+          config = env[:machine].provider_config
+
+          # Check for storage pool, where box image should be created
+          fog_pool = Libvirt::Util::Collection.find_matching(
+            env[:libvirt_compute].pools.all, config.storage_pool_name)
+          return @app.call(env) if fog_pool
+
+          @logger.info("No storage pool '#{config.storage_pool_name}' is available.")
+
+          # If user specified other pool than default, don't create default
+          # storage pool, just write error message.
+          raise Errors::NoStoragePool if config.storage_pool_name != 'default'
+
+          @logger.info("Creating storage pool 'default'")
+
+          # Fog libvirt currently doesn't support creating pools. Use
+          # ruby-libvirt client directly.
+          begin
+            libvirt_pool = env[:libvirt_compute].client.create_storage_pool_xml(
+              to_xml('default_storage_pool'))
+          rescue => e
+            raise Errors::CreatingStoragePoolError,
+              :error_message => e.message
+          end
+          raise Errors::NoStoragePool if !libvirt_pool
+
+          @app.call(env)
+        end
+
+      end
+    end
+  end
+end
+
diff --git a/lib/vagrant-libvirt/action/is_created.rb b/lib/vagrant-libvirt/action/is_created.rb
new file mode 100644
index 0000000..39760a0
--- /dev/null
+++ b/lib/vagrant-libvirt/action/is_created.rb
@@ -0,0 +1,18 @@
+module VagrantPlugins
+  module Libvirt
+    module Action
+      # This can be used with "Call" built-in to check if the machine
+      # is created and branch in the middleware.
+      class IsCreated
+        def initialize(app, env)
+          @app = app
+        end
+
+        def call(env)
+          env[:result] = env[:machine].state.id != :not_created
+          @app.call(env)
+        end
+      end
+    end
+  end
+end
diff --git a/lib/vagrant-libvirt/action/message_already_created.rb b/lib/vagrant-libvirt/action/message_already_created.rb
new file mode 100644
index 0000000..a803d61
--- /dev/null
+++ b/lib/vagrant-libvirt/action/message_already_created.rb
@@ -0,0 +1,16 @@
+module VagrantPlugins
+  module Libvirt
+    module Action
+      class MessageAlreadyCreated
+        def initialize(app, env)
+          @app = app
+        end
+
+        def call(env)
+          env[:ui].info(I18n.t("vagrant_libvirt.already_created"))
+          @app.call(env)
+        end
+      end
+    end
+  end
+end
diff --git a/lib/vagrant-libvirt/action/message_not_created.rb b/lib/vagrant-libvirt/action/message_not_created.rb
new file mode 100644
index 0000000..14dfc0e
--- /dev/null
+++ b/lib/vagrant-libvirt/action/message_not_created.rb
@@ -0,0 +1,16 @@
+module VagrantPlugins
+  module Libvirt
+    module Action
+      class MessageNotCreated
+        def initialize(app, env)
+          @app = app
+        end
+
+        def call(env)
+          env[:ui].info(I18n.t("vagrant_libvirt.not_created"))
+          @app.call(env)
+        end
+      end
+    end
+  end
+end
diff --git a/lib/vagrant-libvirt/action/read_ssh_info.rb b/lib/vagrant-libvirt/action/read_ssh_info.rb
new file mode 100644
index 0000000..336ba96
--- /dev/null
+++ b/lib/vagrant-libvirt/action/read_ssh_info.rb
@@ -0,0 +1,51 @@
+require "log4r"
+
+module VagrantPlugins
+  module Libvirt
+    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?
+
+          # Find the machine
+          server = libvirt.servers.get(machine.id)
+          if server.nil?
+            # The machine can't be found
+            @logger.info("Machine couldn't be found, assuming it got destroyed.")
+            machine.id = nil
+            return nil
+          end
+
+          # Get ip address of machine
+          ip_address = server.public_ip_address
+          ip_address = server.private_ip_address if ip_address == nil
+          return nil if ip_address == nil
+
+          # Return the info
+          # TODO: Some info should be configurable in Vagrantfile
+          return {
+            :host => ip_address,
+            :port => 22,
+            :username => 'root',
+          }
+        end
+ 
+      end
+    end
+  end
+end
diff --git a/lib/vagrant-libvirt/action/read_state.rb b/lib/vagrant-libvirt/action/read_state.rb
new file mode 100644
index 0000000..f7543fa
--- /dev/null
+++ b/lib/vagrant-libvirt/action/read_state.rb
@@ -0,0 +1,38 @@
+require "log4r"
+
+module VagrantPlugins
+  module Libvirt
+    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?
+
+          # Find the machine
+          server = libvirt.servers.get(machine.id)
+          if server.nil? || [:"shutting-down", :terminated].include?(server.state.to_sym)
+            # The machine can't be found
+            @logger.info("Machine not found or terminated, assuming it got destroyed.")
+            machine.id = nil
+            return :not_created
+          end
+
+          # Return the state
+          return server.state.to_sym
+        end
+      end
+    end
+  end
+end
diff --git a/lib/vagrant-libvirt/action/set_name_of_domain.rb b/lib/vagrant-libvirt/action/set_name_of_domain.rb
new file mode 100644
index 0000000..fa9c0ef
--- /dev/null
+++ b/lib/vagrant-libvirt/action/set_name_of_domain.rb
@@ -0,0 +1,31 @@
+module VagrantPlugins
+  module Libvirt
+    module Action
+
+      # Setup name for domain and domain volumes.
+      class SetNameOfDomain
+        def initialize(app, env)
+          @app = app
+        end
+
+        def call(env)
+          env[:domain_name] = env[:root_path].basename.to_s.dup
+          env[:domain_name].gsub!(/[^-a-z0-9_]/i, "")
+          env[:domain_name] << "_#{Time.now.to_i}"
+
+          # Check if the domain name is not already taken
+          domain = Libvirt::Util::Collection.find_matching(
+            env[:libvirt_compute].servers.all, env[:domain_name])
+          if domain != nil
+            raise Vagrant::Errors::DomainNameExists,
+              :domain_name => env[:domain_name]
+          end
+
+          @app.call(env)
+        end
+      end
+
+    end
+  end
+end
+
diff --git a/lib/vagrant-libvirt/action/start_domain.rb b/lib/vagrant-libvirt/action/start_domain.rb
new file mode 100644
index 0000000..5ea9332
--- /dev/null
+++ b/lib/vagrant-libvirt/action/start_domain.rb
@@ -0,0 +1,27 @@
+require 'log4r'
+
+module VagrantPlugins
+  module Libvirt
+    module Action
+
+      # Just start the domain.
+      class StartDomain
+        def initialize(app, env)
+          @logger = Log4r::Logger.new("vagrant_libvirt::action::start_domain")
+          @app = app
+        end
+
+        def call(env)
+          env[:ui].info(I18n.t("vagrant_libvirt.starting_domain"))
+
+          domain = env[:libvirt_compute].servers.get(env[:machine].id.to_s)
+          raise Errors::NoDomainError if domain == nil
+          domain.start
+
+          @app.call(env)
+        end
+      end
+
+    end
+  end
+end
diff --git a/lib/vagrant-libvirt/action/sync_folders.rb b/lib/vagrant-libvirt/action/sync_folders.rb
new file mode 100644
index 0000000..f16fa02
--- /dev/null
+++ b/lib/vagrant-libvirt/action/sync_folders.rb
@@ -0,0 +1,58 @@
+require "log4r"
+require "vagrant/util/subprocess"
+
+module VagrantPlugins
+  module Libvirt
+    module Action
+      # This middleware uses `rsync` to sync the folders over to the
+      # libvirt domain.
+      class SyncFolders
+        def initialize(app, env)
+          @app    = app
+          @logger = Log4r::Logger.new("vagrant_libvirt::action::sync_folders")
+        end
+
+        def call(env)
+          @app.call(env)
+
+          ssh_info = env[:machine].ssh_info
+
+          env[:machine].config.vm.synced_folders.each do |id, data|
+            hostpath  = File.expand_path(data[:hostpath], env[:root_path])
+            guestpath = data[:guestpath]
+
+            # Make sure there is a trailing slash on the host path to
+            # avoid creating an additional directory with rsync
+            hostpath = "#{hostpath}/" if hostpath !~ /\/$/
+
+            env[:ui].info(I18n.t("vagrant_libvirt.rsync_folder",
+                                :hostpath => hostpath,
+                                :guestpath => guestpath))
+
+            # Create the guest path
+            env[:machine].communicate.sudo("mkdir -p '#{guestpath}'")
+            env[:machine].communicate.sudo(
+              "chown #{ssh_info[:username]} '#{guestpath}'")
+
+            # Rsync over to the guest path using the SSH info
+            command = [
+              "rsync", "--verbose", "--archive", "-z",
+              "--exclude", ".vagrant/",
+              "-e", "ssh -p #{ssh_info[:port]} -o StrictHostKeyChecking=no -i '#{ssh_info[:private_key_path]}'",
+              hostpath,
+              "#{ssh_info[:username]}@#{ssh_info[:host]}:#{guestpath}"]
+
+            r = Vagrant::Util::Subprocess.execute(*command)
+            if r.exit_code != 0
+              raise Errors::RsyncError,
+                :guestpath => guestpath,
+                :hostpath => hostpath,
+                :stderr => r.stderr
+            end
+          end
+        end
+      end
+    end
+  end
+end
+
diff --git a/lib/vagrant-libvirt/action/timed_provision.rb b/lib/vagrant-libvirt/action/timed_provision.rb
new file mode 100644
index 0000000..b5cecd6
--- /dev/null
+++ b/lib/vagrant-libvirt/action/timed_provision.rb
@@ -0,0 +1,21 @@
+require "vagrant-libvirt/util/timer"
+
+module VagrantPlugins
+  module Libvirt
+    module Action
+      # This is the same as the builtin provision except it times the
+      # provisioner runs.
+      class TimedProvision < Vagrant::Action::Builtin::Provision
+        def run_provisioner(env, p)
+          timer = Util::Timer.time do
+            super
+          end
+
+          env[:metrics] ||= {}
+          env[:metrics]["provisioner_times"] ||= []
+          env[:metrics]["provisioner_times"] << [p.class.to_s, timer]
+        end
+      end
+    end
+  end
+end
diff --git a/lib/vagrant-libvirt/action/wait_till_up.rb b/lib/vagrant-libvirt/action/wait_till_up.rb
new file mode 100644
index 0000000..f42f901
--- /dev/null
+++ b/lib/vagrant-libvirt/action/wait_till_up.rb
@@ -0,0 +1,96 @@
+require 'log4r'
+require 'vagrant-libvirt/util/timer'
+require 'vagrant/util/retryable'
+
+module VagrantPlugins
+  module Libvirt
+    module Action
+
+      # Wait till domain is started, till it obtains an IP address and is
+      # accessible via ssh.
+      class WaitTillUp
+        include Vagrant::Util::Retryable
+
+        def initialize(app, env)
+          @logger = Log4r::Logger.new("vagrant_libvirt::action::wait_till_up")
+          @app = app
+        end
+
+        def call(env)
+          # Initialize metrics if they haven't been
+          env[:metrics] ||= {}
+
+          # Get domain object
+          domain = env[:libvirt_compute].servers.get(env[:machine].id.to_s)
+          raise NoDomainError if domain == nil
+
+          # Wait for domain to obtain an ip address. Ip address is searched
+          # from arp table, either localy or remotely via ssh, if libvirt
+          # connection was done via ssh.
+          env[:ip_address] = nil
+          env[:metrics]["instance_ip_time"] = Util::Timer.time do
+            env[:ui].info(I18n.t("vagrant_libvirt.waiting_for_ip"))
+            retryable(:on => Fog::Errors::TimeoutError, :tries => 300) do
+              # If we're interrupted don't worry about waiting
+              next if env[:interrupted]
+
+              # Wait for domain to obtain an ip address
+              domain.wait_for(2) {
+                addresses.each_pair do |type, ip|
+                  env[:ip_address] = ip[0]
+                end
+                env[:ip_address] != nil
+              }
+            end
+          end
+          terminate(env) if env[:interrupted]
+          @logger.info("Got IP address #{env[:ip_address]}")
+          @logger.info("Time for getting IP: #{env[:metrics]["instance_ip_time"]}")
+
+          # Machine has ip address assigned, now wait till we are able to
+          # connect via ssh.
+          env[:metrics]["instance_ssh_time"] = Util::Timer.time do
+            env[:ui].info(I18n.t("vagrant_libvirt.waiting_for_ssh"))
+            retryable(:on => Fog::Errors::TimeoutError, :tries => 60) do
+              # If we're interrupted don't worry about waiting
+              next if env[:interrupted]
+
+              # Wait till we are able to connect via ssh.
+              while true
+                # If we're interrupted then just back out
+                break if env[:interrupted]
+                break if env[:machine].communicate.ready?
+                sleep 2
+              end            
+            end
+          end
+          terminate(env) if env[:interrupted]
+          @logger.info("Time for SSH ready: #{env[:metrics]["instance_ssh_time"]}")
+
+          # Booted and ready for use.
+          #env[:ui].info(I18n.t("vagrant_libvirt.ready"))
+          
+          @app.call(env)
+        end
+
+        def recover(env)
+          return if env["vagrant.error"].is_a?(Vagrant::Errors::VagrantError)
+
+          if env[:machine].provider.state.id != :not_created
+            # Undo the import
+            terminate(env)
+          end
+        end
+
+        def terminate(env)
+          destroy_env = env.dup
+          destroy_env.delete(:interrupted)
+          destroy_env[:config_validate] = false
+          destroy_env[:force_confirm_destroy] = true
+          env[:action_runner].run(Action.action_destroy, destroy_env)        
+        end
+      end
+    end
+  end
+end
+
diff --git a/lib/vagrant-libvirt/config.rb b/lib/vagrant-libvirt/config.rb
new file mode 100644
index 0000000..501effc
--- /dev/null
+++ b/lib/vagrant-libvirt/config.rb
@@ -0,0 +1,48 @@
+require 'vagrant'
+
+module VagrantPlugins
+  module Libvirt
+    class Config < Vagrant.plugin('2', :config)
+      # A hypervisor name to access via Libvirt.
+      attr_accessor :driver
+
+      # The name of the server, where libvirtd is running.
+      attr_accessor :host
+
+      # If use ssh tunnel to connect to Libvirt.
+      attr_accessor :connect_via_ssh
+
+      # The username to access Libvirt.
+      attr_accessor :username
+
+      # Password for Libvirt connection.
+      attr_accessor :password
+
+      # Libvirt storage pool name, where box image and instance snapshots will
+      # be stored.
+      attr_accessor :storage_pool_name
+
+      def initialize
+        @driver            = UNSET_VALUE
+        @host              = UNSET_VALUE
+        @connect_via_ssh   = UNSET_VALUE
+        @username          = UNSET_VALUE
+        @password          = UNSET_VALUE
+        @storage_pool_name = UNSET_VALUE
+      end
+
+      def finalize!
+        @driver   = 'qemu' if @driver == UNSET_VALUE
+        @host     = nil if @host     == UNSET_VALUE
+        @connect_via_ssh = false if @connect_via_ssh == UNSET_VALUE
+        @username = nil if @username == UNSET_VALUE
+        @password = nil if @password == UNSET_VALUE
+        @storage_pool_name = 'default' if @storage_pool_name == UNSET_VALUE
+      end
+
+      def validate(machine)
+      end
+    end
+  end
+end
+
diff --git a/lib/vagrant-libvirt/errors.rb b/lib/vagrant-libvirt/errors.rb
new file mode 100644
index 0000000..b158dec
--- /dev/null
+++ b/lib/vagrant-libvirt/errors.rb
@@ -0,0 +1,90 @@
+require 'vagrant'
+
+module VagrantPlugins
+  module Libvirt
+    module Errors
+      class VagrantLibvirtError < Vagrant::Errors::VagrantError
+        error_namespace("vagrant_libvirt.errors")
+      end
+
+      # Storage pools and volumes exceptions
+      class NoStoragePool < VagrantLibvirtError
+        error_key(:no_storage_pool)
+      end
+
+      class DomainVolumeExists < VagrantLibvirtError
+        error_key(:domain_volume_exists)
+      end
+
+      class NoDomainVolume < VagrantLibvirtError
+        error_key(:no_domain_volume)
+      end
+
+      class CreatingStoragePoolError < VagrantLibvirtError
+        error_key(:creating_storage_pool_error)
+      end
+
+      class ImageUploadError < VagrantLibvirtError
+        error_key(:image_upload_error_error)
+      end
+
+
+      # Box exceptions
+      class NoBoxVolume < VagrantLibvirtError
+        error_key(:no_box_volume)
+      end
+
+      class NoBoxVirtualSizeSet < VagrantLibvirtError
+        error_key(:no_box_virtual_size_error)
+      end
+
+      class NoBoxFormatSet < VagrantLibvirtError
+        error_key(:no_box_format_error)
+      end
+
+      class WrongBoxFormatSet < VagrantLibvirtError
+        error_key(:wrong_box_format_error)
+      end
+
+
+      # Fog libvirt exceptions
+      class FogLibvirtConnectionError < VagrantLibvirtError
+        error_key(:fog_libvirt_connection_error)
+      end
+
+      class FogCreateVolumeError < VagrantLibvirtError
+        error_key(:fog_create_volume_error)
+      end
+
+      class FogCreateDomainVolumeError < VagrantLibvirtError
+        error_key(:fog_create_domain_volume_error)
+      end
+
+      class FogCreateServerError < VagrantLibvirtError
+        error_key(:fog_create_server_error)
+      end
+
+
+      # Other exceptions
+      class InterfaceSlotNotAvailable < VagrantLibvirtError
+        error_key(:interface_slot_not_available)
+      end
+
+      class RsyncError < VagrantLibvirtError
+        error_key(:rsync_error)
+      end
+
+      class DomainNameExists < VagrantLibvirtError
+        error_key(:domain_name_exists_error)
+      end
+
+      class NoDomainError < VagrantLibvirtError
+        error_key(:no_domain_error)
+      end
+
+      class AttachDeviceError < VagrantLibvirtError
+        error_key(:attach_device_error)
+      end
+    end
+  end
+end
diff --git a/lib/vagrant-libvirt/plugin.rb b/lib/vagrant-libvirt/plugin.rb
new file mode 100644
index 0000000..fbe162c
--- /dev/null
+++ b/lib/vagrant-libvirt/plugin.rb
@@ -0,0 +1,77 @@
+begin
+  require 'vagrant'
+rescue LoadError
+  raise "The Vagrant Libvirt plugin must be run within Vagrant."
+end
+
+
+# This is a sanity check to make sure no one is attempting to install
+# this into an early Vagrant version.
+if Vagrant::VERSION < '1.1.0'
+  raise "The Vagrant Libvirt plugin is only compatible with Vagrant 1.1+"
+end
+
+module VagrantPlugins
+  module Libvirt
+    class Plugin < Vagrant.plugin('2')
+      name "libvirt"
+      description <<-DESC
+      Vagrant plugin to manage VMs in libvirt.
+      DESC
+
+
+      config("libvirt", :provider) do
+        require_relative "config"
+        Config
+      end
+
+      provider "libvirt" do
+        # Setup logging and i18n
+        setup_logging
+        setup_i18n
+
+        require_relative "provider"
+        Provider
+      end
+
+
+      # This initializes the internationalization strings.
+      def self.setup_i18n
+        I18n.load_path << File.expand_path("locales/en.yml", Libvirt.source_root)
+        I18n.reload!
+      end
+
+
+      # This sets up our log level to be whatever VAGRANT_LOG is.
+      def self.setup_logging
+        require "log4r"
+
+        level = nil
+        begin
+          level = Log4r.const_get(ENV["VAGRANT_LOG"].upcase)
+        rescue NameError
+          # This means that the logging constant wasn't found,
+          # which is fine. We just keep `level` as `nil`. But
+          # we tell the user.
+          level = nil
+        end
+
+        # Some constants, such as "true" resolve to booleans, so the
+        # above error checking doesn't catch it. This will check to make
+        # sure that the log level is an integer, as Log4r requires.
+        level = nil if !level.is_a?(Integer)
+
+        # Set the logging level on all "vagrant" namespaced
+        # logs as long as we have a valid level.
+        if level
+          logger = Log4r::Logger.new("vagrant_libvirt")
+          logger.outputters = Log4r::Outputter.stderr
+          logger.level = level
+          logger = nil
+        end
+      end
+
+    end
+  end
+end
+
diff --git a/lib/vagrant-libvirt/provider.rb b/lib/vagrant-libvirt/provider.rb
new file mode 100644
index 0000000..1b18aef
--- /dev/null
+++ b/lib/vagrant-libvirt/provider.rb
@@ -0,0 +1,76 @@
+require 'vagrant'
+
+module VagrantPlugins
+  module Libvirt
+
+    # This is the base class for a provider for the V2 API. A provider
+    # is responsible for creating compute resources to match the
+    # needs of a Vagrant-configured system.
+    class Provider < Vagrant.plugin('2', :provider)
+      def initialize(machine)
+        @machine = machine
+      end
+
+      # This should return an action callable for the given name.
+      def action(name)
+        # Attempt to get the action method from the Action class if it
+        # exists, otherwise return nil to show that we don't support the
+        # given action.
+        action_method = "action_#{name}"
+        return Action.send(action_method) if Action.respond_to?(action_method)
+        nil
+      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
+      # become `nil`).
+      def machine_id_changed
+      end
+
+      # This should return a hash of information that explains how to
+      # 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.
+        #
+        # Ssh info has following format..
+        #
+        #{
+        #  :host => "1.2.3.4",
+        #  :port => "22",
+        #  :username => "mitchellh",
+        #  :private_key_path => "/path/to/my/key"
+        #}
+        env = @machine.action("read_ssh_info")
+        env[:machine_ssh_info]
+      end
+
+      # 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")
+
+        state_id = env[:machine_state_id]
+
+        # Get the short and long description
+        short = I18n.t("vagrant_libvirt.states.short_#{state_id}")
+        long  = I18n.t("vagrant_libvirt.states.long_#{state_id}")
+
+        # Return the MachineState object
+        Vagrant::MachineState.new(state_id, short, long)
+      end
+
+      def to_s
+        id = @machine.id.nil? ? "new" : @machine.id
+        "Libvirt (#{id})"
+      end
+    end
+  end
+end
+
diff --git a/lib/vagrant-libvirt/templates/default_storage_pool.xml.erb b/lib/vagrant-libvirt/templates/default_storage_pool.xml.erb
new file mode 100644
index 0000000..b63eea7
--- /dev/null
+++ b/lib/vagrant-libvirt/templates/default_storage_pool.xml.erb
@@ -0,0 +1,13 @@
+<pool type='dir'>
+  <name>default</name>
+  <source>
+  </source>
+  <target>
+    <path>/var/lib/libvirt/images</path>
+    <permissions>
+      <mode>0755</mode>
+      <owner>-1</owner>
+      <group>-1</group>
+    </permissions>
+  </target>
+</pool>
diff --git a/lib/vagrant-libvirt/templates/domain.xml.erb b/lib/vagrant-libvirt/templates/domain.xml.erb
new file mode 100644
index 0000000..d1eb492
--- /dev/null
+++ b/lib/vagrant-libvirt/templates/domain.xml.erb
@@ -0,0 +1,34 @@
+<domain type='<%= @domain_type %>'>
+  <name><%= @name %></name>
+  <memory><%= @memory_size %></memory>
+  <vcpu><%= @cpus %></vcpu>
+  <os>
+    <type arch='x86_64'>hvm</type>
+    <boot dev='hd'/>
+  </os>
+  <features>
+    <acpi/>
+    <apic/>
+    <pae/>
+  </features>
+  <clock offset='utc'/>
+  <devices>
+    <disk type='file' device='disk'>
+      <driver name='qemu' type='qcow2'/>
+      <source file='<%= @domain_volume_path %>'/>
+      <%# we need to ensure a unique target dev -%>
+      <target dev='vda' bus='virtio'/>
+    </disk>
+    <serial type='pty'>
+      <target port='0'/>
+    </serial>
+    <console type='pty'>
+      <target port='0'/>
+    </console>
+    <input type='mouse' bus='ps2'/>
+    <graphics type='vnc' port='5900' autoport='yes' listen='127.0.0.1' keymap='en-us'/>
+    <video>
+      <model type='cirrus' vram='9216' heads='1'/>
+    </video>
+  </devices>
+</domain>
diff --git a/lib/vagrant-libvirt/templates/interface.xml.erb b/lib/vagrant-libvirt/templates/interface.xml.erb
new file mode 100644
index 0000000..39edc0f
--- /dev/null
+++ b/lib/vagrant-libvirt/templates/interface.xml.erb
@@ -0,0 +1,7 @@
+<interface type='network'>
+  <source network='<%= @network_name %>'/>
+  <target dev='vnet<%= @iface_number %>'/>
+  <alias name='net<%= @iface_number %>'/>
+  <model type='virtio'/>
+</interface>
+
diff --git a/lib/vagrant-libvirt/templates/volume_snapshot.xml.erb b/lib/vagrant-libvirt/templates/volume_snapshot.xml.erb
new file mode 100644
index 0000000..304d248
--- /dev/null
+++ b/lib/vagrant-libvirt/templates/volume_snapshot.xml.erb
@@ -0,0 +1,26 @@
+<volume>
+  <name><%= @name %></name>
+  <capacity unit="G"><%= @capacity %></capacity>
+
+  <target>
+    <format type='qcow2'/>
+    <permissions>
+      <owner>0</owner>
+      <group>0</group>
+      <mode>0600</mode>
+      <label>virt_image_t</label>
+    </permissions>
+  </target>
+
+  <backingStore>
+    <path><%= @backing_file %></path>
+    <format type='qcow2'/>
+    <permissions>
+      <owner>0</owner>
+      <group>0</group>
+      <mode>0600</mode>
+      <label>virt_image_t</label>
+    </permissions>
+  </backingStore>
+</volume>
+
diff --git a/lib/vagrant-libvirt/util.rb b/lib/vagrant-libvirt/util.rb
new file mode 100644
index 0000000..870fea4
--- /dev/null
+++ b/lib/vagrant-libvirt/util.rb
@@ -0,0 +1,10 @@
+module VagrantPlugins
+  module Libvirt
+    module Util
+      autoload :ErbTemplate, 'vagrant-libvirt/util/erb_template'
+      autoload :Collection,  'vagrant-libvirt/util/collection'
+      autoload :Timer,  'vagrant-libvirt/util/timer'
+    end
+  end
+end
+
diff --git a/lib/vagrant-libvirt/util/collection.rb b/lib/vagrant-libvirt/util/collection.rb
new file mode 100644
index 0000000..89d901e
--- /dev/null
+++ b/lib/vagrant-libvirt/util/collection.rb
@@ -0,0 +1,22 @@
+module VagrantPlugins
+  module Libvirt
+    module Util
+      module Collection
+
+        # This method finds a matching _thing_ in a collection of
+        # _things_. This works matching if the ID or NAME equals to
+        # `name`. Or, if `name` is a regexp, a partial match is chosen
+        # as well.
+        def self.find_matching(collection, name)
+          collection.each do |single|
+            return single if single.name == name
+          end
+
+          nil
+        end
+
+      end
+    end
+  end
+end
+
diff --git a/lib/vagrant-libvirt/util/erb_template.rb b/lib/vagrant-libvirt/util/erb_template.rb
new file mode 100644
index 0000000..4f2b4be
--- /dev/null
+++ b/lib/vagrant-libvirt/util/erb_template.rb
@@ -0,0 +1,21 @@
+require 'erb'
+
+module VagrantPlugins
+  module Libvirt
+    module Util
+      module ErbTemplate
+
+        # Taken from fog source.
+        def to_xml template_name = nil
+          erb = template_name || self.class.to_s.split("::").last.downcase
+          path = File.join(File.dirname(__FILE__), "..", "templates",
+                           "#{erb}.xml.erb")
+          template = File.read(path)
+          ERB.new(template, nil, '-').result(binding)
+        end
+ 
+      end
+    end
+  end
+end
+
diff --git a/lib/vagrant-libvirt/util/timer.rb b/lib/vagrant-libvirt/util/timer.rb
new file mode 100644
index 0000000..6349d49
--- /dev/null
+++ b/lib/vagrant-libvirt/util/timer.rb
@@ -0,0 +1,17 @@
+module VagrantPlugins
+  module Libvirt
+    module Util
+      class Timer
+        # A basic utility method that times the execution of the given
+        # block and returns it.
+        def self.time
+          start_time = Time.now.to_f
+          yield
+          end_time = Time.now.to_f
+
+          end_time - start_time
+        end
+      end
+    end
+  end
+end
diff --git a/lib/vagrant-libvirt/version.rb b/lib/vagrant-libvirt/version.rb
new file mode 100644
index 0000000..5e8b1a3
--- /dev/null
+++ b/lib/vagrant-libvirt/version.rb
@@ -0,0 +1,5 @@
+module VagrantPlugins
+  module Libvirt
+    VERSION = "0.0.1"
+  end
+end
diff --git a/locales/en.yml b/locales/en.yml
new file mode 100644
index 0000000..9e999cd
--- /dev/null
+++ b/locales/en.yml
@@ -0,0 +1,103 @@
+en:
+  vagrant_libvirt:
+    already_created: |-
+      The machine is already created.
+    not_created: |-
+      Machine is not created. Please run `vagrant up` first.
+    finding_volume: |-
+      Checking if volume is available.
+    creating_domain: |-
+      Creating machine with the following settings...
+    uploading_volume: |-
+      Uploading base box image as volume into libvirt storage...
+    creating_domain_volume: |-
+      Creating image (snapshot of base box volume).
+    removing_domain_volume: |-
+      Removing image (snapshot of base box volume).
+    starting_domain: |-
+      Starting machine.
+    terminating: |-
+      Removing machine...
+    poweroff_domain: |-
+      Poweroff machine.
+    destroy_domain: |-
+      Removing machine...
+    waiting_for_ready: |-
+      Waiting for machine to become "ready"...
+    waiting_for_ip: |-
+      Waiting for machine to get an IP address...
+    waiting_for_ssh: |-
+      Waiting for SSH to become available...
+    booted: |-
+      Machine is booted.
+    rsync_folder: |-
+      Rsyncing folder: %{hostpath} => %{guestpath}
+    ready: |-
+      Machine is booted and ready for use!
+
+    errors:
+      fog_error: |-
+        There was an error talking to Libvirt. The error message is shown
+        below:
+
+        %{message}
+      no_matching_volume: |-
+        No matching volume was found! Please check your volume setting
+        to make sure you have a valid volume chosen.
+      no_storage_pool: |-
+        No usable storage pool found! Please check if storage pool is
+        created and available.
+      no_box_volume: |-
+        Volume for box image is missing in storage pools. Try to run vagrant
+        again, or check if storage volume is accessible.
+      domain_volume_exists: |-
+        Volume for domain is already created. Please run 'vagrant destroy' first.
+      no_domain_volume: |-
+        Volume for domain is missing. Try to run 'vagrant up' again.
+      interface_slot_not_available: |-
+        Interface adapter number is already in use. Please specify other adapter
+        number.
+      rsync_error: |-
+        There was an error when attemping to rsync a share folder.
+        Please inspect the error message below for more info.
+
+        Host path: %{hostpath}
+        Guest path: %{guestpath}
+        Error: %{stderr}
+      no_box_virtual_size: |-
+        No image virtual size specified for box.
+      no_box_format: |-
+        No image format specified for box.
+      wrong_box_format: |-
+        Wrong image format specified for box.
+      fog_libvirt_connection_error: |-
+        Error while connecting to libvirt: %{error_message}
+      fog_create_volume_error: |-
+        Error while creating a storage pool volume: %{error_message}
+      fog_create_domain_volume_error: |-
+        Error while creating volume for domain: %{error_message}
+      fog_create_server_error: |-
+        Error while creating domain: %{error_message}
+      domain_name_exists: |-
+        Name of domain about to create is already taken. Please try to run
+        `vagrant up` command again.
+      creating_storage_pool_error: |-
+        There was error while creating libvirt storage pool: %{error_message}
+      image_upload_error: |-
+        Error while uploading image to storage pool: %{error_message}
+      no_domain_error: |-
+        No domain found. %{error_message}
+      attach_device_error: |-
+        Error while attaching new device to domain. %{error_message}
+
+    states:
+      short_not_created: |-
+        not created
+      long_not_created: |-
+        The Libvirt domain is not created. Run `vagrant up` to create it.
+
+      short_running: |-
+        running
+      long_running: |-
+        The Libvirt domain is running. To stop this machine, you can run
+        `vagrant halt`. To destroy the machine, you can run `vagrant destroy`.
diff --git a/vagrant-libvirt.gemspec b/vagrant-libvirt.gemspec
new file mode 100644
index 0000000..ae4bba7
--- /dev/null
+++ b/vagrant-libvirt.gemspec
@@ -0,0 +1,23 @@
+# -*- encoding: utf-8 -*-
+require File.expand_path('../lib/vagrant-libvirt/version', __FILE__)
+
+Gem::Specification.new do |gem|
+  gem.authors       = ["Lukas Stanek"]
+  gem.email         = ["ls at elostech.cz"]
+  gem.description   = %q{Vagrant provider for libvirt.}
+  gem.summary       = %q{Vagrant provider for libvirt.}
+  gem.homepage      = "http://www.vagrantup.com"
+
+  gem.files         = `git ls-files`.split($\)
+  gem.executables   = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
+  gem.test_files    = gem.files.grep(%r{^(test|spec|features)/})
+  gem.name          = "vagrant-libvirt"
+  gem.require_paths = ["lib"]
+  gem.version       = VagrantPlugins::Libvirt::VERSION
+
+  gem.add_runtime_dependency "fog", "~> 1.10.0"
+  gem.add_runtime_dependency "ruby-libvirt", "~> 0.4.0"
+
+  gem.add_development_dependency "rake"
+end
+

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-ruby-extras/vagrant-libvirt.git



More information about the Pkg-ruby-extras-commits mailing list