Skip to content
This repository has been archived by the owner on Jun 5, 2020. It is now read-only.

Commit

Permalink
(CLOUD-295) Adds support for RDS related resources
Browse files Browse the repository at this point in the history
  • Loading branch information
petems authored and garethr committed May 14, 2015
1 parent 5e1649a commit 7367700
Show file tree
Hide file tree
Showing 24 changed files with 1,056 additions and 2 deletions.
53 changes: 53 additions & 0 deletions examples/postgres-rds-example/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
# RDS

[Amazon Relational Database Service](http://aws.amazon.com/rds/) (Amazon RDS) is a web service that makes it easy to set up, operate, and scale a relational database in the cloud.

## How

This example creates a security group to allow Postgres RDS instance, then creates an RDS instance with that security group assigned.

puppet apply rds_security.pp

Unfortunatly, it's not possible to assign the EC2 group and the allowed IP's to the `db_securitygroup` through the API, so you have to do this manually though the console for now:

## Add the Security Group We Made with Puppet**
![Add EC2 Security Group](./images/add-rds-securitygroup.png?raw=true)

## Add an IP to allow access to the RDS instance
**Note: Enter `0.0.0.0/32` to allow all IPs**
![Add IP to allow](./images/add-ip-to-allow.png?raw=true)

## It should look something like this
![Final Look](./images/final-screen.png?raw=true)

You can now check your security group is correct by using Puppet resource commands:

puppet resource rds_db_securitygroup rds-postgres-db_securitygroup

It should return something like this:

```puppet
rds_db_securitygroup { 'rds-postgres-db_securitygroup':
ensure => 'present',
ec2_security_groups => [{'ec2_security_group_id' => 'sg-83fb3z5', 'ec2_security_group_name' => 'rds-postgres-group', 'ec2_security_group_owner_id' => '4822239859', 'status' => 'authorized'}],
ip_ranges => [{'ip_range' => '0.0.0.0/32', 'status' => 'authorized'}],
owner_id => '239838031',
region => 'us-west-2',
}
```
When this is complete, create the RDS Postgres instance:

puppet apply rds_postgres.pp

This can take a while to setup, but when it's complete, you should be able to access it:

```bash
psql -d postgresql -h puppetlabs-aws-postgres.cwgutxb9fmx.us-west-2.rds.amazonaws.com -U root

Password for user root: pullZstringz345
psql (9.4.0, server 9.3.5)
SSL connection (protocol: TLSv1.2, cipher: DHE-RSA-AES256-GCM-SHA384, bits: 256, compression: off)
Type "help" for help.

postgresql=> exit
```
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
15 changes: 15 additions & 0 deletions examples/postgres-rds-example/rds_postgres.pp
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
rds_instance { 'puppetlabs-aws-postgres':
ensure => 'present',
allocated_storage => '5',
db_instance_class => 'db.m3.medium',
db_name => 'postgresql',
engine => 'postgres',
license_model => 'postgresql-license',
db_security_groups => 'rds-postgres-db_securitygroup',
master_username => 'root',
master_user_password=> 'pullZstringz345',
multi_az => 'false',
region => 'us-west-2',
skip_final_snapshot => 'true',
storage_type => 'gp2',
}
18 changes: 18 additions & 0 deletions examples/postgres-rds-example/rds_security.pp
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
ec2_securitygroup { 'rds-postgres-group':
ensure => present,
region => 'us-west-2',
description => 'Group for Allowing access to Postgres (Port 5432)',
ingress => [{
security_group => 'rds-postgres-group',
},{
protocol => 'tcp',
port => 5432,
cidr => '0.0.0.0/0',
}]
}

rds_db_securitygroup { 'rds-postgres-db_securitygroup':
ensure => present,
region => 'us-west-2',
description => 'An RDS Security group to allow Postgres',
}
37 changes: 37 additions & 0 deletions lib/puppet/provider/rds_db_parameter_group/v2.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
require_relative '../../../puppet_x/puppetlabs/aws.rb'

Puppet::Type.type(:rds_db_parameter_group).provide(:v2, :parent => PuppetX::Puppetlabs::Aws) do
confine feature: :aws

mk_resource_methods

def self.instances
regions.collect do |region|
instances = []
rds_client(region).describe_db_parameter_groups.each do |response|
response.data.db_parameter_groups.each do |db_parameter_group|
# There's always a default class
hash = db_parameter_group_to_hash(region, db_parameter_group)
instances << new(hash) if hash[:name]
end
end
instances
end.flatten
end

def self.db_parameter_group_to_hash(region, db_parameter_group)
{
:ensure => :present,
:name => db_parameter_group.db_parameter_group_name,
:description => db_parameter_group.description,
:family => db_parameter_group.db_parameter_group_family,
:region => region,
}
end

def exists?
Puppet.info("Checking if DB Parameter Group #{name} exists")
[:present, :creating, :available].include? @property_hash[:ensure]
end

end
93 changes: 93 additions & 0 deletions lib/puppet/provider/rds_db_securitygroup/v2.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
require_relative '../../../puppet_x/puppetlabs/aws.rb'

Puppet::Type.type(:rds_db_securitygroup).provide(:v2, :parent => PuppetX::Puppetlabs::Aws) do
confine feature: :aws

mk_resource_methods

def self.instances
regions.collect do |region|
instances = []
rds_client(region).describe_db_security_groups.each do |response|
response.data.db_security_groups.each do |db_security_group|
# There's always a default class
unless db_security_group.db_security_group_name =~ /^default$/
hash = db_security_group_to_hash(region, db_security_group)
instances << new(hash) if hash[:name]
end
end
end
instances
end.flatten
end

def self.prefetch(resources)
instances.each do |prov|
if resource = resources[prov.name] # rubocop:disable Lint/AssignmentInCondition
resource.provider = prov if resource[:region] == prov.region
end
end
end

read_only(:owner_id)

def self.db_security_group_to_hash(region, db_security_group)
{
:ensure => :present,
:region => region,
:name => db_security_group.db_security_group_name,
:description => db_security_group.db_security_group_description,
:owner_id => db_security_group.owner_id,
:security_groups => ec2_security_group_to_array_of_hashes(db_security_group.ec2_security_groups),
:ip_ranges => ip_ranges_to_array_of_hashes(db_security_group.ip_ranges),
}
end

def exists?
Puppet.info("Checking if DB Security Group #{name} exists")
[:present, :creating, :available].include? @property_hash[:ensure]
end

def create
Puppet.info("Creating DB Security Group #{name}")
config = {
:db_security_group_name => resource[:name],
:db_security_group_description => resource[:description],
}

rds_client(resource[:region]).create_db_security_group(config)

@property_hash[:ensure] = :present
end

def destroy
Puppet.info("Deleting DB Security Group #{name} in region #{resource[:region]}")
rds = rds_client(resource[:region])
config = {
db_security_group_name: name,
}
rds.delete_db_security_group(config)
@property_hash[:ensure] = :absent
end

def self.ec2_security_group_to_array_of_hashes(ec2_security_groups)
ec2_security_groups.collect do |group|
{
:status => group.status,
:ec2_security_group_name => group.ec2_security_group_name,
:ec2_security_group_owner_id => group.ec2_security_group_owner_id,
:ec2_security_group_id => group.ec2_security_group_id,
}
end
end

def self.ip_ranges_to_array_of_hashes(ip_ranges)
ip_ranges.collect do |group|
{
:status => group.status,
:ip_range => group.cidrip,
}
end
end

end
122 changes: 122 additions & 0 deletions lib/puppet/provider/rds_instance/v2.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
require_relative '../../../puppet_x/puppetlabs/aws.rb'

Puppet::Type.type(:rds_instance).provide(:v2, :parent => PuppetX::Puppetlabs::Aws) do
confine feature: :aws

mk_resource_methods

def self.instances
regions.collect do |region|
instances = []
rds_client(region).describe_db_instances.each do |response|
response.data.db_instances.each do |db|
unless db.db_instance_status =~ /^deleted$|^deleting$/
hash = db_instance_to_hash(region, db)
instances << new(hash) if hash[:name]
end
end
end
instances
end.flatten
end

read_only(:auto_minor_version_upgrade,
:backup_retention_period, :character_set_name, :creation_date_time,
:iops, :master_username,
:multi_az, :backup_window, :vpc_id, :license_model)

def self.prefetch(resources)
instances.each do |prov|
if resource = resources[prov.name] # rubocop:disable Lint/AssignmentInCondition
resource.provider = prov if resource[:region] == prov.region
end
end
end

def self.db_instance_to_hash(region, instance)
if instance.respond_to?('skip_final_snapshot')
skip_final_snapshot = instance.skip_final_snapshot
else
skip_final_snapshot = true
end
if instance.respond_to?('final_db_snapshot_identifier')
final_db_snapshot_identifier = instance.final_db_snapshot_identifier
else
final_db_snapshot_identifier = ''
end
if instance.respond_to?('backup_retention_period')
backup_retention_period = instance.backup_retention_period
else
backup_retention_period = 0
end
config = {
ensure: :present,
name: instance.db_instance_identifier,
region: region,
engine: instance.engine,
db_instance_class: instance.db_instance_class,
master_username: instance.master_username,
db_name: instance.db_name,
allocated_storage: instance.allocated_storage,
storage_type: instance.storage_type,
license_model: instance.license_model,
multi_az: instance.multi_az,
iops: instance.iops,
backup_retention_period: backup_retention_period,
skip_final_snapshot: skip_final_snapshot,
final_db_snapshot_identifier: final_db_snapshot_identifier,
db_parameter_group_name: instance.db_parameter_groups.collect(&:db_parameter_group_name).first,
db_security_groups: instance.db_security_groups.collect(&:db_security_group_name),
}
if instance.respond_to?('endpoint') && !instance.endpoint.nil?
config[:endpoint] = instance.endpoint.address
config[:port] = instance.endpoint.port
end
config
end

def exists?
dest_region = resource[:region] if resource
Puppet.info("Checking if instance #{name} exists in region #{dest_region || region}")
[:present, :creating, :available, :backing_up].include? @property_hash[:ensure]
end

def create
Puppet.info("Starting DB instance #{name}")
config = {
db_instance_identifier: resource[:name],
db_name: resource[:db_name],
db_instance_class: resource[:db_instance_class],
engine: resource[:engine],
engine_version: resource[:engine_version],
license_model: resource[:license_model],
storage_type: resource[:storage_type],
multi_az: resource[:multi_az],
allocated_storage: resource[:allocated_storage],
iops: resource[:iops],
master_username: resource[:master_username],
master_user_password: resource[:master_user_password],
subnet_group_name: resource[:subnet_group_name],
db_security_groups: resource[:db_security_groups],
db_parameter_group_name: resource[:db_parameter_group_name],
}

rds_client(resource[:region]).create_db_instance(config)

@property_hash[:ensure] = :present
end

def destroy
Puppet.info("Deleting database #{name} in region #{resource[:region]}")
rds = rds_client(resource[:region])
Puppet.info("Skip Final Snapshot: #{resource[:skip_final_snapshot]}")
config = {
db_instance_identifier: name,
skip_final_snapshot: skip_final_snapshot,
final_db_snapshot_identifier: final_db_snapshot_identifier,
}
rds.delete_db_instance(config)
@property_hash[:ensure] = :absent
end

end
35 changes: 35 additions & 0 deletions lib/puppet/type/rds_db_parameter_group.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
Puppet::Type.newtype(:rds_db_parameter_group) do
@doc = 'Type representing an RDS DB Parameter group.'

ensurable

newparam(:name, namevar: true) do
desc 'The name of the DB Parameter Group (also known as the db_parameter_group_name).'
validate do |value|
fail 'name should be a String' unless value.is_a?(String)
end
end

newproperty(:description) do
desc 'The description of a DB parameter group.'
validate do |value|
fail 'description should be a String' unless value.is_a?(String)
end
end

newproperty(:family) do
desc 'The name of the DB family that this DB parameter group is compatible with (eg. mysql5.1).'
validate do |value|
fail 'family should be a String' unless value.is_a?(String)
end
end

newproperty(:region) do
desc 'The region in which to create the db_parameter_group.'
validate do |value|
fail 'region should be a String' unless value.is_a?(String)
fail 'region should not contain spaces' if value =~ /\s/
end
end

end
Loading

0 comments on commit 7367700

Please sign in to comment.