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,94 @@
|
|
|
1
|
+
require_relative '../template'
|
|
2
|
+
|
|
3
|
+
class Formatron
|
|
4
|
+
module CloudFormation
|
|
5
|
+
module Resources
|
|
6
|
+
# Generates CloudFormation template IAM resources
|
|
7
|
+
module IAM
|
|
8
|
+
# rubocop:disable Metrics/MethodLength
|
|
9
|
+
def self.role
|
|
10
|
+
{
|
|
11
|
+
Type: 'AWS::IAM::Role',
|
|
12
|
+
Properties: {
|
|
13
|
+
AssumeRolePolicyDocument: {
|
|
14
|
+
Version: '2012-10-17',
|
|
15
|
+
Statement: [{
|
|
16
|
+
Effect: 'Allow',
|
|
17
|
+
Principal: { Service: ['ec2.amazonaws.com'] },
|
|
18
|
+
Action: ['sts:AssumeRole']
|
|
19
|
+
}]
|
|
20
|
+
},
|
|
21
|
+
Path: '/'
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
end
|
|
25
|
+
# rubocop:enable Metrics/MethodLength
|
|
26
|
+
|
|
27
|
+
def self.instance_profile(role:)
|
|
28
|
+
{
|
|
29
|
+
Type: 'AWS::IAM::InstanceProfile',
|
|
30
|
+
Properties: {
|
|
31
|
+
Path: '/',
|
|
32
|
+
Roles: [Template.ref(role)]
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# rubocop:disable Metrics/MethodLength
|
|
38
|
+
def self.policy(role:, name:, statements:)
|
|
39
|
+
{
|
|
40
|
+
Type: 'AWS::IAM::Policy',
|
|
41
|
+
Properties: {
|
|
42
|
+
Roles: [Template.ref(role)],
|
|
43
|
+
PolicyName: name,
|
|
44
|
+
PolicyDocument: {
|
|
45
|
+
Version: '2012-10-17',
|
|
46
|
+
Statement: statements.collect do |statement|
|
|
47
|
+
{
|
|
48
|
+
Effect: 'Allow',
|
|
49
|
+
Action: statement[:actions],
|
|
50
|
+
Resource: statement[:resources]
|
|
51
|
+
}
|
|
52
|
+
end
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
end
|
|
57
|
+
# rubocop:enable Metrics/MethodLength
|
|
58
|
+
|
|
59
|
+
# rubocop:disable Metrics/MethodLength
|
|
60
|
+
def self.user(policy_name:, statements:)
|
|
61
|
+
{
|
|
62
|
+
Type: 'AWS::IAM::User',
|
|
63
|
+
Properties: {
|
|
64
|
+
Path: '/',
|
|
65
|
+
Policies: [{
|
|
66
|
+
PolicyName: policy_name,
|
|
67
|
+
PolicyDocument: {
|
|
68
|
+
Version: '2012-10-17',
|
|
69
|
+
Statement: statements.collect do |statement|
|
|
70
|
+
{
|
|
71
|
+
Effect: 'Allow',
|
|
72
|
+
Action: statement[:actions],
|
|
73
|
+
Resource: statement[:resources]
|
|
74
|
+
}
|
|
75
|
+
end
|
|
76
|
+
}
|
|
77
|
+
}]
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
end
|
|
81
|
+
# rubocop:enable Metrics/MethodLength
|
|
82
|
+
|
|
83
|
+
def self.access_key(user_name:)
|
|
84
|
+
{
|
|
85
|
+
Type: 'AWS::IAM::AccessKey',
|
|
86
|
+
Properties: {
|
|
87
|
+
UserName: user_name
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
end
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
require_relative '../template'
|
|
2
|
+
|
|
3
|
+
class Formatron
|
|
4
|
+
module CloudFormation
|
|
5
|
+
module Resources
|
|
6
|
+
# Generates CloudFormation template Route53 resources
|
|
7
|
+
module Route53
|
|
8
|
+
# rubocop:disable Metrics/MethodLength
|
|
9
|
+
def self.hosted_zone(name:, vpc:)
|
|
10
|
+
{
|
|
11
|
+
Type: 'AWS::Route53::HostedZone',
|
|
12
|
+
Properties: {
|
|
13
|
+
HostedZoneConfig: {
|
|
14
|
+
Comment: Template.join(
|
|
15
|
+
'Private Hosted Zone for CloudFormation Stack: ',
|
|
16
|
+
Template.ref('AWS::StackName')
|
|
17
|
+
)
|
|
18
|
+
},
|
|
19
|
+
Name: name,
|
|
20
|
+
VPCs: [{
|
|
21
|
+
VPCId: Template.ref(vpc),
|
|
22
|
+
VPCRegion: Template.ref('AWS::Region')
|
|
23
|
+
}]
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
end
|
|
27
|
+
# rubocop:enable Metrics/MethodLength
|
|
28
|
+
|
|
29
|
+
# rubocop:disable Metrics/MethodLength
|
|
30
|
+
def self.record_set(
|
|
31
|
+
hosted_zone_id:,
|
|
32
|
+
sub_domain:,
|
|
33
|
+
hosted_zone_name:,
|
|
34
|
+
instance:,
|
|
35
|
+
attribute:
|
|
36
|
+
)
|
|
37
|
+
{
|
|
38
|
+
Type: 'AWS::Route53::RecordSet',
|
|
39
|
+
Properties: {
|
|
40
|
+
HostedZoneId: hosted_zone_id,
|
|
41
|
+
Name: "#{sub_domain}.#{hosted_zone_name}",
|
|
42
|
+
ResourceRecords: [
|
|
43
|
+
Template.get_attribute(instance, attribute)
|
|
44
|
+
],
|
|
45
|
+
TTL: '900',
|
|
46
|
+
Type: 'A'
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
end
|
|
50
|
+
# rubocop:enable Metrics/MethodLength
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
class Formatron
|
|
2
|
+
module CloudFormation
|
|
3
|
+
# Generates scripts for setting up instances with CloudFormation init
|
|
4
|
+
module Scripts
|
|
5
|
+
def self.hostname(sub_domain:, hosted_zone_name:)
|
|
6
|
+
# rubocop:disable Metrics/LineLength
|
|
7
|
+
<<-EOH.gsub(/^ {10}/, '')
|
|
8
|
+
#/bin/bash -v
|
|
9
|
+
set -e
|
|
10
|
+
SHORTNAME=#{sub_domain}
|
|
11
|
+
PUBLIC_DNS=${SHORTNAME}.#{hosted_zone_name}
|
|
12
|
+
PRIVATE_IPV4=`(curl http://169.254.169.254/latest/meta-data/local-ipv4)`
|
|
13
|
+
hostname $SHORTNAME
|
|
14
|
+
echo $PUBLIC_DNS | tee /etc/hostname
|
|
15
|
+
echo "$PRIVATE_IPV4 $PUBLIC_DNS $SHORTNAME" >> /etc/hosts
|
|
16
|
+
EOH
|
|
17
|
+
# rubocop:enable Metrics/LineLength
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
# rubocop:disable Metrics/MethodLength
|
|
21
|
+
def self.nat(cidr:)
|
|
22
|
+
# rubocop:disable Metrics/LineLength
|
|
23
|
+
<<-EOH.gsub(/^ {10}/, '')
|
|
24
|
+
#/bin/bash -v
|
|
25
|
+
set -e
|
|
26
|
+
if ! grep --quiet '^net.ipv4.ip_forward=1$' /etc/sysctl.conf; then
|
|
27
|
+
sed -i '/^#net.ipv4.ip_forward=1$/c\\net.ipv4.ip_forward=1' /etc/sysctl.conf
|
|
28
|
+
sysctl -p /etc/sysctl.conf
|
|
29
|
+
fi
|
|
30
|
+
iptables -t nat -A POSTROUTING -o eth0 -s #{cidr} -j MASQUERADE
|
|
31
|
+
iptables-save > /etc/iptables.rules
|
|
32
|
+
cat << EOF > /etc/network/if-pre-up.d/iptablesload
|
|
33
|
+
#!/bin/sh
|
|
34
|
+
iptables-restore < /etc/iptables.rules
|
|
35
|
+
exit 0
|
|
36
|
+
EOF
|
|
37
|
+
chmod +x /etc/network/if-pre-up.d/iptablesload
|
|
38
|
+
EOH
|
|
39
|
+
# rubocop:enable Metrics/LineLength
|
|
40
|
+
end
|
|
41
|
+
# rubocop:enable Metrics/MethodLength
|
|
42
|
+
|
|
43
|
+
# rubocop:disable Metrics/MethodLength
|
|
44
|
+
# rubocop:disable Metrics/ParameterLists
|
|
45
|
+
def self.chef_server(
|
|
46
|
+
username:,
|
|
47
|
+
first_name:,
|
|
48
|
+
last_name:,
|
|
49
|
+
email:,
|
|
50
|
+
password:,
|
|
51
|
+
organization_short_name:,
|
|
52
|
+
organization_full_name:,
|
|
53
|
+
bucket:,
|
|
54
|
+
user_pem_key:,
|
|
55
|
+
organization_pem_key:,
|
|
56
|
+
kms_key:,
|
|
57
|
+
chef_server_version:,
|
|
58
|
+
ssl_cert_key:,
|
|
59
|
+
ssl_key_key:,
|
|
60
|
+
cookbooks_bucket:
|
|
61
|
+
)
|
|
62
|
+
# rubocop:disable Metrics/LineLength
|
|
63
|
+
<<-EOH.gsub(/^ {10}/, '')
|
|
64
|
+
#!/bin/bash -v
|
|
65
|
+
|
|
66
|
+
set -e
|
|
67
|
+
|
|
68
|
+
export HOME=/root
|
|
69
|
+
|
|
70
|
+
source /tmp/formatron/script-variables
|
|
71
|
+
|
|
72
|
+
apt-get -y update
|
|
73
|
+
apt-get -y install wget ntp cron git libfreetype6 libpng3 python-pip
|
|
74
|
+
pip install awscli
|
|
75
|
+
|
|
76
|
+
mkdir -p $HOME/.aws
|
|
77
|
+
cat << EOF > $HOME/.aws/config
|
|
78
|
+
[default]
|
|
79
|
+
s3 =
|
|
80
|
+
signature_version = s3v4
|
|
81
|
+
region = ${REGION}
|
|
82
|
+
EOF
|
|
83
|
+
|
|
84
|
+
mkdir -p /etc/opscode
|
|
85
|
+
cat << EOF > /etc/opscode/chef-server.rb
|
|
86
|
+
bookshelf['enable'] = false
|
|
87
|
+
bookshelf['external_url'] = 'https://s3-${REGION}.amazonaws.com'
|
|
88
|
+
bookshelf['vip'] = 's3-${REGION}.amazonaws.com'
|
|
89
|
+
bookshelf['access_key_id'] = '${ACCESS_KEY_ID}'
|
|
90
|
+
bookshelf['secret_access_key'] = '${SECRET_ACCESS_KEY}'
|
|
91
|
+
opscode_erchef['s3_bucket'] = '#{cookbooks_bucket}'
|
|
92
|
+
nginx['ssl_certificate'] = '/etc/nginx/ssl/chef.crt'
|
|
93
|
+
nginx['ssl_certificate_key'] = '/etc/nginx/ssl/chef.key'
|
|
94
|
+
EOF
|
|
95
|
+
|
|
96
|
+
mkdir -p /etc/nginx/ssl
|
|
97
|
+
aws s3api get-object --bucket #{bucket} --key #{ssl_cert_key} /etc/nginx/ssl/chef.crt
|
|
98
|
+
aws s3api get-object --bucket #{bucket} --key #{ssl_key_key} /etc/nginx/ssl/chef.key
|
|
99
|
+
|
|
100
|
+
wget -O /tmp/chef-server-core.deb https://web-dl.packagecloud.io/chef/stable/packages/ubuntu/trusty/chef-server-core_#{chef_server_version}_amd64.deb
|
|
101
|
+
dpkg -i /tmp/chef-server-core.deb
|
|
102
|
+
|
|
103
|
+
chef-server-ctl reconfigure >> /var/log/chef-install.log
|
|
104
|
+
chef-server-ctl user-create #{username} #{first_name} #{last_name} #{email} #{password} --filename $HOME/user.pem >> /var/log/chef-install.log
|
|
105
|
+
chef-server-ctl org-create #{organization_short_name} "#{organization_full_name}" --association_user #{username} --filename $HOME/organization.pem >> /var/log/chef-install.log
|
|
106
|
+
|
|
107
|
+
chef-server-ctl install opscode-manage >> /var/log/chef-install.log
|
|
108
|
+
chef-server-ctl reconfigure >> /var/log/chef-install.log
|
|
109
|
+
opscode-manage-ctl reconfigure >> /var/log/chef-install.log
|
|
110
|
+
|
|
111
|
+
chef-server-ctl install opscode-push-jobs-server >> /var/log/chef-install.log
|
|
112
|
+
chef-server-ctl reconfigure >> /var/log/chef-install.log
|
|
113
|
+
opscode-push-jobs-server-ctl reconfigure >> /var/log/chef-install.log
|
|
114
|
+
|
|
115
|
+
chef-server-ctl install opscode-reporting >> /var/log/chef-install.log
|
|
116
|
+
chef-server-ctl reconfigure >> /var/log/chef-install.log
|
|
117
|
+
opscode-reporting-ctl reconfigure >> /var/log/chef-install.log
|
|
118
|
+
|
|
119
|
+
aws s3api put-object --bucket #{bucket} --key #{user_pem_key} --body $HOME/user.pem --ssekms-key-id #{kms_key} --server-side-encryption aws:kms
|
|
120
|
+
aws s3api put-object --bucket #{bucket} --key #{organization_pem_key} --body $HOME/organization.pem --ssekms-key-id #{kms_key} --server-side-encryption aws:kms
|
|
121
|
+
EOH
|
|
122
|
+
# rubocop:enable Metrics/LineLength
|
|
123
|
+
end
|
|
124
|
+
# rubocop:enable Metrics/ParameterLists
|
|
125
|
+
# rubocop:enable Metrics/MethodLength
|
|
126
|
+
end
|
|
127
|
+
end
|
|
128
|
+
end
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
require_relative 'template/vpc'
|
|
2
|
+
require_relative 'template/parameters'
|
|
3
|
+
require 'formatron/aws'
|
|
4
|
+
|
|
5
|
+
class Formatron
|
|
6
|
+
module CloudFormation
|
|
7
|
+
# generates a CloudFormation template
|
|
8
|
+
class Template
|
|
9
|
+
REGION_MAP = 'regionMap'
|
|
10
|
+
|
|
11
|
+
# rubocop:disable Metrics/MethodLength
|
|
12
|
+
# rubocop:disable Metrics/ParameterLists
|
|
13
|
+
def initialize(
|
|
14
|
+
formatron:,
|
|
15
|
+
external:,
|
|
16
|
+
hosted_zone_name:,
|
|
17
|
+
key_pair:,
|
|
18
|
+
kms_key:,
|
|
19
|
+
hosted_zone_id:,
|
|
20
|
+
target:
|
|
21
|
+
)
|
|
22
|
+
@formatron = formatron
|
|
23
|
+
@external = external
|
|
24
|
+
@external_formatron = external.formatron
|
|
25
|
+
@external_outputs = external.outputs
|
|
26
|
+
@hosted_zone_name = hosted_zone_name
|
|
27
|
+
@key_pair = key_pair
|
|
28
|
+
@kms_key = kms_key
|
|
29
|
+
@hosted_zone_id = hosted_zone_id
|
|
30
|
+
@bucket = formatron.bucket
|
|
31
|
+
@name = formatron.name
|
|
32
|
+
@target = target
|
|
33
|
+
end
|
|
34
|
+
# rubocop:enable Metrics/ParameterLists
|
|
35
|
+
# rubocop:enable Metrics/MethodLength
|
|
36
|
+
|
|
37
|
+
# rubocop:disable Metrics/MethodLength
|
|
38
|
+
def hash
|
|
39
|
+
resources = {}
|
|
40
|
+
outputs = {}
|
|
41
|
+
parameters = {}
|
|
42
|
+
@formatron.vpc.each do |key, vpc|
|
|
43
|
+
template_vpc = VPC.new(
|
|
44
|
+
vpc: vpc,
|
|
45
|
+
external: @external_formatron.vpc[key],
|
|
46
|
+
hosted_zone_name: @hosted_zone_name,
|
|
47
|
+
key_pair: @key_pair,
|
|
48
|
+
kms_key: @kms_key,
|
|
49
|
+
hosted_zone_id: @hosted_zone_id,
|
|
50
|
+
bucket: @bucket,
|
|
51
|
+
name: @name,
|
|
52
|
+
target: @target
|
|
53
|
+
)
|
|
54
|
+
template_vpc.merge resources: resources, outputs: outputs
|
|
55
|
+
end
|
|
56
|
+
template_parameters = Parameters.new keys: @external_outputs.hash.keys
|
|
57
|
+
template_parameters.merge parameters: parameters
|
|
58
|
+
{
|
|
59
|
+
AWSTemplateFormatVersion: '2010-09-09',
|
|
60
|
+
Description: "Formatron stack: #{@formatron.name}",
|
|
61
|
+
Mappings: {
|
|
62
|
+
REGION_MAP => AWS::REGIONS
|
|
63
|
+
},
|
|
64
|
+
Parameters: parameters,
|
|
65
|
+
Resources: resources,
|
|
66
|
+
Outputs: outputs
|
|
67
|
+
}
|
|
68
|
+
end
|
|
69
|
+
# rubocop:enable Metrics/MethodLength
|
|
70
|
+
|
|
71
|
+
def self.ref(logical_id)
|
|
72
|
+
{
|
|
73
|
+
Ref: logical_id
|
|
74
|
+
}
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def self.join(*items)
|
|
78
|
+
{
|
|
79
|
+
'Fn::Join' => [
|
|
80
|
+
'', items
|
|
81
|
+
]
|
|
82
|
+
}
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def self.find_in_map(map, key, property)
|
|
86
|
+
{
|
|
87
|
+
'Fn::FindInMap' => [
|
|
88
|
+
map,
|
|
89
|
+
key,
|
|
90
|
+
property
|
|
91
|
+
]
|
|
92
|
+
}
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
def self.base_64(value)
|
|
96
|
+
{
|
|
97
|
+
'Fn::Base64' => value
|
|
98
|
+
}
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
def self.get_attribute(resource, attribute)
|
|
102
|
+
{
|
|
103
|
+
'Fn::GetAtt' => [resource, attribute]
|
|
104
|
+
}
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
def self.output(value)
|
|
108
|
+
{
|
|
109
|
+
Value: value
|
|
110
|
+
}
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
end
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
class Formatron
|
|
2
|
+
module CloudFormation
|
|
3
|
+
class Template
|
|
4
|
+
# generates CloudFormation parameter declarations
|
|
5
|
+
class Parameters
|
|
6
|
+
def initialize(keys:)
|
|
7
|
+
@keys = keys
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def merge(parameters:)
|
|
11
|
+
@keys.each do |key|
|
|
12
|
+
parameters[key] = {
|
|
13
|
+
Type: 'String'
|
|
14
|
+
}
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
require_relative 'vpc/subnet'
|
|
2
|
+
require 'formatron/cloud_formation/resources/ec2'
|
|
3
|
+
require 'formatron/cloud_formation/resources/route53'
|
|
4
|
+
require 'formatron/util/vpc'
|
|
5
|
+
|
|
6
|
+
class Formatron
|
|
7
|
+
module CloudFormation
|
|
8
|
+
class Template
|
|
9
|
+
# generates CloudFormation VPC resources
|
|
10
|
+
# rubocop:disable Metrics/ClassLength
|
|
11
|
+
class VPC
|
|
12
|
+
VPC_PREFIX = 'vpc'
|
|
13
|
+
INTERNET_GATEWAY_PREFIX = 'internetGateway'
|
|
14
|
+
VPC_GATEWAY_ATTACHMENT_PREFIX = 'vpcGatewayAttachment'
|
|
15
|
+
ROUTE_TABLE_PREFIX = 'routeTable'
|
|
16
|
+
ROUTE_PREFIX = 'route'
|
|
17
|
+
HOSTED_ZONE_PREFIX = 'hostedZone'
|
|
18
|
+
|
|
19
|
+
# rubocop:disable Metrics/MethodLength
|
|
20
|
+
# rubocop:disable Metrics/ParameterLists
|
|
21
|
+
def initialize(
|
|
22
|
+
vpc:,
|
|
23
|
+
external:,
|
|
24
|
+
hosted_zone_name:,
|
|
25
|
+
key_pair:,
|
|
26
|
+
kms_key:,
|
|
27
|
+
hosted_zone_id:,
|
|
28
|
+
bucket:,
|
|
29
|
+
name:,
|
|
30
|
+
target:
|
|
31
|
+
)
|
|
32
|
+
@vpc = vpc
|
|
33
|
+
@external = external
|
|
34
|
+
@hosted_zone_name = hosted_zone_name
|
|
35
|
+
@key_pair = key_pair
|
|
36
|
+
@kms_key = kms_key
|
|
37
|
+
@hosted_zone_id = hosted_zone_id
|
|
38
|
+
@bucket = bucket
|
|
39
|
+
@name = name
|
|
40
|
+
@target = target
|
|
41
|
+
end
|
|
42
|
+
# rubocop:enable Metrics/ParameterLists
|
|
43
|
+
# rubocop:enable Metrics/MethodLength
|
|
44
|
+
|
|
45
|
+
def merge(resources:, outputs:)
|
|
46
|
+
@guid = @vpc.guid
|
|
47
|
+
if @guid.nil?
|
|
48
|
+
@guid = @external.guid
|
|
49
|
+
_merge_external resources: resources, outputs: outputs
|
|
50
|
+
else
|
|
51
|
+
_merge_local resources: resources, outputs: outputs
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
# rubocop:disable Metrics/MethodLength
|
|
56
|
+
def _merge_local(resources:, outputs:)
|
|
57
|
+
@cidr = @vpc.cidr
|
|
58
|
+
@logical_id = "#{VPC_PREFIX}#{@guid}"
|
|
59
|
+
@internet_gateway_id = "#{INTERNET_GATEWAY_PREFIX}#{@guid}"
|
|
60
|
+
@vpc_gateway_attachment_id =
|
|
61
|
+
"#{VPC_GATEWAY_ATTACHMENT_PREFIX}#{@guid}"
|
|
62
|
+
@route_table_id =
|
|
63
|
+
"#{ROUTE_TABLE_PREFIX}#{@guid}"
|
|
64
|
+
@route_id =
|
|
65
|
+
"#{ROUTE_PREFIX}#{@guid}"
|
|
66
|
+
@private_hosted_zone_id =
|
|
67
|
+
"#{HOSTED_ZONE_PREFIX}#{@guid}"
|
|
68
|
+
@vpc.subnet.each do |_, subnet|
|
|
69
|
+
template_subnet = Subnet.new(
|
|
70
|
+
subnet: subnet,
|
|
71
|
+
external: nil,
|
|
72
|
+
vpc_guid: @guid,
|
|
73
|
+
vpc_cidr: @cidr,
|
|
74
|
+
key_pair: @key_pair,
|
|
75
|
+
hosted_zone_name: @hosted_zone_name,
|
|
76
|
+
kms_key: @kms_key,
|
|
77
|
+
nats: Util::VPC.instances(:nat, @vpc),
|
|
78
|
+
private_hosted_zone_id: @private_hosted_zone_id,
|
|
79
|
+
public_hosted_zone_id: @hosted_zone_id,
|
|
80
|
+
bucket: @bucket,
|
|
81
|
+
name: @name,
|
|
82
|
+
target: @target
|
|
83
|
+
)
|
|
84
|
+
template_subnet.merge resources: resources, outputs: outputs
|
|
85
|
+
end
|
|
86
|
+
_add_vpc resources, outputs
|
|
87
|
+
_add_internet_gateway resources
|
|
88
|
+
_add_vpc_gateway_attachment resources
|
|
89
|
+
_add_route_table resources
|
|
90
|
+
_add_route resources
|
|
91
|
+
_add_private_hosted_zone resources, outputs
|
|
92
|
+
end
|
|
93
|
+
# rubocop:enable Metrics/MethodLength
|
|
94
|
+
|
|
95
|
+
# rubocop:disable Metrics/MethodLength
|
|
96
|
+
def _merge_external(resources:, outputs:)
|
|
97
|
+
@cidr = @external.cidr
|
|
98
|
+
@private_hosted_zone_id =
|
|
99
|
+
"#{HOSTED_ZONE_PREFIX}#{@guid}"
|
|
100
|
+
@vpc.subnet.each do |key, subnet|
|
|
101
|
+
template_subnet = Subnet.new(
|
|
102
|
+
subnet: subnet,
|
|
103
|
+
external: @external.subnet[key],
|
|
104
|
+
vpc_guid: @guid,
|
|
105
|
+
vpc_cidr: @cidr,
|
|
106
|
+
key_pair: @key_pair,
|
|
107
|
+
hosted_zone_name: @hosted_zone_name,
|
|
108
|
+
kms_key: @kms_key,
|
|
109
|
+
nats: Util::VPC.instances(:nat, @external, @vpc),
|
|
110
|
+
private_hosted_zone_id: @private_hosted_zone_id,
|
|
111
|
+
public_hosted_zone_id: @hosted_zone_id,
|
|
112
|
+
bucket: @bucket,
|
|
113
|
+
name: @name,
|
|
114
|
+
target: @target
|
|
115
|
+
)
|
|
116
|
+
template_subnet.merge resources: resources, outputs: outputs
|
|
117
|
+
end
|
|
118
|
+
end
|
|
119
|
+
# rubocop:enable Metrics/MethodLength
|
|
120
|
+
|
|
121
|
+
def _add_vpc(resources, outputs)
|
|
122
|
+
resources[@logical_id] = Resources::EC2.vpc cidr: @cidr
|
|
123
|
+
outputs[@logical_id] = Template.output Template.ref(@logical_id)
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
def _add_internet_gateway(resources)
|
|
127
|
+
resources[@internet_gateway_id] = Resources::EC2.internet_gateway
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
def _add_vpc_gateway_attachment(resources)
|
|
131
|
+
resources[
|
|
132
|
+
@vpc_gateway_attachment_id
|
|
133
|
+
] = Resources::EC2.vpc_gateway_attachment(
|
|
134
|
+
vpc: @logical_id,
|
|
135
|
+
gateway: @internet_gateway_id
|
|
136
|
+
)
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
def _add_route_table(resources)
|
|
140
|
+
resources[
|
|
141
|
+
@route_table_id
|
|
142
|
+
] = Resources::EC2.route_table(
|
|
143
|
+
vpc: @logical_id
|
|
144
|
+
)
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
def _add_route(resources)
|
|
148
|
+
resources[
|
|
149
|
+
@route_id
|
|
150
|
+
] = Resources::EC2.route(
|
|
151
|
+
vpc_gateway_attachment: @vpc_gateway_attachment_id,
|
|
152
|
+
internet_gateway: @internet_gateway_id,
|
|
153
|
+
route_table: @route_table_id
|
|
154
|
+
)
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
def _add_private_hosted_zone(resources, outputs)
|
|
158
|
+
resources[@private_hosted_zone_id] = Resources::Route53.hosted_zone(
|
|
159
|
+
name: @hosted_zone_name,
|
|
160
|
+
vpc: @logical_id
|
|
161
|
+
)
|
|
162
|
+
outputs[@private_hosted_zone_id] = Template.output(
|
|
163
|
+
Template.ref(@private_hosted_zone_id)
|
|
164
|
+
)
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
private(
|
|
168
|
+
:_merge_local,
|
|
169
|
+
:_merge_external,
|
|
170
|
+
:_add_vpc,
|
|
171
|
+
:_add_internet_gateway,
|
|
172
|
+
:_add_vpc_gateway_attachment,
|
|
173
|
+
:_add_route_table,
|
|
174
|
+
:_add_route,
|
|
175
|
+
:_add_private_hosted_zone
|
|
176
|
+
)
|
|
177
|
+
end
|
|
178
|
+
# rubocop:enable Metrics/ClassLength
|
|
179
|
+
end
|
|
180
|
+
end
|
|
181
|
+
end
|