vagrant-lxd 0.3.4 → 0.4.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 +4 -4
- data/Gemfile.lock +1 -1
- data/README.md +26 -1
- data/lib/vagrant-lxd/config.rb +42 -1
- data/lib/vagrant-lxd/driver.rb +73 -34
- data/lib/vagrant-lxd/driver/certificate.rb +88 -0
- data/lib/vagrant-lxd/version.rb +1 -1
- data/templates/locales/en.yml +15 -3
- metadata +4 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 37988b3901f0e99417203fbab0b8c532e631f0c4
|
4
|
+
data.tar.gz: c39bdfa2e6e7912cd5dc3cad36600bc6d98ff51d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1c14feb0f9522935357fe750329e288697bb8dc226218aeeebec74baa8e78afc36689a3972db637db9fa0e507e594dcfc9ae8df0c68a25550ee6359e536f6d35
|
7
|
+
data.tar.gz: 68cb1f0440026627051a5754e64857b25a78dc5d7a0d155c798304af8676efff555a5e226e01be3daa6d4d258e0d64856fa6195070c8a8366004df987bade911
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -67,7 +67,7 @@ VM images from [Vagrant Cloud][cloud] should work without modification:
|
|
67
67
|
|
68
68
|
#### Configuration
|
69
69
|
|
70
|
-
Below is an example Vagrantfile showing
|
70
|
+
Below is an example Vagrantfile showing most of the provider's
|
71
71
|
configurable values, along with their defaults. The `debian/stretch64`
|
72
72
|
box is available on the Vagrant Cloud, so you should be able to copy
|
73
73
|
this file and adjust it as you see fit.
|
@@ -90,6 +90,27 @@ Vagrant.configure('2') do |config|
|
|
90
90
|
end
|
91
91
|
```
|
92
92
|
|
93
|
+
### Client Authentication
|
94
|
+
|
95
|
+
The LXD API uses client certificates to authenticate requests.
|
96
|
+
|
97
|
+
By default, the plugin will first try to use files from
|
98
|
+
`~/.config/lxc/client.crt` and `client.key`, if they exist. Otherwise,
|
99
|
+
it will generate a new 4096-bit RSA certificate (and accompanying
|
100
|
+
private key) in Vagrant's data directory. When using the plugin for the
|
101
|
+
first time, you will need to add this certificate to LXD's trust store
|
102
|
+
by running:
|
103
|
+
|
104
|
+
$ lxc config trust add ~/.vagrant.d/data/lxd/client.crt
|
105
|
+
|
106
|
+
If you would rather use an existing certificate, you can specify the
|
107
|
+
files for the plugin to use with the following settings:
|
108
|
+
|
109
|
+
config.vm.provider 'lxd' do |lxd|
|
110
|
+
lxd.client_certificate = '/path/to/client.crt'
|
111
|
+
lxd.client_key = '/path/to/client.key'
|
112
|
+
end
|
113
|
+
|
93
114
|
### Synced Folders
|
94
115
|
|
95
116
|
In order to use shared folders, you must first add your user ID to the
|
@@ -177,6 +198,10 @@ configuration documentation][docs] for details.
|
|
177
198
|
lxd.privileged = true
|
178
199
|
end
|
179
200
|
|
201
|
+
Note that enabling these options will invalidate any user and group ID
|
202
|
+
mappings you may have configured for synced folders, since privileged
|
203
|
+
containers use the same UID and GID space as the host machine.
|
204
|
+
|
180
205
|
[docs]: https://lxd.readthedocs.io/en/latest/containers/
|
181
206
|
|
182
207
|
## Hacking
|
data/lib/vagrant-lxd/config.rb
CHANGED
@@ -18,6 +18,7 @@
|
|
18
18
|
#
|
19
19
|
|
20
20
|
require 'uri'
|
21
|
+
require 'openssl'
|
21
22
|
|
22
23
|
module VagrantLXD
|
23
24
|
class Config < Vagrant.plugin('2', :config)
|
@@ -32,6 +33,8 @@ module VagrantLXD
|
|
32
33
|
attr_accessor :profiles
|
33
34
|
attr_accessor :vagrant_uid
|
34
35
|
attr_accessor :vagrant_gid
|
36
|
+
attr_accessor :client_certificate
|
37
|
+
attr_accessor :client_key
|
35
38
|
|
36
39
|
def initialize
|
37
40
|
@name = UNSET_VALUE
|
@@ -45,6 +48,8 @@ module VagrantLXD
|
|
45
48
|
@api_endpoint = UNSET_VALUE
|
46
49
|
@vagrant_uid = UNSET_VALUE
|
47
50
|
@vagrant_gid = UNSET_VALUE
|
51
|
+
@client_certificate = UNSET_VALUE
|
52
|
+
@client_key = UNSET_VALUE
|
48
53
|
end
|
49
54
|
|
50
55
|
def validate(machine)
|
@@ -110,6 +115,30 @@ module VagrantLXD
|
|
110
115
|
errors << "Invalid `vagrant_gid' (value must be a non-negative integer): #{vagrant_gid.inspect}"
|
111
116
|
end
|
112
117
|
|
118
|
+
if client_certificate.is_a? String
|
119
|
+
begin
|
120
|
+
OpenSSL::X509::Certificate.new(File.read(client_certificate))
|
121
|
+
rescue Exception => e
|
122
|
+
errors << "Invalid `client_certificate' (unable to read certificate): #{e.message}"
|
123
|
+
end
|
124
|
+
elsif not client_certificate.nil?
|
125
|
+
errors << "Invalid `client_certificate' (value must be a string): #{client_certificate.inspect}"
|
126
|
+
elsif not client_key.nil?
|
127
|
+
errors << "You must provide both `client_certificate' and `client_key'"
|
128
|
+
end
|
129
|
+
|
130
|
+
if client_key.is_a? String
|
131
|
+
begin
|
132
|
+
OpenSSL::PKey.read(File.read(client_key))
|
133
|
+
rescue Exception => e
|
134
|
+
errors << "Invalid `client_key' (unable to read key): #{e.message}"
|
135
|
+
end
|
136
|
+
elsif not client_key.nil?
|
137
|
+
errors << "Invalid `client_key' (value must be a string): #{client_key.inspect}"
|
138
|
+
elsif not client_certificate.nil?
|
139
|
+
errors << "You must provide both `client_certificate' and `client_key'"
|
140
|
+
end
|
141
|
+
|
113
142
|
{ Version::NAME => errors }
|
114
143
|
end
|
115
144
|
|
@@ -148,7 +177,7 @@ module VagrantLXD
|
|
148
177
|
|
149
178
|
if api_endpoint == UNSET_VALUE
|
150
179
|
@api_endpoint = URI('https://127.0.0.1:8443')
|
151
|
-
|
180
|
+
elsif String === api_endpoint
|
152
181
|
@api_endpoint = URI(api_endpoint)
|
153
182
|
end
|
154
183
|
|
@@ -159,6 +188,18 @@ module VagrantLXD
|
|
159
188
|
if vagrant_gid == UNSET_VALUE
|
160
189
|
@vagrant_gid = vagrant_uid
|
161
190
|
end
|
191
|
+
|
192
|
+
if client_certificate == UNSET_VALUE
|
193
|
+
@client_certificate = nil
|
194
|
+
elsif String === client_certificate
|
195
|
+
@client_certificate = File.expand_path(client_certificate)
|
196
|
+
end
|
197
|
+
|
198
|
+
if client_key == UNSET_VALUE
|
199
|
+
@client_key = nil
|
200
|
+
elsif String === client_key
|
201
|
+
@client_key = File.expand_path(client_key)
|
202
|
+
end
|
162
203
|
end
|
163
204
|
end
|
164
205
|
end
|
data/lib/vagrant-lxd/driver.rb
CHANGED
@@ -24,7 +24,7 @@ require 'tempfile'
|
|
24
24
|
require 'timeout'
|
25
25
|
require 'monitor'
|
26
26
|
require 'vagrant/machine_state'
|
27
|
-
require 'vagrant-lxd/
|
27
|
+
require 'vagrant-lxd/driver/certificate'
|
28
28
|
|
29
29
|
module VagrantLXD
|
30
30
|
class Driver
|
@@ -88,6 +88,10 @@ module VagrantLXD
|
|
88
88
|
error_key 'lxd_disk_unmount_failure'
|
89
89
|
end
|
90
90
|
|
91
|
+
class CertificateGenerationFailure < Vagrant::Errors::VagrantError
|
92
|
+
error_key 'lxd_certificate_generation_failure'
|
93
|
+
end
|
94
|
+
|
91
95
|
class SnapshotNotFound < Vagrant::Errors::VagrantError
|
92
96
|
error_key 'snapshot_not_found'
|
93
97
|
end
|
@@ -118,6 +122,8 @@ module VagrantLXD
|
|
118
122
|
attr_reader :nesting
|
119
123
|
attr_reader :privileged
|
120
124
|
attr_reader :profiles
|
125
|
+
attr_reader :client_certificate
|
126
|
+
attr_reader :client_key
|
121
127
|
attr_reader :vagrant_uid
|
122
128
|
attr_reader :vagrant_gid
|
123
129
|
|
@@ -132,10 +138,11 @@ module VagrantLXD
|
|
132
138
|
@ephemeral = machine.provider_config.ephemeral
|
133
139
|
@profiles = machine.provider_config.profiles
|
134
140
|
@name = machine.provider_config.name
|
141
|
+
@client_certificate = machine.provider_config.client_certificate
|
142
|
+
@client_key = machine.provider_config.client_key
|
135
143
|
@vagrant_uid = machine.provider_config.vagrant_uid
|
136
144
|
@vagrant_gid = machine.provider_config.vagrant_gid
|
137
145
|
@logger = Log4r::Logger.new('vagrant::lxd::driver')
|
138
|
-
@lxd = Hyperkit::Client.new(api_endpoint: api_endpoint.to_s, verify_ssl: false, user_agent: USER_AGENT)
|
139
146
|
end
|
140
147
|
|
141
148
|
def validate!
|
@@ -156,18 +163,18 @@ module VagrantLXD
|
|
156
163
|
end
|
157
164
|
|
158
165
|
def mount(name, options)
|
159
|
-
container =
|
166
|
+
container = lxd.container(machine_id)
|
160
167
|
devices = container[:devices].to_hash
|
161
168
|
devices[name] = { type: 'disk', path: options[:guestpath], source: options[:hostpath] }.merge(options[:config])
|
162
169
|
container[:devices] = devices
|
163
|
-
|
170
|
+
lxd.update_container(machine_id, container)
|
164
171
|
rescue Hyperkit::BadRequest => e
|
165
172
|
@machine.ui.error 'Failed to mount synced folder'
|
166
173
|
fail DiskMountFailure, machine_name: @machine.name, guestpath: options[:guestpath], reason: e.reason
|
167
174
|
end
|
168
175
|
|
169
176
|
def mounted?(name, options)
|
170
|
-
container =
|
177
|
+
container = lxd.container(machine_id)
|
171
178
|
devices = container[:devices].to_hash
|
172
179
|
name = name.to_sym
|
173
180
|
begin
|
@@ -179,18 +186,18 @@ module VagrantLXD
|
|
179
186
|
end
|
180
187
|
|
181
188
|
def unmount(name, options)
|
182
|
-
container =
|
189
|
+
container = lxd.container(machine_id)
|
183
190
|
devices = container[:devices].to_hash
|
184
191
|
devices.delete(name.to_sym)
|
185
192
|
container[:devices] = devices
|
186
|
-
|
193
|
+
lxd.update_container(machine_id, container)
|
187
194
|
rescue Hyperkit::BadRequest => e
|
188
195
|
@machine.ui.error 'Failed to unmount synced folder'
|
189
196
|
fail DiskUnmountFailure, machine_name: @machine.name, guestpath: options[:guestpath], reason: e.reason
|
190
197
|
end
|
191
198
|
|
192
199
|
def attach(container)
|
193
|
-
|
200
|
+
lxd.container(container) # Query LXD to make sure the container exists.
|
194
201
|
|
195
202
|
if in_state? NOT_CREATED
|
196
203
|
@machine.id = container
|
@@ -211,17 +218,17 @@ module VagrantLXD
|
|
211
218
|
#
|
212
219
|
|
213
220
|
def snapshot_list
|
214
|
-
|
221
|
+
lxd.snapshots(machine_id)
|
215
222
|
end
|
216
223
|
|
217
224
|
def snapshot_save(name)
|
218
225
|
snapshot_delete(name) # noops if the snapshot doesn't exist
|
219
|
-
operation =
|
226
|
+
operation = lxd.create_snapshot(machine_id, name, sync: false)
|
220
227
|
wait_for_operation(operation)
|
221
228
|
end
|
222
229
|
|
223
230
|
def snapshot_restore(name)
|
224
|
-
operation =
|
231
|
+
operation = lxd.restore_snapshot(machine_id, name, sync: false)
|
225
232
|
wait_for_operation(operation)
|
226
233
|
rescue Hyperkit::BadRequest
|
227
234
|
@logger.warn 'Snapshot restoration failed: ' << name
|
@@ -229,14 +236,14 @@ module VagrantLXD
|
|
229
236
|
end
|
230
237
|
|
231
238
|
def snapshot_delete(name)
|
232
|
-
|
239
|
+
lxd.delete_snapshot(machine_id, name)
|
233
240
|
rescue Hyperkit::NotFound
|
234
241
|
@logger.warn 'No such snapshot: ' << name
|
235
242
|
end
|
236
243
|
|
237
244
|
def state
|
238
245
|
return NOT_CREATED if machine_id.nil?
|
239
|
-
container_state =
|
246
|
+
container_state = lxd.container_state(machine_id)
|
240
247
|
container_state[:status].downcase.to_sym
|
241
248
|
rescue Hyperkit::NotFound
|
242
249
|
NOT_CREATED
|
@@ -250,28 +257,28 @@ module VagrantLXD
|
|
250
257
|
|
251
258
|
Driver.synchronize do
|
252
259
|
begin
|
253
|
-
image =
|
260
|
+
image = lxd.image(fingerprint)
|
254
261
|
@logger.debug 'Using image: ' << image.inspect
|
255
262
|
rescue Hyperkit::NotFound
|
256
|
-
image =
|
263
|
+
image = lxd.create_image_from_file(file)
|
257
264
|
@logger.debug 'Created image: ' << image.inspect
|
258
265
|
begin
|
259
|
-
|
260
|
-
|
266
|
+
lxd.update_image(fingerprint, properties: IMAGE_PROPERTIES)
|
267
|
+
lxd.create_image_alias(fingerprint, machine_id, IMAGE_PROPERTIES)
|
261
268
|
rescue Hyperkit::Error
|
262
269
|
@logger.error 'Failed to set description for image: ' << e.reason
|
263
270
|
end
|
264
271
|
end
|
265
272
|
end
|
266
273
|
|
267
|
-
container =
|
274
|
+
container = lxd.create_container(machine_id, ephemeral: ephemeral, fingerprint: fingerprint, config: config, profiles: profiles)
|
268
275
|
@logger.debug 'Created container: ' << container.inspect
|
269
276
|
|
270
277
|
@machine.id = machine_id
|
271
278
|
end
|
272
279
|
rescue Hyperkit::Error => e
|
273
|
-
|
274
|
-
|
280
|
+
lxd.delete_container(machine_id) rescue nil unless container.nil?
|
281
|
+
lxd.delete_image(image[:metadata][:fingerprint]) rescue nil unless image.nil?
|
275
282
|
if e.reason =~ /Container '([^']+)' already exists/
|
276
283
|
@machine.ui.error e.reason
|
277
284
|
fail ContainerAlreadyExists, machine_name: @machine.name, container: $1
|
@@ -284,9 +291,9 @@ module VagrantLXD
|
|
284
291
|
def resume
|
285
292
|
case state
|
286
293
|
when :stopped
|
287
|
-
|
294
|
+
lxd.start_container(machine_id)
|
288
295
|
when :frozen
|
289
|
-
|
296
|
+
lxd.unfreeze_container(machine_id, timeout: timeout)
|
290
297
|
end
|
291
298
|
rescue Hyperkit::BadRequest
|
292
299
|
@machine.ui.warn "Container failed to start within #{timeout} seconds"
|
@@ -295,7 +302,7 @@ module VagrantLXD
|
|
295
302
|
|
296
303
|
def halt(force = false)
|
297
304
|
if in_state? :running, :frozen
|
298
|
-
|
305
|
+
lxd.stop_container(machine_id, timeout: timeout, force: force)
|
299
306
|
end
|
300
307
|
rescue Hyperkit::BadRequest
|
301
308
|
if force
|
@@ -308,7 +315,7 @@ module VagrantLXD
|
|
308
315
|
|
309
316
|
def suspend
|
310
317
|
if in_state? :running
|
311
|
-
|
318
|
+
lxd.freeze_container(machine_id, timeout: timeout)
|
312
319
|
end
|
313
320
|
rescue Hyperkit::BadRequest
|
314
321
|
@machine.ui.warn "Container failed to suspend within #{timeout} seconds"
|
@@ -325,9 +332,9 @@ module VagrantLXD
|
|
325
332
|
end
|
326
333
|
|
327
334
|
def configure
|
328
|
-
container =
|
335
|
+
container = lxd.container(machine_id)
|
329
336
|
container[:config] = container[:config].to_hash.merge(config)
|
330
|
-
|
337
|
+
lxd.update_container(machine_id, container)
|
331
338
|
rescue Hyperkit::Error => e
|
332
339
|
@machine.ui.error 'Failed to configure container'
|
333
340
|
fail ContainerConfigurationFailure, machine_name: @machine.name, reason: e.reason
|
@@ -349,12 +356,22 @@ module VagrantLXD
|
|
349
356
|
# used by the rest of the plugin.
|
350
357
|
#
|
351
358
|
|
359
|
+
def lxd
|
360
|
+
@lxd ||= Hyperkit::Client.new(
|
361
|
+
api_endpoint: api_endpoint.to_s,
|
362
|
+
client_cert: cert.certificate,
|
363
|
+
client_key: cert.key,
|
364
|
+
verify_ssl: false,
|
365
|
+
user_agent: USER_AGENT,
|
366
|
+
)
|
367
|
+
end
|
368
|
+
|
352
369
|
def machine_id
|
353
370
|
@machine.id
|
354
371
|
end
|
355
372
|
|
356
373
|
def delete_container
|
357
|
-
|
374
|
+
lxd.delete_container(machine_id)
|
358
375
|
rescue Hyperkit::NotFound
|
359
376
|
@logger.warn "Container '#{machine_id}' not found, unable to destroy"
|
360
377
|
rescue Hyperkit::Error => e
|
@@ -369,7 +386,7 @@ module VagrantLXD
|
|
369
386
|
end
|
370
387
|
|
371
388
|
def delete_image
|
372
|
-
|
389
|
+
lxd.delete_image(container[:config][:'volatile.base_image'])
|
373
390
|
rescue Hyperkit::NotFound
|
374
391
|
@logger.warn "Image for '#{machine_id}' not found, unable to destroy"
|
375
392
|
rescue Hyperkit::BadRequest
|
@@ -380,17 +397,17 @@ module VagrantLXD
|
|
380
397
|
# is enabled or setting sync: true. TODO Upstream a better fix than
|
381
398
|
# this, so that `wait_for_operation` really does.
|
382
399
|
def wait_for_operation(operation)
|
383
|
-
|
400
|
+
lxd.wait_for_operation(operation.id)
|
384
401
|
rescue Faraday::TimeoutError
|
385
402
|
retry
|
386
403
|
end
|
387
404
|
|
388
405
|
def container
|
389
|
-
|
406
|
+
lxd.container(machine_id)
|
390
407
|
end
|
391
408
|
|
392
409
|
def connection_usable?
|
393
|
-
|
410
|
+
lxd.images
|
394
411
|
rescue Faraday::ConnectionFailed
|
395
412
|
false
|
396
413
|
else
|
@@ -398,7 +415,7 @@ module VagrantLXD
|
|
398
415
|
end
|
399
416
|
|
400
417
|
def authentication_usable?
|
401
|
-
connection_usable? and
|
418
|
+
connection_usable? and lxd.containers
|
402
419
|
rescue Hyperkit::Forbidden
|
403
420
|
false
|
404
421
|
else
|
@@ -425,7 +442,7 @@ module VagrantLXD
|
|
425
442
|
@logger.debug "Looking up ipv4 address for #{machine_id}..."
|
426
443
|
Timeout.timeout(timeout) do
|
427
444
|
loop do
|
428
|
-
container_state =
|
445
|
+
container_state = lxd.container_state(machine_id)
|
429
446
|
if address = container_state[:network][:eth0][:addresses].find { |a| a[:family] == 'inet' }
|
430
447
|
return address[:address]
|
431
448
|
else
|
@@ -439,6 +456,16 @@ module VagrantLXD
|
|
439
456
|
fail NetworkAddressAcquisitionTimeout, time_limit: timeout, lxd_bridge: 'lxdbr0' # FIXME Hardcoded bridge name
|
440
457
|
end
|
441
458
|
|
459
|
+
def cert
|
460
|
+
@cert ||= if client_certificate
|
461
|
+
Certificate.new(client_certificate, client_key)
|
462
|
+
else
|
463
|
+
Driver.synchronize do
|
464
|
+
locate_or_generate_client_certificate
|
465
|
+
end
|
466
|
+
end
|
467
|
+
end
|
468
|
+
|
442
469
|
def config
|
443
470
|
# NOTE We reuse ActiveSupport for `#deep_dup` here, but if the Hyperkit
|
444
471
|
# dependency ever goes away, drop ActiveSupport and use some other
|
@@ -469,6 +496,18 @@ module VagrantLXD
|
|
469
496
|
config
|
470
497
|
end
|
471
498
|
|
499
|
+
def locate_or_generate_client_certificate
|
500
|
+
vagrant_path = @machine.env.data_dir / 'lxd'
|
501
|
+
default_path = Certificate.default_path / 'lxc'
|
502
|
+
|
503
|
+
search_paths = [vagrant_path, default_path]
|
504
|
+
|
505
|
+
Certificate.locate(search_paths) or
|
506
|
+
Certificate.generate(vagrant_path)
|
507
|
+
rescue Certificate::GenerationFailure => e
|
508
|
+
fail CertificateGenerationFailure, reason: e.message, api_endpoint: @api_endpoint.to_s, default_path: default_path, vagrant_path: vagrant_path
|
509
|
+
end
|
510
|
+
|
472
511
|
# TODO Image handling should be moved into its own class.
|
473
512
|
def prepare_image_file
|
474
513
|
tmpdir = Dir.mktmpdir
|
@@ -520,7 +559,7 @@ module VagrantLXD
|
|
520
559
|
machine: @machine.name,
|
521
560
|
api_endpoint: @api_endpoint.to_s,
|
522
561
|
https_address: @api_endpoint.host,
|
523
|
-
client_cert:
|
562
|
+
client_cert: cert.certificate.to_s,
|
524
563
|
)
|
525
564
|
end
|
526
565
|
end
|
@@ -0,0 +1,88 @@
|
|
1
|
+
#
|
2
|
+
# Copyright (c) 2019 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 'etc'
|
21
|
+
require 'openssl'
|
22
|
+
require 'pathname'
|
23
|
+
require 'socket'
|
24
|
+
require 'vagrant-lxd/version'
|
25
|
+
|
26
|
+
module VagrantLXD
|
27
|
+
class Driver
|
28
|
+
class Certificate < Struct.new(:certificate, :key)
|
29
|
+
PKEY_BITS = 4096
|
30
|
+
CERT_EXPIRY_YEARS = 10
|
31
|
+
|
32
|
+
GenerationFailure = Class.new(Exception)
|
33
|
+
|
34
|
+
@logger = Log4r::Logger.new('vagrant::lxd::driver::certificate')
|
35
|
+
|
36
|
+
def Certificate.default_path
|
37
|
+
Pathname.new('~/.config').expand_path
|
38
|
+
end
|
39
|
+
|
40
|
+
def Certificate.issuer_name
|
41
|
+
version = "#{Version::DESCRIPTION} #{Version::VERSION}"
|
42
|
+
username = Etc.getpwuid(Process.uid).name
|
43
|
+
hostname = Socket.gethostname
|
44
|
+
"/O=linuxcontainers.org/OU=#{version}/CN=#{username}@#{hostname}"
|
45
|
+
end
|
46
|
+
|
47
|
+
def Certificate.locate(paths)
|
48
|
+
if path = paths.find { |x| usable?(x) }
|
49
|
+
@logger.debug "Found usable certificate under #{path}"
|
50
|
+
Certificate.new(path / 'client.crt', path / 'client.key')
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def Certificate.generate(path)
|
55
|
+
@logger.debug 'Generating new client certificate...'
|
56
|
+
name = OpenSSL::X509::Name.parse(issuer_name)
|
57
|
+
pkey = OpenSSL::PKey::RSA.new(PKEY_BITS)
|
58
|
+
cert = OpenSSL::X509::Certificate.new
|
59
|
+
cert.serial = 0
|
60
|
+
cert.version = 3
|
61
|
+
cert.issuer = name
|
62
|
+
cert.subject = name
|
63
|
+
cert.public_key = pkey.public_key
|
64
|
+
cert.not_before = Time.now
|
65
|
+
cert.not_after = Time.now + (365 * 24 * 60 * 60 * CERT_EXPIRY_YEARS)
|
66
|
+
cert.sign(pkey, OpenSSL::Digest::SHA1.new)
|
67
|
+
@logger.debug "Saving new certificate to disk under #{path}..."
|
68
|
+
FileUtils.mkdir_p(path, mode: 0o700)
|
69
|
+
File.write(path / 'client.crt', cert.to_s, 0, perm: 0o600)
|
70
|
+
File.write(path / 'client.key', pkey.to_s, 0, perm: 0o600)
|
71
|
+
Certificate.new(path / 'client.crt', path / 'client.key')
|
72
|
+
rescue Exception => e
|
73
|
+
@logger.error 'Certificate creation failed: ' << e.message
|
74
|
+
fail GenerationFailure, e.message
|
75
|
+
end
|
76
|
+
|
77
|
+
def Certificate.usable?(path)
|
78
|
+
@logger.debug "Checking for existing client certificate in #{path}..."
|
79
|
+
OpenSSL::PKey.read(File.read(path / 'client.key'))
|
80
|
+
OpenSSL::X509::Certificate.new(File.read(path / 'client.crt'))
|
81
|
+
rescue Exception
|
82
|
+
false
|
83
|
+
else
|
84
|
+
true
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
data/lib/vagrant-lxd/version.rb
CHANGED
data/templates/locales/en.yml
CHANGED
@@ -32,13 +32,13 @@ en:
|
|
32
32
|
|
33
33
|
errors:
|
34
34
|
lxd_connection_failure: |-
|
35
|
-
The provider was unable to contact the
|
35
|
+
The LXD provider was unable to contact the daemon at %{api_endpoint}.
|
36
36
|
|
37
37
|
It's possible that LXD isn't installed, or that it isn't configured to
|
38
38
|
accept HTTPS connections from your machine. You can check whether HTTPS
|
39
39
|
access is enabled with the following command:
|
40
40
|
|
41
|
-
$ lxc config
|
41
|
+
$ lxc config get core.https_address
|
42
42
|
|
43
43
|
If the result is empty or an error is shown, you will need to correct
|
44
44
|
the way LXD is configured before Vagrant can use it. This can be done
|
@@ -51,7 +51,7 @@ en:
|
|
51
51
|
https://linuxcontainers.org/lxd/getting-started-cli/#initial-configuration
|
52
52
|
|
53
53
|
lxd_authentication_failure: |-
|
54
|
-
The provider could not authenticate to the
|
54
|
+
The LXD provider could not authenticate to the daemon at %{api_endpoint}.
|
55
55
|
|
56
56
|
You may need configure LXD to allow requests from this machine. The
|
57
57
|
easiest way to do this is to add your LXC client certificate to LXD's
|
@@ -156,6 +156,18 @@ en:
|
|
156
156
|
You will either need to delete this container and try again, or attach
|
157
157
|
the VM to it with `vagrant lxd attach %{machine_name} %{container}`.
|
158
158
|
|
159
|
+
lxd_certificate_generation_failure: |-
|
160
|
+
The LXD provider was unable to generate a client certificate for
|
161
|
+
authenticating to the daemon at %{api_endpoint}.
|
162
|
+
|
163
|
+
It tried to place the files in %{vagrant_path}.
|
164
|
+
|
165
|
+
The underlying error message was: %{reason}
|
166
|
+
|
167
|
+
You can use an existing certificate by setting the `client_certificate`
|
168
|
+
and `client_key` options in the LXD provider's configuration, or by
|
169
|
+
placing 'client.crt' and 'client.key' files in %{default_path}.
|
170
|
+
|
159
171
|
snapshot_not_found: |-
|
160
172
|
The snapshot name `%{snapshot_name}` was not found for the
|
161
173
|
virtual machine `%{machine}`.
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: vagrant-lxd
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Evan Hanson
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-
|
11
|
+
date: 2019-03-29 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: hyperkit
|
@@ -45,6 +45,7 @@ files:
|
|
45
45
|
- lib/vagrant-lxd/command.rb
|
46
46
|
- lib/vagrant-lxd/config.rb
|
47
47
|
- lib/vagrant-lxd/driver.rb
|
48
|
+
- lib/vagrant-lxd/driver/certificate.rb
|
48
49
|
- lib/vagrant-lxd/plugin.rb
|
49
50
|
- lib/vagrant-lxd/provider.rb
|
50
51
|
- lib/vagrant-lxd/synced_folder.rb
|
@@ -71,7 +72,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
71
72
|
version: '0'
|
72
73
|
requirements: []
|
73
74
|
rubyforge_project:
|
74
|
-
rubygems_version: 2.6.
|
75
|
+
rubygems_version: 2.6.8
|
75
76
|
signing_key:
|
76
77
|
specification_version: 4
|
77
78
|
summary: Vagrant LXD provider
|