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.
Files changed (36) hide show
  1. data/lib/bosh/cli/commands/aws.rb +464 -0
  2. data/lib/bosh_cli_plugin_aws/aws_config.rb +141 -0
  3. data/lib/bosh_cli_plugin_aws/aws_provider.rb +53 -0
  4. data/lib/bosh_cli_plugin_aws/bat_manifest.rb +40 -0
  5. data/lib/bosh_cli_plugin_aws/bootstrap.rb +31 -0
  6. data/lib/bosh_cli_plugin_aws/bosh_bootstrap.rb +158 -0
  7. data/lib/bosh_cli_plugin_aws/bosh_manifest.rb +71 -0
  8. data/lib/bosh_cli_plugin_aws/ec2.rb +265 -0
  9. data/lib/bosh_cli_plugin_aws/elb.rb +132 -0
  10. data/lib/bosh_cli_plugin_aws/micro_bosh_bootstrap.rb +64 -0
  11. data/lib/bosh_cli_plugin_aws/microbosh_manifest.rb +117 -0
  12. data/lib/bosh_cli_plugin_aws/migration.rb +40 -0
  13. data/lib/bosh_cli_plugin_aws/migration_helper.rb +150 -0
  14. data/lib/bosh_cli_plugin_aws/migrator.rb +137 -0
  15. data/lib/bosh_cli_plugin_aws/rds.rb +182 -0
  16. data/lib/bosh_cli_plugin_aws/route53.rb +103 -0
  17. data/lib/bosh_cli_plugin_aws/s3.rb +93 -0
  18. data/lib/bosh_cli_plugin_aws/version.rb +5 -0
  19. data/lib/bosh_cli_plugin_aws/vpc.rb +181 -0
  20. data/lib/bosh_cli_plugin_aws.rb +31 -0
  21. data/migrations/20130412000811_create_key_pairs.rb +8 -0
  22. data/migrations/20130412004642_create_vpc.rb +65 -0
  23. data/migrations/20130412181302_create_route53_records.rb +37 -0
  24. data/migrations/20130412183544_create_rds_dbs.rb +35 -0
  25. data/migrations/20130412192351_create_s3.rb +4 -0
  26. data/migrations/20130529212130_create_more_unique_s3_buckets.rb +33 -0
  27. data/migrations/20130531180445_create_bosh_rds_db.rb +30 -0
  28. data/migrations/20130826150635_update_elb_for_websockets.rb +97 -0
  29. data/migrations/20130827000001_add_secondary_az_to_vpc.rb +34 -0
  30. data/templates/aws_configuration_template.yml.erb +187 -0
  31. data/templates/aws_migration.erb +5 -0
  32. data/templates/aws_migration_spec.erb +12 -0
  33. data/templates/bat.yml.erb +84 -0
  34. data/templates/bosh.yml.erb +198 -0
  35. data/templates/micro_bosh.yml.erb +82 -0
  36. metadata +163 -0
@@ -0,0 +1,64 @@
1
+ require_relative "bootstrap"
2
+
3
+ module Bosh
4
+ module Aws
5
+ class MicroBoshBootstrap < Bootstrap
6
+ def start
7
+ cleanup_previous_deployments
8
+ generate_deployment_manifest
9
+ deploy
10
+
11
+ login("admin", "admin")
12
+ end
13
+
14
+ def deploy
15
+ Dir.chdir("deployments") do
16
+ micro = Bosh::Cli::Command::Micro.new(runner)
17
+ micro.options = self.options
18
+ micro.micro_deployment("micro")
19
+ micro.perform(micro_ami)
20
+ end
21
+ end
22
+
23
+ def manifest
24
+ unless @manifest
25
+ vpc_receipt_filename = File.expand_path("aws_vpc_receipt.yml")
26
+ route53_receipt_filename = File.expand_path("aws_route53_receipt.yml")
27
+
28
+ vpc_config = load_yaml_file(vpc_receipt_filename)
29
+ route53_config = load_yaml_file(route53_receipt_filename)
30
+
31
+ @manifest = Bosh::Aws::MicroboshManifest.new(vpc_config, route53_config, options)
32
+ end
33
+
34
+ @manifest
35
+ end
36
+
37
+ def generate_deployment_manifest
38
+ deployment_folder = File.join("deployments", manifest.deployment_name)
39
+
40
+ FileUtils.mkdir_p deployment_folder
41
+ if File.exists?(manifest.certificate.certificate_path)
42
+ FileUtils.cp manifest.certificate.certificate_path, File.join(deployment_folder, manifest.certificate.certificate_path)
43
+ end
44
+ if File.exists?(manifest.certificate.key_path)
45
+ FileUtils.cp manifest.certificate.key_path, File.join(deployment_folder, manifest.certificate.key_path)
46
+ end
47
+
48
+ Dir.chdir(deployment_folder) do
49
+ write_yaml(manifest, manifest.file_name)
50
+ end
51
+ end
52
+
53
+ def cleanup_previous_deployments
54
+ rm_files = %w[bosh-deployments.yml micro bosh-registry.log]
55
+ rm_files.each { |file| FileUtils.rm_rf File.join("deployments", file) }
56
+ end
57
+
58
+ def micro_ami
59
+ ENV["BOSH_OVERRIDE_MICRO_STEMCELL_AMI"] ||
60
+ Net::HTTP.get("#{AWS_JENKINS_BUCKET}.s3.amazonaws.com", "/last_successful-bosh-stemcell-aws_ami_us-east-1").strip
61
+ end
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,117 @@
1
+ require 'common/ssl'
2
+
3
+ module Bosh
4
+ module Aws
5
+ class MicroboshManifest
6
+ attr_reader :vpc_receipt, :route53_receipt, :hm_director_password, :hm_director_user
7
+
8
+ def initialize(vpc_receipt, route53_receipt, options={})
9
+ @vpc_receipt = vpc_receipt
10
+ @route53_receipt = route53_receipt
11
+ @hm_director_user = options[:hm_director_user]
12
+ @hm_director_password = options[:hm_director_password]
13
+ end
14
+
15
+ def file_name
16
+ "micro_bosh.yml"
17
+ end
18
+
19
+ def deployment_name
20
+ "micro"
21
+ end
22
+
23
+ def vpc_config
24
+ vpc_receipt['original_configuration']
25
+ end
26
+
27
+ def name
28
+ vpc_config['name'] || warning('Missing name field')
29
+ end
30
+
31
+ def vip
32
+ route53_receipt['elastic_ips']['micro']['ips'][0] || warning('Missing vip field')
33
+ end
34
+
35
+ def subnet
36
+ vpc_receipt['vpc']['subnets']['bosh1'] || warning('Missing bosh subnet field')
37
+ end
38
+
39
+ def availability_zone
40
+ vpc_config['vpc']['subnets']['bosh1']['availability_zone'] || warning('Missing availability zone in vpc.subnets.bosh')
41
+ end
42
+
43
+ def access_key_id
44
+ vpc_config['aws']['access_key_id'] || warning('Missing aws access_key_id field')
45
+ end
46
+
47
+ def secret_access_key
48
+ vpc_config['aws']['secret_access_key'] || warning('Missing aws secret_access_key field')
49
+ end
50
+
51
+ def region
52
+ vpc_config['aws']['region'] || warning('Missing aws region field')
53
+ end
54
+
55
+ def key_pair_name
56
+ vpc_config['key_pairs'].any? ? vpc_config['key_pairs'].keys[0] : warning("Missing key_pairs field, must have at least 1 keypair")
57
+ end
58
+
59
+ def private_key_path
60
+ vpc_config['key_pairs'].any? ? vpc_config['key_pairs'].values[0].gsub(/\.pub$/, '') : warning("Missing key_pairs field, must have at least 1 keypair")
61
+ end
62
+
63
+ def compiled_package_cache?
64
+ !!vpc_config['compiled_package_cache']
65
+ end
66
+
67
+ def cache_access_key_id
68
+ vpc_config['compiled_package_cache']['access_key_id'] || warning('Missing compiled_package_cache access_key_id field')
69
+ end
70
+
71
+ def cache_secret_access_key
72
+ vpc_config['compiled_package_cache']['secret_access_key'] || warning('Missing compiled_package_cache secret_access_key field')
73
+ end
74
+
75
+ def cache_bucket_name
76
+ vpc_config['compiled_package_cache']['bucket_name'] || warning('Missing compiled_package_cache bucket_name field')
77
+ end
78
+
79
+ def director_ssl_key
80
+ certificate.key.gsub("\n", "\n ")
81
+ end
82
+
83
+ def director_ssl_cert
84
+ certificate.certificate.gsub("\n", "\n ")
85
+ end
86
+
87
+ def certificate
88
+ @cert if @cert
89
+ key_path = director_ssl['private_key_path'] || 'director.key'
90
+ cert_path = director_ssl['certificate_path'] || 'director.pem'
91
+ @cert = Bosh::Ssl::Certificate.new(key_path, cert_path, "*.#{vpc_config['vpc']['domain']}").load_or_create
92
+ end
93
+
94
+ def director_ssl
95
+ ssl_certs['director_cert'] || {}
96
+ end
97
+
98
+ def ssl_certs
99
+ vpc_config['ssl_certs'] || {}
100
+ end
101
+
102
+ # RSpec overloads to_yaml when you set up expectations on an object;
103
+ # so to_y is just a way to get directly at the to_yaml implementation without fighting RSpec.
104
+ def to_y
105
+ ERB.new(File.read(get_template("micro_bosh.yml.erb"))).result(binding)
106
+ end
107
+
108
+ def to_yaml
109
+ to_y
110
+ end
111
+
112
+ def get_template(template)
113
+ File.expand_path("../../../templates/#{template}", __FILE__)
114
+ end
115
+ end
116
+ end
117
+ end
@@ -0,0 +1,40 @@
1
+ module Bosh
2
+ module Aws
3
+ class Migration
4
+
5
+ attr_reader :s3, :elb, :ec2, :rds, :route53, :logger, :config
6
+
7
+ def initialize(config, receipt_bucket_name)
8
+ @config = config
9
+ @receipt_bucket_name = receipt_bucket_name
10
+ aws_config = config['aws']
11
+ @s3 = S3.new(aws_config)
12
+ @elb = ELB.new(aws_config)
13
+ @ec2 = EC2.new(aws_config)
14
+ @rds = RDS.new(aws_config)
15
+ @route53 = Route53.new(aws_config)
16
+ @logger = Bosh::Clouds::Config.logger
17
+ end
18
+
19
+ def run
20
+ say "Executing migration #{self.class.name}"
21
+ execute
22
+ end
23
+
24
+ def save_receipt(receipt_name, receipt)
25
+ receipt_yaml = YAML.dump(receipt)
26
+ s3.upload_to_bucket(@receipt_bucket_name, "receipts/#{receipt_name}.yml", receipt_yaml)
27
+
28
+ File.open("#{receipt_name}.yml", "w+") do |f|
29
+ f.write(receipt_yaml)
30
+ end
31
+
32
+ say "details in S3 receipt: #{receipt_name} and file: #{receipt_name}.yml"
33
+ end
34
+
35
+ def load_receipt(receipt_name)
36
+ YAML.load(s3.fetch_object_contents(@receipt_bucket_name, "receipts/#{receipt_name}.yml"))
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,150 @@
1
+ module Bosh
2
+ module Aws
3
+ module MigrationHelper
4
+ class Template
5
+ attr_reader :timestamp_string, :name, :class_name
6
+
7
+ def initialize(name)
8
+ @timestamp_string = Time.new.getutc.strftime("%Y%m%d%H%M%S")
9
+ @name = name
10
+ @class_name = MigrationHelper.to_class_name(name)
11
+ end
12
+
13
+ def file_prefix
14
+ "#{timestamp_string}_#{name}"
15
+ end
16
+
17
+ def render(template_name = "aws_migration")
18
+ template_file_path = File.expand_path("../../templates/#{template_name}.erb", File.dirname(__FILE__))
19
+ template = ERB.new(File.new(template_file_path).read(), 0, '<>%-')
20
+ template.result(binding)
21
+ end
22
+ end
23
+
24
+ class RdsDb
25
+
26
+ attr_accessor :instance_id, :receipt, :tag, :subnet_ids
27
+
28
+ def initialize(args = {})
29
+ vpc_receipt = args.fetch(:vpc_receipt).fetch('vpc')
30
+ vpc_subnets = vpc_receipt.fetch('subnets')
31
+ @rds_db_conf = args.fetch(:rds_db_conf)
32
+ @instance_id = @rds_db_conf.fetch('instance')
33
+ @tag = @rds_db_conf.fetch('tag')
34
+ @subnet_ids = @rds_db_conf.fetch('subnets').map { |s| vpc_subnets[s] }
35
+ @vpc_id = vpc_receipt.fetch('id')
36
+ end
37
+
38
+ def create!
39
+ return if RdsDb.aws_rds.database_exists? @instance_id
40
+ creation_opts = [@instance_id, @subnet_ids, @vpc_id]
41
+
42
+ if @rds_db_conf["aws_creation_options"]
43
+ creation_opts << @rds_db_conf["aws_creation_options"]
44
+ end
45
+
46
+ @response = RdsDb.aws_rds.create_database(*creation_opts)
47
+ output_rds_properties
48
+ end
49
+
50
+ def output_rds_properties
51
+ RdsDb.receipt["deployment_manifest"] ||= {}
52
+ RdsDb.receipt["deployment_manifest"]["properties"] ||= {}
53
+ RdsDb.receipt["deployment_manifest"]["properties"][@instance_id] = {
54
+ "db_scheme" => @response[:engine],
55
+ "roles" => [
56
+ {
57
+ "tag" => "admin",
58
+ "name" => @response[:master_username],
59
+ "password" => @response[:master_user_password]
60
+ }
61
+ ],
62
+ "databases" => [
63
+ {
64
+ "tag" => @tag,
65
+ "name" => @instance_id
66
+ }
67
+ ]
68
+ }
69
+ end
70
+
71
+ def update_receipt
72
+ return unless RdsDb.deployment_properties[instance_id]
73
+
74
+ db_instance = RdsDb.aws_rds.database(instance_id)
75
+ RdsDb.receipt['deployment_manifest']['properties'][instance_id].merge!(
76
+ 'address' => db_instance.endpoint_address,
77
+ 'port' => db_instance.endpoint_port
78
+ )
79
+ end
80
+
81
+ def self.deployment_properties
82
+ RdsDb.receipt.fetch('deployment_manifest', {}).fetch('properties', {})
83
+ end
84
+
85
+ def self.aws_rds
86
+ @aws_rds
87
+ end
88
+
89
+ def self.aws_rds=(arg)
90
+ @aws_rds = arg
91
+ end
92
+
93
+ def self.receipt
94
+ @receipt ||= {}
95
+ end
96
+
97
+ def self.was_rds_eventually_available?
98
+ return true if all_rds_instances_available?(:silent => true)
99
+ (1..540).any? do |attempt| # wait up to 3 hours, checking every 20s
100
+ Kernel.sleep 20
101
+ all_rds_instances_available?
102
+ end
103
+ end
104
+
105
+ def self.all_rds_instances_available?(opts = {})
106
+ silent = opts[:silent]
107
+ say("checking rds status...") unless silent
108
+ aws_rds.databases.all? do |db_instance|
109
+ say(" #{db_instance.db_name} #{db_instance.db_instance_status} #{db_instance.endpoint_address}") unless silent
110
+ !db_instance.endpoint_address.nil?
111
+ end
112
+ end
113
+ end
114
+
115
+
116
+ def self.aws_migration_directory
117
+ File.expand_path("../../migrations", File.dirname(__FILE__))
118
+ end
119
+
120
+ def self.aws_spec_migration_directory
121
+ File.expand_path("../../spec/migrations", File.dirname(__FILE__))
122
+ end
123
+
124
+ def self.generate_migration_file(name)
125
+ template = Template.new(name)
126
+
127
+ filename = "#{aws_migration_directory}/#{template.file_prefix}.rb"
128
+ spec_filename = "#{aws_spec_migration_directory}/#{template.file_prefix}_spec.rb"
129
+
130
+ puts "Creating #{filename} and #{spec_filename}"
131
+
132
+ File.open(filename, 'w+') { |f| f.write(template.render) }
133
+ File.open(spec_filename, 'w+') { |f| f.write(template.render("aws_migration_spec")) }
134
+ end
135
+
136
+ def self.to_class_name(name)
137
+ name.split('_').map(&:capitalize).join('')
138
+ end
139
+
140
+ def self.all_rds_instances_available?(rds, opts = {})
141
+ silent = opts[:silent]
142
+ say("checking rds status...") unless silent
143
+ rds.databases.all? do |db_instance|
144
+ say(" #{db_instance.db_name} #{db_instance.db_instance_status} #{db_instance.endpoint_address}") unless silent
145
+ !db_instance.endpoint_address.nil?
146
+ end
147
+ end
148
+ end
149
+ end
150
+ end
@@ -0,0 +1,137 @@
1
+ module Bosh
2
+ module Aws
3
+ class Migrator
4
+
5
+ def initialize(config)
6
+ @config = config
7
+ @migration_path = MigrationHelper.aws_migration_directory
8
+ end
9
+
10
+ def migrate
11
+ return unless needs_migration?
12
+
13
+ run_migrations(pending_migrations)
14
+ end
15
+
16
+ def migrate_version(version)
17
+ return unless needs_migration?
18
+
19
+ migration_to_run = pending_migrations.detect do |migration|
20
+ migration.version == version.to_i
21
+ end
22
+
23
+ run_migrations([migration_to_run])
24
+ end
25
+
26
+ def pending_migrations
27
+ migrations - environment_migrations
28
+ end
29
+
30
+ def migrations
31
+ @migrations ||= load_migrations
32
+ end
33
+
34
+ def environment_migrations
35
+ @environment_migrations ||= load_migrations_for_env
36
+ end
37
+
38
+ def needs_migration?
39
+ ensure_bucket_exists
40
+ environment_migrations.nil? || environment_migrations != migrations
41
+ end
42
+
43
+ private
44
+
45
+ attr_reader :migration_path
46
+
47
+ def aws_s3
48
+ @aws_s3 ||= Bosh::Aws::S3.new(@config['aws'])
49
+ end
50
+
51
+ def ensure_bucket_exists
52
+ unless aws_s3.bucket_exists?(bucket_name)
53
+ aws_s3.create_bucket(bucket_name)
54
+ end
55
+ end
56
+
57
+ def s3_safe_vpc_domain
58
+ @config['vpc']['domain'].gsub('.', '-')
59
+ end
60
+
61
+ def bucket_name
62
+ if aws_s3.bucket_exists?("#{@config['name']}-bosh-artifacts")
63
+ "#{@config['name']}-bosh-artifacts"
64
+ else
65
+ "#{s3_safe_vpc_domain}-bosh-artifacts"
66
+ end
67
+ end
68
+
69
+ def migrations_name
70
+ "aws_migrations/migrations.yaml"
71
+ end
72
+
73
+ def run_migrations(migrations_to_run)
74
+ migrations_to_run.each do |migration|
75
+ migration.load_class.new(@config, bucket_name).run
76
+ record_migration(migration)
77
+ end
78
+ end
79
+
80
+ def load_migrations
81
+ Dir.glob(File.join(migration_path, "*.rb")).collect do |migration_file_path|
82
+ version, name = migration_file_path.scan(/([0-9]+)_([_a-z0-9]*).rb\z/).first
83
+ MigrationProxy.new(name,version.to_i)
84
+ end.sort
85
+ end
86
+
87
+ def load_migrations_for_env
88
+ yaml_file = aws_s3.fetch_object_contents(bucket_name, migrations_name) || ""
89
+ migrations = YAML.load(yaml_file) || []
90
+
91
+ migrations.collect do |migration_yaml|
92
+ MigrationProxy.new(migration_yaml['name'],migration_yaml['version'].to_i)
93
+ end.sort
94
+ end
95
+
96
+ def record_migration(migration)
97
+ environment_migrations << migration
98
+ migration_yaml = YAML.dump(environment_migrations.collect do |m|
99
+ m.to_hash
100
+ end)
101
+ aws_s3.upload_to_bucket(bucket_name, migrations_name, migration_yaml)
102
+ end
103
+ end
104
+
105
+ class MigrationProxy
106
+ include Comparable
107
+
108
+ attr_reader :name, :version
109
+
110
+ def initialize(name, version)
111
+ @name = name
112
+ @version = version.to_i
113
+ end
114
+
115
+ def load_class
116
+ require File.join(MigrationHelper.aws_migration_directory, "#{version}_#{name}")
117
+ Object.const_get(MigrationHelper.to_class_name(name))
118
+ end
119
+
120
+ def eql?(other)
121
+ version == other.version
122
+ end
123
+
124
+ def <=>(other)
125
+ version <=> other.version
126
+ end
127
+
128
+ def hash
129
+ (name.to_s + version.to_s).hash
130
+ end
131
+
132
+ def to_hash
133
+ {"name" => name, "version" => version}
134
+ end
135
+ end
136
+ end
137
+ end
@@ -0,0 +1,182 @@
1
+ require "securerandom"
2
+
3
+ module Bosh
4
+ module Aws
5
+ class RDS
6
+ DEFAULT_RDS_OPTIONS = {
7
+ :allocated_storage => 5,
8
+ :db_instance_class => "db.t1.micro",
9
+ :engine => "mysql",
10
+ :multi_az => true,
11
+ :engine_version => "5.5.31"
12
+ }
13
+ DEFAULT_RDS_PROTOCOL = :tcp
14
+ DEFAULT_MYSQL_PORT = 3306
15
+
16
+ def initialize(credentials)
17
+ @credentials = credentials
18
+ @aws_provider = AwsProvider.new(@credentials)
19
+ end
20
+
21
+ def create_database(name, subnet_ids, vpc_id, options = {})
22
+ create_db_parameter_group('utf8')
23
+ vpc = Bosh::Aws::VPC.find(Bosh::Aws::EC2.new(@credentials), vpc_id)
24
+ create_vpc_db_security_group(vpc, name) if vpc.security_group_by_name(name).nil?
25
+ create_subnet_group(name, subnet_ids) unless subnet_group_exists?(name)
26
+
27
+ # symbolize options keys
28
+ options = options.inject({}) { |memo, (k, v)| memo[k.to_sym] = v; memo }
29
+
30
+ creation_options = DEFAULT_RDS_OPTIONS.merge(options)
31
+ creation_options[:db_instance_identifier] = name
32
+ creation_options[:db_name] ||= name
33
+ creation_options[:vpc_security_group_ids] = [vpc.security_group_by_name(name).id]
34
+ creation_options[:db_subnet_group_name] = name
35
+ creation_options[:db_parameter_group_name] = 'utf8'
36
+ creation_options[:master_username] ||= generate_user
37
+ creation_options[:master_user_password] ||= generate_password
38
+ response = aws_rds_client.create_db_instance(creation_options)
39
+ response.data.merge(:master_user_password => creation_options[:master_user_password])
40
+ end
41
+
42
+ def databases
43
+ aws_rds.db_instances
44
+ end
45
+
46
+ def database(name)
47
+ databases.find { |v| v.id == name }
48
+ end
49
+
50
+ def database_exists?(name)
51
+ !database(name).nil?
52
+ end
53
+
54
+ def delete_databases
55
+ databases.each { |db| db.delete(skip_final_snapshot: true) unless db.db_instance_status == "deleting" }
56
+ end
57
+
58
+ def database_names
59
+ databases.inject({}) do |memo, db_instance|
60
+ memo[db_instance.id] = db_instance.name
61
+ memo
62
+ end
63
+ end
64
+
65
+ def subnet_group_exists?(name)
66
+ aws_rds_client.describe_db_subnet_groups(:db_subnet_group_name => name)
67
+ return true
68
+ rescue AWS::RDS::Errors::DBSubnetGroupNotFoundFault
69
+ return false
70
+ end
71
+
72
+ def db_parameter_group_names
73
+ charset = 'utf8'
74
+ param_names = %w(character_set_server
75
+ character_set_client
76
+ character_set_results
77
+ character_set_database
78
+ character_set_connection)
79
+
80
+ params = param_names.map{|param_name| {:parameter_name => param_name,
81
+ :parameter_value => charset,
82
+ :apply_method => 'immediate'}}
83
+
84
+ params << {:parameter_name => 'collation_connection',
85
+ :parameter_value => 'utf8_unicode_ci',
86
+ :apply_method => 'immediate'}
87
+ params << {:parameter_name => 'collation_server',
88
+ :parameter_value => 'utf8_unicode_ci',
89
+ :apply_method => 'immediate'}
90
+ params
91
+ end
92
+
93
+ def create_db_parameter_group(name)
94
+ aws_rds_client.describe_db_parameter_groups(:db_parameter_group_name => name)
95
+ rescue AWS::RDS::Errors::DBParameterGroupNotFound
96
+ aws_rds_client.create_db_parameter_group(:db_parameter_group_name => name,
97
+ :db_parameter_group_family => 'mysql5.5', :description => name)
98
+ aws_rds_client.modify_db_parameter_group(:db_parameter_group_name => name,
99
+ :parameters => db_parameter_group_names)
100
+ end
101
+
102
+ def delete_db_parameter_group(name)
103
+ aws_rds_client.describe_db_parameter_groups(:db_parameter_group_name => name)
104
+ aws_rds_client.delete_db_parameter_group(:db_parameter_group_name => name)
105
+ rescue AWS::RDS::Errors::DBParameterGroupNotFound
106
+ end
107
+
108
+ def create_subnet_group(name, subnet_ids)
109
+ aws_rds_client.create_db_subnet_group(
110
+ :db_subnet_group_name => name,
111
+ :db_subnet_group_description => name,
112
+ :subnet_ids => subnet_ids
113
+ )
114
+ end
115
+
116
+ def subnet_group_names
117
+ aws_rds_client.describe_db_subnet_groups.data[:db_subnet_groups].map { |sg| sg[:db_subnet_group_name] }
118
+ end
119
+
120
+ def delete_subnet_group(name)
121
+ aws_rds_client.delete_db_subnet_group(:db_subnet_group_name => name)
122
+ end
123
+
124
+ def delete_subnet_groups
125
+ subnet_group_names.each { |name| delete_subnet_group(name) }
126
+ end
127
+
128
+ def create_vpc_db_security_group(vpc, name)
129
+ group_spec = {
130
+ "name" => name,
131
+ "ingress" => [
132
+ {
133
+ "ports" => DEFAULT_MYSQL_PORT,
134
+ "protocol" => DEFAULT_RDS_PROTOCOL,
135
+ "sources" => vpc.cidr_block,
136
+ },
137
+ ],
138
+ }
139
+
140
+ vpc.create_security_groups([group_spec])
141
+ end
142
+
143
+ def security_group_names
144
+ aws_rds_client.describe_db_security_groups.data[:db_security_groups].map { |sg| sg[:db_security_group_name] }
145
+ end
146
+
147
+ def delete_security_group(name)
148
+ aws_rds_client.delete_db_security_group(:db_security_group_name => name)
149
+ end
150
+
151
+ def delete_security_groups
152
+ security_group_names.each do |name|
153
+ delete_security_group(name) unless name == "default"
154
+ end
155
+ end
156
+
157
+ def aws_rds
158
+ aws_provider.rds
159
+ end
160
+
161
+ def aws_rds_client
162
+ aws_provider.rds_client
163
+ end
164
+
165
+ private
166
+
167
+ attr_reader :aws_provider
168
+
169
+ def generate_user
170
+ generate_credential("u", 7)
171
+ end
172
+
173
+ def generate_password
174
+ generate_credential("p", 16)
175
+ end
176
+
177
+ def generate_credential(prefix, length)
178
+ "#{prefix}#{SecureRandom.hex(length)}"
179
+ end
180
+ end
181
+ end
182
+ end