Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 9 additions & 6 deletions docs/PostgreSQLUser.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,10 @@ Properties:
Database:
Host: STRING
Port: INTEGER
Database: STRING
DBName: STRING
DBNameParameterName: STRING
User: STRING
UserParameterName: STRING
Password: STRING
PasswordParameterName: STRING
ServiceToken: !Sub 'arn:aws:lambda:${AWS::Region}:${AWS::AccountId}:function:binxio-cfn-dbuser-provider-vpc-${AppVPC}'
Expand All @@ -27,20 +29,21 @@ Properties:
You can specify the following properties:

- `Name` - of the user to create
- `Password` - of the user
- `Password` - of the user
- `PasswordParameterName` - name of the parameter in the store containing the password of the user
- `WithDatabase` - if a database is to be created with the same name, defaults to true
- `DeletionPolicy` - when the resource is deleted
- `Database` - connection information of the database owner
-- `Host` - the database server is listening on.
-- `Port` - port the database server is listening on.
-- `Database` - name to connect to.
-- `DBName` - name to connect to.
-- `DBNameParameterName` - name of the parameter in the store containing the database name to connect to.
-- `User` - name of the database owner.
-- `Password` - to identify the user with.
-- `UserParameterName` - name of the parameter in the store containing the database owner.
-- `Password` - to identify the user with.
-- `PasswordParameterName` - name of the parameter in the store containing the password of the user

Either `Password` or `PasswordParameterName` is required.
Either `DBName` or `DBNameParameterName`, `User` or `UserParameterName`, `Password` or `PasswordParameterName` is required.

## Return values
There are no return values from this resources.

41 changes: 33 additions & 8 deletions src/postgresql_user_provider.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import boto3
import logging
import os
import psycopg2
from botocore.exceptions import ClientError
from psycopg2.extensions import AsIs
from cfn_resource_provider import ResourceProvider

log = logging.getLogger()
log.setLevel(os.environ.get("LOG_LEVEL", "INFO"))

request_schema = {
"$schema": "http://json-schema.org/draft-04/schema#",
Expand Down Expand Up @@ -46,13 +48,19 @@
"type": "object",
"oneOf": [
{"required": ["DBName", "Host", "Port", "User", "Password"]},
{"required": ["DBName", "Host", "Port", "User", "PasswordParameterName"]}
{"required": ["DBName", "Host", "Port", "User", "PasswordParameterName"]},
{"required": ["DBName", "Host", "Port", "UserParameterName", "PasswordParameterName"]},
{"required": ["DBNameParameterName", "Host", "Port", "UserParameterName", "PasswordParameterName"]},
],
"properties": {
"DBName": {
"type": "string",
"description": "the name of the database"
},
"DBNameParameterName": {
"type": "string",
"description": "the name of the database name in the Parameter Store"
},
"Host": {
"type": "string",
"description": "the host of the database"
Expand All @@ -66,6 +74,10 @@
"type": "string",
"description": "the username of the database owner"
},
"UserParameterName": {
"type": "string",
"description": "the name of the database owner username in the Parameter Store"
},
"Password": {
"type": "string",
"description": "the password of the database owner"
Expand All @@ -88,30 +100,33 @@ def __init__(self):
self.connection = None
self.request_schema = request_schema

def is_valid_request(self):
return super(PostgreSQLUser, self).is_valid_request()

def convert_property_types(self):
self.heuristic_convert_property_types(self.properties)

def get_password(self, name):
def get_ssm_parameter(self, name):
try:
response = self.ssm.get_parameter(Name=name, WithDecryption=True)
return response['Parameter']['Value']
except ClientError as e:
raise ValueError('Could not obtain password using name {}, {}'.format(name, e))
raise ValueError('Could not obtain value using name {}, {}'.format(name, e))

@property
def user_password(self):
if 'Password' in self.properties:
return self.get('Password')
else:
return self.get_password(self.get('PasswordParameterName'))
return self.get_ssm_parameter(self.get('PasswordParameterName'))

@property
def dbowner_password(self):
db = self.get('Database')
if 'Password' in db:
return db.get('Password')
else:
return self.get_password(db['PasswordParameterName'])
return self.get_ssm_parameter(db['PasswordParameterName'])

@property
def user(self):
Expand All @@ -127,11 +142,19 @@ def port(self):

@property
def dbname(self):
return self.get('Database', {}).get('DBName', None)
db = self.get('Database')
if 'DBName' in db:
return db.get('DBName')
else:
return self.get_ssm_parameter(db['DBNameParameterName'])

@property
def dbowner(self):
return self.get('Database', {}).get('User', None)
db = self.get('Database')
if 'User' in db:
return db.get('User')
else:
return self.get_ssm_parameter(db['UserParameterName'])

@property
def with_database(self):
Expand All @@ -144,7 +167,8 @@ def deletion_policy(self):
@property
def connect_info(self):
return {'host': self.host, 'port': self.port, 'dbname': self.dbname,
'user': self.dbowner, 'password': self.dbowner_password}
'user': self.dbowner, 'password': self.dbowner_password,
'connect_timeout': 60}

@property
def allow_update(self):
Expand All @@ -163,6 +187,7 @@ def connect(self):
self.connection = psycopg2.connect(**self.connect_info)
self.connection.set_session(autocommit=True)
except Exception as e:
log.error('Failed to connect to database - check its running and reachable')
raise ValueError('Failed to connect, %s' % e)

def close(self):
Expand Down