]> review.fuel-infra Code Review - openstack-build/heat-build.git/commitdiff
Add AWS::RDS::DBInstance
authorTomas Sedovic <tomas@sedovic.cz>
Wed, 18 Jul 2012 13:39:37 +0000 (15:39 +0200)
committerTomas Sedovic <tomas@sedovic.cz>
Mon, 23 Jul 2012 16:38:16 +0000 (18:38 +0200)
Fixes #163

This is an initial implementation of the DBInstance resource type and a
sample Wordpress template showing it off.

Change-Id: I5e156dc58eee563ae9de068664bafa1af1fb5ffe
Signed-off-by: Tomas Sedovic <tomas@sedovic.cz>
heat/engine/dbinstance.py [new file with mode: 0644]
heat/engine/resource_types.py
templates/WordPress_With_RDS.template [new file with mode: 0644]

diff --git a/heat/engine/dbinstance.py b/heat/engine/dbinstance.py
new file mode 100644 (file)
index 0000000..5ed960a
--- /dev/null
@@ -0,0 +1,203 @@
+# 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.
+
+import urllib2
+import json
+
+from heat.common import exception
+from heat.engine import stack
+from heat.db import api as db_api
+from heat.engine import parser
+from novaclient.exceptions import NotFound
+
+from heat.openstack.common import log as logging
+
+logger = logging.getLogger(__file__)
+
+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": "List"
+    },
+
+    "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": "F16-x86_64-cfntools",
+        "InstanceType": { "Fn::FindInMap": [ "DBInstanceToInstance",
+                                             { "Ref": "DBInstanceClass" },
+                                             "Instance" ] },
+        "KeyName": { "Ref": "KeyName" },
+        "UserData": { "Fn::Base64": { "Fn::Join": ["", [
+          "#!/bin/bash -v\n",
+          "/opt/aws/bin/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"
+        ]]}}
+      }
+    }
+  },
+
+  "Outputs": {
+  }
+}
+'''
+
+
+class DBInstance(stack.Stack):
+
+    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},
+    }
+
+    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':
+                params[key] = self.properties[key]
+        p = self.stack.resolve_static_data(params)
+        return p
+
+    def handle_create(self):
+        templ = json.loads(mysql_template)
+        self.create_with_template(templ)
+
+    def FnGetAtt(self, key):
+        '''
+        We don't really support any of these yet.
+        '''
+        if key == 'Endpoint.Address':
+            if self.nested() and 'DatabaseInstance' in self.nested().resources:
+                return self.nested().resources['DatabaseInstance']._ipaddress()
+            else:
+                return '0.0.0.0'
+        elif key == 'Endpoint.Port':
+            return self.properties['Port']
+        else:
+            raise exception.InvalidTemplateAttribute(resource=self.name,
+                                                     key=key)
index e12e3f3088762fd813d2705582a83dc33becc589..be2646cd3f95ef072024b0d3e88f5fa7e4643556 100644 (file)
@@ -22,6 +22,7 @@ from heat.engine import resources
 
 from heat.engine import autoscaling
 from heat.engine import cloud_watch
+from heat.engine import dbinstance
 from heat.engine import eip
 from heat.engine import instance
 from heat.engine import loadbalancer
@@ -51,6 +52,7 @@ _resource_classes = {
     'AWS::AutoScaling::LaunchConfiguration': autoscaling.LaunchConfiguration,
     'AWS::AutoScaling::AutoScalingGroup': autoscaling.AutoScalingGroup,
     'AWS::AutoScaling::ScalingPolicy': autoscaling.ScalingPolicy,
+    'AWS::RDS::DBInstance': dbinstance.DBInstance,
 }
 
 
diff --git a/templates/WordPress_With_RDS.template b/templates/WordPress_With_RDS.template
new file mode 100644 (file)
index 0000000..9a1b865
--- /dev/null
@@ -0,0 +1,167 @@
+{
+  "AWSTemplateFormatVersion" : "2010-09-09",
+
+  "Description" : "AWS CloudFormation Sample Template WordPress_With_RDS: WordPress is web software you can use to create a beautiful website or blog. This template installs two instances: one running a WordPress deployment and the other using RDS as a data storage.",
+
+  "Parameters" : {
+
+    "KeyName" : {
+      "Description" : "Name of an existing EC2 KeyPair to enable SSH access to the instances",
+      "Type" : "String"
+    },
+
+    "InstanceType" : {
+      "Description" : "WebServer EC2 instance type",
+      "Type" : "String",
+      "Default" : "m1.large",
+      "AllowedValues" : [ "t1.micro", "m1.small", "m1.large", "m1.xlarge", "m2.xlarge", "m2.2xlarge", "m2.4xlarge", "c1.medium", "c1.xlarge", "cc1.4xlarge" ],
+      "ConstraintDescription" : "must be a valid EC2 instance type."
+    },
+
+    "DBClass" : {
+      "Default" : "db.m1.small",
+      "Description" : "Database instance class",
+      "Type" : "String",
+      "AllowedValues" : [ "db.m1.small", "db.m1.large", "db.m1.xlarge", "db.m2.xlarge", "db.m2.2xlarge", "db.m2.4xlarge" ],
+      "ConstraintDescription" : "must select a valid database instance type."
+    },
+
+    "DBName": {
+      "Default": "wordpress",
+      "Description" : "The WordPress database name",
+      "Type": "String",
+      "MinLength": "1",
+      "MaxLength": "64",
+      "AllowedPattern" : "[a-zA-Z][a-zA-Z0-9]*",
+      "ConstraintDescription" : "must begin with a letter and contain only alphanumeric characters."
+    },
+
+    "DBUsername": {
+      "Default": "admin",
+      "NoEcho": "true",
+      "Description" : "The WordPress database admin account username",
+      "Type": "String",
+      "MinLength": "1",
+      "MaxLength": "16",
+      "AllowedPattern" : "[a-zA-Z][a-zA-Z0-9]*",
+      "ConstraintDescription" : "must begin with a letter and contain only alphanumeric characters."
+    },
+
+    "DBPassword": {
+      "Default": "admin",
+      "NoEcho": "true",
+      "Description" : "The WordPress database admin account password",
+      "Type": "String",
+      "MinLength": "1",
+      "MaxLength": "41",
+      "AllowedPattern" : "[a-zA-Z0-9]*",
+      "ConstraintDescription" : "must contain only alphanumeric characters."
+    },
+
+    "DBRootPassword": {
+      "Default": "admin",
+      "NoEcho": "true",
+      "Description" : "Root password for MySQL",
+      "Type": "String",
+      "MinLength": "1",
+      "MaxLength": "41",
+      "AllowedPattern" : "[a-zA-Z0-9]*",
+      "ConstraintDescription" : "must contain only alphanumeric characters."
+    },
+
+    "DBAllocatedStorage" : {
+      "Default": "5",
+      "Description" : "The size of the database (Gb)",
+      "Type": "Number",
+      "MinValue": "5",
+      "MaxValue": "1024",
+      "ConstraintDescription" : "must be between 5 and 1024Gb."
+    },
+
+    "LinuxDistribution": {
+      "Default": "F16",
+      "Description" : "Distribution of choice",
+      "Type": "String",
+      "AllowedValues" : [ "F16", "F17", "U10", "RHEL-6.1", "RHEL-6.2", "RHEL-6.3" ]
+    }
+  },
+
+  "Mappings" : {
+    "AWSInstanceType2Arch" : {
+      "t1.micro"    : { "Arch" : "32" },
+      "m1.small"    : { "Arch" : "32" },
+      "m1.large"    : { "Arch" : "64" },
+      "m1.xlarge"   : { "Arch" : "64" },
+      "m2.xlarge"   : { "Arch" : "64" },
+      "m2.2xlarge"  : { "Arch" : "64" },
+      "m2.4xlarge"  : { "Arch" : "64" },
+      "c1.medium"   : { "Arch" : "32" },
+      "c1.xlarge"   : { "Arch" : "64" },
+      "cc1.4xlarge" : { "Arch" : "64" }
+    },
+    "DistroArch2AMI": {
+      "F16"      : { "32" : "F16-i386-cfntools", "64" : "F16-x86_64-cfntools" },
+      "F17"      : { "32" : "F17-i386-cfntools", "64" : "F17-x86_64-cfntools" },
+      "U10"      : { "32" : "U10-i386-cfntools", "64" : "U10-x86_64-cfntools" },
+      "RHEL-6.1" : { "32" : "rhel61-i386-cfntools", "64" : "rhel61-x86_64-cfntools" },
+      "RHEL-6.2" : { "32" : "rhel62-i386-cfntools", "64" : "rhel62-x86_64-cfntools" },
+      "RHEL-6.3" : { "32" : "rhel63-i386-cfntools", "64" : "rhel63-x86_64-cfntools" }
+    }
+  },
+
+  "Resources" : {
+    "DatabaseServer": {
+      "Type": "AWS::RDS::DBInstance",
+      "Properties": {
+        "DBName"            : { "Ref" : "DBName" },
+        "Engine"            : "MySQL",
+        "MasterUsername"    : { "Ref" : "DBUsername" },
+        "DBInstanceClass"   : { "Ref" : "DBClass" },
+        "DBSecurityGroups"  : [],
+        "AllocatedStorage"  : { "Ref" : "DBAllocatedStorage" },
+        "MasterUserPassword": { "Ref" : "DBPassword" }
+      }
+    },
+
+    "WebServer": {
+      "Type": "AWS::EC2::Instance",
+      "DependsOn": "DatabaseServer",
+      "Metadata" : {
+        "AWS::CloudFormation::Init" : {
+          "config" : {
+            "packages" : {
+              "yum" : {
+                "httpd"        : [],
+                "wordpress"    : []
+              }
+            },
+            "services" : {
+              "systemd" : {
+                "httpd"    : { "enabled" : "true", "ensureRunning" : "true" }
+              }
+            }
+          }
+        }
+      },
+      "Properties": {
+        "ImageId" : { "Fn::FindInMap" : [ "DistroArch2AMI", { "Ref" : "LinuxDistribution" },
+                          { "Fn::FindInMap" : [ "AWSInstanceType2Arch", { "Ref" : "InstanceType" }, "Arch" ] } ] },
+        "InstanceType"   : { "Ref" : "InstanceType" },
+        "KeyName"        : { "Ref" : "KeyName" },
+        "UserData"       : { "Fn::Base64" : { "Fn::Join" : ["", [
+          "#!/bin/bash -v\n",
+          "/opt/aws/bin/cfn-init\n",
+          "sed --in-place --e s/database_name_here/", { "Ref" : "DBName" }, "/ --e s/username_here/", { "Ref" : "DBUsername" }, "/ --e s/password_here/", { "Ref" : "DBPassword" }, "/ --e s/localhost/", { "Fn::GetAtt" : [ "DatabaseServer", "Endpoint.Address" ]}, "/ /usr/share/wordpress/wp-config.php\n"
+        ]]}}
+      }
+    }
+
+  },
+
+  "Outputs" : {
+    "WebsiteURL" : {
+      "Value" : { "Fn::Join" : ["", ["http://", { "Fn::GetAtt" : [ "WebServer", "PublicIp" ]}, "/wordpress"]] },
+      "Description" : "URL for Wordpress wiki"
+    }
+  }
+}