enscalator 0.4.0.pre.alpha.pre.16
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +15 -0
- data/.rubocop.yml +9 -0
- data/.rubocop_todo.yml +59 -0
- data/.travis.yml +22 -0
- data/CODE_OF_CONDUCT.md +13 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +21 -0
- data/README.md +148 -0
- data/Rakefile +43 -0
- data/bin/console +11 -0
- data/bin/setup +7 -0
- data/enscalator.gemspec +57 -0
- data/exe/enscalator +13 -0
- data/lib/enscalator/core/cf_parameters.rb +146 -0
- data/lib/enscalator/core/cf_resources.rb +225 -0
- data/lib/enscalator/core/instance_type.rb +205 -0
- data/lib/enscalator/core/network_config.rb +21 -0
- data/lib/enscalator/core.rb +10 -0
- data/lib/enscalator/enapp.rb +248 -0
- data/lib/enscalator/helpers/dns.rb +62 -0
- data/lib/enscalator/helpers/stack.rb +107 -0
- data/lib/enscalator/helpers/sub_process.rb +72 -0
- data/lib/enscalator/helpers/wrappers.rb +55 -0
- data/lib/enscalator/helpers.rb +127 -0
- data/lib/enscalator/plugins/amazon_linux.rb +93 -0
- data/lib/enscalator/plugins/auto_scale.rb +80 -0
- data/lib/enscalator/plugins/core_os.rb +88 -0
- data/lib/enscalator/plugins/couchbase.rb +98 -0
- data/lib/enscalator/plugins/debian.rb +71 -0
- data/lib/enscalator/plugins/elastic_beanstalk.rb +74 -0
- data/lib/enscalator/plugins/elasticache.rb +168 -0
- data/lib/enscalator/plugins/elasticsearch_amazon.rb +75 -0
- data/lib/enscalator/plugins/elasticsearch_bitnami.rb +198 -0
- data/lib/enscalator/plugins/elasticsearch_opsworks.rb +225 -0
- data/lib/enscalator/plugins/elb.rb +139 -0
- data/lib/enscalator/plugins/nat_gateway.rb +71 -0
- data/lib/enscalator/plugins/rds.rb +141 -0
- data/lib/enscalator/plugins/redis.rb +38 -0
- data/lib/enscalator/plugins/rethink_db.rb +21 -0
- data/lib/enscalator/plugins/route53.rb +143 -0
- data/lib/enscalator/plugins/ubuntu.rb +85 -0
- data/lib/enscalator/plugins/user-data/elasticsearch +367 -0
- data/lib/enscalator/plugins/vpc_peering_connection.rb +48 -0
- data/lib/enscalator/plugins.rb +30 -0
- data/lib/enscalator/rich_template_dsl.rb +209 -0
- data/lib/enscalator/templates/vpc_peering.rb +112 -0
- data/lib/enscalator/templates.rb +20 -0
- data/lib/enscalator/version.rb +5 -0
- data/lib/enscalator/vpc.rb +11 -0
- data/lib/enscalator/vpc_with_nat_gateway.rb +311 -0
- data/lib/enscalator/vpc_with_nat_instance.rb +402 -0
- data/lib/enscalator.rb +103 -0
- metadata +427 -0
@@ -0,0 +1,71 @@
|
|
1
|
+
module Enscalator
|
2
|
+
module Plugins
|
3
|
+
# VPC NAT Gateway plugin
|
4
|
+
module NATGateway
|
5
|
+
# Allocate new elastic IP in given VPC template
|
6
|
+
#
|
7
|
+
# @param [String] name eip resource name
|
8
|
+
# @param [Array<String>] depends_on list of resource names this resource depends on
|
9
|
+
# @return [Hash] result of Fn::GetAtt function
|
10
|
+
def allocate_new_eip(name, depends_on: [])
|
11
|
+
fail('Dependency on the VPC-gateway attachment must be provided') if depends_on.empty?
|
12
|
+
eip_resource_name = name
|
13
|
+
resource eip_resource_name,
|
14
|
+
DependsOn: depends_on,
|
15
|
+
Type: 'AWS::EC2::EIP',
|
16
|
+
Properties: {
|
17
|
+
Domain: 'vpc'
|
18
|
+
}
|
19
|
+
|
20
|
+
output eip_resource_name,
|
21
|
+
Description: 'Elastic IP address for NAT Gateway',
|
22
|
+
Value: ref(eip_resource_name)
|
23
|
+
|
24
|
+
get_att(eip_resource_name, 'AllocationId')
|
25
|
+
end
|
26
|
+
|
27
|
+
# Create new route rule
|
28
|
+
#
|
29
|
+
# @param [String] name route rule name
|
30
|
+
# @param [Array<String>] depends_on list of resource names this resource depends on
|
31
|
+
def add_route_rule(name, route_table_name, nat_gateway_name, dest_cidr_block, depends_on: [])
|
32
|
+
options = {
|
33
|
+
Type: 'AWS::EC2::Route'
|
34
|
+
}
|
35
|
+
options[:DependsOn] = depends_on unless depends_on.blank?
|
36
|
+
resource name,
|
37
|
+
options.merge(
|
38
|
+
Properties: {
|
39
|
+
RouteTableId: ref(route_table_name),
|
40
|
+
NatGatewayId: ref(nat_gateway_name),
|
41
|
+
DestinationCidrBlock: dest_cidr_block
|
42
|
+
})
|
43
|
+
end
|
44
|
+
|
45
|
+
# Create new NAT gateway
|
46
|
+
def nat_gateway_init(name, subnet_name, route_table_name, dest_cidr_block: '0.0.0.0/0', depends_on: [])
|
47
|
+
nat_gateway_eip_name = "#{name}EIP"
|
48
|
+
nat_gateway_eip = allocate_new_eip(nat_gateway_eip_name, depends_on: depends_on)
|
49
|
+
nat_gateway_name = name
|
50
|
+
nat_gateway_options = {
|
51
|
+
Type: 'AWS::EC2::NatGateway'
|
52
|
+
}
|
53
|
+
nat_gateway_options[:DependsOn] = depends_on unless depends_on.blank?
|
54
|
+
resource nat_gateway_name,
|
55
|
+
nat_gateway_options.merge(
|
56
|
+
Properties: {
|
57
|
+
AllocationId: nat_gateway_eip,
|
58
|
+
SubnetId: ref(subnet_name)
|
59
|
+
})
|
60
|
+
nat_route_rule_name = "#{name}Route"
|
61
|
+
add_route_rule(nat_route_rule_name, route_table_name, nat_gateway_name, dest_cidr_block, depends_on: depends_on)
|
62
|
+
|
63
|
+
output nat_gateway_name,
|
64
|
+
Description: 'NAT Gateway',
|
65
|
+
Value: ref(nat_gateway_name)
|
66
|
+
|
67
|
+
nat_gateway_name
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
@@ -0,0 +1,141 @@
|
|
1
|
+
module Enscalator
|
2
|
+
module Plugins
|
3
|
+
# Amazon RDS instance
|
4
|
+
module RDS
|
5
|
+
# Create new Amazon RDS instance
|
6
|
+
#
|
7
|
+
# @param [String] db_name database name
|
8
|
+
# @param [Boolean] use_snapshot use snapshot or not
|
9
|
+
# @param [Integer] allocated_storage size of instance primary storage
|
10
|
+
# @param [String] storage_type instance storage type
|
11
|
+
# @param [String] multizone deploy as multizone or use only single availability zone
|
12
|
+
# @param [String] parameter_group RDS instance parameter group
|
13
|
+
# @param [String] instance_type instance type
|
14
|
+
# @param [Hash] properties additional properties
|
15
|
+
def rds_init(db_name,
|
16
|
+
use_snapshot: false,
|
17
|
+
allocated_storage: 5,
|
18
|
+
storage_type: 'gp2',
|
19
|
+
multizone: 'false',
|
20
|
+
engine: 'MySQL',
|
21
|
+
engine_version: '5.6',
|
22
|
+
parameter_group: 'default.mysql5.6',
|
23
|
+
instance_type: 'db.t2.small',
|
24
|
+
properties: {})
|
25
|
+
|
26
|
+
parameter_name "RDS#{db_name}"
|
27
|
+
|
28
|
+
parameter_rds_instance_type "RDS#{db_name}", type: instance_type
|
29
|
+
|
30
|
+
parameter_allocated_storage "RDS#{db_name}",
|
31
|
+
default: allocated_storage,
|
32
|
+
min: 5,
|
33
|
+
max: 1024
|
34
|
+
|
35
|
+
parameter "RDS#{db_name}Engine",
|
36
|
+
Default: engine,
|
37
|
+
Description: 'DB engine type of the DB instance',
|
38
|
+
Type: 'String'
|
39
|
+
|
40
|
+
parameter "RDS#{db_name}EngineVersion",
|
41
|
+
Default: engine_version,
|
42
|
+
Description: 'DB engine version of the DB instance',
|
43
|
+
Type: 'String'
|
44
|
+
|
45
|
+
parameter "RDS#{db_name}StorageType",
|
46
|
+
Default: storage_type,
|
47
|
+
Description: 'Storage type to be associated with the DB instance',
|
48
|
+
Type: 'String',
|
49
|
+
AllowedValues: %w( gp2 standard io1 )
|
50
|
+
|
51
|
+
parameter "RDS#{db_name}Multizone",
|
52
|
+
Default: multizone,
|
53
|
+
Description: 'Multizone deployment',
|
54
|
+
Type: 'String'
|
55
|
+
|
56
|
+
parameter "RDS#{db_name}ParameterGroup",
|
57
|
+
Default: parameter_group,
|
58
|
+
Description: 'Custom parameter group for an RDS database family',
|
59
|
+
Type: 'String'
|
60
|
+
|
61
|
+
parameter_username "RDS#{db_name}"
|
62
|
+
|
63
|
+
parameter_password "RDS#{db_name}"
|
64
|
+
|
65
|
+
resource "RDS#{db_name}SubnetGroup",
|
66
|
+
Type: 'AWS::RDS::DBSubnetGroup',
|
67
|
+
Properties: {
|
68
|
+
DBSubnetGroupDescription: 'Subnet group within VPC',
|
69
|
+
SubnetIds: ref_resource_subnets,
|
70
|
+
Tags: [
|
71
|
+
{
|
72
|
+
Key: 'Name',
|
73
|
+
Value: "RDS#{db_name}SubnetGroup"
|
74
|
+
}
|
75
|
+
]
|
76
|
+
}
|
77
|
+
|
78
|
+
# DBName and DBSnapshotIdentifier are mutually exclusive, thus
|
79
|
+
# when snapshot_id is given DBName won't be included to resource parameters
|
80
|
+
props = properties.deep_dup
|
81
|
+
if use_snapshot
|
82
|
+
parameter "RDS#{db_name}SnapshotId",
|
83
|
+
Description: 'Identifier for the DB snapshot to restore from',
|
84
|
+
Type: 'String',
|
85
|
+
MinLength: '1',
|
86
|
+
MaxLength: '64'
|
87
|
+
props[:DBSnapshotIdentifier] = ref("RDS#{db_name}SnapshotId")
|
88
|
+
else
|
89
|
+
props[:DBName] = ref("RDS#{db_name}Name")
|
90
|
+
end
|
91
|
+
|
92
|
+
rds_instance_tags = [
|
93
|
+
{
|
94
|
+
Key: 'Name',
|
95
|
+
Value: "RDS#{db_name}Instance"
|
96
|
+
}
|
97
|
+
]
|
98
|
+
|
99
|
+
# Set instance tags
|
100
|
+
if props.key?(:Tags) && !props[:Tags].empty?
|
101
|
+
props[:Tags].concat(rds_instance_tags)
|
102
|
+
else
|
103
|
+
props[:Tags] = rds_instance_tags
|
104
|
+
end
|
105
|
+
|
106
|
+
rds_props = {
|
107
|
+
PubliclyAccessible: 'false',
|
108
|
+
MultiAZ: ref("RDS#{db_name}Multizone"),
|
109
|
+
Engine: ref("RDS#{db_name}Engine"),
|
110
|
+
EngineVersion: ref("RDS#{db_name}EngineVersion"),
|
111
|
+
MasterUsername: ref("RDS#{db_name}Username"),
|
112
|
+
MasterUserPassword: ref("RDS#{db_name}Password"),
|
113
|
+
DBInstanceClass: ref("RDS#{db_name}InstanceType"),
|
114
|
+
VPCSecurityGroups: [ref_resource_security_group, ref_private_security_group],
|
115
|
+
DBSubnetGroupName: ref("RDS#{db_name}SubnetGroup"),
|
116
|
+
DBParameterGroupName: ref("RDS#{db_name}ParameterGroup"),
|
117
|
+
AllocatedStorage: ref("RDS#{db_name}AllocatedStorage"),
|
118
|
+
StorageType: ref("RDS#{db_name}StorageType")
|
119
|
+
}
|
120
|
+
|
121
|
+
rds_instance_resource_name = "RDS#{db_name}Instance"
|
122
|
+
resource rds_instance_resource_name,
|
123
|
+
Type: 'AWS::RDS::DBInstance',
|
124
|
+
Properties: rds_props.merge(props)
|
125
|
+
|
126
|
+
output "RDS#{db_name}EndpointAddress",
|
127
|
+
Description: "#{db_name} Endpoint Address",
|
128
|
+
Value: get_att("RDS#{db_name}Instance", 'Endpoint.Address')
|
129
|
+
|
130
|
+
rds_instance_resource_name
|
131
|
+
end
|
132
|
+
|
133
|
+
# Ensure that plugin using this template is a subclass of EnAppTemplateDSL
|
134
|
+
def self.included(klass)
|
135
|
+
if klass.superclass != Enscalator::EnAppTemplateDSL
|
136
|
+
fail("Plugin #{name.to_s.demodulize} requires template to be subclass of #{EnAppTemplateDSL}")
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end # RDS
|
140
|
+
end # Plugins
|
141
|
+
end # Enscalator
|
@@ -0,0 +1,38 @@
|
|
1
|
+
module Enscalator
|
2
|
+
module Plugins
|
3
|
+
# Redis on EC2 instance
|
4
|
+
module Redis
|
5
|
+
include Enscalator::Plugins::Ubuntu
|
6
|
+
|
7
|
+
# Create new Redis instance
|
8
|
+
#
|
9
|
+
# @param [String] instance_name instance name
|
10
|
+
# @param [String] key_name instance key
|
11
|
+
# @param [String] instance_type instance type
|
12
|
+
def redis_init(instance_name,
|
13
|
+
key_name:,
|
14
|
+
instance_type: 't2.medium')
|
15
|
+
|
16
|
+
parameter "Ubuntu#{instance_name}KeyName",
|
17
|
+
Default: key_name,
|
18
|
+
Description: 'Keypair name',
|
19
|
+
Type: 'String'
|
20
|
+
|
21
|
+
ubuntu_init instance_name, instance_type: instance_type, properties: { 'UserData' => redis_user_data }
|
22
|
+
end
|
23
|
+
|
24
|
+
# Install and run Redis on EC2 instance
|
25
|
+
# @return [String] user-data
|
26
|
+
def redis_user_data
|
27
|
+
Base64.encode64(%(
|
28
|
+
#!/usr/bin/env bash
|
29
|
+
apt-get update
|
30
|
+
apt-get upgrade -y
|
31
|
+
apt-get install -y redis-server
|
32
|
+
sed -i 's/bind 127.0.0.1/bind 0.0.0.0/' /etc/redis/redis.conf
|
33
|
+
service redis-server restart
|
34
|
+
).gsub(/^\s+/, ''))
|
35
|
+
end
|
36
|
+
end # Redis
|
37
|
+
end # Plugins
|
38
|
+
end # Enscalator
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Enscalator
|
2
|
+
module Plugins
|
3
|
+
# RethinkDB appliance
|
4
|
+
module RethinkDB
|
5
|
+
# Mapping for Rethinkdb x64 images
|
6
|
+
def self.mapping
|
7
|
+
{
|
8
|
+
'eu-central-1': { paravirtual: 'ami-1249740f' },
|
9
|
+
'eu-west-1': { paravirtual: 'ami-7a40f00d' },
|
10
|
+
'ap-northeast-1': { paravirtual: 'ami-90c3c491' },
|
11
|
+
'us-east-1': { paravirtual: 'ami-6ea9fb06' },
|
12
|
+
'us-west-1': { paravirtual: 'ami-7f6d7d3a' },
|
13
|
+
'us-west-2': { paravirtual: 'ami-cf0d2cff' },
|
14
|
+
'ap-southeast-1': { paravirtual: 'ami-aa5b6cf8' },
|
15
|
+
'ap-southeast-2': { paravirtual: 'ami-b9325b83' },
|
16
|
+
'sa-east-1': { paravirtual: 'ami-b38b3aae' }
|
17
|
+
}.with_indifferent_access
|
18
|
+
end
|
19
|
+
end # RethinkDB
|
20
|
+
end # Plugins
|
21
|
+
end # Enscalator
|
@@ -0,0 +1,143 @@
|
|
1
|
+
module Enscalator
|
2
|
+
module Plugins
|
3
|
+
# Create Route53 resources
|
4
|
+
module Route53
|
5
|
+
# Valid types for Route53 healthcheck
|
6
|
+
HEALTH_CHECK_TYPE = %w(HTTP HTTPS HTTP_STR_MATCH HTTPS_STR_MATCH TCP)
|
7
|
+
|
8
|
+
# Valid types for dns records
|
9
|
+
RECORD_TYPE = %w(A AAAA CNAME MX NS PTR SOA SPF SRV TXT)
|
10
|
+
|
11
|
+
# Create Route53 healthcheck for given fqdn/ip address
|
12
|
+
#
|
13
|
+
# @param [String] app_name application name
|
14
|
+
# @param [String] stack_name stack name
|
15
|
+
# @param [String] fqdn fully qualified domain name (FQDN)
|
16
|
+
# @param [String] ip_address ip address
|
17
|
+
# @param [Integer] port number
|
18
|
+
# @param [String] type healthcheck type
|
19
|
+
# @param [String] resource_path uri path healthcheck backend would query
|
20
|
+
# @param [Integer] request_interval query intervals for healthcheck backend
|
21
|
+
# @param [Integer] failure_threshold number of accumulated failures to consider endpoint not healthy
|
22
|
+
# @param [Array] tags additional tags
|
23
|
+
def create_healthcheck(app_name,
|
24
|
+
stack_name,
|
25
|
+
fqdn: nil,
|
26
|
+
ip_address: nil,
|
27
|
+
port: 80,
|
28
|
+
type: 'HTTP',
|
29
|
+
resource_path: '/',
|
30
|
+
request_interval: 30,
|
31
|
+
failure_threshold: 3,
|
32
|
+
tags: [])
|
33
|
+
unless HEALTH_CHECK_TYPE.include?(type)
|
34
|
+
fail("Route53 healthcheck type can only be one of the following: #{HEALTH_CHECK_TYPE.join(',')}")
|
35
|
+
end
|
36
|
+
fail('Route53 healthcheck requires either fqdn or ip address') unless fqdn || ip_address
|
37
|
+
|
38
|
+
properties = {
|
39
|
+
HealthCheckConfig: {
|
40
|
+
IPAddress: ip_address,
|
41
|
+
FullyQualifiedDomainName: fqdn,
|
42
|
+
Port: port,
|
43
|
+
Type: type,
|
44
|
+
ResourcePath: resource_path,
|
45
|
+
RequestInterval: request_interval,
|
46
|
+
FailureThreshold: failure_threshold
|
47
|
+
}
|
48
|
+
}
|
49
|
+
|
50
|
+
properties[:HealthCheckTags] = [
|
51
|
+
{
|
52
|
+
Key: 'Application',
|
53
|
+
Value: app_name
|
54
|
+
},
|
55
|
+
{
|
56
|
+
Key: 'Stack',
|
57
|
+
Value: stack_name
|
58
|
+
}
|
59
|
+
]
|
60
|
+
|
61
|
+
properties[:HealthCheckTags].concat(tags) unless tags.blank?
|
62
|
+
|
63
|
+
resource "#{app_name}Healthcheck",
|
64
|
+
Type: 'AWS::Route53::HealthCheck',
|
65
|
+
Properties: properties
|
66
|
+
end
|
67
|
+
|
68
|
+
# [RESERVED] Create new hosted zone
|
69
|
+
def create_hosted_zone
|
70
|
+
fail('method "create_hosted_zone" is not implemented yet')
|
71
|
+
end
|
72
|
+
|
73
|
+
# TODO: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-route53-recordset.html
|
74
|
+
|
75
|
+
# Create new single record set for given hosted zone
|
76
|
+
#
|
77
|
+
# @param [String] app_name application name
|
78
|
+
# @param [String] stack_name stack name
|
79
|
+
# @param [String] zone_name hosted zone name
|
80
|
+
# @param [String] record_name dns record name
|
81
|
+
# @param [Integer] ttl time to live
|
82
|
+
# @param [String] type dns record type
|
83
|
+
# @param [Hash] healthcheck reference to the healthcheck resource
|
84
|
+
# @param [Hash] alias_target alias target
|
85
|
+
# @param [Array] resource_records resources associated with record_name
|
86
|
+
def create_single_dns_record(app_name,
|
87
|
+
stack_name,
|
88
|
+
zone_name,
|
89
|
+
record_name,
|
90
|
+
ttl: 300,
|
91
|
+
type: 'A',
|
92
|
+
healthcheck: nil,
|
93
|
+
zone_id: nil,
|
94
|
+
alias_target: {},
|
95
|
+
resource_records: [])
|
96
|
+
if type && !RECORD_TYPE.include?(type)
|
97
|
+
fail("Route53 record type can only be one of the following: #{RECORD_TYPE.join(',')}")
|
98
|
+
end
|
99
|
+
if healthcheck && (!healthcheck.is_a?(Hash) || !healthcheck.include?(:Ref))
|
100
|
+
fail('healthcheck must be a valid cloudformation Ref function')
|
101
|
+
end
|
102
|
+
if alias_target && (!alias_target.is_a?(Hash))
|
103
|
+
fail('AliasTarget must be a Hash')
|
104
|
+
end
|
105
|
+
|
106
|
+
name = app_name || stack_name.titleize.remove(/\s/)
|
107
|
+
properties = {
|
108
|
+
Name: record_name,
|
109
|
+
Comment: "#{type} record for #{[app_name, 'in '].join(' ') if app_name}#{stack_name} stack",
|
110
|
+
Type: type
|
111
|
+
}
|
112
|
+
|
113
|
+
# HostedZoneId and HostedZoneName options are mutually exclusive
|
114
|
+
if zone_id && !zone_id.nil?
|
115
|
+
properties[:HostedZoneId] = zone_id
|
116
|
+
else
|
117
|
+
properties[:HostedZoneName] = zone_name
|
118
|
+
end
|
119
|
+
|
120
|
+
if !alias_target.blank?
|
121
|
+
fail('AliasTarget can be created only for A or AAAA type records') unless %w(A AAAA).include?(type)
|
122
|
+
unless alias_target.key?(:HostedZoneId) && alias_target.key?(:DNSName)
|
123
|
+
fail('AliasTarget must have HostedZoneId and DNSName properties')
|
124
|
+
end
|
125
|
+
properties[:AliasTarget] = alias_target
|
126
|
+
else
|
127
|
+
properties[:TTL] = ttl
|
128
|
+
properties[:HealthCheckId] = healthcheck if healthcheck
|
129
|
+
properties[:ResourceRecords] = resource_records.empty? ? ref("#{app_name}PublicIpAddress") : resource_records
|
130
|
+
end
|
131
|
+
|
132
|
+
resource "#{name}Hostname",
|
133
|
+
Type: 'AWS::Route53::RecordSet',
|
134
|
+
Properties: properties
|
135
|
+
end
|
136
|
+
|
137
|
+
# [RESERVED] Create multiple record sets for given hosted zone
|
138
|
+
def create_multiple_dns_records
|
139
|
+
fail('method "create_multiple_dns_records" is not implemented')
|
140
|
+
end
|
141
|
+
end # module Route53
|
142
|
+
end # module Plugins
|
143
|
+
end # module Enscalator
|
@@ -0,0 +1,85 @@
|
|
1
|
+
module Enscalator
|
2
|
+
module Plugins
|
3
|
+
# Ubuntu appliance
|
4
|
+
module Ubuntu
|
5
|
+
class << self
|
6
|
+
# Supported storage types in AWS
|
7
|
+
STORAGE = [:ebs, :'ebs-io1', :'ebs-ssd', :'instance-store']
|
8
|
+
|
9
|
+
# Supported Ubuntu image architectures
|
10
|
+
ARCH = [:amd64, :i386]
|
11
|
+
|
12
|
+
# Supported Ubuntu releases
|
13
|
+
RELEASE = {
|
14
|
+
vivid: '15.04',
|
15
|
+
utopic: '14.10',
|
16
|
+
trusty: '14.04',
|
17
|
+
saucy: '13.10',
|
18
|
+
raring: '13.04',
|
19
|
+
quantal: '12.10',
|
20
|
+
precise: '12.04'
|
21
|
+
}
|
22
|
+
|
23
|
+
# Structure to hold parsed record
|
24
|
+
Struct.new('Ubuntu', :name, :edition, :state, :timestamp, :root_storage, :arch, :region, :ami, :virtualization)
|
25
|
+
|
26
|
+
# Get mapping for Ubuntu images
|
27
|
+
#
|
28
|
+
# @param [Symbol, String] release a codename or version number
|
29
|
+
# @param [Symbol] storage storage kind
|
30
|
+
# @param [Symbol] arch architecture
|
31
|
+
# @raise [ArgumentError] if release is nil, empty or not one of supported values
|
32
|
+
# @raise [ArgumentError] if storage is nil, empty or not one of supported values
|
33
|
+
# @raise [ArgumentError] if arch is nil, empty or not one of supported values
|
34
|
+
# @return [Hash] mapping for Ubuntu amis
|
35
|
+
def get_mapping(release: :trusty, storage: :ebs, arch: :amd64)
|
36
|
+
fail ArgumentError, 'release can be either codename or version' unless RELEASE.to_a.flatten.include? release
|
37
|
+
fail ArgumentError, "storage can only be one of #{STORAGE}" unless STORAGE.include? storage
|
38
|
+
fail ArgumentError, "arch can only be one of #{ARCH}" unless ARCH.include? arch
|
39
|
+
begin
|
40
|
+
version = RELEASE.keys.include?(release) ? release : RELEASE.key(release)
|
41
|
+
body = open("https://cloud-images.ubuntu.com/query/#{version}/server/released.current.txt") { |f| f.read }
|
42
|
+
body.split("\n").map { |m| m.squeeze("\t").split("\t").reject { |r| r.include? 'aki' } }
|
43
|
+
.map { |l| Struct::Ubuntu.new(*l) }
|
44
|
+
.select { |r| r.root_storage == storage.to_s && r.arch == arch.to_s }
|
45
|
+
.group_by(&:region)
|
46
|
+
.map { |k, v| [k, v.map { |i| [i.virtualization, i.ami] }.to_h] }
|
47
|
+
.to_h
|
48
|
+
.with_indifferent_access
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end # class << self
|
52
|
+
|
53
|
+
# Create new Ubuntu instance
|
54
|
+
#
|
55
|
+
# @param [String] instance_name instance name
|
56
|
+
# @param [String] storage storage kind (ebs or ephemeral)
|
57
|
+
# @param [String] arch architecture (amd64 or i386)
|
58
|
+
# @param [String] instance_type instance type
|
59
|
+
def ubuntu_init(instance_name,
|
60
|
+
storage: :ebs,
|
61
|
+
arch: :amd64,
|
62
|
+
instance_type: 't2.medium', properties: {})
|
63
|
+
|
64
|
+
mapping 'AWSUbuntuAMI', Ubuntu.get_mapping(storage: storage, arch: arch)
|
65
|
+
|
66
|
+
parameter_allocated_storage "Ubuntu#{instance_name}",
|
67
|
+
default: 5,
|
68
|
+
min: 5,
|
69
|
+
max: 1024
|
70
|
+
|
71
|
+
parameter_ec2_instance_type "Ubuntu#{instance_name}", type: instance_type
|
72
|
+
|
73
|
+
instance_vpc "Ubuntu#{instance_name}",
|
74
|
+
find_in_map('AWSUbuntuAMI', ref('AWS::Region'), 'hvm'),
|
75
|
+
ref_application_subnets.first,
|
76
|
+
[ref_private_security_group, ref_application_security_group],
|
77
|
+
depends_on: [],
|
78
|
+
properties: {
|
79
|
+
KeyName: ref("Ubuntu#{instance_name}KeyName"),
|
80
|
+
InstanceType: ref("Ubuntu#{instance_name}InstanceType")
|
81
|
+
}.merge(properties)
|
82
|
+
end
|
83
|
+
end # Ubuntu
|
84
|
+
end # Plugins
|
85
|
+
end # Enscalator
|