vagrant-libvirt 0.0.1 → 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +3 -0
- data/README.md +149 -4
- data/Rakefile +3 -3
- data/example_box/README.md +9 -0
- data/example_box/metadata.json +3 -3
- data/lib/vagrant-libvirt.rb +11 -2
- data/lib/vagrant-libvirt/action.rb +172 -13
- data/lib/vagrant-libvirt/action/cleanup_data_dir.rb +22 -0
- data/lib/vagrant-libvirt/action/connect_libvirt.rb +3 -5
- data/lib/vagrant-libvirt/action/create_domain.rb +3 -2
- data/lib/vagrant-libvirt/action/destroy_domain.rb +1 -4
- data/lib/vagrant-libvirt/action/halt_domain.rb +36 -0
- data/lib/vagrant-libvirt/action/handle_box_image.rb +2 -2
- data/lib/vagrant-libvirt/action/is_running.rb +21 -0
- data/lib/vagrant-libvirt/action/is_suspended.rb +21 -0
- data/lib/vagrant-libvirt/action/message_not_running.rb +16 -0
- data/lib/vagrant-libvirt/action/message_not_suspended.rb +16 -0
- data/lib/vagrant-libvirt/action/read_ssh_info.rb +44 -10
- data/lib/vagrant-libvirt/action/read_state.rb +0 -1
- data/lib/vagrant-libvirt/action/resume_domain.rb +27 -0
- data/lib/vagrant-libvirt/action/suspend_domain.rb +28 -0
- data/lib/vagrant-libvirt/action/wait_till_up.rb +7 -0
- data/lib/vagrant-libvirt/errors.rb +9 -0
- data/lib/vagrant-libvirt/version.rb +1 -1
- data/locales/en.yml +29 -9
- metadata +21 -5
- checksums.yaml +0 -7
data/.gitignore
CHANGED
data/README.md
CHANGED
@@ -4,16 +4,19 @@ This is a [Vagrant](http://www.vagrantup.com) 1.1+ plugin that adds an
|
|
4
4
|
[Libvirt](http://libvirt.org) provider to Vagrant, allowing Vagrant to
|
5
5
|
control and provision machines via Libvirt toolkit.
|
6
6
|
|
7
|
+
This plugin is inspired by existing [vagrant-aws](https://github.com/mitchellh/vagrant-aws) provider.
|
8
|
+
|
7
9
|
**Note:** This plugin requires Vagrant 1.1+.
|
8
10
|
|
9
|
-
## Features
|
11
|
+
## Features (Version 0.0.2)
|
10
12
|
|
11
|
-
* Upload
|
12
|
-
*
|
13
|
+
* Upload box image (qcow2 format) to Libvirt storage pool.
|
14
|
+
* Create volume as COW diff image for domains.
|
13
15
|
* Create and boot Libvirt domains.
|
14
16
|
* SSH into domains.
|
15
17
|
* Provision domains with any built-in Vagrant provisioner.
|
16
18
|
* Minimal synced folder support via `rsync`.
|
19
|
+
* Up, destroy, suspend, resume, halt, ssh, provision subcommands.
|
17
20
|
|
18
21
|
## Usage
|
19
22
|
|
@@ -29,5 +32,147 @@ $ vagrant up --provider=libvirt
|
|
29
32
|
```
|
30
33
|
|
31
34
|
Of course prior to doing this, you'll need to obtain an Libvirt-compatible
|
32
|
-
box file for Vagrant.
|
35
|
+
box file for Vagrant.
|
36
|
+
|
37
|
+
### Problems with plugin installation
|
38
|
+
|
39
|
+
In case of problems with building nokogiri gem, install missing development
|
40
|
+
libraries libxslt and libxml2.
|
41
|
+
|
42
|
+
In Ubuntu, Debian, ...
|
43
|
+
```
|
44
|
+
$ sudo apt-get install libxslt-dev libxml2-dev
|
45
|
+
```
|
46
|
+
|
47
|
+
In RedHat, Centos, Fedora, ...
|
48
|
+
```
|
49
|
+
# yum install libxslt-devel libxml2-devel
|
50
|
+
```
|
51
|
+
|
52
|
+
## Quick Start
|
53
|
+
|
54
|
+
After installing the plugin (instructions above), the quickest way to get
|
55
|
+
started is to add Libvirt box and specify all the details manually within
|
56
|
+
a `config.vm.provider` block. So first, add Libvirt box using any name you
|
57
|
+
want. This is just an example of Libvirt CentOS 6.4 box available:
|
58
|
+
|
59
|
+
```
|
60
|
+
$ vagrant box add centos64 http://kwok.cz/centos64.box
|
61
|
+
...
|
62
|
+
```
|
63
|
+
|
64
|
+
And then make a Vagrantfile that looks like the following, filling in
|
65
|
+
your information where necessary.
|
66
|
+
|
67
|
+
```
|
68
|
+
Vagrant.configure("2") do |config|
|
69
|
+
config.vm.define :test_vm do |test_vm|
|
70
|
+
test_vm.vm.box = "centos64"
|
71
|
+
end
|
72
|
+
|
73
|
+
config.vm.provider :libvirt do |libvirt|
|
74
|
+
libvirt.driver = "qemu"
|
75
|
+
libvirt.host = "example.com"
|
76
|
+
libvirt.connect_via_ssh = true
|
77
|
+
libvirt.username = "root"
|
78
|
+
#libvirt.password = "secret"
|
79
|
+
libvirt.storage_pool_name = "default"
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
```
|
84
|
+
|
85
|
+
And then run `vagrant up --provider=libvirt`. Other way to tell Vagrant to
|
86
|
+
use Libvirt provider is to setup environment variable `export VAGRANT_DEFAULT_PROVIDER=libvirt`.
|
87
|
+
|
88
|
+
This will first upload box image to remote Libvirt storage pool as new volume.
|
89
|
+
Then create and start a CentOS 6.4 domain on example.com Libvirt host. In this
|
90
|
+
example configuration, connection to Libvirt is tunneled via SSH.
|
91
|
+
|
92
|
+
## Box Format
|
93
|
+
|
94
|
+
Every provider in Vagrant must introduce a custom box format. This
|
95
|
+
provider introduces `Libvirt` boxes. You can view an example box in
|
96
|
+
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.
|
97
|
+
|
98
|
+
The box format is qcow2 image file `box.img`, the required `metadata.json` file
|
99
|
+
along with a `Vagrantfile` that does default settings for the
|
100
|
+
provider-specific configuration for this provider.
|
101
|
+
|
102
|
+
## Configuration
|
103
|
+
|
104
|
+
This provider exposes quite a few provider-specific configuration options:
|
105
|
+
|
106
|
+
* `driver` - A hypervisor name to access. For now only qemu is supported.
|
107
|
+
* `host` - The name of the server, where libvirtd is running.
|
108
|
+
* `connect_via_ssh` - If use ssh tunnel to connect to Libvirt.
|
109
|
+
* `username` - Username and password to access Libvirt.
|
110
|
+
* `password` - Password to access Libvirt.
|
111
|
+
* `storage_pool_name` - Libvirt storage pool name, where box image and
|
112
|
+
instance snapshots will be stored.
|
113
|
+
|
114
|
+
## Networks
|
115
|
+
|
116
|
+
Networking features in the form of `config.vm.network` are supported only
|
117
|
+
in bridged format, no hostonly network is supported in current version of
|
118
|
+
provider.
|
119
|
+
|
120
|
+
Example of network interface definition:
|
121
|
+
|
122
|
+
```
|
123
|
+
config.vm.define :test_vm do |test_vm|
|
124
|
+
test_vm.vm.network :bridged, :bridge => "default", :adapter => 1
|
125
|
+
end
|
126
|
+
```
|
127
|
+
|
128
|
+
Bridged network adapter connected to network `default` is defined.
|
129
|
+
|
130
|
+
## Getting IP address
|
131
|
+
|
132
|
+
There is a little problem to find out which IP address was assigned to remote
|
133
|
+
domain. Fog library uses SSH connection to remote libvirt host and by default
|
134
|
+
checks arpwatch entries there.
|
135
|
+
|
136
|
+
Vagrant Libvirt provider is using dnsmasq leases files to find out, which IPs
|
137
|
+
dhcp server offered. VMs IP address is then saved to `$data_dir/ip` file for
|
138
|
+
later use. Of course, VMs IP can be changed over time. That's why IP is
|
139
|
+
checked, if matches with VMs MAC address after each reading from this state
|
140
|
+
file. Mismatch error is shown if IP doesn't match.
|
141
|
+
|
142
|
+
|
143
|
+
## Synced Folders
|
144
|
+
|
145
|
+
There is minimal support for synced folders. Upon `vagrant up`, the Libvirt
|
146
|
+
provider will use `rsync` (if available) to uni-directionally sync the folder
|
147
|
+
to the remote machine over SSH.
|
148
|
+
|
149
|
+
This is good enough for all built-in Vagrant provisioners (shell,
|
150
|
+
chef, and puppet) to work!
|
151
|
+
|
152
|
+
## Development
|
153
|
+
|
154
|
+
To work on the `vagrant-libvirt` plugin, clone this repository out, and use
|
155
|
+
[Bundler](http://gembundler.com) to get the dependencies:
|
156
|
+
|
157
|
+
```
|
158
|
+
$ bundle
|
159
|
+
```
|
160
|
+
|
161
|
+
Once you have the dependencies, verify the unit tests pass with `rake`:
|
162
|
+
|
163
|
+
```
|
164
|
+
$ bundle exec rake
|
165
|
+
```
|
166
|
+
|
167
|
+
If those pass, you're ready to start developing the plugin. You can test
|
168
|
+
the plugin without installing it into your Vagrant environment by just
|
169
|
+
creating a `Vagrantfile` in the top level of this directory (it is gitignored)
|
170
|
+
that uses it, and uses bundler to execute Vagrant:
|
171
|
+
|
172
|
+
```
|
173
|
+
$ bundle exec vagrant up --provider=libvirt
|
174
|
+
```
|
175
|
+
|
176
|
+
## Future work
|
33
177
|
|
178
|
+
Take a look on [open issues](https://github.com/pradels/vagrant-libvirt/issues?state=open).
|
data/Rakefile
CHANGED
data/example_box/README.md
CHANGED
@@ -12,3 +12,12 @@ $ tar cvzf custom_box.box ./metadata.json ./Vagrantfile ./box.img
|
|
12
12
|
This box works by using Vagrant's built-in Vagrantfile merging to setup
|
13
13
|
defaults for Libvirt. These defaults can easily be overwritten by higher-level
|
14
14
|
Vagrantfiles (such as project root Vagrantfiles).
|
15
|
+
|
16
|
+
## Box Metadata
|
17
|
+
|
18
|
+
Libvirt box should define at least three data fields in `metadata.json` file.
|
19
|
+
|
20
|
+
* provider - Provider name is libvirt.
|
21
|
+
* format - Currently supported format is qcow2.
|
22
|
+
* virtual_size - Virtual size of image in GBytes.
|
23
|
+
|
data/example_box/metadata.json
CHANGED
data/lib/vagrant-libvirt.rb
CHANGED
@@ -11,7 +11,7 @@ module VagrantPlugins
|
|
11
11
|
# Hold connection handler so there is no need to connect more times than
|
12
12
|
# one. This can be annoying when there are more machines to create, or when
|
13
13
|
# doing state action first and then some other.
|
14
|
-
#
|
14
|
+
#
|
15
15
|
# TODO Don't sure if this is the best solution
|
16
16
|
@@libvirt_connection = nil
|
17
17
|
def self.libvirt_connection
|
@@ -24,7 +24,16 @@ module VagrantPlugins
|
|
24
24
|
|
25
25
|
def self.source_root
|
26
26
|
@source_root ||= Pathname.new(File.expand_path("../../", __FILE__))
|
27
|
-
end
|
27
|
+
end
|
28
28
|
end
|
29
29
|
end
|
30
30
|
|
31
|
+
# set provider by bash env
|
32
|
+
# export VAGRANT_DEFAULT_PROVIDER=libvirt
|
33
|
+
Vagrant::Environment.class_eval do
|
34
|
+
def default_provider
|
35
|
+
(ENV['VAGRANT_DEFAULT_PROVIDER'] || :virtualbox).to_sym
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
|
@@ -12,23 +12,78 @@ module VagrantPlugins
|
|
12
12
|
b.use ConfigValidate
|
13
13
|
b.use ConnectLibvirt
|
14
14
|
b.use Call, IsCreated do |env, b2|
|
15
|
-
if
|
16
|
-
|
17
|
-
|
15
|
+
# Create VM if not yet created.
|
16
|
+
if !env[:result]
|
17
|
+
b2.use SetNameOfDomain
|
18
|
+
b2.use HandleStoragePool
|
19
|
+
b2.use HandleBoxImage
|
20
|
+
b2.use CreateDomainVolume
|
21
|
+
b2.use CreateDomain
|
22
|
+
b2.use CreateNetworkInterfaces
|
23
|
+
|
24
|
+
b2.use TimedProvision
|
25
|
+
b2.use StartDomain
|
26
|
+
b2.use WaitTillUp
|
27
|
+
b2.use SyncFolders
|
28
|
+
else
|
29
|
+
b2.use action_start
|
18
30
|
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
# Assuming VM is created, just start it. This action is not called
|
36
|
+
# directly by any subcommand. VM can be suspended, already running or in
|
37
|
+
# poweroff state.
|
38
|
+
def self.action_start
|
39
|
+
Vagrant::Action::Builder.new.tap do |b|
|
40
|
+
b.use ConfigValidate
|
41
|
+
b.use ConnectLibvirt
|
42
|
+
b.use Call, IsRunning do |env, b2|
|
43
|
+
# If the VM is running, then our work here is done, exit
|
44
|
+
next if env[:result]
|
45
|
+
|
46
|
+
b2.use Call, IsSuspended do |env2, b3|
|
47
|
+
if env2[:result]
|
48
|
+
b3.use ResumeDomain
|
49
|
+
next
|
50
|
+
end
|
19
51
|
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
52
|
+
# VM is not running or suspended. Start it.. Machine should gain
|
53
|
+
# IP address when comming up, so wait for dhcp lease and store IP
|
54
|
+
# into machines data_dir.
|
55
|
+
b3.use StartDomain
|
56
|
+
b3.use WaitTillUp
|
57
|
+
end
|
26
58
|
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
# This is the action that is primarily responsible for halting the
|
63
|
+
# virtual machine.
|
64
|
+
def self.action_halt
|
65
|
+
Vagrant::Action::Builder.new.tap do |b|
|
66
|
+
b.use ConfigValidate
|
67
|
+
b.use ConnectLibvirt
|
68
|
+
b.use Call, IsCreated do |env, b2|
|
69
|
+
if !env[:result]
|
70
|
+
b2.use MessageNotCreated
|
71
|
+
next
|
72
|
+
end
|
73
|
+
|
74
|
+
b2.use Call, IsSuspended do |env2, b3|
|
75
|
+
b3.use ResumeDomain if env2[:result]
|
76
|
+
end
|
27
77
|
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
78
|
+
b2.use Call, IsRunning do |env2, b3|
|
79
|
+
next if !env2[:result]
|
80
|
+
|
81
|
+
# VM is running, halt it.. Cleanup running instance data. Now
|
82
|
+
# only IP address is stored.
|
83
|
+
b3.use HaltDomain
|
84
|
+
b3.use CleanupDataDir
|
85
|
+
end
|
86
|
+
end
|
32
87
|
end
|
33
88
|
end
|
34
89
|
|
@@ -45,6 +100,102 @@ module VagrantPlugins
|
|
45
100
|
|
46
101
|
b2.use ConnectLibvirt
|
47
102
|
b2.use DestroyDomain
|
103
|
+
|
104
|
+
# Cleanup running instance data. Now only IP address is stored.
|
105
|
+
b2.use CleanupDataDir
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
# This action is called to SSH into the machine.
|
111
|
+
def self.action_ssh
|
112
|
+
Vagrant::Action::Builder.new.tap do |b|
|
113
|
+
b.use ConfigValidate
|
114
|
+
b.use Call, IsCreated do |env, b2|
|
115
|
+
if !env[:result]
|
116
|
+
b2.use MessageNotCreated
|
117
|
+
next
|
118
|
+
end
|
119
|
+
|
120
|
+
b2.use ConnectLibvirt
|
121
|
+
b2.use Call, IsRunning do |env2, b3|
|
122
|
+
if !env2[:result]
|
123
|
+
b3.use MessageNotRunning
|
124
|
+
next
|
125
|
+
end
|
126
|
+
|
127
|
+
b3.use SSHExec
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
# This action is called when `vagrant provision` is called.
|
134
|
+
def self.action_provision
|
135
|
+
Vagrant::Action::Builder.new.tap do |b|
|
136
|
+
b.use ConfigValidate
|
137
|
+
b.use Call, IsCreated do |env, b2|
|
138
|
+
if !env[:result]
|
139
|
+
b2.use MessageNotCreated
|
140
|
+
next
|
141
|
+
end
|
142
|
+
|
143
|
+
b2.use ConnectLibvirt
|
144
|
+
b2.use Call, IsRunning do |env2, b3|
|
145
|
+
if !env2[:result]
|
146
|
+
b3.use MessageNotRunning
|
147
|
+
next
|
148
|
+
end
|
149
|
+
|
150
|
+
b3.use Provision
|
151
|
+
b3.use SyncFolders
|
152
|
+
end
|
153
|
+
end
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
# This is the action that is primarily responsible for suspending
|
158
|
+
# the virtual machine.
|
159
|
+
def self.action_suspend
|
160
|
+
Vagrant::Action::Builder.new.tap do |b|
|
161
|
+
b.use ConfigValidate
|
162
|
+
b.use Call, IsCreated do |env, b2|
|
163
|
+
if !env[:result]
|
164
|
+
b2.use MessageNotCreated
|
165
|
+
next
|
166
|
+
end
|
167
|
+
|
168
|
+
b2.use ConnectLibvirt
|
169
|
+
b2.use Call, IsRunning do |env2, b3|
|
170
|
+
if !env2[:result]
|
171
|
+
b3.use MessageNotRunning
|
172
|
+
next
|
173
|
+
end
|
174
|
+
b3.use SuspendDomain
|
175
|
+
end
|
176
|
+
end
|
177
|
+
end
|
178
|
+
end
|
179
|
+
|
180
|
+
# This is the action that is primarily responsible for resuming
|
181
|
+
# suspended machines.
|
182
|
+
def self.action_resume
|
183
|
+
Vagrant::Action::Builder.new.tap do |b|
|
184
|
+
b.use ConfigValidate
|
185
|
+
b.use Call, IsCreated do |env, b2|
|
186
|
+
if !env[:result]
|
187
|
+
b2.use MessageNotCreated
|
188
|
+
next
|
189
|
+
end
|
190
|
+
|
191
|
+
b2.use ConnectLibvirt
|
192
|
+
b2.use Call, IsSuspended do |env2, b3|
|
193
|
+
if !env2[:result]
|
194
|
+
b3.use MessageNotSuspended
|
195
|
+
next
|
196
|
+
end
|
197
|
+
b3.use ResumeDomain
|
198
|
+
end
|
48
199
|
end
|
49
200
|
end
|
50
201
|
end
|
@@ -73,8 +224,12 @@ module VagrantPlugins
|
|
73
224
|
action_root = Pathname.new(File.expand_path("../action", __FILE__))
|
74
225
|
autoload :ConnectLibvirt, action_root.join("connect_libvirt")
|
75
226
|
autoload :IsCreated, action_root.join("is_created")
|
227
|
+
autoload :IsRunning, action_root.join("is_running")
|
228
|
+
autoload :IsSuspended, action_root.join("is_suspended")
|
76
229
|
autoload :MessageAlreadyCreated, action_root.join("message_already_created")
|
77
230
|
autoload :MessageNotCreated, action_root.join("message_not_created")
|
231
|
+
autoload :MessageNotRunning, action_root.join("message_not_running")
|
232
|
+
autoload :MessageNotSuspended, action_root.join("message_not_suspended")
|
78
233
|
autoload :HandleStoragePool, action_root.join("handle_storage_pool")
|
79
234
|
autoload :HandleBoxImage, action_root.join("handle_box_image")
|
80
235
|
autoload :SetNameOfDomain, action_root.join("set_name_of_domain")
|
@@ -83,6 +238,10 @@ module VagrantPlugins
|
|
83
238
|
autoload :CreateNetworkInterfaces, action_root.join("create_network_interfaces")
|
84
239
|
autoload :DestroyDomain, action_root.join("destroy_domain")
|
85
240
|
autoload :StartDomain, action_root.join("start_domain")
|
241
|
+
autoload :HaltDomain, action_root.join("halt_domain")
|
242
|
+
autoload :SuspendDomain, action_root.join("suspend_domain")
|
243
|
+
autoload :ResumeDomain, action_root.join("resume_domain")
|
244
|
+
autoload :CleanupDataDir, action_root.join("cleanup_data_dir")
|
86
245
|
autoload :ReadState, action_root.join("read_state")
|
87
246
|
autoload :ReadSSHInfo, action_root.join("read_ssh_info")
|
88
247
|
autoload :TimedProvision, action_root.join("timed_provision")
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'log4r'
|
2
|
+
|
3
|
+
module VagrantPlugins
|
4
|
+
module Libvirt
|
5
|
+
module Action
|
6
|
+
class CleanupDataDir
|
7
|
+
def initialize(app, env)
|
8
|
+
@logger = Log4r::Logger.new("vagrant_libvirt::action::cleanup_data_dir")
|
9
|
+
@app = app
|
10
|
+
end
|
11
|
+
|
12
|
+
def call(env)
|
13
|
+
# Remove file holding IP address
|
14
|
+
ip_file_path = env[:machine].data_dir + 'ip'
|
15
|
+
File.delete(ip_file_path) if File.exists?(ip_file_path)
|
16
|
+
|
17
|
+
@app.call(env)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -48,11 +48,9 @@ module VagrantPlugins
|
|
48
48
|
conn_attr[:libvirt_password] = config.password if config.password
|
49
49
|
|
50
50
|
# Setup command for retrieving IP address for newly created machine
|
51
|
-
# with some MAC address. Get it
|
52
|
-
|
53
|
-
conn_attr[:libvirt_ip_command]
|
54
|
-
conn_attr[:libvirt_ip_command] << 's/.*(\([0-9\.]*\)).*/\1/'
|
55
|
-
conn_attr[:libvirt_ip_command] << "'"
|
51
|
+
# with some MAC address. Get it from dnsmasq leases table.
|
52
|
+
conn_attr[:libvirt_ip_command] = "cat /var/lib/libvirt/dnsmasq/*.leases"
|
53
|
+
conn_attr[:libvirt_ip_command] << " | grep $mac | awk ' { print $3 }'"
|
56
54
|
|
57
55
|
@logger.info("Connecting to Libvirt (#{uri}) ...")
|
58
56
|
begin
|
@@ -14,11 +14,11 @@ module VagrantPlugins
|
|
14
14
|
|
15
15
|
def call(env)
|
16
16
|
# Gather some info about domain
|
17
|
-
# TODO from Vagrantfile
|
18
17
|
@name = env[:domain_name]
|
18
|
+
|
19
19
|
@cpus = 1
|
20
20
|
@memory_size = 512*1024
|
21
|
-
|
21
|
+
|
22
22
|
# TODO get type from driver config option
|
23
23
|
@domain_type = 'kvm'
|
24
24
|
|
@@ -37,6 +37,7 @@ module VagrantPlugins
|
|
37
37
|
env[:ui].info(" -- Cpus: #{@cpus}")
|
38
38
|
env[:ui].info(" -- Memory: #{@memory_size/1024}M")
|
39
39
|
env[:ui].info(" -- Base box: #{env[:machine].box.name}")
|
40
|
+
env[:ui].info(" -- Storage pool: #{env[:machine].provider_config.storage_pool_name}")
|
40
41
|
env[:ui].info(" -- Image: #{@domain_volume_path}")
|
41
42
|
|
42
43
|
# Create libvirt domain.
|
@@ -4,15 +4,13 @@ module VagrantPlugins
|
|
4
4
|
module Libvirt
|
5
5
|
module Action
|
6
6
|
class DestroyDomain
|
7
|
-
|
8
7
|
def initialize(app, env)
|
9
8
|
@logger = Log4r::Logger.new("vagrant_libvirt::action::destroy_domain")
|
10
9
|
@app = app
|
11
10
|
end
|
12
11
|
|
13
12
|
def call(env)
|
14
|
-
|
15
|
-
# Destroy the server and remove the tracking ID
|
13
|
+
# Destroy the server, remove the tracking ID
|
16
14
|
env[:ui].info(I18n.t("vagrant_libvirt.destroy_domain"))
|
17
15
|
|
18
16
|
domain = env[:libvirt_compute].servers.get(env[:machine].id.to_s)
|
@@ -21,7 +19,6 @@ module VagrantPlugins
|
|
21
19
|
|
22
20
|
@app.call(env)
|
23
21
|
end
|
24
|
-
|
25
22
|
end
|
26
23
|
end
|
27
24
|
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require 'log4r'
|
2
|
+
|
3
|
+
module VagrantPlugins
|
4
|
+
module Libvirt
|
5
|
+
module Action
|
6
|
+
# Halt the domain.
|
7
|
+
class HaltDomain
|
8
|
+
def initialize(app, env)
|
9
|
+
@logger = Log4r::Logger.new("vagrant_libvirt::action::halt_domain")
|
10
|
+
@app = app
|
11
|
+
end
|
12
|
+
|
13
|
+
def call(env)
|
14
|
+
env[:ui].info(I18n.t("vagrant_libvirt.halt_domain"))
|
15
|
+
|
16
|
+
domain = env[:libvirt_compute].servers.get(env[:machine].id.to_s)
|
17
|
+
raise Errors::NoDomainError if domain == nil
|
18
|
+
|
19
|
+
@logger.info("Trying gracefull shutdown.")
|
20
|
+
domain.shutdown
|
21
|
+
begin
|
22
|
+
domain.wait_for(30) {
|
23
|
+
!ready?
|
24
|
+
}
|
25
|
+
rescue Fog::Errors::TimeoutError
|
26
|
+
@logger.info("VM is still running. Calling force poweroff.")
|
27
|
+
domain.poweroff
|
28
|
+
end
|
29
|
+
|
30
|
+
@app.call(env)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
@@ -12,7 +12,7 @@ module VagrantPlugins
|
|
12
12
|
def call(env)
|
13
13
|
|
14
14
|
# Verify box metadata for mandatory values.
|
15
|
-
#
|
15
|
+
#
|
16
16
|
# Virtual size has to be set for allocating space in storage pool.
|
17
17
|
box_virtual_size = env[:machine].box.metadata['virtual_size']
|
18
18
|
if box_virtual_size == nil
|
@@ -103,7 +103,7 @@ module VagrantPlugins
|
|
103
103
|
sent = stream.send buff
|
104
104
|
progress += sent
|
105
105
|
yield progress
|
106
|
-
end
|
106
|
+
end
|
107
107
|
end
|
108
108
|
rescue => e
|
109
109
|
raise Errors::ImageUploadError,
|
@@ -0,0 +1,21 @@
|
|
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 running and branch in the middleware.
|
6
|
+
class IsRunning
|
7
|
+
def initialize(app, env)
|
8
|
+
@app = app
|
9
|
+
end
|
10
|
+
|
11
|
+
def call(env)
|
12
|
+
domain = env[:libvirt_compute].servers.get(env[:machine].id.to_s)
|
13
|
+
raise Errors::NoDomainError if domain == nil
|
14
|
+
env[:result] = domain.state.to_s == 'running'
|
15
|
+
|
16
|
+
@app.call(env)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,21 @@
|
|
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 suspended and branch in the middleware.
|
6
|
+
class IsSuspended
|
7
|
+
def initialize(app, env)
|
8
|
+
@app = app
|
9
|
+
end
|
10
|
+
|
11
|
+
def call(env)
|
12
|
+
domain = env[:libvirt_compute].servers.get(env[:machine].id.to_s)
|
13
|
+
raise Errors::NoDomainError if domain == nil
|
14
|
+
env[:result] = domain.state.to_s == 'paused'
|
15
|
+
|
16
|
+
@app.call(env)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module VagrantPlugins
|
2
|
+
module Libvirt
|
3
|
+
module Action
|
4
|
+
class MessageNotRunning
|
5
|
+
def initialize(app, env)
|
6
|
+
@app = app
|
7
|
+
end
|
8
|
+
|
9
|
+
def call(env)
|
10
|
+
env[:ui].info(I18n.t("vagrant_libvirt.not_running"))
|
11
|
+
@app.call(env)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module VagrantPlugins
|
2
|
+
module Libvirt
|
3
|
+
module Action
|
4
|
+
class MessageNotSuspended
|
5
|
+
def initialize(app, env)
|
6
|
+
@app = app
|
7
|
+
end
|
8
|
+
|
9
|
+
def call(env)
|
10
|
+
env[:ui].info(I18n.t("vagrant_libvirt.not_suspended"))
|
11
|
+
@app.call(env)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -18,23 +18,58 @@ module VagrantPlugins
|
|
18
18
|
@app.call(env)
|
19
19
|
end
|
20
20
|
|
21
|
-
|
22
|
-
def read_ssh_info(libvirt, machine)
|
21
|
+
def read_ssh_info(libvirt,machine)
|
23
22
|
return nil if machine.id.nil?
|
24
23
|
|
25
24
|
# Find the machine
|
26
|
-
|
27
|
-
if
|
25
|
+
domain = libvirt.servers.get(machine.id)
|
26
|
+
if domain.nil?
|
28
27
|
# The machine can't be found
|
29
28
|
@logger.info("Machine couldn't be found, assuming it got destroyed.")
|
30
29
|
machine.id = nil
|
31
30
|
return nil
|
32
31
|
end
|
33
32
|
|
34
|
-
#
|
35
|
-
|
36
|
-
|
37
|
-
|
33
|
+
# IP address of machine is stored in $data_dir/ip file. Why? Commands
|
34
|
+
# like ssh or provision need to get IP of VM long time after it was
|
35
|
+
# started and gathered IP. Record in arp table is lost, and this is
|
36
|
+
# the way how to store this info. Not an ideal solution, but libvirt
|
37
|
+
# doesn't provide way how to get IP of some domain.
|
38
|
+
ip_file = machine.data_dir + 'ip'
|
39
|
+
raise Errors::NoIpAddressError if not File.exists?(ip_file)
|
40
|
+
ip_address = File.open(ip_file, 'r') do |file|
|
41
|
+
file.read
|
42
|
+
end
|
43
|
+
|
44
|
+
# Check if stored IP address matches with MAC address of machine.
|
45
|
+
# Command is executed either localy, or on remote libvirt hypervisor,
|
46
|
+
# depends on establised fog libvirt connection.
|
47
|
+
ip_match = false
|
48
|
+
ip_command = "ping -c1 #{ip_address} > /dev/null && "
|
49
|
+
ip_command << "arp -an | grep $mac | sed '"
|
50
|
+
ip_command << 's/.*(\([0-9\.]*\)).*/\1/' + "'"
|
51
|
+
options_hash = { :ip_command => ip_command }
|
52
|
+
3.times do |x|
|
53
|
+
break if ip_match
|
54
|
+
domain.wait_for(1) {
|
55
|
+
begin
|
56
|
+
addresses(service, options_hash).each_pair do |type, ip|
|
57
|
+
if ip[0] != nil
|
58
|
+
ip_match = true
|
59
|
+
break
|
60
|
+
end
|
61
|
+
end
|
62
|
+
rescue Fog::Errors::Error
|
63
|
+
# Sometimes, if pinging happen too quickly after after IP
|
64
|
+
# assignment, machine is not responding yet. Give it a little
|
65
|
+
# time..
|
66
|
+
sleep 1
|
67
|
+
end
|
68
|
+
|
69
|
+
break if ip_match
|
70
|
+
}
|
71
|
+
end
|
72
|
+
raise Errors::IpAddressMismatchError if not ip_match
|
38
73
|
|
39
74
|
# Return the info
|
40
75
|
# TODO: Some info should be configurable in Vagrantfile
|
@@ -43,8 +78,7 @@ module VagrantPlugins
|
|
43
78
|
:port => 22,
|
44
79
|
:username => 'root',
|
45
80
|
}
|
46
|
-
end
|
47
|
-
|
81
|
+
end
|
48
82
|
end
|
49
83
|
end
|
50
84
|
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'log4r'
|
2
|
+
|
3
|
+
module VagrantPlugins
|
4
|
+
module Libvirt
|
5
|
+
module Action
|
6
|
+
# Resume suspended domain.
|
7
|
+
class ResumeDomain
|
8
|
+
def initialize(app, env)
|
9
|
+
@logger = Log4r::Logger.new("vagrant_libvirt::action::resume_domain")
|
10
|
+
@app = app
|
11
|
+
end
|
12
|
+
|
13
|
+
def call(env)
|
14
|
+
env[:ui].info(I18n.t("vagrant_libvirt.resuming_domain"))
|
15
|
+
|
16
|
+
domain = env[:libvirt_compute].servers.get(env[:machine].id.to_s)
|
17
|
+
raise Errors::NoDomainError if domain == nil
|
18
|
+
|
19
|
+
domain.resume
|
20
|
+
@logger.info("Machine #{env[:machine].id} is resumed.")
|
21
|
+
|
22
|
+
@app.call(env)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'log4r'
|
2
|
+
|
3
|
+
module VagrantPlugins
|
4
|
+
module Libvirt
|
5
|
+
module Action
|
6
|
+
# Suspend domain.
|
7
|
+
class SuspendDomain
|
8
|
+
def initialize(app, env)
|
9
|
+
@logger = Log4r::Logger.new("vagrant_libvirt::action::suspend_domain")
|
10
|
+
@app = app
|
11
|
+
end
|
12
|
+
|
13
|
+
# make pause
|
14
|
+
def call(env)
|
15
|
+
env[:ui].info(I18n.t("vagrant_libvirt.suspending_domain"))
|
16
|
+
|
17
|
+
domain = env[:libvirt_compute].servers.get(env[:machine].id.to_s)
|
18
|
+
raise Errors::NoDomainError if domain == nil
|
19
|
+
|
20
|
+
domain.suspend
|
21
|
+
@logger.info("Machine #{env[:machine].id} is suspended ")
|
22
|
+
|
23
|
+
@app.call(env)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -47,6 +47,13 @@ module VagrantPlugins
|
|
47
47
|
@logger.info("Got IP address #{env[:ip_address]}")
|
48
48
|
@logger.info("Time for getting IP: #{env[:metrics]["instance_ip_time"]}")
|
49
49
|
|
50
|
+
# Save newly assigned IP address to machines data_dir
|
51
|
+
ip_file_path = env[:machine].data_dir + 'ip'
|
52
|
+
@logger.info("Saving IP address to #{ip_file_path} file.")
|
53
|
+
File.open(ip_file_path, 'w') do |file|
|
54
|
+
file.write(env[:ip_address])
|
55
|
+
end
|
56
|
+
|
50
57
|
# Machine has ip address assigned, now wait till we are able to
|
51
58
|
# connect via ssh.
|
52
59
|
env[:metrics]["instance_ssh_time"] = Util::Timer.time do
|
@@ -85,6 +85,15 @@ module VagrantPlugins
|
|
85
85
|
class AttachDeviceError < VagrantLibvirtError
|
86
86
|
error_key(:attach_device_error)
|
87
87
|
end
|
88
|
+
|
89
|
+
class NoIpAddressError < VagrantLibvirtError
|
90
|
+
error_key(:no_ip_address_error)
|
91
|
+
end
|
92
|
+
|
93
|
+
class IpAddressMismatchError < VagrantLibvirtError
|
94
|
+
error_key(:ip_address_mismatch_error)
|
95
|
+
end
|
96
|
+
|
88
97
|
end
|
89
98
|
end
|
90
99
|
end
|
data/locales/en.yml
CHANGED
@@ -1,13 +1,17 @@
|
|
1
1
|
en:
|
2
2
|
vagrant_libvirt:
|
3
3
|
already_created: |-
|
4
|
-
The
|
4
|
+
The domain is already created.
|
5
5
|
not_created: |-
|
6
|
-
|
6
|
+
Domain is not created. Please run `vagrant up` first.
|
7
|
+
not_running: |-
|
8
|
+
Domain is not running. Please run `vagrant up` or `vagrant resume` first.
|
9
|
+
not_suspended: |-
|
10
|
+
Domain is not suspended.
|
7
11
|
finding_volume: |-
|
8
12
|
Checking if volume is available.
|
9
13
|
creating_domain: |-
|
10
|
-
Creating
|
14
|
+
Creating domain with the following settings...
|
11
15
|
uploading_volume: |-
|
12
16
|
Uploading base box image as volume into libvirt storage...
|
13
17
|
creating_domain_volume: |-
|
@@ -15,17 +19,23 @@ en:
|
|
15
19
|
removing_domain_volume: |-
|
16
20
|
Removing image (snapshot of base box volume).
|
17
21
|
starting_domain: |-
|
18
|
-
Starting
|
22
|
+
Starting domain.
|
19
23
|
terminating: |-
|
20
|
-
Removing
|
24
|
+
Removing domain...
|
21
25
|
poweroff_domain: |-
|
22
|
-
Poweroff
|
26
|
+
Poweroff domain.
|
23
27
|
destroy_domain: |-
|
24
|
-
Removing
|
28
|
+
Removing domain...
|
29
|
+
halt_domain: |-
|
30
|
+
Halting domain...
|
31
|
+
resuming_domain: |-
|
32
|
+
Resuming domain...
|
33
|
+
suspending_domain: |-
|
34
|
+
Suspending domain...
|
25
35
|
waiting_for_ready: |-
|
26
|
-
Waiting for
|
36
|
+
Waiting for domain to become "ready"...
|
27
37
|
waiting_for_ip: |-
|
28
|
-
Waiting for
|
38
|
+
Waiting for domain to get an IP address...
|
29
39
|
waiting_for_ssh: |-
|
30
40
|
Waiting for SSH to become available...
|
31
41
|
booted: |-
|
@@ -89,8 +99,18 @@ en:
|
|
89
99
|
No domain found. %{error_message}
|
90
100
|
attach_device_error: |-
|
91
101
|
Error while attaching new device to domain. %{error_message}
|
102
|
+
no_ip_address_error: |-
|
103
|
+
No IP address found.
|
104
|
+
ip_address_mismatch_error: |-
|
105
|
+
IP address mismatch. Possible reason is that domain IP address changed.
|
106
|
+
You can run `vagrant destroy` and then `vagrant up` to rebuild your
|
107
|
+
project.
|
92
108
|
|
93
109
|
states:
|
110
|
+
short_paused: |-
|
111
|
+
pause
|
112
|
+
short_shutoff: |-
|
113
|
+
shutoff
|
94
114
|
short_not_created: |-
|
95
115
|
not created
|
96
116
|
long_not_created: |-
|
metadata
CHANGED
@@ -1,18 +1,20 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: vagrant-libvirt
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.2
|
5
|
+
prerelease:
|
5
6
|
platform: ruby
|
6
7
|
authors:
|
7
8
|
- Lukas Stanek
|
8
9
|
autorequire:
|
9
10
|
bindir: bin
|
10
11
|
cert_chain: []
|
11
|
-
date: 2013-
|
12
|
+
date: 2013-04-02 00:00:00.000000000 Z
|
12
13
|
dependencies:
|
13
14
|
- !ruby/object:Gem::Dependency
|
14
15
|
name: fog
|
15
16
|
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
16
18
|
requirements:
|
17
19
|
- - ~>
|
18
20
|
- !ruby/object:Gem::Version
|
@@ -20,6 +22,7 @@ dependencies:
|
|
20
22
|
type: :runtime
|
21
23
|
prerelease: false
|
22
24
|
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
23
26
|
requirements:
|
24
27
|
- - ~>
|
25
28
|
- !ruby/object:Gem::Version
|
@@ -27,6 +30,7 @@ dependencies:
|
|
27
30
|
- !ruby/object:Gem::Dependency
|
28
31
|
name: ruby-libvirt
|
29
32
|
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
30
34
|
requirements:
|
31
35
|
- - ~>
|
32
36
|
- !ruby/object:Gem::Version
|
@@ -34,6 +38,7 @@ dependencies:
|
|
34
38
|
type: :runtime
|
35
39
|
prerelease: false
|
36
40
|
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
37
42
|
requirements:
|
38
43
|
- - ~>
|
39
44
|
- !ruby/object:Gem::Version
|
@@ -41,6 +46,7 @@ dependencies:
|
|
41
46
|
- !ruby/object:Gem::Dependency
|
42
47
|
name: rake
|
43
48
|
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
44
50
|
requirements:
|
45
51
|
- - ! '>='
|
46
52
|
- !ruby/object:Gem::Version
|
@@ -48,6 +54,7 @@ dependencies:
|
|
48
54
|
type: :development
|
49
55
|
prerelease: false
|
50
56
|
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
51
58
|
requirements:
|
52
59
|
- - ! '>='
|
53
60
|
- !ruby/object:Gem::Version
|
@@ -69,20 +76,28 @@ files:
|
|
69
76
|
- example_box/metadata.json
|
70
77
|
- lib/vagrant-libvirt.rb
|
71
78
|
- lib/vagrant-libvirt/action.rb
|
79
|
+
- lib/vagrant-libvirt/action/cleanup_data_dir.rb
|
72
80
|
- lib/vagrant-libvirt/action/connect_libvirt.rb
|
73
81
|
- lib/vagrant-libvirt/action/create_domain.rb
|
74
82
|
- lib/vagrant-libvirt/action/create_domain_volume.rb
|
75
83
|
- lib/vagrant-libvirt/action/create_network_interfaces.rb
|
76
84
|
- lib/vagrant-libvirt/action/destroy_domain.rb
|
85
|
+
- lib/vagrant-libvirt/action/halt_domain.rb
|
77
86
|
- lib/vagrant-libvirt/action/handle_box_image.rb
|
78
87
|
- lib/vagrant-libvirt/action/handle_storage_pool.rb
|
79
88
|
- lib/vagrant-libvirt/action/is_created.rb
|
89
|
+
- lib/vagrant-libvirt/action/is_running.rb
|
90
|
+
- lib/vagrant-libvirt/action/is_suspended.rb
|
80
91
|
- lib/vagrant-libvirt/action/message_already_created.rb
|
81
92
|
- lib/vagrant-libvirt/action/message_not_created.rb
|
93
|
+
- lib/vagrant-libvirt/action/message_not_running.rb
|
94
|
+
- lib/vagrant-libvirt/action/message_not_suspended.rb
|
82
95
|
- lib/vagrant-libvirt/action/read_ssh_info.rb
|
83
96
|
- lib/vagrant-libvirt/action/read_state.rb
|
97
|
+
- lib/vagrant-libvirt/action/resume_domain.rb
|
84
98
|
- lib/vagrant-libvirt/action/set_name_of_domain.rb
|
85
99
|
- lib/vagrant-libvirt/action/start_domain.rb
|
100
|
+
- lib/vagrant-libvirt/action/suspend_domain.rb
|
86
101
|
- lib/vagrant-libvirt/action/sync_folders.rb
|
87
102
|
- lib/vagrant-libvirt/action/timed_provision.rb
|
88
103
|
- lib/vagrant-libvirt/action/wait_till_up.rb
|
@@ -103,25 +118,26 @@ files:
|
|
103
118
|
- vagrant-libvirt.gemspec
|
104
119
|
homepage: http://www.vagrantup.com
|
105
120
|
licenses: []
|
106
|
-
metadata: {}
|
107
121
|
post_install_message:
|
108
122
|
rdoc_options: []
|
109
123
|
require_paths:
|
110
124
|
- lib
|
111
125
|
required_ruby_version: !ruby/object:Gem::Requirement
|
126
|
+
none: false
|
112
127
|
requirements:
|
113
128
|
- - ! '>='
|
114
129
|
- !ruby/object:Gem::Version
|
115
130
|
version: '0'
|
116
131
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
132
|
+
none: false
|
117
133
|
requirements:
|
118
134
|
- - ! '>='
|
119
135
|
- !ruby/object:Gem::Version
|
120
136
|
version: '0'
|
121
137
|
requirements: []
|
122
138
|
rubyforge_project:
|
123
|
-
rubygems_version:
|
139
|
+
rubygems_version: 1.8.25
|
124
140
|
signing_key:
|
125
|
-
specification_version:
|
141
|
+
specification_version: 3
|
126
142
|
summary: Vagrant provider for libvirt.
|
127
143
|
test_files: []
|
checksums.yaml
DELETED
@@ -1,7 +0,0 @@
|
|
1
|
-
---
|
2
|
-
SHA1:
|
3
|
-
metadata.gz: 857a7572e2968583b54a002899aeb4ed206ce1a9
|
4
|
-
data.tar.gz: b2272a7a10779ccbaef6f5c8aa1eda3d7cc77d9f
|
5
|
-
SHA512:
|
6
|
-
metadata.gz: 1eb41e05a79497bd68f8b8616d75b61ed8a4e7d4a9787ea90ec5ef0a061847f8ca12e2b6f80e3d95b941a6483cd2ef21df48ffd020cdda1949e4ea5d30784c2e
|
7
|
-
data.tar.gz: cb6363c8c70efaac9b3ed73cdace2ef42c658b946571a5d5bc8693144273af6612b0afdcc79ca8de69b685380fc33c7b009ca46bcae8b1de0cf9d5ce37125e91
|