heat/heat/engine/resources/dbinstance.py

245 lines
7.8 KiB
Python

# vim: tabstop=4 shiftwidth=4 softtabstop=4
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from heat.common import template_format
from heat.engine import stack_resource
from heat.openstack.common import log as logging
logger = logging.getLogger(__name__)
mysql_template = r'''
{
"AWSTemplateFormatVersion": "2010-09-09",
"Description": "Builtin RDS::DBInstance",
"Parameters" : {
"DBInstanceClass" : {
"Type": "String"
},
"DBName" : {
"Type": "String"
},
"MasterUsername" : {
"Type": "String"
},
"MasterUserPassword" : {
"Type": "String"
},
"AllocatedStorage" : {
"Type": "String"
},
"DBSecurityGroups" : {
"Type": "CommaDelimitedList",
"Default": ""
},
"Port" : {
"Type": "String"
},
"KeyName" : {
"Type" : "String"
}
},
"Mappings" : {
"DBInstanceToInstance" : {
"db.m1.small": {"Instance": "m1.small"},
"db.m1.large": {"Instance": "m1.large"},
"db.m1.xlarge": {"Instance": "m1.xlarge"},
"db.m2.xlarge": {"Instance": "m2.xlarge"},
"db.m2.2xlarge": {"Instance": "m2.2xlarge"},
"db.m2.4xlarge": {"Instance": "m2.4xlarge"}
}
},
"Resources": {
"DatabaseInstance": {
"Type": "AWS::EC2::Instance",
"Metadata": {
"AWS::CloudFormation::Init": {
"config": {
"packages": {
"yum": {
"mysql" : [],
"mysql-server" : []
}
},
"services": {
"systemd": {
"mysqld" : { "enabled" : "true", "ensureRunning" : "true" }
}
}
}
}
},
"Properties": {
"ImageId": "F17-x86_64-cfntools",
"InstanceType": { "Fn::FindInMap": [ "DBInstanceToInstance",
{ "Ref": "DBInstanceClass" },
"Instance" ] },
"KeyName": { "Ref": "KeyName" },
"UserData": { "Fn::Base64": { "Fn::Join": ["", [
"#!/bin/bash -v\n",
"# Helper function\n",
"function error_exit\n",
"{\n",
" /opt/aws/bin/cfn-signal -e 1 -r \"$1\" '",
{ "Ref" : "WaitHandle" }, "'\n",
" exit 1\n",
"}\n",
"/opt/aws/bin/cfn-init -s ", { "Ref" : "AWS::StackName" },
" -r DatabaseInstance",
" --region ", { "Ref" : "AWS::Region" },
" || error_exit 'Failed to run cfn-init'\n",
"# Setup MySQL root password and create a user\n",
"mysqladmin -u root password '", {"Ref":"MasterUserPassword"},"'\n",
"cat << EOF | mysql -u root --password='",
{ "Ref" : "MasterUserPassword" }, "'\n",
"CREATE DATABASE ", { "Ref" : "DBName" }, ";\n",
"GRANT ALL PRIVILEGES ON ", { "Ref" : "DBName" },
".* TO \"", { "Ref" : "MasterUsername" }, "\"@\"%\"\n",
"IDENTIFIED BY \"", { "Ref" : "MasterUserPassword" }, "\";\n",
"FLUSH PRIVILEGES;\n",
"EXIT\n",
"EOF\n",
"# Database setup completed, signal success\n",
"/opt/aws/bin/cfn-signal -e 0 -r \"MySQL server setup complete\" '",
{ "Ref" : "WaitHandle" }, "'\n"
]]}}
}
},
"WaitHandle" : {
"Type" : "AWS::CloudFormation::WaitConditionHandle"
},
"WaitCondition" : {
"Type" : "AWS::CloudFormation::WaitCondition",
"DependsOn" : "DatabaseInstance",
"Properties" : {
"Handle" : {"Ref" : "WaitHandle"},
"Timeout" : "600"
}
}
},
"Outputs": {
}
}
'''
class DBInstance(stack_resource.StackResource):
properties_schema = {
'DBSnapshotIdentifier': {'Type': 'String',
'Implemented': False},
'AllocatedStorage': {'Type': 'String',
'Required': True},
'AvailabilityZone': {'Type': 'String',
'Implemented': False},
'BackupRetentionPeriod': {'Type': 'String',
'Implemented': False},
'DBInstanceClass': {'Type': 'String',
'Required': True},
'DBName': {'Type': 'String',
'Required': False},
'DBParameterGroupName': {'Type': 'String',
'Implemented': False},
'DBSecurityGroups': {'Type': 'List',
'Required': False, 'Default': []},
'DBSubnetGroupName': {'Type': 'String',
'Implemented': False},
'Engine': {'Type': 'String',
'AllowedValues': ['MySQL'],
'Required': True},
'EngineVersion': {'Type': 'String',
'Implemented': False},
'LicenseModel': {'Type': 'String',
'Implemented': False},
'MasterUsername': {'Type': 'String',
'Required': True},
'MasterUserPassword': {'Type': 'String',
'Required': True},
'Port': {'Type': 'String',
'Default': '3306',
'Required': False},
'PreferredBackupWindow': {'Type': 'String',
'Implemented': False},
'PreferredMaintenanceWindow': {'Type': 'String',
'Implemented': False},
'MultiAZ': {'Type': 'Boolean',
'Implemented': False},
}
# We only support a couple of the attributes right now
attributes_schema = {
"Endpoint.Address": "Connection endpoint for the database.",
"Endpoint.Port": ("The port number on which the database accepts "
"connections.")
}
def _params(self):
params = {
'KeyName': {'Ref': 'KeyName'},
}
# Add the DBInstance parameters specified in the user's template
# Ignore the not implemented ones
for key, value in self.properties_schema.items():
if value.get('Implemented', True) and key != 'Engine':
# There is a mismatch between the properties "List" format
# and the parameters "CommaDelimitedList" format, so we need
# to translate lists into the expected comma-delimited form
if isinstance(self.properties[key], list):
params[key] = ','.join(self.properties[key])
else:
params[key] = self.properties[key]
p = self.stack.resolve_static_data(params)
return p
def handle_create(self):
templ = template_format.parse(mysql_template)
return self.create_with_template(templ, self._params())
def handle_delete(self):
return self.delete_nested()
def _resolve_attribute(self, name):
'''
We don't really support any of these yet.
'''
if name == 'Endpoint.Address':
if self.nested() and 'DatabaseInstance' in self.nested().resources:
return self.nested().resources['DatabaseInstance']._ipaddress()
else:
return '0.0.0.0'
elif name == 'Endpoint.Port':
return self.properties['Port']
def resource_mapping():
return {
'AWS::RDS::DBInstance': DBInstance,
}