vagrant-lxd 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +3 -0
- data/Gemfile +11 -0
- data/Gemfile.lock +148 -0
- data/LICENSE.md +675 -0
- data/README.md +121 -0
- data/Rakefile +12 -0
- data/lib/vagrant-lxd.rb +23 -0
- data/lib/vagrant-lxd/action.rb +314 -0
- data/lib/vagrant-lxd/capability.rb +27 -0
- data/lib/vagrant-lxd/command.rb +145 -0
- data/lib/vagrant-lxd/config.rb +92 -0
- data/lib/vagrant-lxd/driver.rb +418 -0
- data/lib/vagrant-lxd/plugin.rb +52 -0
- data/lib/vagrant-lxd/provider.rb +49 -0
- data/lib/vagrant-lxd/synced_folder.rb +76 -0
- data/lib/vagrant-lxd/version.rb +26 -0
- data/templates/locales/en.yml +110 -0
- data/vagrant-lxd.gemspec +39 -0
- metadata +76 -0
data/README.md
ADDED
@@ -0,0 +1,121 @@
|
|
1
|
+
# vagrant-lxd
|
2
|
+
|
3
|
+
This is a [Vagrant][] plugin that adds the ability to manage containers
|
4
|
+
with [LXD][].
|
5
|
+
|
6
|
+
[Vagrant]: https://www.vagrantup.com/
|
7
|
+
[LXD]: https://linuxcontainers.org/lxd/
|
8
|
+
|
9
|
+
## Features
|
10
|
+
|
11
|
+
The following features are currently supported:
|
12
|
+
|
13
|
+
- VM management (create, suspend, destroy, etc.)
|
14
|
+
- IPv4 networking
|
15
|
+
- Synced folders
|
16
|
+
- Snapshots
|
17
|
+
|
18
|
+
The following features are not expected to work yet:
|
19
|
+
|
20
|
+
- Forwarded ports
|
21
|
+
- Static IP addresses
|
22
|
+
- IPv6 networking
|
23
|
+
|
24
|
+
The plugin requires LXD 2.0 and Vagrant 1.8.7 or newer.
|
25
|
+
|
26
|
+
## Installation
|
27
|
+
|
28
|
+
Installing the plugin from this repository is a three-step process.
|
29
|
+
|
30
|
+
1. Use Bundler to install development dependencies:
|
31
|
+
|
32
|
+
$ bundle install
|
33
|
+
|
34
|
+
2. Build the gem:
|
35
|
+
|
36
|
+
$ bundle exec rake build
|
37
|
+
|
38
|
+
3. Install it as a Vagrant plugin:
|
39
|
+
|
40
|
+
$ vagrant plugin install pkg/vagrant-lxd-<version>.gem
|
41
|
+
|
42
|
+
## Usage
|
43
|
+
|
44
|
+
### Quick Start
|
45
|
+
|
46
|
+
This plugin reuses the `lxc` box format, so VM images from [Vagrant
|
47
|
+
Cloud][cloud] should work without modification:
|
48
|
+
|
49
|
+
$ vagrant init --minimal debian/stretch64
|
50
|
+
$ vagrant up --provider lxd
|
51
|
+
|
52
|
+
[cloud]: https://app.vagrantup.com/boxes/search?provider=lxc
|
53
|
+
|
54
|
+
#### Configuration
|
55
|
+
|
56
|
+
Below is an example Vagrantfile showing all of the provider's
|
57
|
+
configurable values, along with their defaults. The `debian/stretch64`
|
58
|
+
box is available on the Vagrant Cloud, so you should be able to copy
|
59
|
+
this file and adjust it as you see fit.
|
60
|
+
|
61
|
+
``` ruby
|
62
|
+
Vagrant.configure('2') do |config|
|
63
|
+
config.vm.box = 'debian/stretch64'
|
64
|
+
|
65
|
+
config.vm.provider 'lxd' do |lxd|
|
66
|
+
lxd.api_endpoint = 'https://127.0.0.1:8443'
|
67
|
+
lxd.timeout = 10
|
68
|
+
lxd.name = nil
|
69
|
+
lxd.ephemeral = false
|
70
|
+
end
|
71
|
+
end
|
72
|
+
```
|
73
|
+
|
74
|
+
### Shared Folders
|
75
|
+
|
76
|
+
In order to use shared folders, you must first add your user ID to the
|
77
|
+
host machine's subuid(5) and subgid(5) files:
|
78
|
+
|
79
|
+
$ echo root:$(id -u):1 | sudo tee -a /etc/subuid
|
80
|
+
$ echo root:$(id -g):1 | sudo tee -a /etc/subgid
|
81
|
+
|
82
|
+
For more information about these commands, and user/group ID mapping in
|
83
|
+
general, we recommend [this article][1].
|
84
|
+
|
85
|
+
[1]: https://insights.ubuntu.com/2017/06/15/custom-user-mappings-in-lxd-containers/
|
86
|
+
|
87
|
+
### Shared LXD Containers
|
88
|
+
|
89
|
+
It's possible to share a single LXD container between multiple Vagrant
|
90
|
+
VMs by "attaching" them to the container by name.
|
91
|
+
|
92
|
+
For example, to associate the "default" VM with a preexisting LXD
|
93
|
+
container called "my-container", use the `vagrant lxd attach` command:
|
94
|
+
|
95
|
+
$ lxc list -cn # list available containers
|
96
|
+
+--------------+
|
97
|
+
| NAME |
|
98
|
+
+--------------+
|
99
|
+
| my-container |
|
100
|
+
+--------------+
|
101
|
+
|
102
|
+
$ vagrant lxd detach default # detach from current container, if necessary
|
103
|
+
==> default: Machine is not attached to a container, skipping...
|
104
|
+
|
105
|
+
$ vagrant lxd attach default my-container
|
106
|
+
==> default: Attaching to container 'my-container'...
|
107
|
+
|
108
|
+
## Hacking
|
109
|
+
|
110
|
+
To run Vagrant with the plugin automatically loaded, you can use the
|
111
|
+
`bundle exec` command:
|
112
|
+
|
113
|
+
$ bundle exec vagrant <command>
|
114
|
+
|
115
|
+
## Contributing
|
116
|
+
|
117
|
+
1. Fork it from <https://gitlab.com/catalyst-it/vagrant-lxd>
|
118
|
+
2. Create a feature branch (`git checkout -b my-new-feature`)
|
119
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
120
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
121
|
+
5. Create a Merge Request at <https://gitlab.com/catalyst-it/vagrant-lxd/merge_requests>
|
data/Rakefile
ADDED
data/lib/vagrant-lxd.rb
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
#
|
2
|
+
# Copyright (c) 2017 Catalyst.net Ltd
|
3
|
+
#
|
4
|
+
# This file is part of vagrant-lxd.
|
5
|
+
#
|
6
|
+
# vagrant-lxd is free software: you can redistribute it and/or modify
|
7
|
+
# it under the terms of the GNU General Public License as published by
|
8
|
+
# the Free Software Foundation, either version 3 of the License, or (at
|
9
|
+
# your option) any later version.
|
10
|
+
#
|
11
|
+
# vagrant-lxd is distributed in the hope that it will be useful, but
|
12
|
+
# WITHOUT ANY WARRANTY; without even the implied warranty of
|
13
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
14
|
+
# General Public License for more details.
|
15
|
+
#
|
16
|
+
# You should have received a copy of the GNU General Public License
|
17
|
+
# along with vagrant-lxd. If not, see <http://www.gnu.org/licenses/>.
|
18
|
+
#
|
19
|
+
|
20
|
+
require 'i18n'
|
21
|
+
require 'vagrant-lxd/plugin'
|
22
|
+
|
23
|
+
I18n.load_path << File.expand_path('../../templates/locales/en.yml', __FILE__)
|
@@ -0,0 +1,314 @@
|
|
1
|
+
#
|
2
|
+
# Copyright (c) 2017 Catalyst.net Ltd
|
3
|
+
#
|
4
|
+
# This file is part of vagrant-lxd.
|
5
|
+
#
|
6
|
+
# vagrant-lxd is free software: you can redistribute it and/or modify
|
7
|
+
# it under the terms of the GNU General Public License as published by
|
8
|
+
# the Free Software Foundation, either version 3 of the License, or (at
|
9
|
+
# your option) any later version.
|
10
|
+
#
|
11
|
+
# vagrant-lxd is distributed in the hope that it will be useful, but
|
12
|
+
# WITHOUT ANY WARRANTY; without even the implied warranty of
|
13
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
14
|
+
# General Public License for more details.
|
15
|
+
#
|
16
|
+
# You should have received a copy of the GNU General Public License
|
17
|
+
# along with vagrant-lxd. If not, see <http://www.gnu.org/licenses/>.
|
18
|
+
#
|
19
|
+
|
20
|
+
require 'vagrant/action/builder'
|
21
|
+
require 'vagrant/machine_state'
|
22
|
+
require 'vagrant-lxd/driver'
|
23
|
+
|
24
|
+
module VagrantLXD
|
25
|
+
module Action
|
26
|
+
|
27
|
+
#
|
28
|
+
# The LXD class is middleware that simply forwards its call to the
|
29
|
+
# corresponding method on the LXD driver and copies the result into
|
30
|
+
# the env hash under the key `:machine_<method>`.
|
31
|
+
#
|
32
|
+
# The method to be called is controlled by the proxy object's class
|
33
|
+
# name. The correct instance to use for a particular method call is
|
34
|
+
# retrieved with `LXD.action`.
|
35
|
+
#
|
36
|
+
class LXD
|
37
|
+
def initialize(app, env, *args)
|
38
|
+
@app = app
|
39
|
+
@args = args
|
40
|
+
@driver = Driver.new(env[:machine])
|
41
|
+
end
|
42
|
+
|
43
|
+
def call(env)
|
44
|
+
env[:"machine_#{method}"] = @driver.send(method, *@args)
|
45
|
+
@app.call(env)
|
46
|
+
end
|
47
|
+
|
48
|
+
private
|
49
|
+
|
50
|
+
def method
|
51
|
+
self.class.to_s.split('::').last.downcase
|
52
|
+
end
|
53
|
+
|
54
|
+
def LXD.action(name)
|
55
|
+
const = name.to_s.sub(/[a-z]/, &:upcase)
|
56
|
+
const_get(const)
|
57
|
+
rescue NameError
|
58
|
+
Class.new(LXD).tap do |proxy|
|
59
|
+
const_set(const, proxy)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
#
|
65
|
+
# Message issues a message to the user through the `env[:ui]` object
|
66
|
+
# provided to this middleware. The level is controlled via `type`,
|
67
|
+
# which should be a method on `env[:ui]`.
|
68
|
+
#
|
69
|
+
class Message
|
70
|
+
def initialize(app, env, type, message)
|
71
|
+
@app = app
|
72
|
+
@type = type
|
73
|
+
@message = message
|
74
|
+
end
|
75
|
+
|
76
|
+
def call(env)
|
77
|
+
env[:ui].send(@type, @message)
|
78
|
+
@app.call(env)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
#
|
83
|
+
# Check whether the LXD driver is usable and immediately signal an
|
84
|
+
# error if not (preventing any remaining middlewares from running).
|
85
|
+
#
|
86
|
+
class ConnectionValidate
|
87
|
+
def initialize(app, env)
|
88
|
+
@app = app
|
89
|
+
@driver = Driver.new(env[:machine])
|
90
|
+
end
|
91
|
+
|
92
|
+
def call(env)
|
93
|
+
@driver.validate!
|
94
|
+
@app.call(env)
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
#
|
99
|
+
# Action definitions.
|
100
|
+
#
|
101
|
+
class << Action
|
102
|
+
include Vagrant::Action::Builtin
|
103
|
+
|
104
|
+
def up
|
105
|
+
builder do |b|
|
106
|
+
b.use Call, state do |env, c|
|
107
|
+
case env[:machine_state]
|
108
|
+
when Vagrant::MachineState::NOT_CREATED_ID
|
109
|
+
c.use Message, :info, 'Machine has not been created yet, starting...'
|
110
|
+
c.use HandleBox
|
111
|
+
c.use LXD.action(:create)
|
112
|
+
c.use LXD.action(:resume)
|
113
|
+
c.use SyncedFolders
|
114
|
+
c.use WaitForCommunicator
|
115
|
+
c.use Provision
|
116
|
+
when :running
|
117
|
+
c.use Message, :info, 'Machine is already running.'
|
118
|
+
when :frozen, :stopped
|
119
|
+
c.use resume
|
120
|
+
else
|
121
|
+
c.use Message, :error, "Machine cannot be started while #{env[:machine_state]}."
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
def destroy
|
128
|
+
builder do |b|
|
129
|
+
b.use Call, IsState, Vagrant::MachineState::NOT_CREATED_ID do |env, c|
|
130
|
+
if env[:result]
|
131
|
+
next
|
132
|
+
else
|
133
|
+
c.use Call, DestroyConfirm do |env, d|
|
134
|
+
if env[:result]
|
135
|
+
d.use halt
|
136
|
+
d.use Message, :info, 'Destroying machine and associated data...'
|
137
|
+
d.use LXD.action(:destroy)
|
138
|
+
else
|
139
|
+
d.use Message, :info, 'Machine will not be destroyed.'
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
def halt
|
148
|
+
builder do |b|
|
149
|
+
b.use Call, state do |env, c|
|
150
|
+
case env[:machine_state]
|
151
|
+
when Vagrant::MachineState::NOT_CREATED_ID
|
152
|
+
next
|
153
|
+
when :stopped
|
154
|
+
c.use Message, :info, 'Machine is already stopped.'
|
155
|
+
when :frozen, :running
|
156
|
+
c.use Message, :info, 'Stopping machine...'
|
157
|
+
c.use LXD.action(:halt)
|
158
|
+
else
|
159
|
+
c.use Message, :error, "Machine cannot be stopped while #{env[:machine_state]}."
|
160
|
+
end
|
161
|
+
end
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
def suspend
|
166
|
+
builder do |b|
|
167
|
+
b.use Call, state do |env, c|
|
168
|
+
case env[:machine_state]
|
169
|
+
when Vagrant::MachineState::NOT_CREATED_ID
|
170
|
+
next
|
171
|
+
when :frozen
|
172
|
+
c.use Message, :info, 'Machine is already suspended.'
|
173
|
+
when :running
|
174
|
+
c.use Message, :info, 'Suspending machine...'
|
175
|
+
c.use LXD.action(:suspend)
|
176
|
+
else
|
177
|
+
c.use Message, :error, "Machine cannot be suspended while #{env[:machine_state]}."
|
178
|
+
end
|
179
|
+
end
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
183
|
+
def resume
|
184
|
+
builder do |b|
|
185
|
+
b.use Call, state do |env, c|
|
186
|
+
case env[:machine_state]
|
187
|
+
when Vagrant::MachineState::NOT_CREATED_ID
|
188
|
+
next
|
189
|
+
when :running
|
190
|
+
c.use Message, :info, 'Machine is already running.'
|
191
|
+
when :frozen, :stopped
|
192
|
+
c.use Message, :info, 'Resuming machine...'
|
193
|
+
c.use LXD.action(:resume)
|
194
|
+
c.use SyncedFolders
|
195
|
+
c.use WaitForCommunicator
|
196
|
+
c.use Provision
|
197
|
+
else
|
198
|
+
c.use Message, :error, "Machine cannot be resumed while #{env[:machine_state]}."
|
199
|
+
end
|
200
|
+
end
|
201
|
+
end
|
202
|
+
end
|
203
|
+
|
204
|
+
def reload
|
205
|
+
builder do |b|
|
206
|
+
b.use Call, state do |env, c|
|
207
|
+
case env[:machine_state]
|
208
|
+
when Vagrant::MachineState::NOT_CREATED_ID
|
209
|
+
next
|
210
|
+
when :frozen, :running
|
211
|
+
c.use halt
|
212
|
+
end
|
213
|
+
c.use resume
|
214
|
+
end
|
215
|
+
end
|
216
|
+
end
|
217
|
+
|
218
|
+
def provision
|
219
|
+
builder do |b|
|
220
|
+
b.use Call, IsState, Vagrant::MachineState::NOT_CREATED_ID do |env, c|
|
221
|
+
if env[:result]
|
222
|
+
next
|
223
|
+
else
|
224
|
+
c.use Provision
|
225
|
+
end
|
226
|
+
end
|
227
|
+
end
|
228
|
+
end
|
229
|
+
|
230
|
+
def snapshot_list
|
231
|
+
builder do |b|
|
232
|
+
b.use Call, IsState, Vagrant::MachineState::NOT_CREATED_ID do |env, c|
|
233
|
+
if env[:result]
|
234
|
+
next
|
235
|
+
else
|
236
|
+
c.use LXD.action(:snapshot_list)
|
237
|
+
end
|
238
|
+
end
|
239
|
+
end
|
240
|
+
end
|
241
|
+
|
242
|
+
def snapshot_save
|
243
|
+
builder do |b|
|
244
|
+
b.use Call, IsState, Vagrant::MachineState::NOT_CREATED_ID do |env, c|
|
245
|
+
if env[:result]
|
246
|
+
next
|
247
|
+
else
|
248
|
+
c.use Message, :info, I18n.t('vagrant.actions.vm.snapshot.saving', name: env[:snapshot_name])
|
249
|
+
c.use LXD.action(:snapshot_save), env[:snapshot_name]
|
250
|
+
c.use Message, :success, I18n.t('vagrant.actions.vm.snapshot.saved', name: env[:snapshot_name])
|
251
|
+
end
|
252
|
+
end
|
253
|
+
end
|
254
|
+
end
|
255
|
+
|
256
|
+
def snapshot_restore
|
257
|
+
builder do |b|
|
258
|
+
b.use Call, IsState, Vagrant::MachineState::NOT_CREATED_ID do |env, c|
|
259
|
+
if env[:result]
|
260
|
+
next
|
261
|
+
else
|
262
|
+
c.use Message, :info, I18n.t('vagrant.actions.vm.snapshot.restoring', name: env[:snapshot_name])
|
263
|
+
c.use LXD.action(:snapshot_restore), env[:snapshot_name]
|
264
|
+
c.use Message, :success, I18n.t('vagrant.actions.vm.snapshot.restored', name: env[:snapshot_name])
|
265
|
+
c.use Call, IsEnvSet, :snapshot_delete do |env, d|
|
266
|
+
d.use snapshot_delete if env[:result]
|
267
|
+
end
|
268
|
+
end
|
269
|
+
end
|
270
|
+
end
|
271
|
+
end
|
272
|
+
|
273
|
+
def snapshot_delete
|
274
|
+
builder do |b|
|
275
|
+
b.use Call, IsState, Vagrant::MachineState::NOT_CREATED_ID do |env, c|
|
276
|
+
if env[:result]
|
277
|
+
next
|
278
|
+
else
|
279
|
+
c.use Message, :info, I18n.t('vagrant.actions.vm.snapshot.deleting', name: env[:snapshot_name])
|
280
|
+
c.use LXD.action(:snapshot_delete), env[:snapshot_name]
|
281
|
+
c.use Message, :info, I18n.t('vagrant.actions.vm.snapshot.deleted', name: env[:snapshot_name])
|
282
|
+
end
|
283
|
+
end
|
284
|
+
end
|
285
|
+
end
|
286
|
+
|
287
|
+
def state
|
288
|
+
builder { |b| b.use LXD.action(:state) }
|
289
|
+
end
|
290
|
+
|
291
|
+
def info
|
292
|
+
builder { |b| b.use LXD.action(:info) }
|
293
|
+
end
|
294
|
+
|
295
|
+
def ssh
|
296
|
+
builder { |b| b.use SSHExec }
|
297
|
+
end
|
298
|
+
|
299
|
+
def ssh_run
|
300
|
+
builder { |b| b.use SSHRun }
|
301
|
+
end
|
302
|
+
|
303
|
+
private
|
304
|
+
|
305
|
+
def builder
|
306
|
+
Vagrant::Action::Builder.new.tap do |b|
|
307
|
+
b.use ConfigValidate
|
308
|
+
b.use ConnectionValidate
|
309
|
+
yield b
|
310
|
+
end
|
311
|
+
end
|
312
|
+
end
|
313
|
+
end
|
314
|
+
end
|