vagrant-lxc-2.1-patch 1.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.
Files changed (64) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +31 -0
  3. data/.rspec +2 -0
  4. data/.travis.yml +10 -0
  5. data/.vimrc +1 -0
  6. data/BOXES.md +47 -0
  7. data/CHANGELOG.md +510 -0
  8. data/CONTRIBUTING.md +24 -0
  9. data/Gemfile +24 -0
  10. data/Guardfile +7 -0
  11. data/LICENSE.txt +22 -0
  12. data/README.md +187 -0
  13. data/Rakefile +3 -0
  14. data/lib/vagrant-lxc.rb +10 -0
  15. data/lib/vagrant-lxc/action.rb +234 -0
  16. data/lib/vagrant-lxc/action/boot.rb +42 -0
  17. data/lib/vagrant-lxc/action/clear_forwarded_ports.rb +56 -0
  18. data/lib/vagrant-lxc/action/compress_rootfs.rb +30 -0
  19. data/lib/vagrant-lxc/action/create.rb +57 -0
  20. data/lib/vagrant-lxc/action/destroy.rb +18 -0
  21. data/lib/vagrant-lxc/action/destroy_confirm.rb +17 -0
  22. data/lib/vagrant-lxc/action/fetch_ip_with_lxc_info.rb +43 -0
  23. data/lib/vagrant-lxc/action/forced_halt.rb +20 -0
  24. data/lib/vagrant-lxc/action/forward_ports.rb +121 -0
  25. data/lib/vagrant-lxc/action/gc_private_network_bridges.rb +47 -0
  26. data/lib/vagrant-lxc/action/handle_box_metadata.rb +94 -0
  27. data/lib/vagrant-lxc/action/prepare_nfs_settings.rb +64 -0
  28. data/lib/vagrant-lxc/action/prepare_nfs_valid_ids.rb +19 -0
  29. data/lib/vagrant-lxc/action/private_networks.rb +46 -0
  30. data/lib/vagrant-lxc/action/setup_package_files.rb +60 -0
  31. data/lib/vagrant-lxc/action/warn_networks.rb +25 -0
  32. data/lib/vagrant-lxc/command/root.rb +58 -0
  33. data/lib/vagrant-lxc/command/sudoers.rb +97 -0
  34. data/lib/vagrant-lxc/config.rb +73 -0
  35. data/lib/vagrant-lxc/driver.rb +288 -0
  36. data/lib/vagrant-lxc/driver/cli.rb +166 -0
  37. data/lib/vagrant-lxc/errors.rb +62 -0
  38. data/lib/vagrant-lxc/plugin.rb +51 -0
  39. data/lib/vagrant-lxc/provider.rb +101 -0
  40. data/lib/vagrant-lxc/provider/cap/public_address.rb +17 -0
  41. data/lib/vagrant-lxc/sudo_wrapper.rb +104 -0
  42. data/lib/vagrant-lxc/synced_folder.rb +72 -0
  43. data/lib/vagrant-lxc/version.rb +5 -0
  44. data/locales/en.yml +82 -0
  45. data/scripts/lxc-template +171 -0
  46. data/scripts/pipework +422 -0
  47. data/spec/Vagrantfile +26 -0
  48. data/spec/fixtures/sample-ip-addr-output +2 -0
  49. data/spec/spec_helper.rb +35 -0
  50. data/spec/support/.gitkeep +0 -0
  51. data/spec/unit/action/clear_forwarded_ports_spec.rb +43 -0
  52. data/spec/unit/action/compress_rootfs_spec.rb +29 -0
  53. data/spec/unit/action/forward_ports_spec.rb +117 -0
  54. data/spec/unit/action/handle_box_metadata_spec.rb +126 -0
  55. data/spec/unit/action/setup_package_files_spec.rb +83 -0
  56. data/spec/unit/driver/cli_spec.rb +263 -0
  57. data/spec/unit/driver_spec.rb +268 -0
  58. data/spec/unit/support/unit_example_group.rb +38 -0
  59. data/spec/unit_helper.rb +17 -0
  60. data/tasks/spec.rake +40 -0
  61. data/templates/sudoers.rb.erb +129 -0
  62. data/vagrant-lxc.gemspec +20 -0
  63. data/vagrant-spec.config.rb +24 -0
  64. metadata +119 -0
@@ -0,0 +1,263 @@
1
+ require 'unit_helper'
2
+
3
+ require 'vagrant-lxc/sudo_wrapper'
4
+ require 'vagrant-lxc/driver/cli'
5
+
6
+ describe Vagrant::LXC::Driver::CLI do
7
+ let(:sudo_wrapper) { double(Vagrant::LXC::SudoWrapper, run: true, wrapper_path: nil) }
8
+
9
+ subject { described_class.new(sudo_wrapper) }
10
+
11
+ describe 'list' do
12
+ let(:lxc_ls_out) { "dup-container\na-container dup-container" }
13
+ let(:result) { @result }
14
+
15
+ before do
16
+ allow(subject).to receive(:run).with(:ls).and_return(lxc_ls_out)
17
+ @result = subject.list
18
+ end
19
+
20
+ it 'grabs previously created containers from lxc-ls output' do
21
+ expect(result).to be_an Enumerable
22
+ expect(result).to include 'a-container'
23
+ expect(result).to include 'dup-container'
24
+ end
25
+
26
+ it 'removes duplicates from lxc-ls output' do
27
+ expect(result.uniq).to eq(result)
28
+ end
29
+ end
30
+
31
+ describe 'version' do
32
+ before do
33
+ allow(subject).to receive(:run).with(:create, '--version').and_return(lxc_version_out)
34
+ end
35
+
36
+ describe 'lxc version after 1.x.x' do
37
+ let(:lxc_version_out) { "1.0.0\n" }
38
+
39
+ it 'parses the version from the output' do
40
+ expect(subject.version).to eq('1.0.0')
41
+ end
42
+ end
43
+ end
44
+
45
+ describe 'config' do
46
+ before do
47
+ allow(subject).to receive(:run).with(:config, 'lxc.lxcpath').and_return(lxc_config_out)
48
+ allow(subject).to receive(:run).with(:create, '--version').and_return(lxc_version_out)
49
+ end
50
+
51
+ describe 'lxc version after 1.x.x'do
52
+ let(:lxc_config_out) { "/var/lib/lxc\n" }
53
+ let(:lxc_version_out) { "1.0.0\n" }
54
+
55
+ it 'parser the lxc.lxcpath value' do
56
+ expect(subject.config('lxc.lxcpath')).not_to end_with("\n")
57
+ end
58
+ end
59
+ end
60
+
61
+ describe 'create' do
62
+ let(:template) { 'quantal-64' }
63
+ let(:name) { 'quantal-container' }
64
+ let(:backingstore) { 'btrfs' }
65
+ let(:backingstore_opts) { [['--dir', '/tmp/foo'], ['--foo', 'bar']] }
66
+ let(:config_file) { 'config' }
67
+ let(:template_args) { { '--extra-param' => 'param', '--other' => 'value' } }
68
+
69
+ subject { described_class.new(sudo_wrapper, name) }
70
+
71
+ before do
72
+ allow(subject).to receive(:run) { |*args| @run_args = args }
73
+ end
74
+
75
+ it 'issues a lxc-create with provided template, container name and hash of arguments' do
76
+ subject.create(template, backingstore, backingstore_opts, config_file, template_args)
77
+ expect(subject).to have_received(:run).with(
78
+ :create,
79
+ '-B', backingstore,
80
+ '--template', template,
81
+ '--name', name,
82
+ *(backingstore_opts.flatten),
83
+ '-f', config_file,
84
+ '--',
85
+ '--extra-param', 'param',
86
+ '--other', 'value'
87
+ )
88
+ end
89
+
90
+ it 'wraps a low level error into something more meaningful in case the container already exists' do
91
+ allow(subject).to receive(:run) { raise Vagrant::LXC::Errors::ExecuteError, stderr: 'alreAdy Exists' }
92
+ expect {
93
+ subject.create(template, backingstore, backingstore_opts, config_file, template_args)
94
+ }.to raise_error(Vagrant::LXC::Errors::ContainerAlreadyExists)
95
+ end
96
+ end
97
+
98
+ describe 'destroy' do
99
+ let(:name) { 'a-container-for-destruction' }
100
+
101
+ subject { described_class.new(sudo_wrapper, name) }
102
+
103
+ before do
104
+ allow(subject).to receive(:run)
105
+ subject.destroy
106
+ end
107
+
108
+ it 'issues a lxc-destroy with container name' do
109
+ expect(subject).to have_received(:run).with(:destroy, '--name', name)
110
+ end
111
+ end
112
+
113
+ describe 'start' do
114
+ let(:name) { 'a-container' }
115
+ subject { described_class.new(sudo_wrapper, name) }
116
+
117
+ before do
118
+ allow(subject).to receive(:run)
119
+ end
120
+
121
+ it 'starts container on the background' do
122
+ subject.start
123
+ expect(subject).to have_received(:run).with(
124
+ :start,
125
+ '-d',
126
+ '--name', name
127
+ )
128
+ end
129
+ end
130
+
131
+ describe 'stop' do
132
+ let(:name) { 'a-running-container' }
133
+ subject { described_class.new(sudo_wrapper, name) }
134
+
135
+ before do
136
+ allow(subject).to receive(:run)
137
+ end
138
+
139
+ context 'lxc-attach is supported' do
140
+ before do
141
+ subject.stub(attach: true, supports_attach?: true)
142
+ subject.stop
143
+ end
144
+
145
+ it 'runs a /sbin/halt within the container' do
146
+ expect(subject).to have_received(:attach).with('/sbin/halt')
147
+ end
148
+
149
+ it 'issues a lxc-stop with provided container name' do
150
+ expect(subject).to have_received(:run).with(:stop, '--name', name)
151
+ end
152
+ end
153
+
154
+ context 'lxc-attach is not supported' do
155
+ before do
156
+ subject.stub(attach: false, supports_attach?: false)
157
+ subject.stop
158
+ end
159
+
160
+ it 'runs a /sbin/halt within the container' do
161
+ expect(subject).to_not have_received(:attach)
162
+ end
163
+
164
+ it 'issues a lxc-stop with provided container name' do
165
+ expect(subject).to have_received(:run).with(:stop, '--name', name)
166
+ end
167
+ end
168
+ end
169
+
170
+ describe 'state' do
171
+ let(:name) { 'a-container' }
172
+ subject { described_class.new(sudo_wrapper, name) }
173
+
174
+ before do
175
+ allow(subject).to receive(:run).and_return("state: STOPPED\npid: 2")
176
+ end
177
+
178
+ it 'calls lxc-info with the right arguments' do
179
+ subject.state
180
+ expect(subject).to have_received(:run).with(:info, '--name', name, retryable: true)
181
+ end
182
+
183
+ it 'maps the output of lxc-info status out to a symbol' do
184
+ expect(subject.state).to eq(:stopped)
185
+ end
186
+
187
+ it 'is not case sensitive' do
188
+ allow(subject).to receive(:run).and_return("StatE: STarTED\npid: 2")
189
+ expect(subject.state).to eq(:started)
190
+ end
191
+ end
192
+
193
+ describe 'attach' do
194
+ let(:name) { 'a-running-container' }
195
+ let(:command) { ['ls', 'cat /tmp/file'] }
196
+ let(:command_output) { 'folders list' }
197
+ subject { described_class.new(sudo_wrapper, name) }
198
+
199
+ before do
200
+ subject.stub(run: command_output)
201
+ end
202
+
203
+ it 'calls lxc-attach with specified command' do
204
+ subject.attach(*command)
205
+ expect(subject).to have_received(:run).with(:attach, '--name', name, '--', *command)
206
+ end
207
+
208
+ it 'supports a "namespaces" parameter' do
209
+ allow(subject).to receive(:run).with(:attach, '-h', :show_stderr => true).and_return({:stdout => '', :stderr => '--namespaces'})
210
+ subject.attach *(command + [{namespaces: ['network', 'mount']}])
211
+ expect(subject).to have_received(:run).with(:attach, '--name', name, '--namespaces', 'NETWORK|MOUNT', '--', *command)
212
+ end
213
+ end
214
+
215
+ describe 'transition block' do
216
+ before do
217
+ subject.stub(run: true, sleep: true, state: :stopped)
218
+ end
219
+
220
+ it 'yields a cli object' do
221
+ allow(subject).to receive(:shutdown)
222
+ subject.transition_to(:stopped) { |c| c.shutdown }
223
+ expect(subject).to have_received(:shutdown)
224
+ end
225
+
226
+ it 'throws an exception if block is not provided' do
227
+ expect {
228
+ subject.transition_to(:running)
229
+ }.to raise_error(described_class::TransitionBlockNotProvided)
230
+ end
231
+
232
+ skip 'waits for the expected container state'
233
+ end
234
+
235
+ describe 'check for whether lxc-attach is supported' do
236
+ let(:name) { 'a-running-container' }
237
+ subject { described_class.new(sudo_wrapper, name) }
238
+
239
+ context 'lxc-attach is present on system' do
240
+ before { subject.stub(run: true) }
241
+
242
+ it 'returns true if `lxc-attach --name CNAME -- /bin/true` works' do
243
+ expect(subject.supports_attach?).to be_truthy
244
+ expect(subject).to have_received(:run).with(
245
+ :attach, '--name', name, '--', '/bin/true'
246
+ )
247
+ end
248
+ end
249
+
250
+ context 'lxc-attach is not present on system' do
251
+ before do
252
+ allow(subject).to receive(:run).and_raise(Vagrant::LXC::Errors::ExecuteError.new('msg'))
253
+ end
254
+
255
+ it 'returns true if `lxc-attach --name CNAME -- /bin/true` works' do
256
+ expect(subject.supports_attach?).to be_falsy
257
+ expect(subject).to have_received(:run).with(
258
+ :attach, '--name', name, '--', '/bin/true'
259
+ )
260
+ end
261
+ end
262
+ end
263
+ end
@@ -0,0 +1,268 @@
1
+ require 'unit_helper'
2
+
3
+ require 'vagrant-lxc/driver'
4
+ require 'vagrant-lxc/driver/cli'
5
+ require 'vagrant-lxc/sudo_wrapper'
6
+
7
+ describe Vagrant::LXC::Driver do
8
+ describe 'container name validation' do
9
+ let(:unknown_container) { described_class.new('unknown', nil, cli) }
10
+ let(:valid_container) { described_class.new('valid', nil, cli) }
11
+ let(:new_container) { described_class.new(nil, nil) }
12
+ let(:cli) { double(Vagrant::LXC::Driver::CLI, list: ['valid']) }
13
+
14
+ it 'raises a ContainerNotFound error if an unknown container name gets provided' do
15
+ expect {
16
+ unknown_container.validate!
17
+ }.to raise_error
18
+ end
19
+
20
+ it 'does not raise a ContainerNotFound error if a valid container name gets provided' do
21
+ expect {
22
+ valid_container.validate!
23
+ }.not_to raise_error
24
+ end
25
+
26
+ it 'does not raise a ContainerNotFound error if nil is provider as name' do
27
+ expect {
28
+ new_container.validate!
29
+ }.not_to raise_error
30
+ end
31
+ end
32
+
33
+ describe 'creation' do
34
+ let(:name) { 'container-name' }
35
+ let(:backingstore) { 'btrfs' }
36
+ let(:backingstore_opts) { [['--dir', '/tmp/foo'], ['--foo', 'bar']] }
37
+ let(:template_name) { 'auto-assigned-template-id' }
38
+ let(:template_path) { '/path/to/lxc-template-from-box' }
39
+ let(:template_opts) { {'--some' => 'random-option'} }
40
+ let(:config_file) { '/path/to/lxc-config-from-box' }
41
+ let(:rootfs_tarball) { '/path/to/cache/rootfs.tar.gz' }
42
+ let(:cli) { double(Vagrant::LXC::Driver::CLI, :create => true, :name= => true) }
43
+
44
+ subject { described_class.new(nil, nil, cli) }
45
+
46
+ before do
47
+ allow(subject).to receive(:import_template).and_yield(template_name)
48
+ subject.create name, backingstore, backingstore_opts, template_path, config_file, template_opts
49
+ end
50
+
51
+ it 'sets the cli object container name' do
52
+ expect(cli).to have_received(:name=).with(name)
53
+ end
54
+
55
+ it 'creates container with the right arguments' do
56
+ expect(cli).to have_received(:create).with(
57
+ template_path,
58
+ backingstore,
59
+ backingstore_opts,
60
+ config_file,
61
+ template_opts
62
+ )
63
+ end
64
+ end
65
+
66
+ describe 'destruction' do
67
+ let(:cli) { double(Vagrant::LXC::Driver::CLI, destroy: true) }
68
+
69
+ subject { described_class.new('name', nil, cli) }
70
+
71
+ before { subject.destroy }
72
+
73
+ it 'delegates to cli object' do
74
+ expect(cli).to have_received(:destroy)
75
+ end
76
+ end
77
+
78
+ describe 'supports_attach?' do
79
+ let(:cli) { double(Vagrant::LXC::Driver::CLI, supports_attach?: true) }
80
+
81
+ subject { described_class.new('name', nil, cli) }
82
+
83
+ it 'delegates to cli object' do
84
+ expect(subject.supports_attach?).to be_truthy
85
+ expect(cli).to have_received(:supports_attach?)
86
+ end
87
+ end
88
+
89
+ describe 'start' do
90
+ let(:customizations) { [['a', '1'], ['b', '2']] }
91
+ let(:internal_customization) { ['internal', 'customization'] }
92
+ let(:cli) { double(Vagrant::LXC::Driver::CLI, start: true) }
93
+ let(:sudo) { double(Vagrant::LXC::SudoWrapper) }
94
+
95
+ subject { described_class.new('name', sudo, cli) }
96
+
97
+ before do
98
+ sudo.should_receive(:run).with('cat', '/var/lib/lxc/name/config').exactly(2).times.
99
+ and_return('# CONFIGURATION')
100
+ sudo.should_receive(:run).twice.with('cp', '-f', %r{/(run|tmp)/.*}, '/var/lib/lxc/name/config')
101
+ sudo.should_receive(:run).twice.with('chown', 'root:root', '/var/lib/lxc/name/config')
102
+ expect(cli).to receive(:config).with("lxc.lxcpath").and_return("/var/lib/lxc")
103
+
104
+ subject.customizations << internal_customization
105
+ subject.start(customizations)
106
+ end
107
+
108
+ it 'prunes previous customizations before writing'
109
+
110
+ it 'writes configurations to config file'
111
+
112
+ it 'starts container with configured customizations' do
113
+ expect(cli).to have_received(:start)
114
+ end
115
+ end
116
+
117
+ describe 'halt' do
118
+ let(:cli) { double(Vagrant::LXC::Driver::CLI, stop: true) }
119
+
120
+ subject { described_class.new('name', nil, cli) }
121
+
122
+ before do
123
+ allow(cli).to receive(:transition_to).and_yield(cli)
124
+ end
125
+
126
+ it 'delegates to cli stop' do
127
+ expect(cli).to receive(:stop)
128
+ subject.forced_halt
129
+ end
130
+
131
+ it 'expects a transition to running state to take place' do
132
+ expect(cli).to receive(:transition_to).with(:stopped)
133
+ subject.forced_halt
134
+ end
135
+
136
+ it 'attempts to force the container to stop in case a shutdown doesnt work' do
137
+ allow(cli).to receive(:shutdown).and_raise(Vagrant::LXC::Driver::CLI::TargetStateNotReached.new :target, :source)
138
+ expect(cli).to receive(:transition_to).with(:stopped)
139
+ expect(cli).to receive(:stop)
140
+ subject.forced_halt
141
+ end
142
+ end
143
+
144
+ describe 'state' do
145
+ let(:cli_state) { :something }
146
+ let(:cli) { double(Vagrant::LXC::Driver::CLI, state: cli_state) }
147
+
148
+ subject { described_class.new('name', nil, cli) }
149
+
150
+ it 'delegates to cli' do
151
+ expect(subject.state).to eq(cli_state)
152
+ end
153
+ end
154
+
155
+ describe 'containers_path' do
156
+ let(:cli) { double(Vagrant::LXC::Driver::CLI, config: cli_config_value) }
157
+
158
+ subject { described_class.new('name', nil, cli) }
159
+
160
+ describe 'lxc version after 1.x.x' do
161
+ let(:cli_config_value) { '/etc/lxc' }
162
+
163
+ it 'delegates to cli' do
164
+ expect(subject.containers_path).to eq(cli_config_value)
165
+ end
166
+ end
167
+ end
168
+
169
+ describe 'folder sharing' do
170
+ let(:shared_folder) { {guestpath: '/vagrant', hostpath: '/path/to/host/dir'} }
171
+ let(:ro_rw_folder) { {guestpath: '/vagrant/ro_rw', hostpath: '/path/to/host/dir', mount_options: ['ro', 'rw']} }
172
+ let(:with_space_folder) { {guestpath: '/tmp/with space', hostpath: '/path/with space'} }
173
+ let(:folders) { [shared_folder, ro_rw_folder, with_space_folder] }
174
+ let(:expected_guest_path) { "vagrant" }
175
+ let(:sudo_wrapper) { double(Vagrant::LXC::SudoWrapper, run: true) }
176
+ let(:rootfs_path) { Pathname('/path/to/rootfs') }
177
+
178
+ subject { described_class.new('name', sudo_wrapper) }
179
+
180
+ describe "with fixed rootfs" do
181
+ before do
182
+ subject.stub(rootfs_path: Pathname('/path/to/rootfs'), system: true)
183
+ subject.share_folders(folders)
184
+ end
185
+
186
+ it 'adds a mount.entry to its local customizations' do
187
+ expect(subject.customizations).to include [
188
+ 'mount.entry',
189
+ "#{shared_folder[:hostpath]} #{expected_guest_path} none bind,create=dir 0 0"
190
+ ]
191
+ end
192
+
193
+ it 'supports additional mount options' do
194
+ expect(subject.customizations).to include [
195
+ 'mount.entry',
196
+ "#{ro_rw_folder[:hostpath]} vagrant/ro_rw none ro,rw 0 0"
197
+ ]
198
+ end
199
+
200
+ it 'supports directories with spaces' do
201
+ expect(subject.customizations).to include [
202
+ 'mount.entry',
203
+ "/path/with\\040space tmp/with\\040space none bind,create=dir 0 0"
204
+ ]
205
+ end
206
+ end
207
+
208
+ describe "with directory-based LXC config" do
209
+ let(:config_string) {
210
+ <<-ENDCONFIG.gsub(/^\s+/, '')
211
+ # Blah blah comment
212
+ lxc.mount.entry = proc proc proc nodev,noexec,nosuid 0 0
213
+ lxc.mount.entry = sysfs sys sysfs defaults 0 0
214
+ lxc.tty = 4
215
+ lxc.pts = 1024
216
+ lxc.rootfs = #{rootfs_path}
217
+ # VAGRANT-BEGIN
218
+ lxc.network.type=veth
219
+ lxc.network.name=eth1
220
+ # VAGRANT-END
221
+ ENDCONFIG
222
+ }
223
+
224
+ before do
225
+ subject { described_class.new('name', sudo_wrapper) }
226
+ subject.stub(config_string: config_string)
227
+ subject.share_folders(folders)
228
+ end
229
+
230
+ it 'adds a mount.entry to its local customizations' do
231
+ expect(subject.customizations).to include [
232
+ 'mount.entry',
233
+ "#{shared_folder[:hostpath]} #{expected_guest_path} none bind,create=dir 0 0"
234
+ ]
235
+ end
236
+ end
237
+
238
+ describe "with overlayfs-based LXC config" do
239
+ let(:config_string) {
240
+ <<-ENDCONFIG.gsub(/^\s+/, '')
241
+ # Blah blah comment
242
+ lxc.mount.entry = proc proc proc nodev,noexec,nosuid 0 0
243
+ lxc.mount.entry = sysfs sys sysfs defaults 0 0
244
+ lxc.tty = 4
245
+ lxc.pts = 1024
246
+ lxc.rootfs = overlayfs:/path/to/master/directory:#{rootfs_path}
247
+ # VAGRANT-BEGIN
248
+ lxc.network.type=veth
249
+ lxc.network.name=eth1
250
+ # VAGRANT-END
251
+ ENDCONFIG
252
+ }
253
+
254
+ before do
255
+ subject { described_class.new('name', sudo_wrapper) }
256
+ subject.stub(config_string: config_string)
257
+ subject.share_folders(folders)
258
+ end
259
+
260
+ it 'adds a mount.entry to its local customizations' do
261
+ expect(subject.customizations).to include [
262
+ 'mount.entry',
263
+ "#{shared_folder[:hostpath]} #{expected_guest_path} none bind,create=dir 0 0"
264
+ ]
265
+ end
266
+ end
267
+ end
268
+ end