vagrant-lxd 0.4.0 → 0.4.5

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 37988b3901f0e99417203fbab0b8c532e631f0c4
4
- data.tar.gz: c39bdfa2e6e7912cd5dc3cad36600bc6d98ff51d
2
+ SHA256:
3
+ metadata.gz: be2300b7aa0ba5ccc8ae1d3ed7af2bbc0da4a1ded7aefe64e9896d26a672d905
4
+ data.tar.gz: c7e73c349e90e91f180e76f1a550d35852b0aa720a406361ef9f94e692eaa68a
5
5
  SHA512:
6
- metadata.gz: 1c14feb0f9522935357fe750329e288697bb8dc226218aeeebec74baa8e78afc36689a3972db637db9fa0e507e594dcfc9ae8df0c68a25550ee6359e536f6d35
7
- data.tar.gz: 68cb1f0440026627051a5754e64857b25a78dc5d7a0d155c798304af8676efff555a5e226e01be3daa6d4d258e0d64856fa6195070c8a8366004df987bade911
6
+ metadata.gz: 9bff61ace1311df547b7b0aa6ccb3917ec950353ac7a164e78971cf2297881e007d559fb86798913d8ae1c91b0c4d9b7d5a2e565d5fd00689ff04f9a64b71dbb
7
+ data.tar.gz: cb70de69a9de248887c1b3b116fb807f324783ce1adde52f411dc83a1f7245a3da08b687c14385ee34183a144823eec469f7a0968baafdc6455af2e3ccfd154b
data/.gitignore CHANGED
@@ -1,5 +1,6 @@
1
1
  /.bundle/
2
+ /.tool-versions
2
3
  /.vagrant/
3
- /pkg/
4
4
  /Vagrantfile
5
+ /pkg/
5
6
  /vendor/
data/Gemfile CHANGED
@@ -1,6 +1,7 @@
1
1
  source 'https://rubygems.org/'
2
2
 
3
3
  group :development do
4
+ require 'pp' # avoid superclass mismatch error
4
5
  gem 'fakefs'
5
6
  gem 'rake'
6
7
  gem 'rspec'
@@ -1,60 +1,63 @@
1
1
  GIT
2
2
  remote: https://github.com/mitchellh/vagrant.git
3
- revision: c6b42a04cd1ca9f0936714ee6a44b4c7c001fdeb
3
+ revision: 7df0e62aded9316485e83fd5548bebbacf702ec7
4
4
  specs:
5
- vagrant (2.2.4.dev)
5
+ vagrant (2.2.10.dev)
6
6
  bcrypt_pbkdf (~> 1.0.0)
7
- childprocess (~> 0.6.0)
7
+ childprocess (~> 3.0.0)
8
8
  ed25519 (~> 1.2.4)
9
9
  erubis (~> 2.7.0)
10
10
  hashicorp-checkpoint (~> 0.1.5)
11
- i18n (~> 1.1.1)
11
+ i18n (~> 1.8)
12
12
  listen (~> 3.1.5)
13
13
  log4r (~> 1.1.9, < 1.1.11)
14
+ mime (~> 0.4.4)
14
15
  net-scp (~> 1.2.0)
15
16
  net-sftp (~> 2.1)
16
- net-ssh (~> 5.1.0)
17
+ net-ssh (~> 5.2.0)
17
18
  rb-kqueue (~> 0.2.0)
18
19
  rest-client (>= 1.6.0, < 3.0)
19
20
  ruby_dep (<= 1.3.1)
20
- rubyzip (~> 1.2.2)
21
- vagrant_cloud (~> 2.0.2)
21
+ rubyzip (~> 2.0)
22
+ vagrant_cloud (~> 2.0.3)
22
23
  wdm (~> 0.1.0)
23
- winrm (~> 2.1)
24
- winrm-elevated (~> 1.1)
25
- winrm-fs (~> 1.0)
24
+ winrm (>= 2.3.4, < 3.0)
25
+ winrm-elevated (>= 1.2.1, < 2.0)
26
+ winrm-fs (>= 1.3.4, < 2.0)
26
27
 
27
28
  PATH
28
29
  remote: .
29
30
  specs:
30
- vagrant-lxd (0.4.0)
31
+ vagrant-lxd (0.4.5)
32
+ activesupport (~> 5.2.3)
33
+ faraday (~> 0.17)
31
34
  hyperkit (~> 1.2.0)
32
35
 
33
36
  GEM
34
37
  remote: https://rubygems.org/
35
38
  specs:
36
- activesupport (5.2.2)
39
+ activesupport (5.2.4.3)
37
40
  concurrent-ruby (~> 1.0, >= 1.0.2)
38
41
  i18n (>= 0.7, < 2)
39
42
  minitest (~> 5.1)
40
43
  tzinfo (~> 1.1)
41
- addressable (2.5.2)
42
- public_suffix (>= 2.0.2, < 4.0)
43
- bcrypt_pbkdf (1.0.0)
44
- builder (3.2.3)
45
- childprocess (0.6.3)
46
- ffi (~> 1.0, >= 1.0.11)
47
- concurrent-ruby (1.1.4)
48
- diff-lcs (1.3)
49
- domain_name (0.5.20180417)
44
+ addressable (2.7.0)
45
+ public_suffix (>= 2.0.2, < 5.0)
46
+ bcrypt_pbkdf (1.0.1)
47
+ builder (3.2.4)
48
+ childprocess (3.0.0)
49
+ concurrent-ruby (1.1.6)
50
+ diff-lcs (1.4.4)
51
+ domain_name (0.5.20190701)
50
52
  unf (>= 0.0.5, < 1.0.0)
51
53
  ed25519 (1.2.4)
54
+ erubi (1.9.0)
52
55
  erubis (2.7.0)
53
- fakefs (0.19.1)
54
- faraday (0.15.4)
56
+ fakefs (1.2.2)
57
+ faraday (0.17.3)
55
58
  multipart-post (>= 1.2, < 3)
56
- ffi (1.10.0)
57
- gssapi (1.2.0)
59
+ ffi (1.13.1)
60
+ gssapi (1.3.0)
58
61
  ffi (>= 1.0.1)
59
62
  gyoku (1.3.1)
60
63
  builder (>= 2.1.2)
@@ -65,7 +68,7 @@ GEM
65
68
  hyperkit (1.2.0)
66
69
  activesupport (>= 4.2.6)
67
70
  sawyer
68
- i18n (1.1.1)
71
+ i18n (1.8.3)
69
72
  concurrent-ruby (~> 1.0)
70
73
  listen (3.1.5)
71
74
  rb-fsevent (~> 0.9, >= 0.9.4)
@@ -73,26 +76,27 @@ GEM
73
76
  ruby_dep (~> 1.2)
74
77
  little-plugger (1.1.4)
75
78
  log4r (1.1.10)
76
- logging (2.2.2)
79
+ logging (2.3.0)
77
80
  little-plugger (~> 1.1)
78
- multi_json (~> 1.10)
79
- mime-types (3.2.2)
81
+ multi_json (~> 1.14)
82
+ mime (0.4.4)
83
+ mime-types (3.3.1)
80
84
  mime-types-data (~> 3.2015)
81
- mime-types-data (3.2018.0812)
82
- minitest (5.11.3)
83
- multi_json (1.13.1)
84
- multipart-post (2.0.0)
85
+ mime-types-data (3.2020.0512)
86
+ minitest (5.14.1)
87
+ multi_json (1.14.1)
88
+ multipart-post (2.1.1)
85
89
  net-scp (1.2.1)
86
90
  net-ssh (>= 2.6.5)
87
91
  net-sftp (2.1.2)
88
92
  net-ssh (>= 2.6.5)
89
- net-ssh (5.1.0)
93
+ net-ssh (5.2.0)
90
94
  netrc (0.11.0)
91
95
  nori (2.6.0)
92
- public_suffix (3.0.3)
93
- rake (12.3.2)
94
- rb-fsevent (0.10.3)
95
- rb-inotify (0.10.0)
96
+ public_suffix (4.0.5)
97
+ rake (13.0.1)
98
+ rb-fsevent (0.10.4)
99
+ rb-inotify (0.10.1)
96
100
  ffi (~> 1.0)
97
101
  rb-kqueue (0.2.5)
98
102
  ffi (>= 0.5.0)
@@ -100,53 +104,54 @@ GEM
100
104
  http-cookie (>= 1.0.2, < 2.0)
101
105
  mime-types (>= 1.16, < 4.0)
102
106
  netrc (~> 0.8)
103
- rspec (3.8.0)
104
- rspec-core (~> 3.8.0)
105
- rspec-expectations (~> 3.8.0)
106
- rspec-mocks (~> 3.8.0)
107
- rspec-core (3.8.0)
108
- rspec-support (~> 3.8.0)
109
- rspec-expectations (3.8.2)
107
+ rspec (3.9.0)
108
+ rspec-core (~> 3.9.0)
109
+ rspec-expectations (~> 3.9.0)
110
+ rspec-mocks (~> 3.9.0)
111
+ rspec-core (3.9.2)
112
+ rspec-support (~> 3.9.3)
113
+ rspec-expectations (3.9.2)
110
114
  diff-lcs (>= 1.2.0, < 2.0)
111
- rspec-support (~> 3.8.0)
112
- rspec-its (1.2.0)
115
+ rspec-support (~> 3.9.0)
116
+ rspec-its (1.3.0)
113
117
  rspec-core (>= 3.0.0)
114
118
  rspec-expectations (>= 3.0.0)
115
- rspec-mocks (3.8.0)
119
+ rspec-mocks (3.9.1)
116
120
  diff-lcs (>= 1.2.0, < 2.0)
117
- rspec-support (~> 3.8.0)
118
- rspec-support (3.8.0)
121
+ rspec-support (~> 3.9.0)
122
+ rspec-support (3.9.3)
119
123
  ruby_dep (1.3.1)
120
124
  rubyntlm (0.6.2)
121
- rubyzip (1.2.2)
122
- sawyer (0.8.1)
123
- addressable (>= 2.3.5, < 2.6)
124
- faraday (~> 0.8, < 1.0)
125
+ rubyzip (2.3.0)
126
+ sawyer (0.8.2)
127
+ addressable (>= 2.3.5)
128
+ faraday (> 0.8, < 2.0)
125
129
  thread_safe (0.3.6)
126
- tzinfo (1.2.5)
130
+ tzinfo (1.2.7)
127
131
  thread_safe (~> 0.1)
128
132
  unf (0.1.4)
129
133
  unf_ext
130
- unf_ext (0.0.7.5)
131
- vagrant_cloud (2.0.2)
134
+ unf_ext (0.0.7.7)
135
+ vagrant_cloud (2.0.3)
132
136
  rest-client (~> 2.0.2)
133
137
  wdm (0.1.1)
134
- winrm (2.3.1)
138
+ winrm (2.3.4)
135
139
  builder (>= 2.1.2)
136
- erubis (~> 2.7)
140
+ erubi (~> 1.8)
137
141
  gssapi (~> 1.2)
138
142
  gyoku (~> 1.0)
139
143
  httpclient (~> 2.2, >= 2.2.0.2)
140
144
  logging (>= 1.6.1, < 3.0)
141
145
  nori (~> 2.0)
142
146
  rubyntlm (~> 0.6.0, >= 0.6.1)
143
- winrm-elevated (1.1.1)
147
+ winrm-elevated (1.2.1)
148
+ erubi (~> 1.8)
144
149
  winrm (~> 2.0)
145
150
  winrm-fs (~> 1.0)
146
- winrm-fs (1.3.2)
147
- erubis (~> 2.7)
151
+ winrm-fs (1.3.4)
152
+ erubi (~> 1.8)
148
153
  logging (>= 1.6.1, < 3.0)
149
- rubyzip (~> 1.1)
154
+ rubyzip (~> 2.0)
150
155
  winrm (~> 2.0)
151
156
 
152
157
  PLATFORMS
@@ -162,4 +167,4 @@ DEPENDENCIES
162
167
  vagrant-lxd!
163
168
 
164
169
  BUNDLED WITH
165
- 2.0.1
170
+ 2.1.4
data/README.md CHANGED
@@ -13,7 +13,8 @@ The following features are currently supported:
13
13
  - VM management (create, suspend, destroy, etc.)
14
14
  - IPv4 networking
15
15
  - Synced folders
16
- - Snapshots
16
+ - Snapshots (via `vagrant snapshot`)
17
+ - Box Packaging (via `vagrant package`)
17
18
 
18
19
  The following features are not expected to work yet:
19
20
 
@@ -147,7 +148,7 @@ is passed through to LXD. The hash values should all be strings:
147
148
  recursive: 'false',
148
149
  }
149
150
 
150
- [disk]: https://lxd.readthedocs.io/en/latest/containers/#type-disk
151
+ [disk]: https://lxd.readthedocs.io/en/latest/instances/#type-disk
151
152
 
152
153
  ### Shared LXD Containers
153
154
 
@@ -191,7 +192,7 @@ In order to run Linux containers on an LXD-backed machine, it must be
191
192
  created with the `nesting` and `privileged` properties set to `true`.
192
193
  These correspond to the `security.nesting` and `security.privileged`
193
194
  configuration items for LXD, respectively. Refer to LXD's [container
194
- configuration documentation][docs] for details.
195
+ configuration documentation][containers] for details.
195
196
 
196
197
  config.vm.provider 'lxd' do |lxd|
197
198
  lxd.nesting = true
@@ -202,7 +203,38 @@ Note that enabling these options will invalidate any user and group ID
202
203
  mappings you may have configured for synced folders, since privileged
203
204
  containers use the same UID and GID space as the host machine.
204
205
 
205
- [docs]: https://lxd.readthedocs.io/en/latest/containers/
206
+ [containers]: https://lxd.readthedocs.io/en/latest/containers/
207
+
208
+ ### Adding Devices
209
+
210
+ You can attach arbitrary devices to the container with the `devices`
211
+ setting. This should be a map of device names to configuration hashes,
212
+ where the hash keys and values are valid [device configuration
213
+ settings][device-config].
214
+
215
+ For example, the following configuration uses a `proxy` device to
216
+ forward local X11 traffic from the container to the host, allowing you
217
+ to run graphical applications transparently from within the guest:
218
+
219
+ # e.g. vagrant ssh -c 'DISPLAY=:0 firefox'
220
+ config.vm.provider 'lxd' do |lxd|
221
+ lxd.devices = {
222
+ x11: {
223
+ type: 'proxy',
224
+ mode: '0777',
225
+ bind: 'container',
226
+ listen: 'unix:/tmp/.X11-unix/X0',
227
+ connect: 'unix:/tmp/.X11-unix/X0',
228
+ 'security.uid': Process.uid.to_s,
229
+ 'security.gid': Process.gid.to_s,
230
+ }
231
+ }
232
+ end
233
+
234
+ Note that disk devices should be configured as [synced
235
+ folders](#synced-folders) rather than ad-hoc devices.
236
+
237
+ [device-config]: https://lxd.readthedocs.io/en/latest/instances/#devices-configuration
206
238
 
207
239
  ## Hacking
208
240
 
@@ -124,6 +124,20 @@ module VagrantLXD
124
124
  end
125
125
  end
126
126
 
127
+ class Package
128
+ def initialize(app, env)
129
+ @app = app
130
+ @env = env
131
+ end
132
+
133
+ def call(env)
134
+ env['package.directory'] = env[:machine_package]
135
+ @app.call(env)
136
+ ensure
137
+ FileUtils.rm_rf(env[:machine_package])
138
+ end
139
+ end
140
+
127
141
  #
128
142
  # Action definitions.
129
143
  #
@@ -227,6 +241,7 @@ module VagrantLXD
227
241
  c.use SetHostname
228
242
  c.use SyncedFolders
229
243
  c.use LXD.action(:resume)
244
+ c.use LXD.action(:reconnect)
230
245
  c.use WaitForCommunicator
231
246
  else
232
247
  c.use Message, :error, "Machine cannot be resumed while #{env[:machine_state]}."
@@ -334,6 +349,24 @@ module VagrantLXD
334
349
  builder { |b| b.use SSHRun }
335
350
  end
336
351
 
352
+ def package
353
+ builder do |b|
354
+ b.use Call, state do |env, c|
355
+ case env[:machine_state]
356
+ when Vagrant::MachineState::NOT_CREATED_ID
357
+ next
358
+ when :frozen, :running
359
+ c.use halt
360
+ end
361
+
362
+ c.use Message, :info, 'Packaging machine...'
363
+ c.use LXD.action(:package)
364
+ c.use Package
365
+ c.use Vagrant::Action::General::Package
366
+ end
367
+ end
368
+ end
369
+
337
370
  private
338
371
 
339
372
  def builder
@@ -29,14 +29,33 @@ module VagrantLXD
29
29
  def Capability.synced_folders(env)
30
30
  logger = Log4r::Logger.new('vagrant::lxd::capability')
31
31
  logger.debug "Checking synced folders support for effective UID/GID #{Process.uid}/#{Process.gid}..."
32
- result = %w(uid gid).all? do |type|
32
+ %w(uid gid).all? do |type|
33
33
  begin
34
- File.readlines("/etc/sub#{type}").grep(/^root:#{Process.send(type)}:[1-9]/).any?
34
+ id = Process.send(type)
35
+ id_map = File.readlines("/etc/sub#{type}")
36
+ id_in_sub_id?(id, id_map)
35
37
  rescue StandardError => e
36
38
  logger.warn "Cannot read subordinate permissions file: #{e.message}"
37
39
  false
38
40
  end
39
41
  end
40
42
  end
43
+
44
+ # Determines whether the given numerical `id` is included in the
45
+ # subordinate map `id_map`, which should be an array of lines from
46
+ # the file /etc/subuid or /etc/subgid.
47
+ #
48
+ # Invalid lines, and any lines for a user or group other than root,
49
+ # are ignored. See subuid(5) and subgid(5) for details about these
50
+ # files, and the expected format of their entries.
51
+ def Capability.id_in_sub_id?(id, id_map)
52
+ id_map.any? do |line|
53
+ if line.match(/^(root|0):(\d+):(\d+)/)
54
+ range_min = $2.to_i
55
+ range_max = range_min + $3.to_i
56
+ id.between?(range_min, range_max)
57
+ end
58
+ end
59
+ end
41
60
  end
42
61
  end
@@ -26,6 +26,7 @@ module VagrantLXD
26
26
  attr_accessor :name
27
27
  attr_accessor :timeout
28
28
  attr_accessor :config
29
+ attr_accessor :devices
29
30
  attr_accessor :environment
30
31
  attr_accessor :ephemeral
31
32
  attr_accessor :nesting
@@ -40,6 +41,7 @@ module VagrantLXD
40
41
  @name = UNSET_VALUE
41
42
  @timeout = UNSET_VALUE
42
43
  @config = UNSET_VALUE
44
+ @devices = UNSET_VALUE
43
45
  @environment = UNSET_VALUE
44
46
  @nesting = UNSET_VALUE
45
47
  @privileged = UNSET_VALUE
@@ -74,15 +76,27 @@ module VagrantLXD
74
76
  if not config.is_a? Hash
75
77
  errors << "Invalid `config' (value must be a hash): #{config.inspect}"
76
78
  elsif not config.keys.all? { |x| x.is_a? Symbol }
77
- errors << "Invalid `config' (hash keys must be symbols): #{config.inspect}"
79
+ errors << "Invalid `config' (keys must be symbols): #{config.inspect}"
80
+ end
81
+
82
+ if not devices.is_a? Hash
83
+ errors << "Invalid `devices' (value must be a hash): #{devices.inspect}"
84
+ elsif not devices.keys.all? { |x| x.is_a? String or x.is_a? Symbol }
85
+ errors << "Invalid `devices' (keys must be strings or symbols): #{devices.inspect}"
86
+ elsif devices.keys.any? { |x| x =~ /^(.*([^a-z0-9.\-_]).*)$/ }
87
+ errors << "Invalid `devices' (device name `#{$1}' contains invalid character '#{$2}'): #{devices.inspect}"
88
+ elsif not devices.values.all? { |x| x.is_a? Hash }
89
+ errors << "Invalid `devices' (values must be hashes): #{devices.inspect}"
90
+ elsif not devices.values.map(&:values).flatten.all? { |x| x.is_a? String }
91
+ errors << "Invalid `devices' (device value must be strings): #{devices.inspect}"
78
92
  end
79
93
 
80
94
  if not environment.is_a? Hash
81
95
  errors << "Invalid `environment' (value must be a hash): #{environment.inspect}"
82
96
  elsif not environment.keys.all? { |x| x.is_a? String or x.is_a? Symbol }
83
- errors << "Invalid `environment' (hash keys must be strings or symbols): #{environment.inspect}"
97
+ errors << "Invalid `environment' (keys must be strings or symbols): #{environment.inspect}"
84
98
  elsif not environment.values.all? { |x| x.is_a? String }
85
- errors << "Invalid `environment' (hash values must be strings): #{environment.inspect}"
99
+ errors << "Invalid `environment' (values must be strings): #{environment.inspect}"
86
100
  end
87
101
 
88
102
  begin
@@ -151,6 +165,10 @@ module VagrantLXD
151
165
  @config = {}
152
166
  end
153
167
 
168
+ if devices == UNSET_VALUE
169
+ @devices = {}
170
+ end
171
+
154
172
  if environment == UNSET_VALUE
155
173
  @environment = {}
156
174
  end
@@ -18,11 +18,14 @@
18
18
  #
19
19
 
20
20
  require 'active_support/core_ext/object/deep_dup'
21
+ require 'active_support/core_ext/hash/except'
21
22
  require 'hyperkit'
23
+ require 'json'
24
+ require 'monitor'
22
25
  require 'securerandom'
23
26
  require 'tempfile'
24
27
  require 'timeout'
25
- require 'monitor'
28
+ require 'yaml'
26
29
  require 'vagrant/machine_state'
27
30
  require 'vagrant-lxd/driver/certificate'
28
31
 
@@ -68,6 +71,10 @@ module VagrantLXD
68
71
  error_key 'lxd_image_creation_failure'
69
72
  end
70
73
 
74
+ class ImageExportFailure < Vagrant::Errors::VagrantError
75
+ error_key 'lxd_image_export_failure'
76
+ end
77
+
71
78
  class ContainerNotFound < Vagrant::Errors::VagrantError
72
79
  error_key 'lxd_container_not_found'
73
80
  end
@@ -112,11 +119,21 @@ module VagrantLXD
112
119
  end
113
120
  end
114
121
 
122
+ module Hyperkit::Client::Containers
123
+ alias extract_container_options_without_devices extract_container_options
124
+
125
+ def extract_container_options(name, options)
126
+ opts = extract_container_options_without_devices(name, options)
127
+ options.slice(:devices).merge(opts)
128
+ end
129
+ end
130
+
115
131
  NOT_CREATED = Vagrant::MachineState::NOT_CREATED_ID
116
132
 
117
133
  attr_reader :api_endpoint
118
134
  attr_reader :name
119
135
  attr_reader :timeout
136
+ attr_reader :devices
120
137
  attr_reader :environment
121
138
  attr_reader :ephemeral
122
139
  attr_reader :nesting
@@ -131,7 +148,8 @@ module VagrantLXD
131
148
  @machine = machine
132
149
  @timeout = machine.provider_config.timeout
133
150
  @api_endpoint = machine.provider_config.api_endpoint
134
- @config = @machine.provider_config.config
151
+ @config = machine.provider_config.config
152
+ @devices = machine.provider_config.devices
135
153
  @environment = machine.provider_config.environment
136
154
  @nesting = machine.provider_config.nesting
137
155
  @privileged = machine.provider_config.privileged
@@ -155,8 +173,8 @@ module VagrantLXD
155
173
  raw_idmap = container[:config][:'raw.idmap']
156
174
  begin
157
175
  raw_idmap and
158
- raw_idmap =~ /^uid #{Process.uid} #{vagrant_uid}$/ and
159
- raw_idmap =~ /^gid #{Process.gid} #{vagrant_gid}$/
176
+ id_in_map?(Process.uid, 'uid', raw_idmap) and
177
+ id_in_map?(Process.gid, 'gid', raw_idmap)
160
178
  end
161
179
  rescue Vagrant::Errors::ProviderNotUsable
162
180
  false
@@ -187,9 +205,7 @@ module VagrantLXD
187
205
 
188
206
  def unmount(name, options)
189
207
  container = lxd.container(machine_id)
190
- devices = container[:devices].to_hash
191
- devices.delete(name.to_sym)
192
- container[:devices] = devices
208
+ container[:devices] = container[:devices].to_hash.except(name.to_sym)
193
209
  lxd.update_container(machine_id, container)
194
210
  rescue Hyperkit::BadRequest => e
195
211
  @machine.ui.error 'Failed to unmount synced folder'
@@ -271,7 +287,7 @@ module VagrantLXD
271
287
  end
272
288
  end
273
289
 
274
- container = lxd.create_container(machine_id, ephemeral: ephemeral, fingerprint: fingerprint, config: config, profiles: profiles)
290
+ container = lxd.create_container(machine_id, devices: devices, ephemeral: ephemeral, fingerprint: fingerprint, config: config, profiles: profiles)
275
291
  @logger.debug 'Created container: ' << container.inspect
276
292
 
277
293
  @machine.id = machine_id
@@ -331,15 +347,53 @@ module VagrantLXD
331
347
  end
332
348
  end
333
349
 
350
+ def package
351
+ if in_state? :stopped
352
+ create_package_directory
353
+ else
354
+ @logger.debug "Skipped packaging (#{machine_id} is not stopped)"
355
+ end
356
+ end
357
+
334
358
  def configure
335
359
  container = lxd.container(machine_id)
336
360
  container[:config] = container[:config].to_hash.merge(config)
361
+ container[:devices] = container[:devices].to_hash.merge(devices)
337
362
  lxd.update_container(machine_id, container)
338
363
  rescue Hyperkit::Error => e
339
364
  @machine.ui.error 'Failed to configure container'
340
365
  fail ContainerConfigurationFailure, machine_name: @machine.name, reason: e.reason
341
366
  end
342
367
 
368
+ # When a container is restarted, the `forkproxy` processes that manage
369
+ # its proxy devices will persist but will not reliably recreate
370
+ # container-side listeners for devices that are configured with
371
+ # "bind=container". Removing and re-creating the devices forces the
372
+ # proxy processes to be recreated, ensuring the listeners are as well.
373
+ def reconnect
374
+ # select proxy devices
375
+ container = lxd.container(machine_id)
376
+ devices = container[:devices].to_hash
377
+ proxies = devices.select { |_, d| d[:type] == 'proxy' }
378
+
379
+ # bail if there's nothing to do
380
+ return if proxies.empty?
381
+
382
+ # TODO move messaging into a dedicated action
383
+ @machine.ui.info 'Reconnecting proxy devices...'
384
+
385
+ # remove proxy devices
386
+ container[:devices] = devices.except(*proxies.keys)
387
+ lxd.update_container(machine_id, container)
388
+
389
+ # restore all devices (including proxies)
390
+ container[:devices] = devices.merge(proxies)
391
+ lxd.update_container(machine_id, container)
392
+ rescue Hyperkit::Error => e
393
+ @machine.ui.error 'Failed to connect proxy devices'
394
+ fail ContainerConfigurationFailure, machine_name: @machine.name, reason: e.reason
395
+ end
396
+
343
397
  def info
344
398
  if in_state? :running, :frozen
345
399
  {
@@ -349,7 +403,7 @@ module VagrantLXD
349
403
  end
350
404
  end
351
405
 
352
- private
406
+ private
353
407
 
354
408
  #
355
409
  # The remaining methods are just conveniences, not part of the API
@@ -496,6 +550,24 @@ module VagrantLXD
496
550
  config
497
551
  end
498
552
 
553
+ # Determines whether the numerical `id` of the specified `type` is
554
+ # included in the given idmap. These values should follow the format
555
+ # of the "raw.idmap" property specified here:
556
+ #
557
+ # https://lxd.readthedocs.io/en/latest/userns-idmap/#custom-idmaps
558
+ #
559
+ def id_in_map?(id, type, map)
560
+ range_types = ['both', type]
561
+ map.each_line.any? do |line|
562
+ range_type, range_values = line.split
563
+ range = range_values.split('-')
564
+ begin
565
+ range_types.include?(range_type) and
566
+ id.between?(range.first.to_i, range.last.to_i)
567
+ end
568
+ end
569
+ end
570
+
499
571
  def locate_or_generate_client_certificate
500
572
  vagrant_path = @machine.env.data_dir / 'lxd'
501
573
  default_path = Certificate.default_path / 'lxc'
@@ -515,11 +587,13 @@ module VagrantLXD
515
587
  lxc_dir = @machine.box.directory
516
588
  lxc_rootfs = lxc_dir / 'rootfs.tar.gz'
517
589
  lxc_fingerprint = Digest::SHA256.file(lxc_rootfs).hexdigest
590
+ lxc_metadata = JSON.load(File.read(lxc_dir / 'metadata.json'))
518
591
 
519
592
  lxd_dir = @machine.box.directory / '..' / 'lxd'
520
593
  lxd_rootfs = lxd_dir / 'rootfs.tar.gz'
521
594
  lxd_metadata = YAML.load(File.read(lxd_dir / 'metadata.yaml')) rescue nil
522
595
 
596
+ # TODO move messaging into a dedicated action
523
597
  if lxd_rootfs.exist? and lxd_metadata.is_a? Hash and lxd_metadata['source_fingerprint'] == lxc_fingerprint
524
598
  @machine.ui.info 'Importing LXC image...'
525
599
  else
@@ -528,6 +602,10 @@ module VagrantLXD
528
602
  SafeChdir.safe_chdir(tmpdir) do
529
603
  FileUtils.cp(lxc_rootfs, tmpdir)
530
604
 
605
+ File.open('metadata.json', 'w') do |metadata|
606
+ metadata.puts JSON.pretty_generate(lxc_metadata.merge('provider' => 'lxd'))
607
+ end
608
+
531
609
  File.open('metadata.yaml', 'w') do |metadata|
532
610
  metadata.puts 'architecture: ' << `uname -m`.strip
533
611
  metadata.puts 'creation_date: ' << Time.now.strftime('%s')
@@ -541,6 +619,7 @@ module VagrantLXD
541
619
  FileUtils.mkdir_p(lxd_dir)
542
620
  FileUtils.mv('rootfs.tar.gz', lxd_dir)
543
621
  FileUtils.mv('metadata.yaml', lxd_dir)
622
+ FileUtils.mv('metadata.json', lxd_dir)
544
623
  end
545
624
  end
546
625
 
@@ -553,6 +632,42 @@ module VagrantLXD
553
632
  FileUtils.rm_rf(tmpdir)
554
633
  end
555
634
 
635
+ # TODO s.a.
636
+ def create_package_directory
637
+ package_directory = Dir.mktmpdir
638
+
639
+ image = begin
640
+ lxd.create_image_from_container(machine_id, IMAGE_PROPERTIES)
641
+ rescue Hyperkit::BadRequest => e
642
+ if e.reason =~ /The image already exists: (\h{64})/
643
+ {
644
+ metadata: { fingerprint: $1 }
645
+ }
646
+ else
647
+ fail ImageExportFailure, machine_name: @machine.name, reason: e.reason
648
+ end
649
+ end
650
+
651
+ lxd.export_image(image[:metadata][:fingerprint], package_directory, filename: 'rootfs.tar.gz')
652
+
653
+ File.open(File.join(package_directory, 'metadata.json'), 'w') do |metadata|
654
+ metadata.puts JSON.pretty_generate({
655
+ 'provider' => 'lxc',
656
+ 'version' => '1.0.0',
657
+ 'built-on' => Time.now.strftime("%a %m %d %H:%M:%S %z %Y"),
658
+ })
659
+ end
660
+ rescue Exception => e
661
+ @machine.ui.error 'Failed to export container image'
662
+ @logger.error 'Error preparing container image: ' << e.message << "\n" << e.backtrace.join("\n")
663
+ fail ImageExportFailure, machine_name: @machine.name, reason: e.message
664
+ else
665
+ package_directory
666
+ ensure
667
+ # If the image was created just for this package, remove it.
668
+ lxd.delete_image(image[:metadata][:fingerprint]) rescue nil if image.is_a? Sawyer::Resource
669
+ end
670
+
556
671
  def error(klass)
557
672
  klass.new(
558
673
  provider: Version::NAME,
@@ -20,7 +20,7 @@
20
20
  module VagrantLXD
21
21
  module Version
22
22
  NAME = 'vagrant-lxd'
23
- VERSION = '0.4.0'
23
+ VERSION = '0.4.5'
24
24
  DESCRIPTION = 'Vagrant LXD provider'
25
25
  end
26
26
  end
@@ -134,6 +134,13 @@ en:
134
134
 
135
135
  https://gitlab.com/catalyst-it/vagrant-lxd/issues
136
136
 
137
+ lxd_image_export_failure: |-
138
+ The provider was unable to export a container image for '%{machine_name}'.
139
+
140
+ The underlying error message was: %{reason}
141
+
142
+ The LXD logs may contain more information about the cause of this failure.
143
+
137
144
  lxd_duplicate_attachment_failure: |-
138
145
  A machine can only be associated with one container at a time.
139
146
 
@@ -35,5 +35,10 @@ Gem::Specification.new do |spec|
35
35
  f.match(%r{^(test|spec|features)/})
36
36
  end
37
37
 
38
+ spec.add_runtime_dependency 'activesupport', '~> 5.2.3'
38
39
  spec.add_runtime_dependency 'hyperkit', '~> 1.2.0'
40
+
41
+ # NOTE fixed to preserve ruby 1.x compatibility, versions after 1.0
42
+ # use the safe navigation operator and thus need ruby 2.3 or newer
43
+ spec.add_runtime_dependency 'faraday', '~> 0.17'
39
44
  end
metadata CHANGED
@@ -1,15 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: vagrant-lxd
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.0
4
+ version: 0.4.5
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-03-29 00:00:00.000000000 Z
11
+ date: 2020-07-06 00:00:00.000000000 Z
12
12
  dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: activesupport
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: 5.2.3
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: 5.2.3
13
27
  - !ruby/object:Gem::Dependency
14
28
  name: hyperkit
15
29
  requirement: !ruby/object:Gem::Requirement
@@ -24,6 +38,20 @@ dependencies:
24
38
  - - "~>"
25
39
  - !ruby/object:Gem::Version
26
40
  version: 1.2.0
41
+ - !ruby/object:Gem::Dependency
42
+ name: faraday
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '0.17'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '0.17'
27
55
  description: A Vagrant plugin that allows management of containers using LXD.
28
56
  email:
29
57
  - evanh@catalyst.net.nz
@@ -71,8 +99,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
71
99
  - !ruby/object:Gem::Version
72
100
  version: '0'
73
101
  requirements: []
74
- rubyforge_project:
75
- rubygems_version: 2.6.8
102
+ rubygems_version: 3.0.3
76
103
  signing_key:
77
104
  specification_version: 4
78
105
  summary: Vagrant LXD provider