bosh_cli_plugin_aws 1.5.0.pre.1113
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/bosh/cli/commands/aws.rb +464 -0
- data/lib/bosh_cli_plugin_aws/aws_config.rb +141 -0
- data/lib/bosh_cli_plugin_aws/aws_provider.rb +53 -0
- data/lib/bosh_cli_plugin_aws/bat_manifest.rb +40 -0
- data/lib/bosh_cli_plugin_aws/bootstrap.rb +31 -0
- data/lib/bosh_cli_plugin_aws/bosh_bootstrap.rb +158 -0
- data/lib/bosh_cli_plugin_aws/bosh_manifest.rb +71 -0
- data/lib/bosh_cli_plugin_aws/ec2.rb +265 -0
- data/lib/bosh_cli_plugin_aws/elb.rb +132 -0
- data/lib/bosh_cli_plugin_aws/micro_bosh_bootstrap.rb +64 -0
- data/lib/bosh_cli_plugin_aws/microbosh_manifest.rb +117 -0
- data/lib/bosh_cli_plugin_aws/migration.rb +40 -0
- data/lib/bosh_cli_plugin_aws/migration_helper.rb +150 -0
- data/lib/bosh_cli_plugin_aws/migrator.rb +137 -0
- data/lib/bosh_cli_plugin_aws/rds.rb +182 -0
- data/lib/bosh_cli_plugin_aws/route53.rb +103 -0
- data/lib/bosh_cli_plugin_aws/s3.rb +93 -0
- data/lib/bosh_cli_plugin_aws/version.rb +5 -0
- data/lib/bosh_cli_plugin_aws/vpc.rb +181 -0
- data/lib/bosh_cli_plugin_aws.rb +31 -0
- data/migrations/20130412000811_create_key_pairs.rb +8 -0
- data/migrations/20130412004642_create_vpc.rb +65 -0
- data/migrations/20130412181302_create_route53_records.rb +37 -0
- data/migrations/20130412183544_create_rds_dbs.rb +35 -0
- data/migrations/20130412192351_create_s3.rb +4 -0
- data/migrations/20130529212130_create_more_unique_s3_buckets.rb +33 -0
- data/migrations/20130531180445_create_bosh_rds_db.rb +30 -0
- data/migrations/20130826150635_update_elb_for_websockets.rb +97 -0
- data/migrations/20130827000001_add_secondary_az_to_vpc.rb +34 -0
- data/templates/aws_configuration_template.yml.erb +187 -0
- data/templates/aws_migration.erb +5 -0
- data/templates/aws_migration_spec.erb +12 -0
- data/templates/bat.yml.erb +84 -0
- data/templates/bosh.yml.erb +198 -0
- data/templates/micro_bosh.yml.erb +82 -0
- metadata +163 -0
@@ -0,0 +1,103 @@
|
|
1
|
+
module Bosh
|
2
|
+
module Aws
|
3
|
+
class Route53
|
4
|
+
|
5
|
+
def initialize(credentials)
|
6
|
+
@aws_provider = AwsProvider.new(credentials)
|
7
|
+
end
|
8
|
+
|
9
|
+
def create_zone(zone)
|
10
|
+
zone = "#{zone}." unless zone =~ /\.$/
|
11
|
+
aws_route53.client.create_hosted_zone(:name => zone, :caller_reference => generate_unique_name)
|
12
|
+
true
|
13
|
+
end
|
14
|
+
|
15
|
+
def delete_zone(zone)
|
16
|
+
zone = "#{zone}." unless zone =~ /\.$/
|
17
|
+
aws_route53.client.delete_hosted_zone(:id => get_zone_id(zone))
|
18
|
+
true
|
19
|
+
end
|
20
|
+
|
21
|
+
def add_record(host, zone, addresses, options={})
|
22
|
+
host = "\\052" if host == "*"
|
23
|
+
zone = "#{zone}." unless zone =~ /\.$/
|
24
|
+
addresses = [addresses] unless addresses.kind_of?(Array)
|
25
|
+
type = options[:type] || "A"
|
26
|
+
ttl = options[:ttl] || 3600
|
27
|
+
aws_route53.client.change_resource_record_sets(
|
28
|
+
hosted_zone_id: get_zone_id(zone),
|
29
|
+
change_batch: {
|
30
|
+
changes: [
|
31
|
+
{
|
32
|
+
action: "CREATE",
|
33
|
+
resource_record_set: {
|
34
|
+
name: "#{host}.#{zone}",
|
35
|
+
type: type,
|
36
|
+
ttl: ttl,
|
37
|
+
resource_records: addresses.map {|address| { value: address} }
|
38
|
+
}
|
39
|
+
}
|
40
|
+
]
|
41
|
+
}
|
42
|
+
)
|
43
|
+
true
|
44
|
+
end
|
45
|
+
|
46
|
+
def delete_record(host, zone, options={})
|
47
|
+
host = "\\052" if host == "*"
|
48
|
+
zone = "#{zone}." unless zone =~ /\.$/
|
49
|
+
record_name = "#{host}.#{zone}"
|
50
|
+
record_type = options[:type] || "A"
|
51
|
+
|
52
|
+
zone_response = aws_route53.client.list_resource_record_sets(:hosted_zone_id => get_zone_id(zone))
|
53
|
+
resource_record_set = zone_response.data[:resource_record_sets].find do |rr|
|
54
|
+
rr[:name] == record_name && rr[:type] == record_type
|
55
|
+
end
|
56
|
+
|
57
|
+
unless resource_record_set
|
58
|
+
raise "no #{record_type} record found for #{record_name}"
|
59
|
+
end
|
60
|
+
aws_route53.client.change_resource_record_sets(
|
61
|
+
hosted_zone_id: get_zone_id(zone),
|
62
|
+
change_batch: {
|
63
|
+
changes: [
|
64
|
+
{
|
65
|
+
action: "DELETE",
|
66
|
+
resource_record_set: resource_record_set
|
67
|
+
}
|
68
|
+
]
|
69
|
+
}
|
70
|
+
)
|
71
|
+
true
|
72
|
+
end
|
73
|
+
|
74
|
+
def delete_all_records(options = {})
|
75
|
+
omit_types = options[:omit_types] || []
|
76
|
+
aws_route53.hosted_zones.each do |zone|
|
77
|
+
zone.rrsets.each do |rs|
|
78
|
+
rs.delete unless omit_types.include?(rs.type)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
private
|
84
|
+
|
85
|
+
attr_reader :aws_provider
|
86
|
+
|
87
|
+
def aws_route53
|
88
|
+
aws_provider.route53
|
89
|
+
end
|
90
|
+
|
91
|
+
def get_zone_id(name)
|
92
|
+
zones_response = aws_route53.client.list_hosted_zones
|
93
|
+
zone = zones_response.data[:hosted_zones].find { |zone| zone[:name] == name }
|
94
|
+
raise "Zone not found for #{name} in route53 zones response #{zones_response.inspect}" if zone.nil?
|
95
|
+
zone.fetch(:id)
|
96
|
+
end
|
97
|
+
|
98
|
+
def generate_unique_name
|
99
|
+
SecureRandom.uuid
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
@@ -0,0 +1,93 @@
|
|
1
|
+
module Bosh
|
2
|
+
module Aws
|
3
|
+
class S3
|
4
|
+
def initialize(credentials)
|
5
|
+
@aws_provider = AwsProvider.new(credentials)
|
6
|
+
end
|
7
|
+
|
8
|
+
def create_bucket(bucket_name)
|
9
|
+
aws_s3.buckets.create(bucket_name)
|
10
|
+
end
|
11
|
+
|
12
|
+
def move_bucket(old_bucket, new_bucket)
|
13
|
+
fetch_bucket(old_bucket).objects.each do |object|
|
14
|
+
object.move_to(object.key, :bucket_name => new_bucket)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def delete_bucket(bucket_name)
|
19
|
+
bucket = fetch_bucket(bucket_name)
|
20
|
+
|
21
|
+
bucket.clear!
|
22
|
+
bucket.delete
|
23
|
+
rescue AWS::S3::Errors::NoSuchBucket
|
24
|
+
end
|
25
|
+
|
26
|
+
def empty
|
27
|
+
aws_s3.buckets.each do |bucket|
|
28
|
+
begin
|
29
|
+
bucket.delete!
|
30
|
+
rescue AWS::S3::Errors::NoSuchBucket
|
31
|
+
# when the bucket goes away while going through the list
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def bucket_names
|
37
|
+
aws_s3.buckets.map &:name
|
38
|
+
end
|
39
|
+
|
40
|
+
def bucket_exists?(bucket_name)
|
41
|
+
bucket_names.include?(bucket_name)
|
42
|
+
end
|
43
|
+
|
44
|
+
def upload_to_bucket(bucket_name, object_name, io)
|
45
|
+
bucket = fetch_bucket(bucket_name)
|
46
|
+
bucket.objects[object_name].write(io)
|
47
|
+
end
|
48
|
+
|
49
|
+
def objects_in_bucket(bucket_name)
|
50
|
+
fetch_bucket(bucket_name).objects.map { |object| object.key }
|
51
|
+
end
|
52
|
+
|
53
|
+
def fetch_object_contents(bucket_name, object_name)
|
54
|
+
bucket = fetch_bucket(bucket_name)
|
55
|
+
Bosh::Common.retryable(on: AWS::S3::Errors::NoSuchBucket, tries: 10) do
|
56
|
+
bucket.objects[object_name].read
|
57
|
+
end
|
58
|
+
rescue AWS::S3::Errors::NoSuchKey
|
59
|
+
nil
|
60
|
+
end
|
61
|
+
|
62
|
+
def copy_remote_file(bucket_name, remote_file, file_name)
|
63
|
+
say("Fetching remote file #{remote_file} from #{bucket_name} bucket")
|
64
|
+
bucket = aws_s3.buckets[bucket_name]
|
65
|
+
object = bucket.objects[remote_file]
|
66
|
+
release_file = Tempfile.new file_name
|
67
|
+
Bosh::Cli::FileWithProgressBar.open(release_file, 'wb') do |f|
|
68
|
+
f.size=object.content_length
|
69
|
+
object.read do |chunk|
|
70
|
+
f.write chunk
|
71
|
+
end
|
72
|
+
end
|
73
|
+
release_file
|
74
|
+
rescue AWS::S3::Errors::NoSuchKey => e
|
75
|
+
new_exception = Exception.new("Can't find #{remote_file} in bucket #{bucket_name}")
|
76
|
+
new_exception.set_backtrace(e.backtrace)
|
77
|
+
raise new_exception
|
78
|
+
end
|
79
|
+
|
80
|
+
private
|
81
|
+
|
82
|
+
attr_reader :aws_provider
|
83
|
+
|
84
|
+
def fetch_bucket(bucket_name)
|
85
|
+
aws_s3.buckets[bucket_name]
|
86
|
+
end
|
87
|
+
|
88
|
+
def aws_s3
|
89
|
+
aws_provider.s3
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
@@ -0,0 +1,181 @@
|
|
1
|
+
module Bosh
|
2
|
+
module Aws
|
3
|
+
class VPC
|
4
|
+
|
5
|
+
DEFAULT_CIDR = "10.0.0.0/16"
|
6
|
+
DEFAULT_ROUTE = "0.0.0.0/0"
|
7
|
+
NAT_INSTANCE_DEFAULTS = {
|
8
|
+
:image_id => "ami-f619c29f",
|
9
|
+
:instance_type => "m1.small"
|
10
|
+
}
|
11
|
+
|
12
|
+
def initialize(ec2, aws_vpc)
|
13
|
+
@ec2 = ec2
|
14
|
+
@aws_vpc = aws_vpc
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.create(ec2, cidr = DEFAULT_CIDR, instance_tenancy = nil)
|
18
|
+
vpc_options = instance_tenancy ? {instance_tenancy: instance_tenancy} : {}
|
19
|
+
self.new(ec2, ec2.vpcs.create(cidr, vpc_options))
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.find(ec2, vpc_id)
|
23
|
+
self.new(ec2, ec2.vpcs[vpc_id])
|
24
|
+
end
|
25
|
+
|
26
|
+
def make_internet_gateway_default_route_for_subnet(subnet)
|
27
|
+
route_table = @aws_vpc.route_tables.create
|
28
|
+
route_table.create_route(DEFAULT_ROUTE, internet_gateway: @aws_vpc.internet_gateway)
|
29
|
+
subnet.route_table = route_table
|
30
|
+
end
|
31
|
+
|
32
|
+
def make_nat_instance_default_route_for_subnet(subnet, nat_instance)
|
33
|
+
route_table = @aws_vpc.route_tables.create
|
34
|
+
route_table.create_route(DEFAULT_ROUTE, instance: nat_instance)
|
35
|
+
subnet.route_table = route_table
|
36
|
+
end
|
37
|
+
|
38
|
+
def vpc_id
|
39
|
+
@aws_vpc.id
|
40
|
+
end
|
41
|
+
|
42
|
+
def cidr_block
|
43
|
+
@aws_vpc.cidr_block
|
44
|
+
end
|
45
|
+
|
46
|
+
def instances_count
|
47
|
+
@aws_vpc.instances.count
|
48
|
+
end
|
49
|
+
|
50
|
+
def dhcp_options
|
51
|
+
@aws_vpc.dhcp_options
|
52
|
+
end
|
53
|
+
|
54
|
+
def state
|
55
|
+
@aws_vpc.state
|
56
|
+
end
|
57
|
+
|
58
|
+
def subnets
|
59
|
+
Hash[@aws_vpc.subnets.map { |subnet| [subnet.tags["Name"], subnet.id] }]
|
60
|
+
end
|
61
|
+
|
62
|
+
def delete_vpc
|
63
|
+
@aws_vpc.delete
|
64
|
+
Bosh::Common.retryable(tries: 30, sleep: 5, on: []) do
|
65
|
+
begin
|
66
|
+
false if @aws_vpc.state
|
67
|
+
rescue AWS::EC2::Errors::InvalidVpcID::NotFound
|
68
|
+
true
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
rescue ::AWS::EC2::Errors::DependencyViolation
|
73
|
+
err "#{@aws_vpc.id} has dependencies that this tool does not delete"
|
74
|
+
end
|
75
|
+
|
76
|
+
def create_security_groups(groups_specs)
|
77
|
+
groups_specs.each do |group_spec|
|
78
|
+
if group_name_available group_spec["name"]
|
79
|
+
security_group = @aws_vpc.security_groups.create(group_spec["name"])
|
80
|
+
Bosh::AwsCloud::ResourceWait.for_sgroup(sgroup: security_group, state: true)
|
81
|
+
group_spec["ingress"].each do |ingress|
|
82
|
+
range_match = ingress["ports"].to_s.match(/(\d+)\s*-\s*(\d+)/)
|
83
|
+
ports = range_match ? (range_match[1].to_i)..(range_match[2].to_i) : ingress["ports"].to_i
|
84
|
+
security_group.authorize_ingress(ingress["protocol"], ports, ingress["sources"])
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
def delete_security_groups
|
91
|
+
@aws_vpc.security_groups.reject { |group| group.name == "default" }.each(&:delete)
|
92
|
+
end
|
93
|
+
|
94
|
+
def security_group_by_name(name)
|
95
|
+
@aws_vpc.security_groups.detect { |sg| sg.name == name }
|
96
|
+
end
|
97
|
+
|
98
|
+
def create_subnets(subnets)
|
99
|
+
subnets.each_pair do |name, subnet_spec|
|
100
|
+
yield "Making subnet #{name} #{subnet_spec["cidr"]}:" if block_given?
|
101
|
+
options = {}
|
102
|
+
options[:availability_zone] = subnet_spec["availability_zone"] if subnet_spec["availability_zone"]
|
103
|
+
|
104
|
+
subnet = @aws_vpc.subnets.create(subnet_spec["cidr"], options)
|
105
|
+
Bosh::AwsCloud::ResourceWait.for_subnet(subnet: subnet, state: :available)
|
106
|
+
|
107
|
+
subnet.add_tag("Name", :value => name)
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
def extract_nat_instance_specs(specs)
|
112
|
+
subnet_specs_with_nats = specs.select do |_, subnet_spec|
|
113
|
+
subnet_spec.has_key?("nat_instance")
|
114
|
+
end
|
115
|
+
|
116
|
+
subnet_specs_with_nats.map do |subnet_name, subnet_spec|
|
117
|
+
nat_instance_spec = subnet_spec["nat_instance"]
|
118
|
+
nat_instance_spec["subnet_id"] = subnets[subnet_name]
|
119
|
+
nat_instance_spec
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
def create_nat_instances(subnets)
|
124
|
+
extract_nat_instance_specs(subnets).each do |subnet_spec|
|
125
|
+
@ec2.create_nat_instance(subnet_spec)
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
def setup_subnet_routes(subnet_specs)
|
130
|
+
subnet_specs.each_pair do |name, subnet_spec|
|
131
|
+
if subnet_spec["default_route"]
|
132
|
+
subnet = @aws_vpc.subnets[subnets[name]]
|
133
|
+
yield " Making routing table for #{name}" if block_given?
|
134
|
+
yield " Binding default route to #{subnet_spec["default_route"]}" if block_given?
|
135
|
+
if subnet_spec["default_route"] == "igw"
|
136
|
+
make_internet_gateway_default_route_for_subnet(subnet)
|
137
|
+
else
|
138
|
+
make_nat_instance_default_route_for_subnet(subnet, @ec2.get_running_instance_by_name(subnet_spec["default_route"]))
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
def delete_subnets
|
145
|
+
@aws_vpc.subnets.each(&:delete)
|
146
|
+
end
|
147
|
+
|
148
|
+
def delete_route_tables
|
149
|
+
@aws_vpc.route_tables.reject(&:main?).each(&:delete)
|
150
|
+
end
|
151
|
+
|
152
|
+
def delete_network_interfaces
|
153
|
+
@aws_vpc.network_interfaces.each(&:delete)
|
154
|
+
end
|
155
|
+
|
156
|
+
def create_dhcp_options(options)
|
157
|
+
default_dhcp_opts = @aws_vpc.dhcp_options
|
158
|
+
|
159
|
+
new_dhcp_options = @ec2.dhcp_options.create(options)
|
160
|
+
new_dhcp_options.associate(vpc_id)
|
161
|
+
#say "\tcreated and associated DHCP options #{new_dhcp_options.id}".make_green
|
162
|
+
|
163
|
+
default_dhcp_opts.delete
|
164
|
+
end
|
165
|
+
|
166
|
+
def attach_internet_gateway(gateway_id)
|
167
|
+
@aws_vpc.internet_gateway = gateway_id
|
168
|
+
end
|
169
|
+
|
170
|
+
private
|
171
|
+
|
172
|
+
def group_name_available(name)
|
173
|
+
@aws_vpc.security_groups.each { |group| group.delete if group.name == name }
|
174
|
+
true
|
175
|
+
rescue ::AWS::EC2::Errors::DependencyViolation => e
|
176
|
+
say "unable to delete security group: #{name}: #{e.message}".make_yellow
|
177
|
+
false
|
178
|
+
end
|
179
|
+
end
|
180
|
+
end
|
181
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'aws-sdk'
|
2
|
+
require 'logger'
|
3
|
+
|
4
|
+
# since this plugin is abusing the AWS CPI, the following hack is needed so that
|
5
|
+
# task_checkpoint & logger is available when ResourceWait.for_resource is called
|
6
|
+
require "cloud"
|
7
|
+
Config = Struct.new(:task_checkpoint, :logger)
|
8
|
+
Bosh::Clouds::Config.configure(Config.new(true, Logger.new(File::NULL)))
|
9
|
+
|
10
|
+
require "cloud/aws/resource_wait"
|
11
|
+
require "common/ssl"
|
12
|
+
|
13
|
+
require "bosh_cli_plugin_aws/version"
|
14
|
+
require "bosh_cli_plugin_aws/ec2"
|
15
|
+
require "bosh_cli_plugin_aws/route53"
|
16
|
+
require "bosh_cli_plugin_aws/s3"
|
17
|
+
require "bosh_cli_plugin_aws/vpc"
|
18
|
+
require "bosh_cli_plugin_aws/rds"
|
19
|
+
require "bosh_cli_plugin_aws/elb"
|
20
|
+
require "bosh_cli_plugin_aws/bosh_bootstrap"
|
21
|
+
require "bosh_cli_plugin_aws/micro_bosh_bootstrap"
|
22
|
+
require "bosh_cli_plugin_aws/aws_config"
|
23
|
+
require 'bosh_cli_plugin_aws/aws_provider'
|
24
|
+
require "bosh/cli/commands/aws"
|
25
|
+
require "bosh/cli/commands/micro"
|
26
|
+
require "bosh_cli_plugin_aws/microbosh_manifest"
|
27
|
+
require "bosh_cli_plugin_aws/bat_manifest"
|
28
|
+
require "bosh_cli_plugin_aws/bosh_manifest"
|
29
|
+
require "bosh_cli_plugin_aws/migration_helper"
|
30
|
+
require "bosh_cli_plugin_aws/migration"
|
31
|
+
require "bosh_cli_plugin_aws/migrator"
|
@@ -0,0 +1,65 @@
|
|
1
|
+
class CreateVpc < Bosh::Aws::Migration
|
2
|
+
def execute
|
3
|
+
receipt = {}
|
4
|
+
|
5
|
+
receipt["aws"] = config["aws"]
|
6
|
+
|
7
|
+
vpc = Bosh::Aws::VPC.create(ec2, config["vpc"]["cidr"], config["vpc"]["instance_tenancy"])
|
8
|
+
receipt["vpc"] = {"id" => vpc.vpc_id, "domain" => config["vpc"]["domain"]}
|
9
|
+
|
10
|
+
receipt["original_configuration"] = config
|
11
|
+
|
12
|
+
unless was_vpc_eventually_available?(vpc)
|
13
|
+
err "VPC #{vpc.vpc_id} was not available within 60 seconds, giving up"
|
14
|
+
end
|
15
|
+
|
16
|
+
say "creating internet gateway"
|
17
|
+
igw = ec2.create_internet_gateway
|
18
|
+
vpc.attach_internet_gateway(igw.id)
|
19
|
+
|
20
|
+
security_groups = config["vpc"]["security_groups"]
|
21
|
+
say "creating security groups: #{security_groups.map { |group| group["name"] }.join(", ")}"
|
22
|
+
vpc.create_security_groups(security_groups)
|
23
|
+
|
24
|
+
subnets = config["vpc"]["subnets"]
|
25
|
+
say "creating subnets: #{subnets.keys.join(", ")}"
|
26
|
+
vpc.create_subnets(subnets) { |msg| say " #{msg}" }
|
27
|
+
vpc.create_nat_instances(subnets)
|
28
|
+
vpc.setup_subnet_routes(subnets) { |msg| say " #{msg}" }
|
29
|
+
receipt["vpc"]["subnets"] = vpc.subnets
|
30
|
+
|
31
|
+
elbs = config["vpc"]["elbs"]
|
32
|
+
ssl_certs = config["ssl_certs"]
|
33
|
+
|
34
|
+
say "creating load balancers: #{elbs.keys.join(", ")}" if elbs
|
35
|
+
elbs.each do |name, settings|
|
36
|
+
settings["domain"] = config["vpc"]["domain"]
|
37
|
+
e = elb.create(name, vpc, settings, ssl_certs)
|
38
|
+
if settings["dns_record"]
|
39
|
+
say "adding CNAME record for #{settings["dns_record"]}.#{config["vpc"]["domain"]}"
|
40
|
+
route53.add_record(settings["dns_record"], config["vpc"]["domain"], [e.dns_name], {ttl: settings["ttl"], type: 'CNAME'})
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
dhcp_options = config["vpc"]["dhcp_options"]
|
45
|
+
say "creating DHCP options"
|
46
|
+
vpc.create_dhcp_options(dhcp_options)
|
47
|
+
rescue Bosh::Aws::ELB::BadCertificateError => e
|
48
|
+
err e.message
|
49
|
+
ensure
|
50
|
+
save_receipt("aws_vpc_receipt", receipt)
|
51
|
+
end
|
52
|
+
|
53
|
+
private
|
54
|
+
|
55
|
+
def was_vpc_eventually_available?(vpc)
|
56
|
+
(1..60).any? do |attempt|
|
57
|
+
begin
|
58
|
+
sleep 1 unless attempt == 1
|
59
|
+
vpc.state.to_s == "available"
|
60
|
+
rescue Exception => e
|
61
|
+
say("Waiting for vpc, continuing after #{e.class}: #{e.message}")
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
class CreateRoute53Records < Bosh::Aws::Migration
|
2
|
+
def execute
|
3
|
+
receipt = {}
|
4
|
+
elastic_ip_specs = config["elastic_ips"]
|
5
|
+
|
6
|
+
if elastic_ip_specs
|
7
|
+
receipt["elastic_ips"] = {}
|
8
|
+
else
|
9
|
+
return
|
10
|
+
end
|
11
|
+
|
12
|
+
count = elastic_ip_specs.map{|_, spec| spec["instances"]}.inject(:+)
|
13
|
+
say "allocating #{count} elastic IP(s)"
|
14
|
+
ec2.allocate_elastic_ips(count)
|
15
|
+
|
16
|
+
elastic_ips = ec2.elastic_ips
|
17
|
+
|
18
|
+
elastic_ip_specs.each do |name, job|
|
19
|
+
receipt["elastic_ips"][name] = {"ips" => elastic_ips.shift(job["instances"])}
|
20
|
+
end
|
21
|
+
|
22
|
+
elastic_ip_specs.each do |name, job|
|
23
|
+
if job["dns_record"]
|
24
|
+
say "adding A record for #{job["dns_record"]}.#{config["vpc"]["domain"]}"
|
25
|
+
route53.add_record(
|
26
|
+
job["dns_record"],
|
27
|
+
config["vpc"]["domain"],
|
28
|
+
receipt["elastic_ips"][name]["ips"],
|
29
|
+
{ttl: job["ttl"]}
|
30
|
+
) # shouldn't have to get domain from config["vpc"]["domain"]; should use config["name"]
|
31
|
+
receipt["elastic_ips"][name]["dns_record"] = job["dns_record"]
|
32
|
+
end
|
33
|
+
end
|
34
|
+
ensure
|
35
|
+
save_receipt("aws_route53_receipt", receipt)
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
class CreateRdsDbs < Bosh::Aws::Migration
|
2
|
+
include Bosh::Aws::MigrationHelper
|
3
|
+
|
4
|
+
def execute
|
5
|
+
if !config["rds"]
|
6
|
+
say "rds not set in config. Skipping"
|
7
|
+
return
|
8
|
+
end
|
9
|
+
|
10
|
+
vpc_receipt = load_receipt("aws_vpc_receipt")
|
11
|
+
db_names = %w(ccdb uaadb)
|
12
|
+
db_configs = config['rds'].select {|c| db_names.include?(c['instance']) }
|
13
|
+
RdsDb.aws_rds = rds
|
14
|
+
dbs = []
|
15
|
+
|
16
|
+
begin
|
17
|
+
db_configs.each do |rds_db_conf|
|
18
|
+
rds_args = { vpc_receipt: vpc_receipt, rds_db_conf: rds_db_conf }
|
19
|
+
rds_db = RdsDb.new(rds_args)
|
20
|
+
dbs << rds_db
|
21
|
+
rds_db.create!
|
22
|
+
end
|
23
|
+
|
24
|
+
if RdsDb.was_rds_eventually_available?
|
25
|
+
dbs.each { |db| db.update_receipt }
|
26
|
+
else
|
27
|
+
err "RDS was not available within 60 minutes, giving up"
|
28
|
+
end
|
29
|
+
|
30
|
+
ensure
|
31
|
+
save_receipt("aws_rds_receipt", RdsDb.receipt)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
class CreateMoreUniqueS3Buckets < Bosh::Aws::Migration
|
2
|
+
def s3_safe_full_domain_name
|
3
|
+
config['vpc']['domain'].gsub(".","-")
|
4
|
+
end
|
5
|
+
|
6
|
+
def old_prefix
|
7
|
+
config['name']
|
8
|
+
end
|
9
|
+
|
10
|
+
def buckets
|
11
|
+
{
|
12
|
+
"#{s3_safe_full_domain_name}-bosh-blobstore" => "#{old_prefix}-bosh-blobstore",
|
13
|
+
"#{s3_safe_full_domain_name}-bosh-artifacts" => "#{old_prefix}-bosh-artifacts"
|
14
|
+
}
|
15
|
+
end
|
16
|
+
|
17
|
+
def execute
|
18
|
+
return if s3_safe_full_domain_name == old_prefix
|
19
|
+
|
20
|
+
buckets.each_key do |bucket|
|
21
|
+
say "creating bucket #{bucket}"
|
22
|
+
s3.create_bucket(bucket)
|
23
|
+
end
|
24
|
+
|
25
|
+
buckets.each_pair do |new_bucket, old_bucket|
|
26
|
+
next unless s3.bucket_exists?(old_bucket)
|
27
|
+
say "moving contents of #{old_bucket} to #{new_bucket}"
|
28
|
+
s3.move_bucket(old_bucket, new_bucket)
|
29
|
+
say "deleting bucket #{old_bucket}"
|
30
|
+
s3.delete_bucket(old_bucket)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
class CreateBoshRdsDb < Bosh::Aws::Migration
|
2
|
+
include Bosh::Aws::MigrationHelper
|
3
|
+
|
4
|
+
def execute
|
5
|
+
vpc_receipt = load_receipt("aws_vpc_receipt")
|
6
|
+
db_names = %w(bosh)
|
7
|
+
db_configs = config['rds'].select {|c| db_names.include?(c['instance']) }
|
8
|
+
RdsDb.aws_rds = rds
|
9
|
+
dbs = []
|
10
|
+
|
11
|
+
begin
|
12
|
+
db_configs.each do |rds_db_conf|
|
13
|
+
rds_args = { vpc_receipt: vpc_receipt, rds_db_conf: rds_db_conf }
|
14
|
+
rds_db = RdsDb.new(rds_args)
|
15
|
+
dbs << rds_db
|
16
|
+
rds_db.create!
|
17
|
+
end
|
18
|
+
|
19
|
+
if RdsDb.was_rds_eventually_available?
|
20
|
+
dbs.each { |db| db.update_receipt }
|
21
|
+
else
|
22
|
+
err "RDS was not available within 60 minutes, giving up"
|
23
|
+
end
|
24
|
+
|
25
|
+
ensure
|
26
|
+
save_receipt("aws_rds_bosh_receipt", RdsDb.receipt)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|