bosh_cli_plugin_aws 1.5.0.pre.1113

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 (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