formatron 0.1.14 → 0.1.15

Sign up to get free protection for your applications and to get access to all the features.
Files changed (30) hide show
  1. checksums.yaml +4 -4
  2. data/formatron.gemspec +2 -1
  3. data/lib/formatron.rb +23 -10
  4. data/lib/formatron/aws.rb +26 -13
  5. data/lib/formatron/chef.rb +53 -9
  6. data/lib/formatron/chef/berkshelf.rb +15 -11
  7. data/lib/formatron/chef/keys.rb +5 -9
  8. data/lib/formatron/chef/knife.rb +39 -30
  9. data/lib/formatron/chef/ssh.rb +4 -1
  10. data/lib/formatron/chef/winrm.rb +37 -0
  11. data/lib/formatron/chef_clients.rb +6 -4
  12. data/lib/formatron/cli/generators/credentials.rb +1 -1
  13. data/lib/formatron/cloud_formation/resources/ec2.rb +58 -57
  14. data/lib/formatron/cloud_formation/scripts.rb +75 -3
  15. data/lib/formatron/cloud_formation/template.rb +6 -0
  16. data/lib/formatron/cloud_formation/template/vpc.rb +8 -0
  17. data/lib/formatron/cloud_formation/template/vpc/subnet.rb +8 -0
  18. data/lib/formatron/cloud_formation/template/vpc/subnet/bastion.rb +12 -0
  19. data/lib/formatron/cloud_formation/template/vpc/subnet/chef_server.rb +12 -0
  20. data/lib/formatron/cloud_formation/template/vpc/subnet/instance.rb +13 -2
  21. data/lib/formatron/cloud_formation/template/vpc/subnet/instance/security_group.rb +47 -2
  22. data/lib/formatron/cloud_formation/template/vpc/subnet/instance/setup.rb +92 -27
  23. data/lib/formatron/cloud_formation/template/vpc/subnet/nat.rb +12 -0
  24. data/lib/formatron/dsl/formatron/global.rb +2 -0
  25. data/lib/formatron/dsl/formatron/global/windows.rb +17 -0
  26. data/lib/formatron/dsl/formatron/vpc/subnet/instance.rb +1 -0
  27. data/lib/formatron/external/dsl.rb +19 -0
  28. data/lib/formatron/util/winrm.rb +40 -0
  29. data/lib/formatron/version.rb +1 -1
  30. metadata +33 -16
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 549a567b83515e35a2ea69ed7c8b3ab8cc820382
4
- data.tar.gz: dcd7078bac7e6e134de753a65129a261afa672d2
3
+ metadata.gz: 932f38c884b67c73450aa6842772390de1db150f
4
+ data.tar.gz: 7e70e25c5de6024938501fc0935c33c392546bc0
5
5
  SHA512:
6
- metadata.gz: e820a4d7134921c97fb114146134e1ecb0c13765ac0f21e1d028a546414a12ccd3693722ff0df140282b49dc6ba6e716692aac9b431d08ae000f1abe8d729b59
7
- data.tar.gz: 30addbe444dde872d6f4b54ca32806f39e95891010c9a00fd213d3e5b70a86355b234c58fbedc4cfc392c7c0f1856006d87584fecba4561ecc8b0c5a7d3936fb
6
+ metadata.gz: 9c1d72b86843a572767eadc0607cc3a8b8275d392b3ad73902186313c04809446dde1ba7bd13c2ea74b2f8b3a371014a2b95c1956a5e98da8b5fb099a7dca76e
7
+ data.tar.gz: 69abb715018d08008170e6192499695561dc8532c00dd5f2aed3283e989538aed49bd3d43d5fbaaa6f71087c20292fd6080d25f7b9185451d242424a3fb1c29d
data/formatron.gemspec CHANGED
@@ -38,7 +38,6 @@ EOH
38
38
  spec.add_development_dependency 'pry-remote', '~> 0.1'
39
39
  spec.add_development_dependency 'pry-nav', '~> 0.2'
40
40
  spec.add_development_dependency 'coveralls', '~> 0.8'
41
- spec.add_development_dependency 'codacy-coverage', '~> 0.3'
42
41
  spec.add_development_dependency 'rubocop', '0.33'
43
42
  spec.add_development_dependency 'guard-livereload', '~> 2.4'
44
43
  spec.add_development_dependency 'guard-rake', '~> 1.0'
@@ -50,5 +49,7 @@ EOH
50
49
  spec.add_runtime_dependency 'deep_merge', '~> 1.0'
51
50
  spec.add_runtime_dependency 'berkshelf', '~> 4.0'
52
51
  spec.add_runtime_dependency 'chef', '~> 12.5'
52
+ spec.add_runtime_dependency 'knife-windows', '~> 1.3'
53
53
  spec.add_runtime_dependency 'net-ssh', '~> 2.9'
54
+ spec.add_runtime_dependency 'winrm', '~> 1.7'
54
55
  end
data/lib/formatron.rb CHANGED
@@ -17,12 +17,14 @@ require 'formatron/external'
17
17
  # rubocop:disable Metrics/ClassLength
18
18
  class Formatron
19
19
  FORMATRONFILE = 'Formatronfile'
20
+ WORKING_DIRECTORY = '.formatron'
20
21
 
21
22
  attr_reader :protected
22
23
  alias_method :protected?, :protected
23
24
 
24
25
  # rubocop:disable Metrics/MethodLength
25
26
  def initialize(credentials:, directory:, target:)
27
+ @working_directory = File.join directory, WORKING_DIRECTORY, target
26
28
  @target = target
27
29
  @aws = AWS.new credentials: credentials
28
30
  @config = Config.target(
@@ -59,9 +61,17 @@ class Formatron
59
61
  external_global = external_formatron.global
60
62
  global = @formatron.global || external_global
61
63
  external_ec2 = external_global.ec2
64
+ external_windows = external_global.windows
62
65
  ec2 = global.ec2 || external_ec2
63
66
  key_pair = ec2.key_pair || external_ec2.key_pair
64
67
  @ec2_key = ec2.private_key || external_ec2.private_key
68
+ windows = global.windows || external_windows
69
+ @administrator_name =
70
+ windows.administrator_name ||
71
+ external_windows.administrator_name
72
+ @administrator_password =
73
+ windows.administrator_password ||
74
+ external_windows.administrator_password
65
75
  @protected = global.protect || external_global.protect
66
76
  @kms_key = global.kms_key || external_global.kms_key
67
77
  @databag_secret = global.databag_secret || external_global.databag_secret
@@ -73,6 +83,8 @@ class Formatron
73
83
  formatron: @formatron,
74
84
  hosted_zone_name: @hosted_zone_name,
75
85
  key_pair: key_pair,
86
+ administrator_name: @administrator_name,
87
+ administrator_password: @administrator_password,
76
88
  kms_key: @kms_key,
77
89
  hosted_zone_id: hosted_zone_id,
78
90
  target: @target,
@@ -91,11 +103,14 @@ class Formatron
91
103
  @chef_clients = {}
92
104
  @vpcs.each do |key, vpc|
93
105
  @chef_clients[key] = ChefClients.new(
106
+ directory: @working_directory,
94
107
  aws: @aws,
95
108
  bucket: @bucket,
96
109
  name: @name,
97
110
  target: @target,
98
111
  ec2_key: @ec2_key,
112
+ administrator_name: @administrator_name,
113
+ administrator_password: @administrator_password,
99
114
  hosted_zone_name: @hosted_zone_name,
100
115
  vpc: vpc,
101
116
  external: @external_vpcs[key],
@@ -160,29 +175,31 @@ class Formatron
160
175
  chef_clients.init
161
176
  instances.values.each do |instance|
162
177
  guid = instance.guid
178
+ os = instance.os
163
179
  next unless guid_filter.nil? || guid_filter.eql?(guid)
164
180
  dsl_chef = instance.chef
165
- next if dsl_chef.nil?
181
+ next if dsl_chef.cookbook.nil?
166
182
  chef = chef_clients.get dsl_chef.server
167
183
  cookbook = dsl_chef.cookbook
168
184
  bastion = dsl_chef.bastion
169
185
  sub_domain = instance.sub_domain
170
- _provision_instance chef, cookbook, sub_domain, guid, bastion
186
+ _provision_instance chef, cookbook, sub_domain, guid, bastion, os
171
187
  end
172
- ensure
173
- chef_clients.unlink
174
188
  end
175
189
  # rubocop:enable Metrics/AbcSize
176
190
  # rubocop:enable Metrics/MethodLength
177
191
 
178
- def _provision_instance(chef, cookbook, sub_domain, guid, bastion)
192
+ # rubocop:disable Metrics/ParameterLists
193
+ def _provision_instance(chef, cookbook, sub_domain, guid, bastion, os)
179
194
  chef.provision(
195
+ os: os,
180
196
  sub_domain: sub_domain,
181
197
  guid: guid,
182
198
  cookbook: cookbook,
183
199
  bastion: bastion
184
200
  )
185
201
  end
202
+ # rubocop:enable Metrics/ParameterLists
186
203
 
187
204
  def destroy
188
205
  _destroy_chef_instances
@@ -319,21 +336,17 @@ class Formatron
319
336
  end
320
337
  end
321
338
 
322
- # rubocop:disable Metrics/MethodLength
323
339
  def _destroy_chef_vpc_instances(key, instances)
324
340
  chef_clients = @chef_clients[key]
325
341
  chef_clients.init
326
342
  instances.values.each do |instance|
327
343
  dsl_chef = instance.chef
328
- next if dsl_chef.nil?
344
+ next if dsl_chef.cookbook.nil?
329
345
  chef = chef_clients.get dsl_chef.server
330
346
  guid = instance.guid
331
347
  _destroy_chef_instance chef, guid
332
348
  end
333
- ensure
334
- chef_clients.unlink
335
349
  end
336
- # rubocop:enable Metrics/MethodLength
337
350
 
338
351
  def _destroy_chef_instance(chef, guid)
339
352
  chef.destroy(
data/lib/formatron/aws.rb CHANGED
@@ -9,31 +9,44 @@ class Formatron
9
9
 
10
10
  REGIONS = {
11
11
  'us-east-1' => {
12
- ami: 'ami-ff02509a'
13
- },
14
- 'us-west-2' => {
15
- ami: 'ami-8ee605bd'
12
+ 'ubuntu' => 'ami-fce3c696',
13
+ 'windows' => 'ami-3586ac5f'
16
14
  },
17
15
  'us-west-1' => {
18
- ami: 'ami-198a495d'
16
+ 'ubuntu' => 'ami-06116566',
17
+ 'windows' => 'ami-95fd8bf5'
18
+ },
19
+ 'us-west-2' => {
20
+ 'ubuntu' => 'ami-9abea4fb',
21
+ 'windows' => 'ami-df8767bf'
19
22
  },
20
23
  'eu-west-1' => {
21
- ami: 'ami-37360a40'
24
+ 'ubuntu' => 'ami-f95ef58a',
25
+ 'windows' => 'ami-8519a9f6'
22
26
  },
23
27
  'eu-central-1' => {
24
- ami: 'ami-46272b5b'
28
+ 'ubuntu' => 'ami-87564feb',
29
+ 'windows' => 'ami-5dd2c931'
30
+ },
31
+ 'ap-northeast-1' => {
32
+ 'ubuntu' => 'ami-a21529cc',
33
+ 'windows' => 'ami-14b8bc7a'
34
+ },
35
+ 'ap-northeast-2' => {
36
+ 'ubuntu' => 'ami-09dc1267',
37
+ 'windows' => 'ami-d31dd3bd'
25
38
  },
26
39
  'ap-southeast-1' => {
27
- ami: 'ami-42170410'
40
+ 'ubuntu' => 'ami-25c00c46',
41
+ 'windows' => 'ami-9801cffb'
28
42
  },
29
43
  'ap-southeast-2' => {
30
- ami: 'ami-6d6c2657'
31
- },
32
- 'ap-northeast-1' => {
33
- ami: 'ami-402e4c40'
44
+ 'ubuntu' => 'ami-6c14310f',
45
+ 'windows' => 'ami-db0a2db8'
34
46
  },
35
47
  'sa-east-1' => {
36
- ami: 'ami-1f4bda02'
48
+ 'ubuntu' => 'ami-0fb83963',
49
+ 'windows' => 'ami-828e0dee'
37
50
  }
38
51
  }
39
52
 
@@ -4,6 +4,7 @@ require_relative 'chef/keys'
4
4
  require_relative 'chef/berkshelf'
5
5
  require_relative 'chef/knife'
6
6
  require_relative 'chef/ssh'
7
+ require_relative 'chef/winrm'
7
8
 
8
9
  class Formatron
9
10
  # manage the instance provisioning with Chef
@@ -11,12 +12,16 @@ class Formatron
11
12
  class Chef
12
13
  # rubocop:disable Metrics/MethodLength
13
14
  # rubocop:disable Metrics/ParameterLists
15
+ # rubocop:disable Metrics/AbcSize
14
16
  def initialize(
17
+ directory:,
15
18
  aws:,
16
19
  bucket:,
17
20
  name:,
18
21
  target:,
19
22
  ec2_key:,
23
+ administrator_name:,
24
+ administrator_password:,
20
25
  username:,
21
26
  organization:,
22
27
  ssl_verify:,
@@ -28,6 +33,7 @@ class Formatron
28
33
  configuration:,
29
34
  databag_secret:
30
35
  )
36
+ @working_directory = File.join directory, guid
31
37
  @aws = aws
32
38
  @name = name
33
39
  @target = target
@@ -38,6 +44,7 @@ class Formatron
38
44
  @bastions = bastions
39
45
  chef_server_url = _chef_server_url
40
46
  @keys = Keys.new(
47
+ directory: @working_directory,
41
48
  aws: @aws,
42
49
  bucket: bucket,
43
50
  name: server_stack,
@@ -46,7 +53,10 @@ class Formatron
46
53
  ec2_key: ec2_key
47
54
  )
48
55
  @knife = Knife.new(
56
+ directory: @working_directory,
49
57
  keys: @keys,
58
+ administrator_name: administrator_name,
59
+ administrator_password: administrator_password,
50
60
  chef_server_url: chef_server_url,
51
61
  username: username,
52
62
  organization: organization,
@@ -55,6 +65,7 @@ class Formatron
55
65
  configuration: configuration
56
66
  )
57
67
  @berkshelf = Berkshelf.new(
68
+ directory: @working_directory,
58
69
  keys: @keys,
59
70
  chef_server_url: chef_server_url,
60
71
  username: username,
@@ -63,7 +74,12 @@ class Formatron
63
74
  @ssh = SSH.new(
64
75
  keys: @keys
65
76
  )
77
+ @winrm = WinRM.new(
78
+ administrator_name: administrator_name,
79
+ administrator_password: administrator_password
80
+ )
66
81
  end
82
+ # rubocop:enable Metrics/AbcSize
67
83
  # rubocop:enable Metrics/ParameterLists
68
84
  # rubocop:enable Metrics/MethodLength
69
85
 
@@ -73,6 +89,7 @@ class Formatron
73
89
  name: @server_stack,
74
90
  target: @target
75
91
  )
92
+ FileUtils.mkdir_p @working_directory
76
93
  @keys.init
77
94
  @knife.init
78
95
  @berkshelf.init
@@ -81,6 +98,7 @@ class Formatron
81
98
  # rubocop:disable Metrics/MethodLength
82
99
  # rubocop:disable Metrics/AbcSize
83
100
  def provision(
101
+ os:,
84
102
  sub_domain:,
85
103
  guid:,
86
104
  cookbook:,
@@ -113,6 +131,7 @@ class Formatron
113
131
  @berkshelf.upload environment: guid, cookbook: cookbook
114
132
  if @knife.node_exists? guid: guid
115
133
  _reprovision_node(
134
+ os: os,
116
135
  bastion_hostname: bastion_hostname,
117
136
  guid: guid,
118
137
  cookbook_name: cookbook_name,
@@ -120,6 +139,7 @@ class Formatron
120
139
  )
121
140
  else
122
141
  _bootstrap_node(
142
+ os: os,
123
143
  bastion_hostname: bastion_hostname,
124
144
  guid: guid,
125
145
  cookbook_name: cookbook_name,
@@ -132,19 +152,22 @@ class Formatron
132
152
 
133
153
  # rubocop:disable Metrics/MethodLength
134
154
  def _reprovision_node(
155
+ os:,
135
156
  bastion_hostname:,
136
157
  guid:,
137
158
  cookbook_name:,
138
159
  hostname:
139
160
  )
140
- if @ssh.bootstrapped?(
161
+ if _bootstrapped?(
162
+ os: os,
141
163
  bastion_hostname: bastion_hostname,
142
164
  hostname: hostname
143
165
  )
144
166
  Formatron::LOG.info do
145
167
  "Run chef-client on existing node #{guid}"
146
168
  end
147
- @ssh.run_chef_client(
169
+ _run_chef_client(
170
+ os: os,
148
171
  bastion_hostname: bastion_hostname,
149
172
  hostname: hostname
150
173
  )
@@ -162,6 +185,7 @@ class Formatron
162
185
  end
163
186
  @knife.delete_client client: guid
164
187
  _bootstrap_node(
188
+ os: os,
165
189
  bastion_hostname: bastion_hostname,
166
190
  guid: guid,
167
191
  cookbook_name: cookbook_name,
@@ -171,8 +195,31 @@ class Formatron
171
195
  end
172
196
  # rubocop:enable Metrics/MethodLength
173
197
 
198
+ def _bootstrapped?(os:, bastion_hostname:, hostname:)
199
+ if os.eql? 'windows'
200
+ @winrm.bootstrapped? hostname: hostname
201
+ else
202
+ @ssh.bootstrapped?(
203
+ bastion_hostname: bastion_hostname,
204
+ hostname: hostname
205
+ )
206
+ end
207
+ end
208
+
209
+ def _run_chef_client(os:, bastion_hostname:, hostname:)
210
+ if os.eql? 'windows'
211
+ @winrm.run_chef_client hostname: hostname
212
+ else
213
+ @ssh.run_chef_client(
214
+ bastion_hostname: bastion_hostname,
215
+ hostname: hostname
216
+ )
217
+ end
218
+ end
219
+
174
220
  # rubocop:disable Metrics/MethodLength
175
221
  def _bootstrap_node(
222
+ os:,
176
223
  bastion_hostname:,
177
224
  guid:,
178
225
  cookbook_name:,
@@ -182,6 +229,7 @@ class Formatron
182
229
  "Bootstrap node #{guid}"
183
230
  end
184
231
  @knife.bootstrap(
232
+ os: os,
185
233
  bastion_hostname: bastion_hostname,
186
234
  guid: guid,
187
235
  cookbook: cookbook_name,
@@ -214,12 +262,6 @@ class Formatron
214
262
  end
215
263
  # rubocop:enable Metrics/MethodLength
216
264
 
217
- def unlink
218
- @keys.unlink
219
- @knife.unlink
220
- @berkshelf.unlink
221
- end
222
-
223
265
  def _chef_server_url
224
266
  "https://#{@chef_sub_domain}.#{@hosted_zone_name}" \
225
267
  "/organizations/#{@organization}"
@@ -233,7 +275,9 @@ class Formatron
233
275
  :_chef_server_url,
234
276
  :_hostname,
235
277
  :_bootstrap_node,
236
- :_reprovision_node
278
+ :_reprovision_node,
279
+ :_bootstrapped?,
280
+ :_run_chef_client
237
281
  )
238
282
  end
239
283
  # rubocop:enable Metrics/ClassLength
@@ -17,39 +17,43 @@ class Formatron
17
17
  }
18
18
  }
19
19
  EOH
20
+ CONFIG_FILE = 'berkshelf.json'
20
21
 
21
- def initialize(keys:, chef_server_url:, username:, ssl_verify:)
22
+ # rubocop:disable Metrics/MethodLength
23
+ def initialize(
24
+ directory:,
25
+ keys:,
26
+ chef_server_url:,
27
+ username:,
28
+ ssl_verify:
29
+ )
30
+ @config_file = File.join directory, CONFIG_FILE
22
31
  @keys = keys
23
32
  @chef_server_url = chef_server_url
24
33
  @username = username
25
34
  @ssl_verify = ssl_verify
26
35
  end
36
+ # rubocop:enable Metrics/MethodLength
27
37
 
28
38
  def init
29
- @config_file = Tempfile.new 'formatron-berkshelf-'
30
- @config_file.write CONFIG_FILE_CONTENTS % {
39
+ File.write(@config_file, CONFIG_FILE_CONTENTS % {
31
40
  server_url: @chef_server_url,
32
41
  user: @username,
33
42
  key_file: @keys.user_key,
34
43
  ssl_verify: @ssl_verify
35
- }
36
- @config_file.close
44
+ })
37
45
  end
38
46
 
39
47
  def upload(cookbook:, environment:)
40
48
  # rubocop:disable Metrics/LineLength
41
49
  command = "berks install -b #{File.join(cookbook, 'Berksfile')}"
42
50
  fail "failed to download cookbooks for opscode environment: #{environment}" unless Util::Shell.exec command
43
- command = "berks upload -c #{@config_file.path} -b #{File.join(cookbook, 'Berksfile')}"
51
+ command = "berks upload -c #{@config_file} -b #{File.join(cookbook, 'Berksfile')}"
44
52
  fail "failed to upload cookbooks for opscode environment: #{environment}" unless Util::Shell.exec command
45
- command = "berks apply #{environment} -c #{@config_file.path} -b #{File.join(cookbook, 'Berksfile.lock')}"
53
+ command = "berks apply #{environment} -c #{@config_file} -b #{File.join(cookbook, 'Berksfile.lock')}"
46
54
  fail "failed to apply cookbooks to opscode environment: #{environment}" unless Util::Shell.exec command
47
55
  # rubocop:enable Metrics/LineLength
48
56
  end
49
-
50
- def unlink
51
- @config_file.unlink unless @config_file.nil?
52
- end
53
57
  end
54
58
  end
55
59
  end