enscalator 0.4.0.pre.alpha.pre.16

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.
Files changed (54) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +15 -0
  3. data/.rubocop.yml +9 -0
  4. data/.rubocop_todo.yml +59 -0
  5. data/.travis.yml +22 -0
  6. data/CODE_OF_CONDUCT.md +13 -0
  7. data/Gemfile +4 -0
  8. data/LICENSE.txt +21 -0
  9. data/README.md +148 -0
  10. data/Rakefile +43 -0
  11. data/bin/console +11 -0
  12. data/bin/setup +7 -0
  13. data/enscalator.gemspec +57 -0
  14. data/exe/enscalator +13 -0
  15. data/lib/enscalator/core/cf_parameters.rb +146 -0
  16. data/lib/enscalator/core/cf_resources.rb +225 -0
  17. data/lib/enscalator/core/instance_type.rb +205 -0
  18. data/lib/enscalator/core/network_config.rb +21 -0
  19. data/lib/enscalator/core.rb +10 -0
  20. data/lib/enscalator/enapp.rb +248 -0
  21. data/lib/enscalator/helpers/dns.rb +62 -0
  22. data/lib/enscalator/helpers/stack.rb +107 -0
  23. data/lib/enscalator/helpers/sub_process.rb +72 -0
  24. data/lib/enscalator/helpers/wrappers.rb +55 -0
  25. data/lib/enscalator/helpers.rb +127 -0
  26. data/lib/enscalator/plugins/amazon_linux.rb +93 -0
  27. data/lib/enscalator/plugins/auto_scale.rb +80 -0
  28. data/lib/enscalator/plugins/core_os.rb +88 -0
  29. data/lib/enscalator/plugins/couchbase.rb +98 -0
  30. data/lib/enscalator/plugins/debian.rb +71 -0
  31. data/lib/enscalator/plugins/elastic_beanstalk.rb +74 -0
  32. data/lib/enscalator/plugins/elasticache.rb +168 -0
  33. data/lib/enscalator/plugins/elasticsearch_amazon.rb +75 -0
  34. data/lib/enscalator/plugins/elasticsearch_bitnami.rb +198 -0
  35. data/lib/enscalator/plugins/elasticsearch_opsworks.rb +225 -0
  36. data/lib/enscalator/plugins/elb.rb +139 -0
  37. data/lib/enscalator/plugins/nat_gateway.rb +71 -0
  38. data/lib/enscalator/plugins/rds.rb +141 -0
  39. data/lib/enscalator/plugins/redis.rb +38 -0
  40. data/lib/enscalator/plugins/rethink_db.rb +21 -0
  41. data/lib/enscalator/plugins/route53.rb +143 -0
  42. data/lib/enscalator/plugins/ubuntu.rb +85 -0
  43. data/lib/enscalator/plugins/user-data/elasticsearch +367 -0
  44. data/lib/enscalator/plugins/vpc_peering_connection.rb +48 -0
  45. data/lib/enscalator/plugins.rb +30 -0
  46. data/lib/enscalator/rich_template_dsl.rb +209 -0
  47. data/lib/enscalator/templates/vpc_peering.rb +112 -0
  48. data/lib/enscalator/templates.rb +20 -0
  49. data/lib/enscalator/version.rb +5 -0
  50. data/lib/enscalator/vpc.rb +11 -0
  51. data/lib/enscalator/vpc_with_nat_gateway.rb +311 -0
  52. data/lib/enscalator/vpc_with_nat_instance.rb +402 -0
  53. data/lib/enscalator.rb +103 -0
  54. metadata +427 -0
@@ -0,0 +1,75 @@
1
+ module Enscalator
2
+ module Plugins
3
+ # Amazon Elasticsearch Service (Amazon ES)
4
+ module ElasticsearchAmazon
5
+ # Create new service instance
6
+ # @param [String] cluster_name name of the cluster resource
7
+ # @param [Hash] properties additional parameters for cluster configuration
8
+ def elasticsearch_init(cluster_name, properties: {})
9
+ cluster_properties = {
10
+ AccessPolicies: {
11
+ Version: '2012-10-17',
12
+ Statement: [
13
+ {
14
+ Effect: 'Allow',
15
+ Principal: {
16
+ AWS: '*'
17
+ }
18
+ }
19
+ ]
20
+ },
21
+ AdvancedOptions: {
22
+ 'rest.action.multi.allow_explicit_index': 'true'
23
+ },
24
+ EBSOptions: {
25
+ EBSEnabled: true,
26
+ Iops: 0,
27
+ VolumeSize: 100,
28
+ VolumeType: 'gp2'
29
+ },
30
+ ElasticsearchClusterConfig: {
31
+ InstanceCount: '1',
32
+ InstanceType: 'm3.medium.elasticsearch'
33
+ },
34
+ SnapshotOptions: {
35
+ AutomatedSnapshotStartHour: '0'
36
+ }
37
+ }
38
+
39
+ # do not modify properties passed from template
40
+ props = properties.deep_dup
41
+
42
+ default_tags = [
43
+ {
44
+ Key: 'ClusterName',
45
+ Value: cluster_name.downcase
46
+ }
47
+ ]
48
+
49
+ if props.key?(:Tags) && !props[:Tags].empty?
50
+ props[:Tags].concat(default_tags)
51
+ else
52
+ props[:Tags] = default_tags
53
+ end
54
+
55
+ resource cluster_name,
56
+ Type: 'AWS::Elasticsearch::Domain',
57
+ Properties: cluster_properties.merge(props)
58
+
59
+ output "#{cluster_name}ResourceID",
60
+ Description: "#{cluster_name} ResourceID",
61
+ Value: ref(cluster_name)
62
+
63
+ output "#{cluster_name}DomainArn",
64
+ Description: "#{cluster_name} DomainArn",
65
+ Value: get_att(cluster_name, 'DomainArn')
66
+
67
+ output "#{cluster_name}DomainEndpoint",
68
+ Description: "#{cluster_name} DomainEndpoint",
69
+ Value: get_att(cluster_name, 'DomainEndpoint')
70
+
71
+ cluster_name
72
+ end
73
+ end # module ElasticsearchAmazon
74
+ end # module Plugins
75
+ end # module Enscalator
@@ -0,0 +1,198 @@
1
+ module Enscalator
2
+ module Plugins
3
+ # Elasticsearch related configuration
4
+ module ElasticsearchBitnami
5
+ # Retrieves mapping for Elasticsearch Bitnami stack
6
+ class << self
7
+ # Supported storage types in AWS
8
+ STORAGE = [:ebs, :'instance-store']
9
+
10
+ # Supported Elasticsearch image architectures
11
+ ARCH = [:amd64, :i386]
12
+
13
+ # Get ami region/virtualization type mapping
14
+ #
15
+ # @param [Symbol] storage image root storage
16
+ # @param [Symbol] arch image architecture type
17
+ # @return [Hash] mapping
18
+ def get_mapping(storage: :ebs, arch: :amd64)
19
+ fail ArgumentError, "storage can only be one of #{STORAGE}" unless STORAGE.include? storage
20
+ fail ArgumentError, "arch can only be one of #{ARCH}" unless ARCH.include? arch
21
+ fetch_mapping(storage, arch)
22
+ end
23
+
24
+ # Get ami release version string
25
+ #
26
+ # @param [Symbol] storage image root storage
27
+ # @param [Symbol] arch image architecture type
28
+ # @return [Hash] mapping
29
+ def get_release_version(storage: :ebs, arch: :amd64)
30
+ fail ArgumentError, "storage can only be one of #{STORAGE}" unless STORAGE.include? storage
31
+ fail ArgumentError, "arch can only be one of #{ARCH}" unless ARCH.include? arch
32
+ fetch_versions
33
+ .select { |r| r.root_storage == storage && r.arch == arch }
34
+ .map { |v| v.version.to_s }.uniq.first
35
+ .gsub(/[-][\w\d]/, '')
36
+ end
37
+
38
+ private
39
+
40
+ # Structure to hold parsed record
41
+ Struct.new('ElasticSearch', :name, :version, :baseos, :root_storage, :arch, :region, :ami, :virtualization)
42
+
43
+ # Always fetches the most recent version
44
+ #
45
+ # @param [Symbol] storage image root storage
46
+ # @param [Symbol] arch image architecture type
47
+ # @return [Hash] mapping
48
+ def fetch_mapping(storage, arch)
49
+ versions = fetch_versions
50
+ versions.select { |r| r.root_storage == storage && r.arch == arch }
51
+ .group_by(&:region)
52
+ .map { |k, v| [k, v.map { |i| [i.virtualization, i.ami] }.to_h] }.to_h
53
+ .with_indifferent_access
54
+ end
55
+
56
+ # Make request to Bitnami Elasticsearch release pages, parse response and make list of versions
57
+ #
58
+ # @return [Array] list of all versions across all AWS regions
59
+ def fetch_versions
60
+ html = Nokogiri::HTML(open('https://bitnami.com/stack/elasticsearch/cloud/amazon'))
61
+ raw_entries = html.xpath('//td[@class="instance_id"]')
62
+ entries = raw_entries.xpath('a')
63
+ raw_entries.xpath('strong/a').each { |sa| entries << sa }
64
+ raw_versions = entries.map do |i|
65
+ [
66
+ i.xpath('@href').first.value.split('/').last,
67
+ i.children.first.text
68
+ ]
69
+ end.to_h
70
+ parse_versions(raw_versions)
71
+ end
72
+
73
+ # Parse list of raw strings
74
+ #
75
+ # @param entries [Array] list of strings
76
+ # @return [Array]
77
+ def parse_versions(entries)
78
+ entries.map do |rw, ami|
79
+ str, region = rw.split('?').map { |s| s.start_with?('region') ? s.split('=').last : s }
80
+ version_str = fix_entry(str).split('-')
81
+ name, version, baseos = version_str
82
+ Struct::ElasticSearch.new(name,
83
+ Semantic::Version.new(version.tr('=', '-')),
84
+ baseos,
85
+ version_str.include?('ebs') ? :ebs : :'instance-store',
86
+ version_str.include?('x64') ? :amd64 : :i386,
87
+ region,
88
+ ami,
89
+ version_str.include?('hvm') ? :hvm : :pv)
90
+ end
91
+ end
92
+
93
+ # Fix elasticsearch version string to have predictable format
94
+ #
95
+ # @param [String] str raw version string
96
+ # @return [String] reformatted version string
97
+ def fix_entry(str)
98
+ pattern = '[-](?:[\w\d]+){1,3}[-]ami'
99
+ token = begin
100
+ Regexp.new(pattern.gsub('?:', '')).match(str)[1]
101
+ rescue
102
+ nil
103
+ end
104
+ str.gsub(Regexp.new(pattern), ['=', token, '-'].join)
105
+ end
106
+ end # class << self
107
+
108
+ # Get aws account id
109
+ # @return [String] account id
110
+ def aws_account_id
111
+ # noinspection RubyArgCount
112
+ Aws::IAM::Client.new.get_user.user.arn.split(':')[4]
113
+ end
114
+
115
+ # Create new elasticsearch instance
116
+ #
117
+ # @param [String] storage_name storage name
118
+ # @param [Integer] allocated_storage size of instance primary storage
119
+ # @param [String] instance_type instance type
120
+ # @param [Hash] properties additional properties
121
+ # @param [String] zone_name route53 zone name
122
+ def elasticsearch_init(storage_name,
123
+ allocated_storage: 5,
124
+ instance_type: 't2.medium',
125
+ properties: {},
126
+ zone_name: nil)
127
+
128
+ @es_key_name = gen_ssh_key_name("Elasticsearch#{storage_name}", region, stack_name)
129
+ pre_run { create_ssh_key(@es_key_name, region, force_create: false) }
130
+
131
+ mapping 'AWSElasticsearchAMI', ElasticsearchBitnami.get_mapping
132
+
133
+ parameter_allocated_storage "Elasticsearch#{storage_name}",
134
+ default: allocated_storage,
135
+ min: 5,
136
+ max: 1024
137
+
138
+ parameter_ec2_instance_type "Elasticsearch#{storage_name}", type: instance_type
139
+
140
+ properties[:KeyName] = @es_key_name
141
+ properties[:InstanceType] = ref("Elasticsearch#{storage_name}InstanceType")
142
+
143
+ version_tag = {
144
+ Key: 'Version',
145
+ Value: ElasticsearchBitnami.get_release_version
146
+ }
147
+
148
+ cluster_name_tag = {
149
+ Key: 'ClusterName',
150
+ Value: storage_name.downcase
151
+ }
152
+
153
+ plugin_tags = [version_tag, cluster_name_tag]
154
+
155
+ # Set instance tags
156
+ if properties.key?(:Tags) && !properties[:Tags].empty?
157
+ properties[:Tags].concat(plugin_tags)
158
+ else
159
+ properties[:Tags] = plugin_tags
160
+ end
161
+
162
+ # Configure instance using user-data
163
+ if !properties.key?(:UserData) || !properties[:UserData].empty?
164
+ properties[:UserData] = Base64.encode64(read_user_data('elasticsearch'))
165
+ end
166
+
167
+ # Assign IAM role to instance
168
+ properties[:IamInstanceProfile] = iam_instance_profile_with_full_access(storage_name, *%w(ec2 s3))
169
+
170
+ storage_resource_name = "Elasticsearch#{storage_name}"
171
+ instance_vpc storage_resource_name,
172
+ find_in_map('AWSElasticsearchAMI', ref('AWS::Region'), :hvm),
173
+ ref_application_subnets.first,
174
+ [ref_private_security_group, ref_resource_security_group],
175
+ depends_on: [],
176
+ properties: properties
177
+
178
+ # create s3 bucket for cluster snapshots
179
+ account_id = aws_account_id
180
+ bucket_name = "elasticsearch-bitnami-#{region}-#{account_id}"
181
+ resource "Elasticsearch#{storage_name}S3Bucket",
182
+ Type: 'AWS::S3::Bucket',
183
+ DeletionPolicy: 'Retain',
184
+ Properties: {
185
+ BucketName: bucket_name
186
+ }
187
+
188
+ # create a DNS record in route53 for instance private ip
189
+ record_name = %W(#{storage_name.downcase.dasherize} #{region} #{zone_name}).join('.')
190
+ create_single_dns_record("#{storage_name}PrivateZone",
191
+ stack_name,
192
+ zone_name,
193
+ record_name,
194
+ resource_records: [get_att(storage_resource_name, 'PrivateIp')])
195
+ end
196
+ end # module ElasticsearchBitnami
197
+ end # module Plugins
198
+ end # module Enscalator
@@ -0,0 +1,225 @@
1
+ module Enscalator
2
+ module Plugins
3
+ # Elasticsearch related configuration
4
+ module ElasticsearchOpsworks
5
+ include Enscalator::Plugins::Elb
6
+
7
+ # Create Elasticsearch cluster using Opsworks
8
+ #
9
+ # @param [String] app_name application name
10
+ # @param [String] ssh_key name of the ssh key
11
+ # @param [String] os base operating system
12
+ # @param [String] cookbook chef cookbook
13
+ def elasticsearch_init(app_name,
14
+ ssh_key:,
15
+ es_config: {},
16
+ os: 'Amazon Linux 2015.09',
17
+ cookbook: 'https://github.com/en-japan-air/opsworks-elasticsearch-cookbook.git')
18
+
19
+ parameter "ES#{app_name}ChefCookbook",
20
+ Default: cookbook,
21
+ Description: 'GitURL',
22
+ Type: 'String'
23
+
24
+ parameter "ES#{app_name}InstanceDefaultOs",
25
+ Default: os,
26
+ Description: ['The stack\'s default operating system, which is installed',
27
+ 'on every instance unless you specify a different',
28
+ 'operating system when you create the instance.'].join(' '),
29
+ Type: 'String'
30
+
31
+ parameter "ES#{app_name}SshKeyName",
32
+ Default: ssh_key,
33
+ Description: 'SSH key name for EC2 instances.',
34
+ Type: 'String'
35
+
36
+ resource 'InstanceRole',
37
+ Type: 'AWS::IAM::InstanceProfile',
38
+ Properties: {
39
+ Path: '/',
40
+ Roles: [
41
+ ref('OpsWorksEC2Role')
42
+ ]
43
+ }
44
+
45
+ resource 'ServiceRole',
46
+ Type: 'AWS::IAM::Role',
47
+ Properties: {
48
+ AssumeRolePolicyDocument: {
49
+ Statement: [
50
+ {
51
+ Effect: 'Allow',
52
+ Principal: {
53
+ Service: [
54
+ 'opsworks.amazonaws.com'
55
+ ]
56
+ },
57
+ Action: [
58
+ 'sts:AssumeRole'
59
+ ]
60
+ }
61
+ ]
62
+ },
63
+ Path: '/',
64
+ Policies: [
65
+ {
66
+ PolicyName: "#{app_name}-opsworks-service",
67
+ PolicyDocument: {
68
+ Statement: [
69
+ {
70
+ Effect: 'Allow',
71
+ Action: %w( ec2:* iam:PassRole cloudwatch:GetMetricStatistics elasticloadbalancing:* ),
72
+ Resource: '*'
73
+ }
74
+ ]
75
+ }
76
+ }
77
+ ]
78
+ }
79
+
80
+ resource 'OpsWorksEC2Role',
81
+ Type: 'AWS::IAM::Role',
82
+ Properties: {
83
+ AssumeRolePolicyDocument: {
84
+ Statement: [
85
+ {
86
+ Effect: 'Allow',
87
+ Principal: {
88
+ Service: [
89
+ 'ec2.amazonaws.com'
90
+ ]
91
+ },
92
+ Action: [
93
+ 'sts:AssumeRole'
94
+ ]
95
+ }
96
+ ]
97
+ },
98
+ Path: '/',
99
+ Policies: [
100
+ {
101
+ PolicyName: "#{app_name}-opsworks-ec2-role",
102
+ PolicyDocument: {
103
+ Statement: [
104
+ {
105
+ Effect: 'Allow',
106
+ Action: %w(
107
+ ec2:DescribeInstances
108
+ ec2:DescribeRegions
109
+ ec2:DescribeSecurityGroups
110
+ ec2:DescribeTags
111
+ cloudwatch:PutMetricData),
112
+ Resource: '*'
113
+ }
114
+ ]
115
+ }
116
+ }
117
+ ]
118
+ }
119
+
120
+ instances_security_group = security_group_vpc("ES#{app_name}", 'so that ES cluster can find other nodes', vpc.id)
121
+
122
+ ops_stack_name = "#{app_name}-ES"
123
+ resource 'ESStack',
124
+ Type: 'AWS::OpsWorks::Stack',
125
+ Properties: {
126
+ Name: ops_stack_name,
127
+ VpcId: vpc.id,
128
+ DefaultSubnetId: ref_resource_subnets.first,
129
+ ConfigurationManager: {
130
+ Name: 'Chef',
131
+ Version: '12'
132
+ },
133
+ UseCustomCookbooks: 'true',
134
+ CustomCookbooksSource: {
135
+ Type: 'git',
136
+ Url: ref("ES#{app_name}ChefCookbook")
137
+ },
138
+ DefaultOs: ref("ES#{app_name}InstanceDefaultOs"),
139
+ DefaultRootDeviceType: 'ebs',
140
+ DefaultSshKeyName: ref("ES#{app_name}SshKeyName"),
141
+ CustomJson: {
142
+ java: {
143
+ jdk_version: '8',
144
+ oracle: {
145
+ accept_oracle_download_terms: 'true'
146
+ },
147
+ accept_license_agreement: 'true',
148
+ install_flavor: 'oracle'
149
+ },
150
+ elasticsearch: {
151
+ plugins: [
152
+ 'analysis-kuromoji',
153
+ 'cloud-aws',
154
+ { name: 'elasticsearch-head', url: 'mobz/elasticsearch-head' }
155
+ ],
156
+ config: {
157
+ 'cluster.name': "#{app_name}-elasticsearch",
158
+ 'path.data': '/mnt/elasticsearch-data',
159
+ 'path.logs': '/mnt/elasticsearch-data/logs/',
160
+ 'network.bind_host': '0.0.0.0',
161
+ 'network.publish_host': '_non_loopback_',
162
+ 'index.routing.allocation.disable_allocation': 'false',
163
+ 'cloud.aws.region': region,
164
+ discovery: {
165
+ type: 'ec2',
166
+ ec2: {
167
+ groups: [ref(instances_security_group)],
168
+ tag: {
169
+ 'opsworks:stack': ops_stack_name
170
+ }
171
+ }
172
+ },
173
+ 'cluster.routing.allocation.awareness.attributes': 'rack_id'
174
+ }.merge(es_config)
175
+ }
176
+ },
177
+ ServiceRoleArn: {
178
+ 'Fn::GetAtt': %w(ServiceRole Arn)
179
+ },
180
+ DefaultInstanceProfileArn: {
181
+ 'Fn::GetAtt': %w(InstanceRole Arn)
182
+ }
183
+ }
184
+
185
+ resource 'ESLayer',
186
+ Type: 'AWS::OpsWorks::Layer',
187
+ Properties: {
188
+ StackId: ref('ESStack'),
189
+ Name: 'Search',
190
+ Type: 'custom',
191
+ Shortname: 'search',
192
+ CustomRecipes: {
193
+ Setup: %w(apt ark java layer-custom::es-opsworks)
194
+ },
195
+ EnableAutoHealing: 'true',
196
+ AutoAssignElasticIps: 'false',
197
+ AutoAssignPublicIps: 'false',
198
+ VolumeConfigurations: [
199
+ {
200
+ MountPoint: '/mnt/elasticsearch-data',
201
+ NumberOfDisks: 1,
202
+ VolumeType: 'gp2',
203
+ Size: 100
204
+ }
205
+ ],
206
+ CustomSecurityGroupIds: [
207
+ {
208
+ 'Fn::GetAtt': %W(#{instances_security_group} GroupId)
209
+ },
210
+ ref_private_security_group
211
+ ]
212
+ }
213
+
214
+ resource 'ESMainInstance',
215
+ Type: 'AWS::OpsWorks::Instance',
216
+ Properties: {
217
+ # EbsOptimized: true, # Not available for m3.medium
218
+ InstanceType: 'm3.medium',
219
+ LayerIds: [ref('ESLayer')],
220
+ StackId: ref('ESStack')
221
+ }
222
+ end
223
+ end # module Elasticsearch
224
+ end # module Plugins
225
+ end # module Enscalator
@@ -0,0 +1,139 @@
1
+ module Enscalator
2
+ module Plugins
3
+ # Internet facing ELB instance
4
+ module Elb
5
+ # Create new ELB instance
6
+ #
7
+ # @param [String, Hash] elb_name ELB instance name - can be either String or Fn::Join
8
+ # @param [Integer] web_server_port application port to which ELB redirects traffic
9
+ # @param [String] zone_name zone name attached to the vpc
10
+ # @return [String] ELB resource name
11
+ def elb_init(elb_name: join('-', aws_stack_name, 'elb'),
12
+ web_server_port: 9000,
13
+ health_check_path: '/',
14
+ zone_name: nil,
15
+ dns_record_name: "elb.#{stack_name.dasherize}.#{zone_name}",
16
+ instances: [],
17
+ ssl: false,
18
+ internal: true)
19
+
20
+ elb_resource_name = 'LoadBalancer'
21
+
22
+ parameter 'WebServerPort',
23
+ Description: 'TCP/IP Port for the web service',
24
+ Default: web_server_port,
25
+ Type: 'Number',
26
+ MinValue: '0',
27
+ MaxValue: '65535',
28
+ ConstraintDescription: 'must be an integer between 0 and 65535.'
29
+
30
+ security_group_vpc 'ELBSecurityGroup',
31
+ 'Security group of the application servers',
32
+ ref('VpcId'),
33
+ security_group_ingress: [
34
+ {
35
+ IpProtocol: 'tcp',
36
+ FromPort: '0',
37
+ ToPort: '65535',
38
+ CidrIp: '10.0.0.0/8'
39
+ }
40
+ ] + (internal ? [] : [
41
+ {
42
+ IpProtocol: 'tcp',
43
+ FromPort: '80',
44
+ ToPort: '80',
45
+ CidrIp: '0.0.0.0/0'
46
+ },
47
+ {
48
+ IpProtocol: 'tcp',
49
+ FromPort: '443',
50
+ ToPort: '443',
51
+ CidrIp: '0.0.0.0/0'
52
+ },
53
+ {
54
+ IpProtocol: 'tcp',
55
+ FromPort: '465',
56
+ ToPort: '465',
57
+ CidrIp: '0.0.0.0/0'
58
+ }
59
+ ]),
60
+ tags: {
61
+ Name: join('-', aws_stack_name, 'app', 'sg'),
62
+ Application: aws_stack_name
63
+ }
64
+
65
+ if ssl
66
+ parameter 'SSLCertificateId',
67
+ Description: 'Id of the SSL certificate (iam-servercertgetattributes -s certname)',
68
+ Type: 'String',
69
+ ConstraintDescription: 'must be a string'
70
+ end
71
+
72
+ properties = {
73
+ LoadBalancerName: elb_name,
74
+ Listeners: [
75
+ {
76
+ LoadBalancerPort: '80',
77
+ InstancePort: ref('WebServerPort'),
78
+ Protocol: 'HTTP'
79
+ }
80
+ ] + (ssl == false ? [] : [
81
+ { LoadBalancerPort: '443',
82
+ InstancePort: ref('WebServerPort'),
83
+ SSLCertificateId: ref('SSLCertificateId'),
84
+ Protocol: 'HTTPS' }
85
+ ]),
86
+ HealthCheck: {
87
+ Target: join('', 'HTTP:', ref_web_server_port, health_check_path),
88
+ HealthyThreshold: '3',
89
+ UnhealthyThreshold: '5',
90
+ Interval: '30',
91
+ Timeout: '5'
92
+ },
93
+ SecurityGroups: [ref('ELBSecurityGroup')],
94
+ Subnets: internal ? ref_application_subnets : public_subnets,
95
+ Tags: [
96
+ {
97
+ Key: 'Name',
98
+ Value: elb_name
99
+ },
100
+ {
101
+ Key: 'Application',
102
+ Value: aws_stack_name
103
+ },
104
+ {
105
+ Key: 'Network',
106
+ Value: (internal ? 'Private' : 'Public')
107
+ }
108
+ ]
109
+ }
110
+
111
+ properties[:Scheme] = 'internal' if internal
112
+ properties[:Instances] = instances if instances && !instances.empty?
113
+
114
+ resource elb_resource_name,
115
+ Type: 'AWS::ElasticLoadBalancing::LoadBalancer',
116
+ Properties: properties
117
+
118
+ # use alias target to create proper cloudformation template for Route53 side of elb configuration
119
+ alias_target = {
120
+ HostedZoneId: get_att(elb_resource_name, 'CanonicalHostedZoneNameID'),
121
+ DNSName: get_att(elb_resource_name, internal ? 'DNSName' : 'CanonicalHostedZoneName')
122
+ }
123
+
124
+ create_single_dns_record(nil,
125
+ stack_name,
126
+ zone_name,
127
+ dns_record_name,
128
+ alias_target: alias_target)
129
+
130
+ output "#{elb_resource_name}DNSName",
131
+ Description: 'LoadBalancer DNS Name',
132
+ Value: get_att(elb_resource_name, 'DNSName')
133
+
134
+ # return resource name
135
+ elb_resource_name
136
+ end
137
+ end # module Elb
138
+ end # module Plugins
139
+ end # module Enscalator