vagrant-masonry 0.13.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 (55) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +3 -0
  3. data/.yardopts +6 -0
  4. data/CHANGELOG +190 -0
  5. data/Gemfile +16 -0
  6. data/LICENSE +15 -0
  7. data/README.md +129 -0
  8. data/docs/GettingStarted.markdown +175 -0
  9. data/examples/Vagrantfile +1 -0
  10. data/examples/roles.yaml +29 -0
  11. data/examples/vms.yaml +12 -0
  12. data/lib/config_builder.rb +24 -0
  13. data/lib/config_builder/action/load_extensions.rb +14 -0
  14. data/lib/config_builder/class_registry.rb +72 -0
  15. data/lib/config_builder/extension_handler.rb +22 -0
  16. data/lib/config_builder/filter.rb +6 -0
  17. data/lib/config_builder/filter/boxes.rb +22 -0
  18. data/lib/config_builder/filter/roles.rb +149 -0
  19. data/lib/config_builder/filter_stack.rb +37 -0
  20. data/lib/config_builder/loader.rb +23 -0
  21. data/lib/config_builder/loader/yaml.rb +44 -0
  22. data/lib/config_builder/loader/yaml_erb.rb +24 -0
  23. data/lib/config_builder/model.rb +67 -0
  24. data/lib/config_builder/model/base.rb +101 -0
  25. data/lib/config_builder/model/network/forwarded_port.rb +37 -0
  26. data/lib/config_builder/model/network/private_network.rb +15 -0
  27. data/lib/config_builder/model/provider/azure.rb +66 -0
  28. data/lib/config_builder/model/provider/libvirt.rb +108 -0
  29. data/lib/config_builder/model/provider/virtualbox.rb +35 -0
  30. data/lib/config_builder/model/provider/vmware.rb +40 -0
  31. data/lib/config_builder/model/provider/vmware_fusion.rb +8 -0
  32. data/lib/config_builder/model/provider/vmware_workstation.rb +8 -0
  33. data/lib/config_builder/model/provider/vsphere.rb +30 -0
  34. data/lib/config_builder/model/provisioner/file.rb +24 -0
  35. data/lib/config_builder/model/provisioner/puppet.rb +37 -0
  36. data/lib/config_builder/model/provisioner/puppet_server.rb +27 -0
  37. data/lib/config_builder/model/provisioner/shell.rb +27 -0
  38. data/lib/config_builder/model/root.rb +69 -0
  39. data/lib/config_builder/model/ssh.rb +110 -0
  40. data/lib/config_builder/model/synced_folder.rb +43 -0
  41. data/lib/config_builder/model/vm.rb +235 -0
  42. data/lib/config_builder/model/winrm.rb +56 -0
  43. data/lib/config_builder/model_delegator.rb +30 -0
  44. data/lib/config_builder/plugin.rb +15 -0
  45. data/lib/config_builder/runner.rb +33 -0
  46. data/lib/config_builder/version.rb +3 -0
  47. data/lib/vagrant-masonry.rb +1 -0
  48. data/spec/config_builder/filter/boxes_spec.rb +87 -0
  49. data/spec/config_builder/filter/roles_spec.rb +287 -0
  50. data/spec/config_builder/loader/yaml_spec.rb +76 -0
  51. data/spec/config_builder/model/provider/vmware_fusion_spec.rb +29 -0
  52. data/spec/spec_helper.rb +4 -0
  53. data/templates/locales/en.yml +11 -0
  54. data/vagrant-masonry.gemspec +24 -0
  55. metadata +128 -0
@@ -0,0 +1,56 @@
1
+ # Vagrant WinRM credential model.
2
+ #
3
+ # @see http://docs.vagrantup.com/v2/vagrantfile
4
+ class ConfigBuilder::Model::WinRM < ConfigBuilder::Model::Base
5
+ # @!attribute [rw] username
6
+ # @return [String] This sets the username that Vagrant will WinRM as by
7
+ # default. Providers are free to override this if they detect a more
8
+ # appropriate user. By default this is "vagrant," since that is what most
9
+ # public boxes are made as.
10
+ def_model_attribute :username
11
+
12
+ # @!attribute [rw] password
13
+ # @return [String] This sets a password that Vagrant will use to
14
+ # authenticate the WinRM user.
15
+ def_model_attribute :password
16
+
17
+ # @!attribute [rw] host
18
+ # @return [String] The hostname or IP to WinRM into. By default this is
19
+ # empty, because the provider usually figures this out for you.
20
+ def_model_attribute :host
21
+
22
+ # @!attribute [rw] port
23
+ # @return [Fixnum] The port to WinRM into. By default this is port 5985.
24
+ def_model_attribute :port
25
+
26
+ # @!attribute [rw] guest_port
27
+ # @return [Fixnum] The port on the guest that WinRM is running on.
28
+ # This is used by some providers to detect forwarded ports for WinRM.
29
+ # For example, if this is set to 5985 (the default), and Vagrant detects
30
+ # a forwarded port to port 5985 on the guest from port 4567 on the host,
31
+ # Vagrant will attempt to use port 4567 to talk to the guest if there is
32
+ # no other option.
33
+ def_model_attribute :guest_port
34
+
35
+ # @!attribute [rw] max_tries
36
+ # @return [Fixnum] Maximum number of retry attempts. By default this is 20.
37
+ def_model_attribute :max_tries
38
+
39
+ # @!attribute [rw] timeout
40
+ # @return [Fixnum] The timeout in seconds. By default this is 1800 seconds.
41
+ def_model_attribute :timeout
42
+
43
+ def to_proc
44
+ Proc.new do |global_config|
45
+ winrm = global_config.winrm
46
+
47
+ with_attr(:username) { |val| winrm.username = val }
48
+ with_attr(:password) { |val| winrm.password = val }
49
+ with_attr(:host) { |val| winrm.host = val }
50
+ with_attr(:guest) { |val| winrm.guest = val }
51
+ with_attr(:guest_port) { |val| winrm.guest_port = val }
52
+ with_attr(:max_tries) { |val| winrm.max_tries = val }
53
+ with_attr(:timeout) { |val| winrm.timeout = val }
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,30 @@
1
+ module ConfigBuilder
2
+ module ModelDelegator
3
+
4
+ def model_delegators
5
+ self.class.model_delegators
6
+ end
7
+
8
+ def eval_models(config)
9
+ model_delegators.each do |model|
10
+ meth = "eval_#{model}"
11
+ send(meth, config)
12
+ end
13
+ end
14
+
15
+ def self.included(klass)
16
+ klass.extend ClassMethods
17
+ end
18
+
19
+ module ClassMethods
20
+ def def_model_delegator(identifier)
21
+ def_model_attribute(identifier)
22
+ model_delegators << identifier
23
+ end
24
+
25
+ def model_delegators
26
+ (@models ||= [])
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,15 @@
1
+ require 'vagrant'
2
+
3
+ require 'config_builder/action/load_extensions'
4
+
5
+ module VagrantPlugins
6
+ module ConfigBuilder
7
+ class Plugin < Vagrant.plugin('2')
8
+ name "Generate Vagrant configuration from logic-less data sources"
9
+
10
+ action_hook('ConfigBuilder: load extensions', :environment_load) do |hook|
11
+ hook.prepend(::ConfigBuilder::Action::LoadExtensions)
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,33 @@
1
+ require 'config_builder/loader'
2
+ require 'config_builder/filter_stack'
3
+ require 'config_builder/model'
4
+ require 'config_builder/extension_handler'
5
+
6
+ module ConfigBuilder
7
+ class Runner
8
+
9
+ def run(identifier, method, value)
10
+ load_extensions
11
+
12
+ data = ConfigBuilder::Loader.generate(identifier, method, value)
13
+ filtered_data = run_filters(data)
14
+ model = generate_model(filtered_data)
15
+ end
16
+
17
+ private
18
+
19
+ def load_extensions
20
+ ext = ConfigBuilder::ExtensionHandler.new
21
+ ext.load_from_plugins
22
+ end
23
+
24
+ def run_filters(data)
25
+ stack = ConfigBuilder::FilterStack.new
26
+ stack.filter(data)
27
+ end
28
+
29
+ def generate_model(filtered_hash)
30
+ ConfigBuilder::Model.generate(filtered_hash)
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,3 @@
1
+ module ConfigBuilder
2
+ VERSION = '0.13.0'
3
+ end
@@ -0,0 +1 @@
1
+ require 'config_builder'
@@ -0,0 +1,87 @@
1
+ require 'spec_helper'
2
+
3
+ describe ConfigBuilder::Filter::Boxes do
4
+
5
+ def dup(o)
6
+ Marshal.load(Marshal.dump(o))
7
+ end
8
+
9
+ let(:boxes) do
10
+ {
11
+ 'first_box' => 'http://box_host/first_box.box',
12
+ 'second_box' => 'http://box_host/second_box.box',
13
+ 'third_box' => 'http://box_host/third_box.box',
14
+ }
15
+ end
16
+
17
+ let(:vms) do
18
+ [
19
+ {'name' => 'one', 'box' => 'first_box'},
20
+ {'name' => 'two', 'box' => 'second_box'},
21
+ {'name' => 'four', 'box' => 'fourth_box'},
22
+ {
23
+ 'name' => 'five',
24
+ 'box' => 'fifth_box',
25
+ 'box_url' => 'https://another_box_host/fifth_box.box',
26
+ },
27
+ ]
28
+ end
29
+
30
+ describe 'without a boxes key' do
31
+ let(:config) do
32
+ {
33
+ 'vms' => vms,
34
+ }
35
+ end
36
+
37
+ before { subject.set_config(config) }
38
+
39
+ it "doesn't modify any boxes" do
40
+ input = dup(config)
41
+ output = subject.run
42
+ expect(output).to eq config
43
+ end
44
+ end
45
+
46
+ describe 'when the boxes key is given' do
47
+ let(:config) do
48
+ {
49
+ 'boxes' => boxes,
50
+ 'vms' => vms,
51
+ }
52
+ end
53
+
54
+ before { subject.set_config(config) }
55
+
56
+ it "removes the 'boxes' key" do
57
+ output = subject.run
58
+ expect(output).to_not have_key 'boxes'
59
+ end
60
+
61
+ it "adds the 'box_url' to VMs whose 'box' value is in the 'boxes' list" do
62
+ output = subject.run
63
+ vms = output['vms']
64
+
65
+ expect(vms[0]['box_url']).to eq 'http://box_host/first_box.box'
66
+ expect(vms[1]['box_url']).to eq 'http://box_host/second_box.box'
67
+ end
68
+
69
+ describe "if the VM 'box' value doesn't have a match in the box list" do
70
+ it "doesn't modify the 'box_url'" do
71
+ output = subject.run
72
+ vms = output['vms']
73
+
74
+ expect(vms[2]['box_url']).to be_nil
75
+ end
76
+ end
77
+
78
+ describe "if the VM 'box_url' is already set" do
79
+ it "doesn't modify the 'box_url'" do
80
+ output = subject.run
81
+ vms = output['vms']
82
+
83
+ expect(vms[3]['box_url']).to eq 'https://another_box_host/fifth_box.box'
84
+ end
85
+ end
86
+ end
87
+ end
@@ -0,0 +1,287 @@
1
+ require 'spec_helper'
2
+
3
+ describe ConfigBuilder::Filter::Roles do
4
+
5
+ def dup(o)
6
+ Marshal.load(Marshal.dump(o))
7
+ end
8
+
9
+ let(:roles) do
10
+ {
11
+ 'shell-provisioner' => {
12
+ 'provisioners' => [
13
+ {'type' => 'shell', 'inline' => '/usr/bin/sl'},
14
+ ],
15
+ },
16
+ 'puppet-provisioner' => {
17
+ 'provisioners' => [
18
+ {'type' => 'puppet', 'manifest' => 'sl.pp'},
19
+ {'type' => 'puppet', 'manifest' => 'starwars.pp'},
20
+ ],
21
+ },
22
+ 'potato-provisioner' => {
23
+ 'provisioners' => [
24
+ {'type' => 'potato', 'potato' => 'POHTAHTO.pp'},
25
+ ],
26
+ },
27
+ 'folders-12' => {
28
+ 'synced_folders' => [
29
+ {'guest_path' => '/guest-1', 'host_path' => './host-1'},
30
+ {'guest_path' => '/guest-2', 'host_path' => './host-2'},
31
+ ],
32
+ },
33
+ 'folders-34' => {
34
+ 'synced_folders' => [
35
+ {'guest_path' => '/guest-3', 'host_path' => './host-3'},
36
+ {'guest_path' => '/guest-4', 'host_path' => './host-4'},
37
+ ],
38
+ },
39
+ 'shared-networks' => {
40
+ 'private_networks' => [
41
+ {'ip' => '1.2.3.4'}
42
+ ]
43
+ }
44
+ }
45
+ end
46
+
47
+ let(:vms) do
48
+ [
49
+ {'name' => 'master'},
50
+ {'name' => 'debian-6-agent'},
51
+ ]
52
+ end
53
+
54
+
55
+ describe "without a top level roles key" do
56
+
57
+ let(:config) do
58
+ {'vms' => vms}
59
+ end
60
+
61
+ before do
62
+ subject.set_config(dup(config))
63
+ end
64
+
65
+ it "doesn't alter the structure" do
66
+ input = dup(config)
67
+ output = subject.run
68
+
69
+ expect(output).to eq config
70
+ end
71
+ end
72
+
73
+ describe 'removing the role' do
74
+ let(:config) do
75
+ {
76
+ 'vms' => [{'name' => 'master'}],
77
+ 'roles' => roles,
78
+ }
79
+ end
80
+
81
+ before do
82
+ subject.set_config(dup(config))
83
+ end
84
+
85
+ it 'strips out the roles key' do
86
+ output = subject.run
87
+ expect(output).to_not have_key 'roles'
88
+ end
89
+ end
90
+
91
+ describe 'and a vm with no roles' do
92
+ let(:vms) { [{'name' => 'master'}] }
93
+
94
+ let(:config) do
95
+ {
96
+ 'vms' => vms,
97
+ 'roles' => roles,
98
+ }
99
+ end
100
+
101
+ before do
102
+ subject.set_config(dup(config))
103
+ end
104
+
105
+ it "doesn't alter the vm" do
106
+ output = subject.run
107
+ expect(output['vms']).to eq vms
108
+ end
109
+ end
110
+
111
+ describe 'and one vm' do
112
+ describe 'with one role' do
113
+ let(:vms) { [{'name' => 'master', 'roles' => 'shell-provisioner'}] }
114
+
115
+ let(:config) do
116
+ {
117
+ 'vms' => vms,
118
+ 'roles' => roles,
119
+ }
120
+ end
121
+
122
+ before do
123
+ subject.set_config(dup(config))
124
+ end
125
+
126
+ let(:filtered_vm) do
127
+ output = subject.run
128
+ output['vms'][0]
129
+ end
130
+
131
+ it "removes the 'roles' key" do
132
+ expect(filtered_vm).to_not have_key 'roles'
133
+ end
134
+
135
+ it 'applies the role' do
136
+ expected = [{
137
+ 'type' => 'shell',
138
+ 'inline' => '/usr/bin/sl',
139
+ }]
140
+
141
+ expect(filtered_vm['provisioners']).to eq expected
142
+ end
143
+ end
144
+
145
+ describe 'with two roles' do
146
+ let(:vms) do
147
+ [{
148
+ 'name' => 'master',
149
+ 'roles' => ['shell-provisioner', 'folders-12'],
150
+ }]
151
+ end
152
+
153
+ let(:config) do
154
+ {
155
+ 'vms' => vms,
156
+ 'roles' => roles,
157
+ }
158
+ end
159
+
160
+ before do
161
+ subject.set_config(dup(config))
162
+ end
163
+
164
+ let(:filtered_vm) do
165
+ output = subject.run
166
+ output['vms'][0]
167
+ end
168
+
169
+ it 'applies all of the roles' do
170
+ expected_prov = [{
171
+ 'type' => 'shell',
172
+ 'inline' => '/usr/bin/sl',
173
+ }]
174
+
175
+ expected_folder = [
176
+ {'guest_path' => '/guest-1', 'host_path' => './host-1'},
177
+ {'guest_path' => '/guest-2', 'host_path' => './host-2'},
178
+ ]
179
+
180
+ expect(filtered_vm['provisioners']).to eq expected_prov
181
+ expect(filtered_vm['synced_folders']).to eq expected_folder
182
+ end
183
+ end
184
+ end
185
+
186
+ describe "with multiple VMs and shared roles" do
187
+ let(:vms) do
188
+ [
189
+ {
190
+ 'name' => 'master',
191
+ 'roles' => ['shell-provisioner', 'potato-provisioner', 'folders-12', 'folders-34', 'shared-networks'],
192
+ },
193
+ {
194
+ 'name' => 'agent',
195
+ 'roles' => ['shell-provisioner', 'puppet-provisioner', 'folders-34', 'shared-networks'],
196
+ }
197
+ ]
198
+ end
199
+
200
+ let(:config) do
201
+ {
202
+ 'vms' => vms,
203
+ 'roles' => roles,
204
+ }
205
+ end
206
+
207
+ before do
208
+ subject.set_config(dup(config))
209
+ end
210
+
211
+ let(:filtered_vms) do
212
+ output = subject.run
213
+ output['vms']
214
+ end
215
+
216
+ describe 'the first node' do
217
+ let(:vm) { filtered_vms[0] }
218
+ it 'has the provisioners set in the right order' do
219
+ expected = [
220
+ {'type' => 'potato', 'potato' => 'POHTAHTO.pp'},
221
+ {'type' => 'shell', 'inline' => '/usr/bin/sl'},
222
+ ]
223
+ expect(vm['provisioners']).to eq expected
224
+ end
225
+
226
+ it 'has the synced folders set in the right order' do
227
+ expected = [
228
+ {'guest_path' => '/guest-3', 'host_path' => './host-3'},
229
+ {'guest_path' => '/guest-4', 'host_path' => './host-4'},
230
+ {'guest_path' => '/guest-1', 'host_path' => './host-1'},
231
+ {'guest_path' => '/guest-2', 'host_path' => './host-2'},
232
+ ]
233
+
234
+ expect(vm['synced_folders']).to eq expected
235
+ end
236
+ end
237
+
238
+ describe 'the second node' do
239
+ let(:vm) { filtered_vms[1] }
240
+
241
+ it 'has the provisioners set in the right order' do
242
+ expected = [
243
+ {'type' => 'puppet', 'manifest' => 'sl.pp'},
244
+ {'type' => 'puppet', 'manifest' => 'starwars.pp'},
245
+ {'type' => 'shell', 'inline' => '/usr/bin/sl'},
246
+ ]
247
+ expect(vm['provisioners']).to eq expected
248
+ end
249
+
250
+ it 'has the synced folders set in the right order' do
251
+ expected = [
252
+ {'guest_path' => '/guest-3', 'host_path' => './host-3'},
253
+ {'guest_path' => '/guest-4', 'host_path' => './host-4'},
254
+ ]
255
+
256
+ expect(vm['synced_folders']).to eq expected
257
+ end
258
+ end
259
+
260
+ context 'when modifying an array inherited from a role' do
261
+ before :each do
262
+ filtered_vms[0]['private_networks'].push 'ip' => '5.6.7.8'
263
+ end
264
+
265
+ it 'other VMs using that role are not affected' do
266
+ expect(filtered_vms[1]['private_networks']).to eq roles['shared-networks']['private_networks']
267
+ end
268
+ end
269
+ end
270
+
271
+ describe 'when a class references a non-existent role' do
272
+ let(:config) do
273
+ {
274
+ 'vms' => [{'name' => 'master', 'roles' => 'nope'}],
275
+ 'roles' => {'yep' => {'box' => 'moxxi'}}
276
+ }
277
+ end
278
+
279
+ before do
280
+ subject.set_config(dup(config))
281
+ end
282
+
283
+ it 'raises an error' do
284
+ expect { subject.run }.to raise_error(/^Requested role "nope" is not defined/)
285
+ end
286
+ end
287
+ end