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
@@ -1,8 +1,9 @@
1
1
  class Formatron
2
2
  module CloudFormation
3
3
  # Generates scripts for setting up instances with CloudFormation init
4
+ # rubocop:disable Metrics/ModuleLength
4
5
  module Scripts
5
- def self.hostname(sub_domain:, hosted_zone_name:)
6
+ def self.linux_common(sub_domain:, hosted_zone_name:)
6
7
  # rubocop:disable Metrics/LineLength
7
8
  <<-EOH.gsub(/^ {10}/, '')
8
9
  #/bin/bash -v
@@ -17,6 +18,75 @@ class Formatron
17
18
  # rubocop:enable Metrics/LineLength
18
19
  end
19
20
 
21
+ def self.windows_common(sub_domain:, hosted_zone_name:)
22
+ # rubocop:disable Metrics/LineLength
23
+ <<-EOH.gsub(/^ {10}/, '')
24
+ wmic computersystem where name="%COMPUTERNAME%" call rename name="#{sub_domain}"
25
+ REG ADD HKLM\\SYSTEM\\CurrentControlSet\\services\\Tcpip\\Parameters /v Domain /t REG_SZ /d #{hosted_zone_name} /f
26
+ shutdown.exe /r /t 00
27
+ EOH
28
+ # rubocop:enable Metrics/LineLength
29
+ end
30
+
31
+ # rubocop:disable Metrics/MethodLength
32
+ def self.windows_administrator(name:, password:)
33
+ # rubocop:disable Metrics/LineLength
34
+ <<-EOH.gsub(/^ {10}/, '')
35
+ $newAdminName = '#{name}'
36
+ $adminPassword = '#{password}'
37
+
38
+ # disable password policy
39
+ secedit /export /cfg c:\\secpol.cfg
40
+ (gc C:\\secpol.cfg).replace("PasswordComplexity = 1", "PasswordComplexity = 0") | Out-File C:\\secpol.cfg
41
+ secedit /configure /db c:\\windows\\security\\local.sdb /cfg c:\\secpol.cfg /areas SECURITYPOLICY
42
+ rm -force c:\\secpol.cfg -confirm:$false
43
+
44
+ # find the local administrator user
45
+ $computerName = $env:COMPUTERNAME
46
+ $computer = [ADSI] "WinNT://$computerName,Computer"
47
+ foreach ( $childObject in $computer.Children ) {
48
+ # Skip objects that are not users.
49
+ if ( $childObject.Class -ne "User" ) {
50
+ continue
51
+ }
52
+ $type = "System.Security.Principal.SecurityIdentifier"
53
+ $childObjectSID = new-object $type($childObject.objectSid[0],0)
54
+ if ( $childObjectSID.Value.EndsWith("-500") ) {
55
+ $adminName = $childObject.Name[0]
56
+
57
+ # set the new password
58
+ $adminUser = [ADSI] "WinNT://$computerName/$adminName,User"
59
+ $adminUser.SetPassword($adminPassword)
60
+
61
+ # set the new name
62
+ $user = Get-WMIObject Win32_UserAccount -Filter "Name='$adminName'"
63
+ $result = $user.Rename($newAdminName)
64
+
65
+ break
66
+ }
67
+ }
68
+ EOH
69
+ # rubocop:enable Metrics/LineLength
70
+ end
71
+ # rubocop:enable Metrics/MethodLength
72
+
73
+ # rubocop:disable Metrics/MethodLength
74
+ def self.windows_signal(wait_condition_handle:)
75
+ {
76
+ 'Fn::Join' => [
77
+ '', [
78
+ 'cfn-signal.exe -e 0 ',
79
+ {
80
+ 'Fn::Base64' => {
81
+ Ref: wait_condition_handle
82
+ }
83
+ }
84
+ ]
85
+ ]
86
+ }
87
+ end
88
+ # rubocop:enable Metrics/MethodLength
89
+
20
90
  # rubocop:disable Metrics/MethodLength
21
91
  def self.nat(cidr:)
22
92
  # rubocop:disable Metrics/LineLength
@@ -66,8 +136,9 @@ class Formatron
66
136
  set -e
67
137
 
68
138
  export HOME=/root
69
-
70
- source /tmp/formatron/script-variables
139
+ export PATH=$PATH:/usr/local/sbin/
140
+ export PATH=$PATH:/usr/sbin/
141
+ export PATH=$PATH:/sbin
71
142
 
72
143
  apt-get -y update
73
144
  apt-get -y install wget ntp cron git libfreetype6 libpng3 python-pip
@@ -134,5 +205,6 @@ class Formatron
134
205
  # rubocop:enable Metrics/ParameterLists
135
206
  # rubocop:enable Metrics/MethodLength
136
207
  end
208
+ # rubocop:enable Metrics/ModuleLength
137
209
  end
138
210
  end
@@ -15,6 +15,8 @@ class Formatron
15
15
  external:,
16
16
  hosted_zone_name:,
17
17
  key_pair:,
18
+ administrator_name:,
19
+ administrator_password:,
18
20
  kms_key:,
19
21
  hosted_zone_id:,
20
22
  target:
@@ -25,6 +27,8 @@ class Formatron
25
27
  @external_outputs = external.outputs
26
28
  @hosted_zone_name = hosted_zone_name
27
29
  @key_pair = key_pair
30
+ @administrator_name = administrator_name
31
+ @administrator_password = administrator_password
28
32
  @kms_key = kms_key
29
33
  @hosted_zone_id = hosted_zone_id
30
34
  @bucket = formatron.bucket
@@ -45,6 +49,8 @@ class Formatron
45
49
  external: @external_formatron.vpc[key],
46
50
  hosted_zone_name: @hosted_zone_name,
47
51
  key_pair: @key_pair,
52
+ administrator_name: @administrator_name,
53
+ administrator_password: @administrator_password,
48
54
  kms_key: @kms_key,
49
55
  hosted_zone_id: @hosted_zone_id,
50
56
  bucket: @bucket,
@@ -23,6 +23,8 @@ class Formatron
23
23
  external:,
24
24
  hosted_zone_name:,
25
25
  key_pair:,
26
+ administrator_name:,
27
+ administrator_password:,
26
28
  kms_key:,
27
29
  hosted_zone_id:,
28
30
  bucket:,
@@ -33,6 +35,8 @@ class Formatron
33
35
  @external = external
34
36
  @hosted_zone_name = hosted_zone_name
35
37
  @key_pair = key_pair
38
+ @administrator_name = administrator_name
39
+ @administrator_password = administrator_password
36
40
  @kms_key = kms_key
37
41
  @hosted_zone_id = hosted_zone_id
38
42
  @bucket = bucket
@@ -72,6 +76,8 @@ class Formatron
72
76
  vpc_guid: @guid,
73
77
  vpc_cidr: @cidr,
74
78
  key_pair: @key_pair,
79
+ administrator_name: @administrator_name,
80
+ administrator_password: @administrator_password,
75
81
  hosted_zone_name: @hosted_zone_name,
76
82
  kms_key: @kms_key,
77
83
  nats: Util::VPC.instances(:nat, @vpc),
@@ -104,6 +110,8 @@ class Formatron
104
110
  vpc_guid: @guid,
105
111
  vpc_cidr: @cidr,
106
112
  key_pair: @key_pair,
113
+ administrator_name: @administrator_name,
114
+ administrator_password: @administrator_password,
107
115
  hosted_zone_name: @hosted_zone_name,
108
116
  kms_key: @kms_key,
109
117
  nats: Util::VPC.instances(:nat, @external, @vpc),
@@ -25,6 +25,8 @@ class Formatron
25
25
  vpc_guid:,
26
26
  vpc_cidr:,
27
27
  key_pair:,
28
+ administrator_name:,
29
+ administrator_password:,
28
30
  hosted_zone_name:,
29
31
  kms_key:,
30
32
  nats:,
@@ -41,6 +43,8 @@ class Formatron
41
43
  @cidr = @subnet.cidr
42
44
  @acl = @subnet.acl
43
45
  @key_pair = key_pair
46
+ @administrator_name = administrator_name
47
+ @administrator_password = administrator_password
44
48
  @hosted_zone_name = hosted_zone_name
45
49
  @kms_key = kms_key
46
50
  @nats = nats
@@ -78,6 +82,8 @@ class Formatron
78
82
  args = {
79
83
  symbol => instance,
80
84
  key_pair: @key_pair,
85
+ administrator_name: @administrator_name,
86
+ administrator_password: @administrator_password,
81
87
  availability_zone: @availability_zone,
82
88
  subnet_guid: @guid,
83
89
  hosted_zone_name: @hosted_zone_name,
@@ -116,6 +122,8 @@ class Formatron
116
122
  args = {
117
123
  symbol => instance,
118
124
  key_pair: @key_pair,
125
+ administrator_name: @administrator_name,
126
+ administrator_password: @administrator_password,
119
127
  availability_zone: @availability_zone,
120
128
  subnet_guid: @guid,
121
129
  hosted_zone_name: @hosted_zone_name,
@@ -12,6 +12,8 @@ class Formatron
12
12
  def initialize(
13
13
  bastion:,
14
14
  key_pair:,
15
+ administrator_name:,
16
+ administrator_password:,
15
17
  availability_zone:,
16
18
  subnet_guid:,
17
19
  hosted_zone_name:,
@@ -25,10 +27,13 @@ class Formatron
25
27
  target:
26
28
  )
27
29
  @bastion = bastion
30
+ _set_os
28
31
  _add_open_ports
29
32
  @instance = Instance.new(
30
33
  instance: bastion,
31
34
  key_pair: key_pair,
35
+ administrator_name: administrator_name,
36
+ administrator_password: administrator_password,
32
37
  availability_zone: availability_zone,
33
38
  subnet_guid: subnet_guid,
34
39
  hosted_zone_name: hosted_zone_name,
@@ -45,6 +50,12 @@ class Formatron
45
50
  # rubocop:enable Metrics/ParameterLists
46
51
  # rubocop:enable Metrics/MethodLength
47
52
 
53
+ def _set_os
54
+ @bastion.os(
55
+ 'ubuntu'
56
+ )
57
+ end
58
+
48
59
  def _add_open_ports
49
60
  @bastion.security_group do |security_group|
50
61
  security_group.open_tcp_port 22
@@ -56,6 +67,7 @@ class Formatron
56
67
  end
57
68
 
58
69
  private(
70
+ :_set_os,
59
71
  :_add_open_ports
60
72
  )
61
73
  end
@@ -20,6 +20,8 @@ class Formatron
20
20
  def initialize(
21
21
  chef_server:,
22
22
  key_pair:,
23
+ administrator_name:,
24
+ administrator_password:,
23
25
  availability_zone:,
24
26
  subnet_guid:,
25
27
  hosted_zone_name:,
@@ -70,6 +72,7 @@ class Formatron
70
72
  @organization_short_name = organization.short_name
71
73
  @organization_full_name = organization.full_name
72
74
  _set_default_instance_type
75
+ _set_os
73
76
  _add_ssl_cert_policy
74
77
  _add_keys_policy
75
78
  _add_open_ports
@@ -77,6 +80,8 @@ class Formatron
77
80
  @instance = Instance.new(
78
81
  instance: @chef_server,
79
82
  key_pair: key_pair,
83
+ administrator_name: administrator_name,
84
+ administrator_password: administrator_password,
80
85
  availability_zone: availability_zone,
81
86
  subnet_guid: subnet_guid,
82
87
  hosted_zone_name: hosted_zone_name,
@@ -100,6 +105,12 @@ class Formatron
100
105
  ) if @chef_server.instance_type.nil?
101
106
  end
102
107
 
108
+ def _set_os
109
+ @chef_server.os(
110
+ 'ubuntu'
111
+ )
112
+ end
113
+
103
114
  def _add_ssl_cert_policy
104
115
  @chef_server.policy do |policy|
105
116
  policy.statement do |statement|
@@ -190,6 +201,7 @@ class Formatron
190
201
 
191
202
  private(
192
203
  :_set_default_instance_type,
204
+ :_set_os,
193
205
  :_add_ssl_cert_policy,
194
206
  :_add_keys_policy,
195
207
  :_add_open_ports,
@@ -33,6 +33,8 @@ class Formatron
33
33
  def initialize(
34
34
  instance:,
35
35
  key_pair:,
36
+ administrator_name:,
37
+ administrator_password:,
36
38
  availability_zone:,
37
39
  subnet_guid:,
38
40
  hosted_zone_name:,
@@ -62,7 +64,10 @@ class Formatron
62
64
  "#{SecurityGroup::SECURITY_GROUP_PREFIX}#{@guid}"
63
65
  @availability_zone = availability_zone
64
66
  @instance_type = @instance.instance_type || 't2.micro'
67
+ @os = @instance.os || 'ubuntu'
65
68
  @key_pair = key_pair
69
+ @administrator_name = administrator_name
70
+ @administrator_password = administrator_password
66
71
  @subnet_guid = subnet_guid
67
72
  @subnet_id = "#{Subnet::SUBNET_PREFIX}#{@subnet_guid}"
68
73
  @sub_domain = @instance.sub_domain
@@ -108,6 +113,7 @@ class Formatron
108
113
  )
109
114
  policy.merge resources: resources
110
115
  security_group = SecurityGroup.new(
116
+ os: @os,
111
117
  security_group: @security_group,
112
118
  instance_guid: @guid,
113
119
  vpc_guid: @vpc_guid,
@@ -121,17 +127,22 @@ class Formatron
121
127
  availability_zone: @availability_zone,
122
128
  instance_type: @instance_type,
123
129
  key_name: @key_pair,
130
+ administrator_name: @administrator_name,
131
+ administrator_password: @administrator_password,
124
132
  subnet: @subnet_id,
125
133
  name: "#{@sub_domain}.#{@hosted_zone_name}",
126
134
  wait_condition_handle: @wait_condition_handle_id,
127
135
  security_group: @security_group_id,
128
136
  logical_id: @instance_id,
129
- source_dest_check: @source_dest_check
137
+ source_dest_check: @source_dest_check,
138
+ os: @os
130
139
  )
131
140
  setup = Setup.new(
132
141
  setup: @setup,
133
142
  sub_domain: @sub_domain,
134
- hosted_zone_name: @hosted_zone_name
143
+ hosted_zone_name: @hosted_zone_name,
144
+ os: @os,
145
+ wait_condition_handle: @wait_condition_handle_id
135
146
  )
136
147
  setup.merge instance: instance
137
148
  block_devices = BlockDevices.new(
@@ -7,16 +7,19 @@ class Formatron
7
7
  class Subnet
8
8
  class Instance
9
9
  # generates CloudFormation security group resource
10
+ # rubocop:disable Metrics/ClassLength
10
11
  class SecurityGroup
11
12
  SECURITY_GROUP_PREFIX = 'securityGroup'
12
13
 
13
14
  # rubocop:disable Metrics/MethodLength
14
15
  def initialize(
16
+ os:,
15
17
  security_group:,
16
18
  instance_guid:,
17
19
  vpc_guid:,
18
20
  vpc_cidr:
19
21
  )
22
+ @os = os
20
23
  @security_group = security_group
21
24
  @vpc_guid = vpc_guid
22
25
  @cidr = vpc_cidr
@@ -32,7 +35,11 @@ class Formatron
32
35
 
33
36
  # rubocop:disable Metrics/MethodLength
34
37
  def merge(resources:)
35
- ingress_rules = _base_ingress_rules
38
+ if @os.eql? 'windows'
39
+ ingress_rules = _base_windows_ingress_rules
40
+ else
41
+ ingress_rules = _base_ingress_rules
42
+ end
36
43
  ingress_rules.concat(
37
44
  @open_tcp_ports.collect do |port|
38
45
  {
@@ -104,11 +111,49 @@ class Formatron
104
111
  end
105
112
  # rubocop:enable Metrics/MethodLength
106
113
 
114
+ # rubocop:disable Metrics/MethodLength
115
+ def _base_windows_ingress_rules
116
+ [{
117
+ cidr: @cidr,
118
+ protocol: 'tcp',
119
+ from_port: '0',
120
+ to_port: '65535'
121
+ }, {
122
+ cidr: @cidr,
123
+ protocol: 'udp',
124
+ from_port: '0',
125
+ to_port: '65535'
126
+ }, {
127
+ cidr: @cidr,
128
+ protocol: 'icmp',
129
+ from_port: '-1',
130
+ to_port: '-1'
131
+ }, {
132
+ cidr: '0.0.0.0/0',
133
+ protocol: 'tcp',
134
+ from_port: '3389',
135
+ to_port: '3389'
136
+ }, {
137
+ cidr: '0.0.0.0/0',
138
+ protocol: 'tcp',
139
+ from_port: '5985',
140
+ to_port: '5985'
141
+ }, {
142
+ cidr: '0.0.0.0/0',
143
+ protocol: 'tcp',
144
+ from_port: '5986',
145
+ to_port: '5986'
146
+ }]
147
+ end
148
+ # rubocop:enable Metrics/MethodLength
149
+
107
150
  private(
108
151
  :_base_egress_rules,
109
- :_base_ingress_rules
152
+ :_base_ingress_rules,
153
+ :_base_windows_ingress_rules
110
154
  )
111
155
  end
156
+ # rubocop:enable Metrics/ClassLength
112
157
  end
113
158
  end
114
159
  end
@@ -7,52 +7,116 @@ class Formatron
7
7
  class Subnet
8
8
  class Instance
9
9
  # Adds setup scripts to an instance
10
+ # rubocop:disable Metrics/ClassLength
10
11
  class Setup
11
- def initialize(setup:, sub_domain:, hosted_zone_name:)
12
+ # rubocop:disable Metrics/MethodLength
13
+ def initialize(
14
+ setup:,
15
+ sub_domain:,
16
+ hosted_zone_name:,
17
+ os:,
18
+ wait_condition_handle:
19
+ )
12
20
  @setup = setup
21
+ @wait_condition_handle = wait_condition_handle
13
22
  @sub_domain = sub_domain
14
23
  @hosted_zone_name = hosted_zone_name
15
24
  @scripts = @setup.script unless @setup.nil?
16
25
  @variables = @setup.variable unless @setup.nil?
26
+ @os = os
17
27
  end
28
+ # rubocop:enable Metrics/MethodLength
18
29
 
19
30
  # rubocop:disable Metrics/MethodLength
20
31
  # rubocop:disable Metrics/AbcSize
21
32
  def merge(instance:)
22
- files = {
23
- '/tmp/formatron/script-0.sh' => {
24
- content: Scripts.hostname(
33
+ env = {}
34
+ @variables.each do |key, value|
35
+ env[key] = value.value
36
+ end unless @variables.nil?
37
+ if @os.eql? 'windows'
38
+ script_key = 'script-0'
39
+ script = "C:\\formatron\\#{script_key}.bat"
40
+ files = {}
41
+ commands = {}
42
+ @scripts.each_index do |index|
43
+ script_key = "script-#{index}"
44
+ script = "C:\\formatron\\#{script_key}.bat"
45
+ files[script] = {
46
+ content: @scripts[index]
47
+ }
48
+ commands[script_key] = {
49
+ command: script,
50
+ env: env
51
+ }
52
+ end unless @scripts.nil?
53
+ setup_script_index = @scripts.nil? ? 0 : @scripts.length
54
+ signal_script_index = setup_script_index + 1
55
+ script_key = "script-#{setup_script_index}"
56
+ script = "C:\\formatron\\#{script_key}.bat"
57
+ files[script] = {
58
+ content: Scripts.windows_common(
25
59
  sub_domain: @sub_domain,
26
60
  hosted_zone_name: @hosted_zone_name
27
- ),
28
- mode: '000755',
29
- owner: 'root',
30
- group: 'root'
61
+ )
31
62
  }
32
- }
33
- @scripts.each_index do |index|
34
- files["/tmp/formatron/script-#{index + 1}.sh"] = {
35
- content: @scripts[index],
36
- mode: '000755',
37
- owner: 'root',
38
- group: 'root'
63
+ commands[script_key] = {
64
+ command: script,
65
+ env: env,
66
+ waitAfterCompletion: 'forever'
39
67
  }
40
- end unless @scripts.nil?
41
- variables = []
42
- @variables.each do |key, value|
43
- variables.concat(["#{key}=", value.value, "\n"])
44
- end unless @variables.nil?
45
- files['/tmp/formatron/script-variables'] = {
46
- content: Template.join(*variables),
47
- mode: '000644',
48
- owner: 'root',
49
- group: 'root'
50
- } unless variables.length == 0
68
+ script_key = "script-#{signal_script_index}"
69
+ script = "C:\\formatron\\#{script_key}.bat"
70
+ files[script] = {
71
+ content: Scripts.windows_signal(
72
+ wait_condition_handle: @wait_condition_handle
73
+ )
74
+ }
75
+ commands[script_key] = {
76
+ command: script,
77
+ env: env
78
+ }
79
+ else
80
+ script_key = 'script-0'
81
+ script = "/tmp/formatron/#{script_key}.sh"
82
+ files = {
83
+ "#{script}" => {
84
+ content: Scripts.linux_common(
85
+ sub_domain: @sub_domain,
86
+ hosted_zone_name: @hosted_zone_name
87
+ ),
88
+ mode: '000755',
89
+ owner: 'root',
90
+ group: 'root'
91
+ }
92
+ }
93
+ commands = {
94
+ "#{script_key}" => {
95
+ command: script,
96
+ env: env
97
+ }
98
+ }
99
+ @scripts.each_index do |index|
100
+ script_key = "script-#{index + 1}"
101
+ script = "/tmp/formatron/#{script_key}.sh"
102
+ files[script] = {
103
+ content: @scripts[index],
104
+ mode: '000755',
105
+ owner: 'root',
106
+ group: 'root'
107
+ }
108
+ commands[script_key] = {
109
+ command: script,
110
+ env: env
111
+ }
112
+ end unless @scripts.nil?
113
+ end
51
114
  instance[:Metadata] = {
52
115
  Comment1: 'Create setup scripts',
53
116
  'AWS::CloudFormation::Init' => {
54
117
  config: {
55
- files: files
118
+ files: files,
119
+ commands: commands
56
120
  }
57
121
  }
58
122
  }
@@ -60,6 +124,7 @@ class Formatron
60
124
  # rubocop:enable Metrics/AbcSize
61
125
  # rubocop:enable Metrics/MethodLength
62
126
  end
127
+ # rubocop:enable Metrics/ClassLength
63
128
  end
64
129
  end
65
130
  end