formatron 0.1.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.
- checksums.yaml +7 -0
- data/.coveralls.yml +1 -0
- data/.gitignore +12 -0
- data/.rspec +2 -0
- data/.rubocop.yml +3 -0
- data/.simplecov +7 -0
- data/.travis.yml +17 -0
- data/CODE_OF_CONDUCT.md +13 -0
- data/Gemfile +6 -0
- data/Guardfile +16 -0
- data/LICENSE.txt +21 -0
- data/README.md +93 -0
- data/Rakefile +16 -0
- data/bin/console +14 -0
- data/bin/setup +7 -0
- data/exe/formatron +20 -0
- data/formatron.gemspec +52 -0
- data/lib/formatron.rb +357 -0
- data/lib/formatron/aws.rb +197 -0
- data/lib/formatron/chef.rb +156 -0
- data/lib/formatron/chef/berkshelf.rb +55 -0
- data/lib/formatron/chef/keys.rb +48 -0
- data/lib/formatron/chef/knife.rb +169 -0
- data/lib/formatron/chef_clients.rb +73 -0
- data/lib/formatron/cli.rb +33 -0
- data/lib/formatron/cli/completion.rb +26 -0
- data/lib/formatron/cli/deploy.rb +57 -0
- data/lib/formatron/cli/destroy.rb +57 -0
- data/lib/formatron/cli/generators/bootstrap.rb +250 -0
- data/lib/formatron/cli/generators/credentials.rb +100 -0
- data/lib/formatron/cli/generators/instance.rb +118 -0
- data/lib/formatron/cli/provision.rb +59 -0
- data/lib/formatron/cloud_formation.rb +54 -0
- data/lib/formatron/cloud_formation/resources/cloud_formation.rb +27 -0
- data/lib/formatron/cloud_formation/resources/ec2.rb +336 -0
- data/lib/formatron/cloud_formation/resources/iam.rb +94 -0
- data/lib/formatron/cloud_formation/resources/route53.rb +54 -0
- data/lib/formatron/cloud_formation/scripts.rb +128 -0
- data/lib/formatron/cloud_formation/template.rb +114 -0
- data/lib/formatron/cloud_formation/template/parameters.rb +20 -0
- data/lib/formatron/cloud_formation/template/vpc.rb +181 -0
- data/lib/formatron/cloud_formation/template/vpc/subnet.rb +187 -0
- data/lib/formatron/cloud_formation/template/vpc/subnet/acl.rb +147 -0
- data/lib/formatron/cloud_formation/template/vpc/subnet/bastion.rb +66 -0
- data/lib/formatron/cloud_formation/template/vpc/subnet/chef_server.rb +205 -0
- data/lib/formatron/cloud_formation/template/vpc/subnet/instance.rb +162 -0
- data/lib/formatron/cloud_formation/template/vpc/subnet/instance/policy.rb +74 -0
- data/lib/formatron/cloud_formation/template/vpc/subnet/instance/security_group.rb +117 -0
- data/lib/formatron/cloud_formation/template/vpc/subnet/instance/setup.rb +68 -0
- data/lib/formatron/cloud_formation/template/vpc/subnet/nat.rb +94 -0
- data/lib/formatron/completion.rb +26 -0
- data/lib/formatron/completion/completion.sh.erb +35 -0
- data/lib/formatron/config.rb +31 -0
- data/lib/formatron/config/reader.rb +29 -0
- data/lib/formatron/dsl.rb +15 -0
- data/lib/formatron/dsl/formatron.rb +25 -0
- data/lib/formatron/dsl/formatron/global.rb +19 -0
- data/lib/formatron/dsl/formatron/global/ec2.rb +17 -0
- data/lib/formatron/dsl/formatron/vpc.rb +17 -0
- data/lib/formatron/dsl/formatron/vpc/subnet.rb +27 -0
- data/lib/formatron/dsl/formatron/vpc/subnet/acl.rb +18 -0
- data/lib/formatron/dsl/formatron/vpc/subnet/chef_server.rb +32 -0
- data/lib/formatron/dsl/formatron/vpc/subnet/chef_server/organization.rb +22 -0
- data/lib/formatron/dsl/formatron/vpc/subnet/instance.rb +29 -0
- data/lib/formatron/dsl/formatron/vpc/subnet/instance/chef.rb +22 -0
- data/lib/formatron/dsl/formatron/vpc/subnet/instance/policy.rb +21 -0
- data/lib/formatron/dsl/formatron/vpc/subnet/instance/policy/statement.rb +23 -0
- data/lib/formatron/dsl/formatron/vpc/subnet/instance/security_group.rb +21 -0
- data/lib/formatron/dsl/formatron/vpc/subnet/instance/setup.rb +22 -0
- data/lib/formatron/dsl/formatron/vpc/subnet/instance/setup/variable.rb +23 -0
- data/lib/formatron/external.rb +61 -0
- data/lib/formatron/external/dsl.rb +171 -0
- data/lib/formatron/external/outputs.rb +25 -0
- data/lib/formatron/generators/bootstrap.rb +90 -0
- data/lib/formatron/generators/bootstrap/config.rb +62 -0
- data/lib/formatron/generators/bootstrap/ec2.rb +17 -0
- data/lib/formatron/generators/bootstrap/formatronfile.rb +52 -0
- data/lib/formatron/generators/bootstrap/formatronfile/Formatronfile.erb +79 -0
- data/lib/formatron/generators/bootstrap/ssl.rb +35 -0
- data/lib/formatron/generators/credentials.rb +17 -0
- data/lib/formatron/generators/instance.rb +64 -0
- data/lib/formatron/generators/instance/config.rb +47 -0
- data/lib/formatron/generators/instance/formatronfile.rb +47 -0
- data/lib/formatron/generators/instance/formatronfile/Formatronfile.erb +16 -0
- data/lib/formatron/generators/util.rb +14 -0
- data/lib/formatron/generators/util/cookbook.rb +65 -0
- data/lib/formatron/generators/util/gitignore.rb +16 -0
- data/lib/formatron/generators/util/readme.rb +18 -0
- data/lib/formatron/logger.rb +8 -0
- data/lib/formatron/s3/chef_server_cert.rb +85 -0
- data/lib/formatron/s3/chef_server_keys.rb +103 -0
- data/lib/formatron/s3/cloud_formation_template.rb +61 -0
- data/lib/formatron/s3/configuration.rb +58 -0
- data/lib/formatron/s3/path.rb +30 -0
- data/lib/formatron/util/dsl.rb +107 -0
- data/lib/formatron/util/shell.rb +20 -0
- data/lib/formatron/util/vpc.rb +15 -0
- data/lib/formatron/version.rb +4 -0
- data/support/cloudformation_describe_stacks_response.rb +36 -0
- data/support/dsl_test.rb +123 -0
- data/support/route53_get_hosted_zone_response.rb +21 -0
- data/support/s3_get_object_response.rb +21 -0
- data/support/template_test.rb +41 -0
- metadata +414 -0
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
require 'formatron/generators/credentials'
|
|
2
|
+
require 'formatron/aws'
|
|
3
|
+
|
|
4
|
+
class Formatron
|
|
5
|
+
class CLI
|
|
6
|
+
module Generators
|
|
7
|
+
# CLI command for credentials generator
|
|
8
|
+
module Credentials
|
|
9
|
+
def self.dot_credentials
|
|
10
|
+
File.join '.formatron', 'credentials.json'
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def self.global_credentials
|
|
14
|
+
File.join Dir.home, dot_credentials
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def self.local_credentials(directory)
|
|
18
|
+
File.join directory, dot_credentials
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def self.default_credentials(directory)
|
|
22
|
+
local = local_credentials directory
|
|
23
|
+
if File.file?(local)
|
|
24
|
+
local
|
|
25
|
+
else
|
|
26
|
+
global_credentials
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def self.default_generated_credentials(directory)
|
|
31
|
+
if File.file?(File.join(directory, 'Formatronfile'))
|
|
32
|
+
local_credentials(directory)
|
|
33
|
+
else
|
|
34
|
+
global_credentials
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def credentials_options(c)
|
|
39
|
+
c.option '-r', '--region STRING', 'The AWS region'
|
|
40
|
+
c.option '-a', '--access-key-id STRING', 'The AWS access key ID'
|
|
41
|
+
c.option(
|
|
42
|
+
'-s',
|
|
43
|
+
'--secret-access-key STRING',
|
|
44
|
+
'The AWS secret access key'
|
|
45
|
+
)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def credentials_directory(options)
|
|
49
|
+
options.directory || Dir.pwd
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def credentials_credentials(options)
|
|
53
|
+
options.credentials ||
|
|
54
|
+
ask('Credentials file? ') do |q|
|
|
55
|
+
q.default =
|
|
56
|
+
Credentials.default_generated_credentials(
|
|
57
|
+
credentials_directory(options)
|
|
58
|
+
)
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def credentials_region(options)
|
|
63
|
+
options.region || choose(
|
|
64
|
+
'Region:',
|
|
65
|
+
*Formatron::AWS::REGIONS.keys
|
|
66
|
+
)
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def credentials_access_key_id(options)
|
|
70
|
+
options.access_key_id || ask('Access Key ID? ')
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def credentials_secret_access_key(options)
|
|
74
|
+
options.secret_access_key || password('Secret Access Key? ')
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def credentials_action(c)
|
|
78
|
+
c.action do |_args, options|
|
|
79
|
+
Formatron::Generators::Credentials.generate(
|
|
80
|
+
credentials_credentials(options),
|
|
81
|
+
credentials_region(options),
|
|
82
|
+
credentials_access_key_id(options),
|
|
83
|
+
credentials_secret_access_key(options)
|
|
84
|
+
)
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def credentials_formatron_command
|
|
89
|
+
command :'generate credentials' do |c|
|
|
90
|
+
c.syntax = 'formatron generate credentials [options]'
|
|
91
|
+
c.summary = 'Generate a credentials JSON file'
|
|
92
|
+
c.description = 'Generate a credentials JSON file'
|
|
93
|
+
credentials_options c
|
|
94
|
+
credentials_action c
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
end
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
require 'formatron/generators/instance'
|
|
2
|
+
|
|
3
|
+
class Formatron
|
|
4
|
+
class CLI
|
|
5
|
+
module Generators
|
|
6
|
+
# CLI command for instance generator
|
|
7
|
+
module Instance
|
|
8
|
+
# rubocop:disable Metrics/MethodLength
|
|
9
|
+
def instance_options(c)
|
|
10
|
+
c.option '-n', '--name STRING', 'The name for the configuration'
|
|
11
|
+
c.option '-i', '--instance-name STRING', 'The name for the instance'
|
|
12
|
+
c.option(
|
|
13
|
+
'-s',
|
|
14
|
+
'--s3-bucket STRING',
|
|
15
|
+
'The S3 bucket to store encrypted configuration'
|
|
16
|
+
)
|
|
17
|
+
c.option(
|
|
18
|
+
'-b',
|
|
19
|
+
'--bootstrap-configuration STRING',
|
|
20
|
+
'The name of the bootstrap configuration to depend on'
|
|
21
|
+
)
|
|
22
|
+
c.option(
|
|
23
|
+
'-p',
|
|
24
|
+
'--vpc STRING',
|
|
25
|
+
'The name of the VPC to add the instance to'
|
|
26
|
+
)
|
|
27
|
+
c.option(
|
|
28
|
+
'-u',
|
|
29
|
+
'--subnet STRING',
|
|
30
|
+
'The name of the subnet to add the instance to'
|
|
31
|
+
)
|
|
32
|
+
c.option(
|
|
33
|
+
'-x',
|
|
34
|
+
'--targets LIST',
|
|
35
|
+
Array,
|
|
36
|
+
'The targets (eg. production test)'
|
|
37
|
+
)
|
|
38
|
+
end
|
|
39
|
+
# rubocop:enable Metrics/MethodLength
|
|
40
|
+
|
|
41
|
+
def instance_directory(options)
|
|
42
|
+
options.directory || ask('Directory? ') do |q|
|
|
43
|
+
q.default = Dir.pwd
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def instance_name(options, directory)
|
|
48
|
+
options.name || ask('Name? ') do |q|
|
|
49
|
+
q.default = File.basename directory
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def instance_instance_name(options, name)
|
|
54
|
+
options.instance_name || ask('Instance Name? ') do |q|
|
|
55
|
+
q.default = name
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def instance_s3_bucket(options)
|
|
60
|
+
options.s3_bucket || ask('S3 Bucket? ')
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def instance_bootstrap_configuration(options)
|
|
64
|
+
options.bootstrap_configuration ||
|
|
65
|
+
ask('Bootstrap configuration? ')
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def instance_vpc(options)
|
|
69
|
+
options.vpc || ask('VPC? ') do |q|
|
|
70
|
+
q.default = 'vpc'
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def instance_subnet(options)
|
|
75
|
+
options.subnet || ask('Subnet? ') do |q|
|
|
76
|
+
q.default = 'private'
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def instance_targets(options)
|
|
81
|
+
options.targets || ask('Targets? ', Array) do |q|
|
|
82
|
+
q.default = 'production test'
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
# rubocop:disable Metrics/MethodLength
|
|
87
|
+
def instance_action(c)
|
|
88
|
+
c.action do |_args, options|
|
|
89
|
+
directory = instance_directory options
|
|
90
|
+
name = instance_name options, directory
|
|
91
|
+
Formatron::Generators::Instance.generate(
|
|
92
|
+
directory,
|
|
93
|
+
name: name,
|
|
94
|
+
instance_name: instance_instance_name(options, name),
|
|
95
|
+
s3_bucket: instance_s3_bucket(options),
|
|
96
|
+
bootstrap_configuration:
|
|
97
|
+
instance_bootstrap_configuration(options),
|
|
98
|
+
vpc: instance_vpc(options),
|
|
99
|
+
subnet: instance_subnet(options),
|
|
100
|
+
targets: instance_targets(options)
|
|
101
|
+
)
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
# rubocop:enable Metrics/MethodLength
|
|
105
|
+
|
|
106
|
+
def instance_formatron_command
|
|
107
|
+
command :'generate instance' do |c|
|
|
108
|
+
c.syntax = 'formatron generate instance [options]'
|
|
109
|
+
c.summary = 'Generate an instance configuration'
|
|
110
|
+
c.description = 'Generate an instance configuration'
|
|
111
|
+
instance_options c
|
|
112
|
+
instance_action c
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
end
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
require 'formatron'
|
|
2
|
+
require 'formatron/config'
|
|
3
|
+
|
|
4
|
+
class Formatron
|
|
5
|
+
class CLI
|
|
6
|
+
# CLI command for provision
|
|
7
|
+
module Provision
|
|
8
|
+
def provision_directory(options)
|
|
9
|
+
options.directory || Dir.pwd
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def provision_credentials(options)
|
|
13
|
+
options.credentials ||
|
|
14
|
+
Generators::Credentials.default_credentials(
|
|
15
|
+
deploy_directory(options)
|
|
16
|
+
)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def provision_target(target, directory)
|
|
20
|
+
target || choose(
|
|
21
|
+
'Target?',
|
|
22
|
+
*Config.targets(directory: directory)
|
|
23
|
+
)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def provision_ok(formatron, target)
|
|
27
|
+
!formatron.protected? || agree(
|
|
28
|
+
"Are you sure you wish to provision protected target: #{target}?"
|
|
29
|
+
) do |q|
|
|
30
|
+
q.default = 'no'
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def provision_action(c)
|
|
35
|
+
c.action do |args, options|
|
|
36
|
+
directory = provision_directory options
|
|
37
|
+
target = provision_target args[0], directory
|
|
38
|
+
formatron = Formatron.new(
|
|
39
|
+
credentials: provision_credentials(options),
|
|
40
|
+
directory: directory,
|
|
41
|
+
target: target
|
|
42
|
+
)
|
|
43
|
+
formatron.provision if provision_ok formatron, target
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def provision_formatron_command
|
|
48
|
+
command :provision do |c|
|
|
49
|
+
c.syntax = 'formatron provision [options] [TARGET]'
|
|
50
|
+
c.summary = 'Provision the instances in a Formatron ' \
|
|
51
|
+
'stack using Opscode Chef'
|
|
52
|
+
c.description = 'Provision the instances in a Formatron ' \
|
|
53
|
+
'stack using Opscode Chef'
|
|
54
|
+
provision_action c
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
require_relative 's3/cloud_formation_template'
|
|
2
|
+
require 'formatron/logger'
|
|
3
|
+
|
|
4
|
+
class Formatron
|
|
5
|
+
# manage the CloudFormation stack
|
|
6
|
+
module CloudFormation
|
|
7
|
+
# rubocop:disable Metrics/MethodLength
|
|
8
|
+
def self.deploy(aws:, bucket:, name:, target:, parameters:)
|
|
9
|
+
stack_name = _stack_name name, target
|
|
10
|
+
Formatron::LOG.info do
|
|
11
|
+
"Deploy CloudFormation stack: #{stack_name}"
|
|
12
|
+
end
|
|
13
|
+
aws.deploy_stack(
|
|
14
|
+
stack_name: stack_name,
|
|
15
|
+
template_url: S3::CloudFormationTemplate.url(
|
|
16
|
+
region: aws.region,
|
|
17
|
+
bucket: bucket,
|
|
18
|
+
name: name,
|
|
19
|
+
target: target
|
|
20
|
+
),
|
|
21
|
+
parameters: parameters
|
|
22
|
+
)
|
|
23
|
+
end
|
|
24
|
+
# rubocop:enable Metrics/MethodLength
|
|
25
|
+
|
|
26
|
+
def self.destroy(aws:, name:, target:)
|
|
27
|
+
stack_name = _stack_name name, target
|
|
28
|
+
Formatron::LOG.info do
|
|
29
|
+
"Destroy CloudFormation stack: #{stack_name}"
|
|
30
|
+
end
|
|
31
|
+
aws.delete_stack stack_name: stack_name
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def self.outputs(aws:, name:, target:)
|
|
35
|
+
stack_name = _stack_name name, target
|
|
36
|
+
Formatron::LOG.info do
|
|
37
|
+
"Query CloudFormation stack outputs: #{stack_name}"
|
|
38
|
+
end
|
|
39
|
+
aws.stack_outputs stack_name: stack_name
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def self.stack_ready!(aws:, name:, target:)
|
|
43
|
+
aws.stack_ready! stack_name: _stack_name(name, target)
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def self._stack_name(name, target)
|
|
47
|
+
"#{name}-#{target}"
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
private_class_method(
|
|
51
|
+
:_stack_name
|
|
52
|
+
)
|
|
53
|
+
end
|
|
54
|
+
end
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
require_relative '../template'
|
|
2
|
+
|
|
3
|
+
class Formatron
|
|
4
|
+
module CloudFormation
|
|
5
|
+
module Resources
|
|
6
|
+
# Generates CloudFormation template CloudFormation resources
|
|
7
|
+
module CloudFormation
|
|
8
|
+
def self.wait_condition_handle
|
|
9
|
+
{
|
|
10
|
+
Type: 'AWS::CloudFormation::WaitConditionHandle'
|
|
11
|
+
}
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def self.wait_condition(instance:, wait_condition_handle:)
|
|
15
|
+
{
|
|
16
|
+
Type: 'AWS::CloudFormation::WaitCondition',
|
|
17
|
+
DependsOn: instance,
|
|
18
|
+
Properties: {
|
|
19
|
+
Handle: Template.ref(wait_condition_handle),
|
|
20
|
+
Timeout: '1800'
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
@@ -0,0 +1,336 @@
|
|
|
1
|
+
require_relative '../template'
|
|
2
|
+
|
|
3
|
+
class Formatron
|
|
4
|
+
module CloudFormation
|
|
5
|
+
module Resources
|
|
6
|
+
# Generates CloudFormation template EC2 resources
|
|
7
|
+
# rubocop:disable Metrics/ModuleLength
|
|
8
|
+
module EC2
|
|
9
|
+
def self.vpc(cidr:)
|
|
10
|
+
{
|
|
11
|
+
Type: 'AWS::EC2::VPC',
|
|
12
|
+
Properties: {
|
|
13
|
+
CidrBlock: cidr,
|
|
14
|
+
EnableDnsSupport: true,
|
|
15
|
+
EnableDnsHostnames: true,
|
|
16
|
+
InstanceTenancy: 'default'
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def self.internet_gateway
|
|
22
|
+
{
|
|
23
|
+
Type: 'AWS::EC2::InternetGateway'
|
|
24
|
+
}
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def self.vpc_gateway_attachment(vpc:, gateway:)
|
|
28
|
+
{
|
|
29
|
+
Type: 'AWS::EC2::VPCGatewayAttachment',
|
|
30
|
+
Properties: {
|
|
31
|
+
InternetGatewayId: Template.ref(gateway),
|
|
32
|
+
VpcId: Template.ref(vpc)
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def self.route_table(vpc:)
|
|
38
|
+
{
|
|
39
|
+
Type: 'AWS::EC2::RouteTable',
|
|
40
|
+
Properties: {
|
|
41
|
+
VpcId: Template.ref(vpc)
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# rubocop:disable Metrics/MethodLength
|
|
47
|
+
def self.route(
|
|
48
|
+
route_table:,
|
|
49
|
+
instance: nil,
|
|
50
|
+
internet_gateway: nil,
|
|
51
|
+
vpc_gateway_attachment: nil
|
|
52
|
+
)
|
|
53
|
+
properties = {
|
|
54
|
+
RouteTableId: Template.ref(route_table),
|
|
55
|
+
DestinationCidrBlock: '0.0.0.0/0'
|
|
56
|
+
}
|
|
57
|
+
properties[:GatewayId] =
|
|
58
|
+
Template.ref internet_gateway unless internet_gateway.nil?
|
|
59
|
+
properties[:InstanceId] =
|
|
60
|
+
Template.ref instance unless instance.nil?
|
|
61
|
+
route = {
|
|
62
|
+
Type: 'AWS::EC2::Route',
|
|
63
|
+
Properties: properties
|
|
64
|
+
}
|
|
65
|
+
route[:DependsOn] =
|
|
66
|
+
vpc_gateway_attachment unless vpc_gateway_attachment.nil?
|
|
67
|
+
route
|
|
68
|
+
end
|
|
69
|
+
# rubocop:enable Metrics/MethodLength
|
|
70
|
+
|
|
71
|
+
# rubocop:disable Metrics/MethodLength
|
|
72
|
+
def self.subnet(
|
|
73
|
+
vpc:,
|
|
74
|
+
cidr:,
|
|
75
|
+
availability_zone:,
|
|
76
|
+
map_public_ip_on_launch:
|
|
77
|
+
)
|
|
78
|
+
{
|
|
79
|
+
Type: 'AWS::EC2::Subnet',
|
|
80
|
+
Properties: {
|
|
81
|
+
VpcId: Template.ref(vpc),
|
|
82
|
+
CidrBlock: cidr,
|
|
83
|
+
MapPublicIpOnLaunch: map_public_ip_on_launch,
|
|
84
|
+
AvailabilityZone: Template.join(
|
|
85
|
+
Template.ref('AWS::Region'),
|
|
86
|
+
availability_zone
|
|
87
|
+
)
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
end
|
|
91
|
+
# rubocop:enable Metrics/MethodLength
|
|
92
|
+
|
|
93
|
+
def self.subnet_route_table_association(route_table:, subnet:)
|
|
94
|
+
{
|
|
95
|
+
Type: 'AWS::EC2::SubnetRouteTableAssociation',
|
|
96
|
+
Properties: {
|
|
97
|
+
RouteTableId: Template.ref(route_table),
|
|
98
|
+
SubnetId: Template.ref(subnet)
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
def self.network_acl(vpc:)
|
|
104
|
+
{
|
|
105
|
+
Type: 'AWS::EC2::NetworkAcl',
|
|
106
|
+
Properties: {
|
|
107
|
+
VpcId: Template.ref(vpc)
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
def self.subnet_network_acl_association(subnet:, network_acl:)
|
|
113
|
+
{
|
|
114
|
+
Type: 'AWS::EC2::SubnetNetworkAclAssociation',
|
|
115
|
+
Properties: {
|
|
116
|
+
SubnetId: Template.ref(subnet),
|
|
117
|
+
NetworkAclId: Template.ref(network_acl)
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
# rubocop:disable Metrics/MethodLength
|
|
123
|
+
# rubocop:disable Metrics/ParameterLists
|
|
124
|
+
def self.network_acl_entry(
|
|
125
|
+
network_acl:,
|
|
126
|
+
cidr:,
|
|
127
|
+
egress:,
|
|
128
|
+
protocol:,
|
|
129
|
+
action:,
|
|
130
|
+
icmp_code: nil,
|
|
131
|
+
icmp_type: nil,
|
|
132
|
+
start_port: nil,
|
|
133
|
+
end_port: nil,
|
|
134
|
+
number:
|
|
135
|
+
)
|
|
136
|
+
resource = {
|
|
137
|
+
Type: 'AWS::EC2::NetworkAclEntry',
|
|
138
|
+
Properties: {
|
|
139
|
+
NetworkAclId: Template.ref(network_acl),
|
|
140
|
+
CidrBlock: cidr,
|
|
141
|
+
Egress: egress,
|
|
142
|
+
Protocol: protocol,
|
|
143
|
+
RuleAction: action,
|
|
144
|
+
RuleNumber: number
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
resource[:Properties][:Icmp] = {
|
|
148
|
+
Code: icmp_code,
|
|
149
|
+
Type: icmp_type
|
|
150
|
+
} unless icmp_code.nil?
|
|
151
|
+
resource[:Properties][:PortRange] = {
|
|
152
|
+
From: start_port,
|
|
153
|
+
To: end_port
|
|
154
|
+
} unless start_port.nil?
|
|
155
|
+
resource
|
|
156
|
+
end
|
|
157
|
+
# rubocop:enable Metrics/ParameterLists
|
|
158
|
+
# rubocop:enable Metrics/MethodLength
|
|
159
|
+
|
|
160
|
+
# rubocop:disable Metrics/MethodLength
|
|
161
|
+
def self.security_group(
|
|
162
|
+
group_description:,
|
|
163
|
+
vpc:,
|
|
164
|
+
egress:,
|
|
165
|
+
ingress:
|
|
166
|
+
)
|
|
167
|
+
{
|
|
168
|
+
Type: 'AWS::EC2::SecurityGroup',
|
|
169
|
+
Properties: {
|
|
170
|
+
GroupDescription: group_description,
|
|
171
|
+
VpcId: Template.ref(vpc),
|
|
172
|
+
SecurityGroupEgress: egress.collect do |rule|
|
|
173
|
+
{
|
|
174
|
+
CidrIp: rule[:cidr],
|
|
175
|
+
IpProtocol: rule[:protocol],
|
|
176
|
+
FromPort: rule[:from_port],
|
|
177
|
+
ToPort: rule[:to_port]
|
|
178
|
+
}
|
|
179
|
+
end,
|
|
180
|
+
SecurityGroupIngress: ingress.collect do |rule|
|
|
181
|
+
{
|
|
182
|
+
CidrIp: rule[:cidr],
|
|
183
|
+
IpProtocol: rule[:protocol],
|
|
184
|
+
FromPort: rule[:from_port],
|
|
185
|
+
ToPort: rule[:to_port]
|
|
186
|
+
}
|
|
187
|
+
end
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
end
|
|
191
|
+
# rubocop:enable Metrics/MethodLength
|
|
192
|
+
|
|
193
|
+
# rubocop:disable Metrics/MethodLength
|
|
194
|
+
def self.security_group_egress(
|
|
195
|
+
security_group:,
|
|
196
|
+
cidr:,
|
|
197
|
+
protocol:,
|
|
198
|
+
from_port:,
|
|
199
|
+
to_port:
|
|
200
|
+
)
|
|
201
|
+
{
|
|
202
|
+
Type: 'AWS::EC2::SecurityGroupEgress',
|
|
203
|
+
Properties: {
|
|
204
|
+
GroupId: Template.ref(security_group),
|
|
205
|
+
CidrIp: cidr,
|
|
206
|
+
IpProtocol: protocol,
|
|
207
|
+
FromPort: from_port,
|
|
208
|
+
ToPort: to_port
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
end
|
|
212
|
+
# rubocop:enable Metrics/MethodLength
|
|
213
|
+
|
|
214
|
+
# rubocop:disable Metrics/MethodLength
|
|
215
|
+
def self.security_group_ingress(
|
|
216
|
+
security_group:,
|
|
217
|
+
cidr:,
|
|
218
|
+
protocol:,
|
|
219
|
+
from_port:,
|
|
220
|
+
to_port:
|
|
221
|
+
)
|
|
222
|
+
{
|
|
223
|
+
Type: 'AWS::EC2::SecurityGroupIngress',
|
|
224
|
+
Properties: {
|
|
225
|
+
GroupId: Template.ref(security_group),
|
|
226
|
+
CidrIp: cidr,
|
|
227
|
+
IpProtocol: protocol,
|
|
228
|
+
FromPort: from_port,
|
|
229
|
+
ToPort: to_port
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
end
|
|
233
|
+
# rubocop:enable Metrics/MethodLength
|
|
234
|
+
|
|
235
|
+
# rubocop:disable Metrics/MethodLength
|
|
236
|
+
# rubocop:disable Metrics/ParameterLists
|
|
237
|
+
# rubocop:disable Metrics/AbcSize
|
|
238
|
+
def self.instance(
|
|
239
|
+
scripts: nil,
|
|
240
|
+
script_variables: nil,
|
|
241
|
+
files: nil,
|
|
242
|
+
instance_profile:,
|
|
243
|
+
availability_zone:,
|
|
244
|
+
instance_type:,
|
|
245
|
+
key_name:,
|
|
246
|
+
subnet:,
|
|
247
|
+
name:,
|
|
248
|
+
wait_condition_handle:,
|
|
249
|
+
security_group:,
|
|
250
|
+
logical_id:,
|
|
251
|
+
source_dest_check:
|
|
252
|
+
)
|
|
253
|
+
files ||= {}
|
|
254
|
+
scripts.each_index do |index|
|
|
255
|
+
files["/tmp/formatron/script-#{index}.sh"] = {
|
|
256
|
+
content: scripts[index],
|
|
257
|
+
mode: '000755',
|
|
258
|
+
owner: 'root',
|
|
259
|
+
group: 'root'
|
|
260
|
+
}
|
|
261
|
+
end unless scripts.nil?
|
|
262
|
+
script_variables_content =
|
|
263
|
+
script_variables.reduce([]) do |content, (key, value)|
|
|
264
|
+
content.concat(["#{key}=", value, "\n"])
|
|
265
|
+
end unless script_variables.nil?
|
|
266
|
+
files['/tmp/formatron/script-variables'] = {
|
|
267
|
+
content: Template.join(*script_variables_content),
|
|
268
|
+
mode: '000644',
|
|
269
|
+
owner: 'root',
|
|
270
|
+
group: 'root'
|
|
271
|
+
} unless script_variables_content.nil?
|
|
272
|
+
{
|
|
273
|
+
Type: 'AWS::EC2::Instance',
|
|
274
|
+
Metadata: {
|
|
275
|
+
Comment1: 'Create setup scripts',
|
|
276
|
+
'AWS::CloudFormation::Init' => {
|
|
277
|
+
config: {
|
|
278
|
+
files: files
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
},
|
|
282
|
+
Properties: {
|
|
283
|
+
IamInstanceProfile: Template.ref(instance_profile),
|
|
284
|
+
AvailabilityZone: Template.join(
|
|
285
|
+
Template.ref('AWS::Region'),
|
|
286
|
+
availability_zone
|
|
287
|
+
),
|
|
288
|
+
ImageId: Template.find_in_map(
|
|
289
|
+
Template::REGION_MAP,
|
|
290
|
+
Template.ref('AWS::Region'),
|
|
291
|
+
'ami'
|
|
292
|
+
),
|
|
293
|
+
SourceDestCheck: source_dest_check,
|
|
294
|
+
InstanceType: instance_type,
|
|
295
|
+
KeyName: key_name,
|
|
296
|
+
SubnetId: Template.ref(subnet),
|
|
297
|
+
SecurityGroupIds: [Template.ref(security_group)],
|
|
298
|
+
Tags: [{
|
|
299
|
+
Key: 'Name',
|
|
300
|
+
Value: name
|
|
301
|
+
}],
|
|
302
|
+
UserData: Template.base_64(
|
|
303
|
+
Template.join(
|
|
304
|
+
# rubocop:disable Metrics/LineLength
|
|
305
|
+
"#!/bin/bash -v\n",
|
|
306
|
+
"function error_exit\n",
|
|
307
|
+
"{\n",
|
|
308
|
+
" cfn-signal -e 1 -r \"$1\" '", Template.ref(wait_condition_handle), "'\n",
|
|
309
|
+
" exit 1\n",
|
|
310
|
+
"}\n",
|
|
311
|
+
"apt-get -y update\n",
|
|
312
|
+
"apt-get -y install python-setuptools\n",
|
|
313
|
+
"easy_install https://s3.amazonaws.com/cloudformation-examples/aws-cfn-bootstrap-latest.tar.gz\n",
|
|
314
|
+
"export PATH=$PATH:/opt/aws/bin\n",
|
|
315
|
+
'cfn-init --region ', Template.ref('AWS::Region'),
|
|
316
|
+
' -v -s ', Template.ref('AWS::StackName'), " -r #{logical_id} ",
|
|
317
|
+
" || error_exit 'Failed to run cfn-init'\n",
|
|
318
|
+
"for file in /tmp/formatron/script-*.sh; do\n",
|
|
319
|
+
" $file || error_exit \"failed to run Formatron setup script: $file\"\n",
|
|
320
|
+
"done\n",
|
|
321
|
+
"# If all went well, signal success\n",
|
|
322
|
+
"cfn-signal -e $? -r 'Formatron instance configuration complete' '", Template.ref(wait_condition_handle), "'\n"
|
|
323
|
+
# rubocop:enable Metrics/LineLength
|
|
324
|
+
)
|
|
325
|
+
)
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
end
|
|
329
|
+
# rubocop:enable Metrics/AbcSize
|
|
330
|
+
# rubocop:enable Metrics/ParameterLists
|
|
331
|
+
# rubocop:enable Metrics/MethodLength
|
|
332
|
+
end
|
|
333
|
+
# rubocop:enable Metrics/ModuleLength
|
|
334
|
+
end
|
|
335
|
+
end
|
|
336
|
+
end
|