vagrant-masonry 0.13.0

Sign up to get free protection for your applications and to get access to all the features.
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