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.
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
@@ -0,0 +1,12 @@
1
+ require 'rubygems'
2
+ require 'bundler/setup'
3
+ require 'rspec/core/rake_task'
4
+
5
+ Bundler::GemHelper.install_tasks
6
+
7
+ RSpec::Core::RakeTask.new(:spec) do |t|
8
+ t.rspec_opts = '-I. -rspec/common'
9
+ t.verbose = false
10
+ end
11
+
12
+ task :default => :spec
@@ -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