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