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

Commit 3c6c127

Browse files
petemsgarethr
authored andcommitted
(CLOUD-295) Adds support for RDS related resources
1 parent 05c059a commit 3c6c127

File tree

24 files changed

+1333
-28
lines changed

24 files changed

+1333
-28
lines changed

README.md

Lines changed: 159 additions & 27 deletions
Large diffs are not rendered by default.
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
# RDS
2+
3+
[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.
4+
5+
## How
6+
7+
This example creates a security group to allow access to a Postgres RDS instance, then creates that RDS instance with the security group assigned.
8+
9+
puppet apply rds_security.pp
10+
11+
Unfortunately, it's not possible to assign the EC2 group and the allowed IPs to the `db_securitygroup` through the API, so you have to do this manually though the console for now:
12+
13+
## Add the Security Group We Made with Puppet**
14+
![Add EC2 Security Group](./images/add-rds-securitygroup.png?raw=true)
15+
16+
## Add an IP to allow access to the RDS instance
17+
**Note: Enter `0.0.0.0/32` to allow all IPs**
18+
![Add IP to allow](./images/add-ip-to-allow.png?raw=true)
19+
20+
## It should look something like this
21+
![Final Look](./images/final-screen.png?raw=true)
22+
23+
You can now check your security group is correct by using Puppet resource commands:
24+
25+
puppet resource rds_db_securitygroup rds-postgres-db_securitygroup
26+
27+
It should return something like this:
28+
29+
~~~
30+
rds_db_securitygroup { 'rds-postgres-db_securitygroup':
31+
ensure => 'present',
32+
ec2_security_groups => [{'ec2_security_group_id' => 'sg-83fb3z5', 'ec2_security_group_name' => 'rds-postgres-group', 'ec2_security_group_owner_id' => '4822239859', 'status' => 'authorized'}],
33+
ip_ranges => [{'ip_range' => '0.0.0.0/32', 'status' => 'authorized'}],
34+
owner_id => '239838031',
35+
region => 'us-west-2',
36+
}
37+
~~~
38+
39+
When this is complete, create the RDS Postgres instance:
40+
41+
puppet apply rds_postgres.pp
42+
43+
This can take a while to setup, but when it's complete, you should be able to access it:
44+
45+
~~~
46+
psql -d postgresql -h puppetlabs-aws-postgres.cwgutxb9fmx.us-west-2.rds.amazonaws.com -U root
47+
48+
Password for user root: pullZstringz345
49+
psql (9.4.0, server 9.3.5)
50+
SSL connection (protocol: TLSv1.2, cipher: DHE-RSA-AES256-GCM-SHA384, bits: 256, compression: off)
51+
Type "help" for help.
52+
53+
postgresql=> exit
54+
~~~
51.7 KB
Loading
249 KB
Loading
96 KB
Loading
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
rds_instance { 'puppetlabs-aws-postgres':
2+
ensure => present,
3+
allocated_storage => '5',
4+
db_instance_class => 'db.m3.medium',
5+
db_name => 'postgresql',
6+
engine => 'postgres',
7+
license_model => 'postgresql-license',
8+
db_security_groups => 'rds-postgres-db_securitygroup',
9+
master_username => 'root',
10+
master_user_password=> 'pullZstringz345',
11+
region => 'us-west-2',
12+
skip_final_snapshot => 'true',
13+
storage_type => 'gp2',
14+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
ec2_securitygroup { 'rds-postgres-group':
2+
ensure => present,
3+
region => 'us-west-2',
4+
description => 'Group for Allowing access to Postgres (Port 5432)',
5+
ingress => [{
6+
security_group => 'rds-postgres-group',
7+
},{
8+
protocol => 'tcp',
9+
port => 5432,
10+
cidr => '0.0.0.0/0',
11+
}]
12+
}
13+
14+
rds_db_securitygroup { 'rds-postgres-db_securitygroup':
15+
ensure => present,
16+
region => 'us-west-2',
17+
description => 'An RDS Security group to allow Postgres',
18+
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
require_relative '../../../puppet_x/puppetlabs/aws.rb'
2+
3+
Puppet::Type.type(:rds_db_parameter_group).provide(:v2, :parent => PuppetX::Puppetlabs::Aws) do
4+
confine feature: :aws
5+
6+
mk_resource_methods
7+
8+
def self.instances
9+
regions.collect do |region|
10+
instances = []
11+
rds_client(region).describe_db_parameter_groups.each do |response|
12+
response.data.db_parameter_groups.each do |db_parameter_group|
13+
# There's always a default class
14+
hash = db_parameter_group_to_hash(region, db_parameter_group)
15+
instances << new(hash) if hash[:name]
16+
end
17+
end
18+
instances
19+
end.flatten
20+
end
21+
22+
def self.db_parameter_group_to_hash(region, db_parameter_group)
23+
{
24+
:ensure => :present,
25+
:name => db_parameter_group.db_parameter_group_name,
26+
:description => db_parameter_group.description,
27+
:family => db_parameter_group.db_parameter_group_family,
28+
:region => region,
29+
}
30+
end
31+
32+
def exists?
33+
Puppet.info("Checking if DB Parameter Group #{name} exists")
34+
[:present, :creating, :available].include? @property_hash[:ensure]
35+
end
36+
37+
end
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
require_relative '../../../puppet_x/puppetlabs/aws.rb'
2+
3+
Puppet::Type.type(:rds_db_securitygroup).provide(:v2, :parent => PuppetX::Puppetlabs::Aws) do
4+
confine feature: :aws
5+
6+
mk_resource_methods
7+
8+
def self.instances
9+
regions.collect do |region|
10+
instances = []
11+
rds_client(region).describe_db_security_groups.each do |response|
12+
response.data.db_security_groups.each do |db_security_group|
13+
# There's always a default class
14+
unless db_security_group.db_security_group_name =~ /^default$/
15+
hash = db_security_group_to_hash(region, db_security_group)
16+
instances << new(hash) if hash[:name]
17+
end
18+
end
19+
end
20+
instances
21+
end.flatten
22+
end
23+
24+
def self.prefetch(resources)
25+
instances.each do |prov|
26+
if resource = resources[prov.name] # rubocop:disable Lint/AssignmentInCondition
27+
resource.provider = prov if resource[:region] == prov.region
28+
end
29+
end
30+
end
31+
32+
read_only(:region, :description)
33+
34+
def self.db_security_group_to_hash(region, db_security_group)
35+
{
36+
:ensure => :present,
37+
:region => region,
38+
:name => db_security_group.db_security_group_name,
39+
:description => db_security_group.db_security_group_description,
40+
:owner_id => db_security_group.owner_id,
41+
:security_groups => ec2_security_group_to_array_of_hashes(db_security_group.ec2_security_groups),
42+
:ip_ranges => ip_ranges_to_array_of_hashes(db_security_group.ip_ranges),
43+
}
44+
end
45+
46+
def exists?
47+
Puppet.info("Checking if DB Security Group #{name} exists")
48+
[:present, :creating, :available].include? @property_hash[:ensure]
49+
end
50+
51+
def create
52+
Puppet.info("Creating DB Security Group #{name}")
53+
config = {
54+
:db_security_group_name => resource[:name],
55+
:db_security_group_description => resource[:description],
56+
}
57+
58+
rds_client(resource[:region]).create_db_security_group(config)
59+
60+
@property_hash[:ensure] = :present
61+
end
62+
63+
def destroy
64+
Puppet.info("Deleting DB Security Group #{name} in region #{resource[:region]}")
65+
rds = rds_client(resource[:region])
66+
config = {
67+
db_security_group_name: name,
68+
}
69+
rds.delete_db_security_group(config)
70+
@property_hash[:ensure] = :absent
71+
end
72+
73+
def self.ec2_security_group_to_array_of_hashes(ec2_security_groups)
74+
ec2_security_groups.collect do |group|
75+
{
76+
:status => group.status,
77+
:ec2_security_group_name => group.ec2_security_group_name,
78+
:ec2_security_group_owner_id => group.ec2_security_group_owner_id,
79+
:ec2_security_group_id => group.ec2_security_group_id,
80+
}
81+
end
82+
end
83+
84+
def self.ip_ranges_to_array_of_hashes(ip_ranges)
85+
ip_ranges.collect do |group|
86+
{
87+
:status => group.status,
88+
:ip_range => group.cidrip,
89+
}
90+
end
91+
end
92+
93+
end
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
require_relative '../../../puppet_x/puppetlabs/aws.rb'
2+
3+
Puppet::Type.type(:rds_instance).provide(:v2, :parent => PuppetX::Puppetlabs::Aws) do
4+
confine feature: :aws
5+
6+
mk_resource_methods
7+
8+
def self.instances
9+
regions.collect do |region|
10+
instances = []
11+
rds_client(region).describe_db_instances.each do |response|
12+
response.data.db_instances.each do |db|
13+
unless db.db_instance_status =~ /^deleted$|^deleting$/
14+
hash = db_instance_to_hash(region, db)
15+
instances << new(hash) if hash[:name]
16+
end
17+
end
18+
end
19+
instances
20+
end.flatten
21+
end
22+
23+
read_only(:iops, :master_username, :multi_az, :license_model,
24+
:db_name, :region, :db_instance_class, :availability_zone,
25+
:engine, :engine_version, :allocated_storage, :storage_type,
26+
:db_security_groups, :db_parameter_group)
27+
28+
def self.prefetch(resources)
29+
instances.each do |prov|
30+
if resource = resources[prov.name] # rubocop:disable Lint/AssignmentInCondition
31+
resource.provider = prov if resource[:region] == prov.region
32+
end
33+
end
34+
end
35+
36+
def self.db_instance_to_hash(region, instance)
37+
config = {
38+
ensure: :present,
39+
name: instance.db_instance_identifier,
40+
region: region,
41+
engine: instance.engine,
42+
engine_version: instance.engine_version,
43+
db_instance_class: instance.db_instance_class,
44+
master_username: instance.master_username,
45+
db_name: instance.db_name,
46+
allocated_storage: instance.allocated_storage,
47+
storage_type: instance.storage_type,
48+
license_model: instance.license_model,
49+
multi_az: instance.multi_az,
50+
iops: instance.iops,
51+
db_parameter_group: instance.db_parameter_groups.collect(&:db_parameter_group_name).first,
52+
db_security_groups: instance.db_security_groups.collect(&:db_security_group_name),
53+
}
54+
if instance.respond_to?('endpoint') && !instance.endpoint.nil?
55+
config[:endpoint] = instance.endpoint.address
56+
config[:port] = instance.endpoint.port
57+
end
58+
config
59+
end
60+
61+
def exists?
62+
dest_region = resource[:region] if resource
63+
Puppet.info("Checking if instance #{name} exists in region #{dest_region || region}")
64+
[:present, :creating, :available, :backing_up].include? @property_hash[:ensure]
65+
end
66+
67+
def create
68+
Puppet.info("Starting DB instance #{name}")
69+
config = {
70+
db_instance_identifier: resource[:name],
71+
db_name: resource[:db_name],
72+
db_instance_class: resource[:db_instance_class],
73+
engine: resource[:engine],
74+
engine_version: resource[:engine_version],
75+
license_model: resource[:license_model],
76+
storage_type: resource[:storage_type],
77+
multi_az: resource[:multi_az].to_s,
78+
allocated_storage: resource[:allocated_storage],
79+
iops: resource[:iops],
80+
master_username: resource[:master_username],
81+
master_user_password: resource[:master_user_password],
82+
subnet_group_name: resource[:db_subnet],
83+
db_security_groups: resource[:db_security_groups],
84+
db_parameter_group_name: resource[:db_parameter_group],
85+
}
86+
87+
rds_client(resource[:region]).create_db_instance(config)
88+
89+
@property_hash[:ensure] = :present
90+
end
91+
92+
def destroy
93+
Puppet.info("Deleting database #{name} in region #{resource[:region]}")
94+
rds = rds_client(resource[:region])
95+
if resource[:skip_final_snapshot].to_s == 'true'
96+
Puppet.info("A snapshot of the database on deletion will be available as #{resource[:final_db_snapshot_identifier]}")
97+
end
98+
config = {
99+
db_instance_identifier: name,
100+
skip_final_snapshot: resource[:skip_final_snapshot].to_s,
101+
final_db_snapshot_identifier: resource[:final_db_snapshot_identifier],
102+
}
103+
rds.delete_db_instance(config)
104+
@property_hash[:ensure] = :absent
105+
end
106+
107+
end

0 commit comments

Comments
 (0)