All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.dasein.cloud.aws.platform.RDS Maven / Gradle / Ivy

There is a newer version: 2015.10.9
Show newest version
/**
 * Copyright (C) 2009-2015 Dell, Inc.
 * See annotations for authorship information
 *
 * ====================================================================
 * 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.
 * ====================================================================
 */

package org.dasein.cloud.aws.platform;

import java.util.*;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.servlet.http.HttpServletResponse;

import org.apache.log4j.Logger;
import org.dasein.cloud.*;
import org.dasein.cloud.aws.AWSCloud;
import org.dasein.cloud.aws.compute.EC2Exception;
import org.dasein.cloud.aws.compute.EC2Method;
import org.dasein.cloud.aws.model.DatabaseProductDefinition;
import org.dasein.cloud.aws.model.DatabaseProvider;
import org.dasein.cloud.aws.model.DatabaseRegion;
import org.dasein.cloud.identity.ServiceAction;
import org.dasein.cloud.network.Direction;
import org.dasein.cloud.network.FirewallRule;
import org.dasein.cloud.network.FirewallSupport;
import org.dasein.cloud.network.Protocol;
import org.dasein.cloud.network.RuleTargetType;
import org.dasein.cloud.platform.*;
import static org.dasein.cloud.platform.DatabaseEngine.*;
import org.dasein.cloud.util.APITrace;
import org.dasein.util.CalendarWrapper;
import org.dasein.util.Jiterator;
import org.dasein.util.JiteratorPopulator;
import org.dasein.util.PopulatorThread;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import static org.dasein.cloud.platform.DatabaseLicenseModel.*;

/**
 * AWS RDS Support
 *
 * @author George Reese
 * @author Stas Maksimov
 * @version 2014.08 deprecated methods moved to capabilities
 * @since ?
 */
public class RDS extends AbstractRelationalDatabaseSupport {
    static private final Logger logger = AWSCloud.getLogger(RDS.class);

    static public final String SERVICE_ID                          = "rds";
    
    static public final String AUTHORIZE_DB_SECURITY_GROUP_INGRESS = "AuthorizeDBSecurityGroupIngress";
    static public final String CREATE_DB_INSTANCE                  = "CreateDBInstance";
    static public final String CREATE_DB_PARAMETER_GROUP           = "CreateDBParameterGroup";
    static public final String CREATE_DB_SECURITY_GROUP            = "CreateDBSecurityGroup";
    static public final String CREATE_DB_SNAPSHOT                  = "CreateDBSnapshot"; 
    static public final String DELETE_DB_INSTANCE                  = "DeleteDBInstance";
    static public final String DELETE_DB_PARAMETER_GROUP           = "DeleteDBParameterGroup";
    static public final String DELETE_DB_SECURITY_GROUP            = "DeleteDBSecurityGroup";
    static public final String DELETE_DB_SNAPSHOT                  = "DeleteDBSnapshot";
    static public final String DESCRIBE_DB_ENGINE_VERSIONS         = "DescribeDBEngineVersions";
    static public final String DESCRIBE_DB_INSTANCES               = "DescribeDBInstances";
    static public final String DESCRIBE_ENGINE_DEFAULT_PARAMETERS  = "DescribeEngineDefaultParameters";
    static public final String DESCRIBE_DB_PARAMETER_GROUPS        = "DescribeDBParameterGroups";
    static public final String DESCRIBE_DB_PARAMETERS              = "DescribeDBParameters";
    static public final String DESCRIBE_DB_SECURITY_GROUPS         = "DescribeDBSecurityGroups";
    static public final String DESCRIBE_DB_SNAPSHOTS               = "DescribeDBSnapshots";
    static public final String DESCRIBE_DB_EVENTS                  = "DescribeDBEvents";
    static public final String MODIFY_DB_INSTANCE                  = "ModifyDBInstance";
    static public final String MODIFY_DB_PARAMETER_GROUP           = "ModifyDBParameterGroup";
    static public final String REBOOT_DB_INSTANCE                  = "RebootDBInstance";
    static public final String RESET_DB_PARAMETER_GROUP            = "ResetDBParameterGroup";
    static public final String RESTORE_DB_INSTANCE_FROM_SNAPSHOT   = "RestoreDBInstanceFromDBSnapshot";
    static public final String RESTORE_DB_INSTANCE_TO_TIME         = "RestoreDBInstanceToPointInTime";
    static public final String REVOKE_DB_SECURITY_GROUP_INGRESS    = "RevokeDBSecurityGroupIngress";

    static private final String AWS_ENGINE_MYSQL = "MySQL";
    static private final String AWS_ENGINE_POSTGRES = "postgres";
    static private final String AWS_ENGINE_ORACLE_SE1 = "oracle-se1";
    static private final String AWS_ENGINE_ORACLE_SE = "oracle-se";
    static private final String AWS_ENGINE_ORACLE_EE = "oracle-ee";
    static private final String AWS_ENGINE_SQLSERVER_EE = "sqlserver-ee";
    static private final String AWS_ENGINE_SQLSERVER_SE = "sqlserver-se";
    static private final String AWS_ENGINE_SQLSERVER_EX = "sqlserver-ex";
    static private final String AWS_ENGINE_SQLSERVER_WEB = "sqlserver-web";

    static public @Nonnull ServiceAction[] asRDSServiceAction(@Nonnull String action) {
        return null; // TODO: implement me
    }

    private volatile transient RDSCapabilities capabilities;

    RDS(AWSCloud provider) {
        super(provider);
    }

    /**
     * Use this to authorize with security groups in EC2-Classic
     * @param groupName
     * @param sourceCidr
     * @throws CloudException
     * @throws InternalException
     */
    private void authorizeClassicDbSecurityGroup(String groupName, String sourceCidr) throws CloudException, InternalException {
        Map parameters = getProvider().getStandardRdsParameters(getProvider().getContext(), AUTHORIZE_DB_SECURITY_GROUP_INGRESS);
        parameters.put("DBSecurityGroupName", groupName);
        parameters.put("CIDRIP", sourceCidr);
        EC2Method method = new EC2Method(SERVICE_ID, getProvider(), parameters);
        try {
            method.invoke();
        }
        catch( EC2Exception e ) {
            String code = e.getCode();
            if( code != null && code.equals("AuthorizationAlreadyExists") ) {
                return;
            }
            throw new CloudException(e);
        }
    }

    public void addAccess(String providerDatabaseId, String sourceCidr) throws CloudException, InternalException {
        APITrace.begin(getProvider(), "RDBMS.addAccess");
        try {
            Database db = getDatabase(providerDatabaseId);
            Iterator securityGroups = getSecurityGroups(providerDatabaseId).iterator();
            String groupName;

            if( !securityGroups.hasNext() ) {
                // FIXME: not sure we need to do this. a db should always have a security group right from the start
                groupName = createSecurityGroup(providerDatabaseId);
                setSecurityGroup(providerDatabaseId, groupName);
            }
            else {
                groupName = securityGroups.next();
            }
            String ec2Type = getProvider().getDataCenterServices().isRegionEC2VPC(getProvider().getContext().getRegionId());
            if(ec2Type.equals(AWSCloud.PLATFORM_EC2)) {
                authorizeClassicDbSecurityGroup(groupName, sourceCidr);
            }
            else if( getProvider().hasNetworkServices() && getProvider().getNetworkServices().hasFirewallSupport() ) {
                FirewallSupport firewallSupport = getProvider().getNetworkServices().getFirewallSupport();
                firewallSupport.authorize(groupName, sourceCidr, Protocol.TCP, db.getHostPort(), db.getHostPort());
            }
        }
        finally {
            APITrace.end();
        }
    }

    /**
     * Formats a time window as hh24:mi-hh24:mi or ddd:hh24:mi-ddd:hh24:mi
     * @param window
     * @param includeDays must be false for PreferredBackupWindow parameter
     * @return formatted time window text representation
     */
    private String getWindowString(TimeWindow window, boolean includeDays) {
        StringBuilder str = new StringBuilder();
        if( includeDays ) {
            if( window.getStartDayOfWeek() == null ) {
                str.append("*");
            }
            else {
                str.append(window.getStartDayOfWeek().getShortString());
            }
            str.append(":");
        }
        str.append(String.format("%02d:%02d", window.getStartHour(), window.getStartMinute()));
        str.append("-");
        if( includeDays ) {
            if( window.getEndDayOfWeek() == null ) {
                str.append("*");
            }
            else {
                str.append(window.getEndDayOfWeek().getShortString());
            }
            str.append(":");
        }
        str.append(String.format("%02d:%02d", window.getEndHour(), window.getEndMinute()));
        return str.toString();
    }
    
    @Override
    public void alterDatabase(String providerDatabaseId, boolean applyImmediately, String productSize, int storageInGigabytes, String configurationId, String newAdminUser, String newAdminPassword, int newPort, int snapshotRetentionInDays, TimeWindow preferredMaintenanceWindow, TimeWindow preferredBackupWindow) throws CloudException, InternalException {
        APITrace.begin(getProvider(), "RDBMS.alterDatabase");
        try {
            Map parameters = getProvider().getStandardRdsParameters(getProvider().getContext(), MODIFY_DB_INSTANCE);
            EC2Method method;

            parameters.put("DBInstanceIdentifier", providerDatabaseId);
            parameters.put("ApplyImmediately", String.valueOf(applyImmediately));
            if( configurationId != null ) {
                parameters.put("DBParameterGroupName", configurationId);
            }
            if( preferredMaintenanceWindow != null ) {
                String window = getWindowString(preferredMaintenanceWindow, true);

                parameters.put("PreferredMaintenanceWindow", window);
            }
            if( preferredBackupWindow != null ) {
                String window = getWindowString(preferredBackupWindow, false);

                parameters.put("PreferredBackupWindow", window);
            }
            if( newAdminPassword != null ) {
                parameters.put("MasterUserPassword", newAdminPassword);
            }
            if( storageInGigabytes > 0 ) {
                parameters.put("AllocatedStorage", String.valueOf(storageInGigabytes));
            }
            if( productSize != null ) {
                parameters.put("DBInstanceClass", productSize);
            }
            if( snapshotRetentionInDays > -1 ) {
                parameters.put("BackupRetentionPeriod", String.valueOf(snapshotRetentionInDays));
            }
            method = new EC2Method(SERVICE_ID, getProvider(), parameters);
            try {
                method.invoke();
            }
            catch( EC2Exception e ) {
                throw new CloudException(e);
            }
        }
        finally {
            APITrace.end();
        }
    }

    /**
     *
     * @param groupName
     * @return groupName if successful
     * @throws CloudException
     * @throws InternalException
     */
    private String createSecurityGroup(String groupName) throws CloudException, InternalException {
        APITrace.begin(getProvider(), "RDBMS.createSecurityGroup");
        try {
            Map parameters = getProvider().getStandardRdsParameters(getProvider().getContext(), CREATE_DB_SECURITY_GROUP);
            EC2Method method;

            parameters.put("DBSecurityGroupName", groupName);
            parameters.put("DBSecurityGroupDescription", "Auto-generated DB security group for " + groupName);
            method = new EC2Method(SERVICE_ID, getProvider(), parameters);
            try {
                method.invoke();
            }
            catch( EC2Exception e ) {
                String code = e.getCode();

                if( code != null && code.equals("DBSecurityGroupAlreadyExists") ) {
                    return groupName;
                }
                throw new CloudException(e);
            }
            return groupName;
        }
        finally {
            APITrace.end();
        }
    }
    
    @Override
    public String createFromScratch(String databaseName, DatabaseProduct product, String engineVersion, String withAdminUser, String withAdminPassword, int hostPort) throws CloudException, InternalException {
        APITrace.begin(getProvider(), "RDBMS.createFromScratch");
        try {
            Map parameters;
            String id = toIdentifier(databaseName);
            EC2Method method;
            NodeList blocks;
            Document doc;

            if( engineVersion == null ) {
                engineVersion = getDefaultVersion(product.getEngine());
            }
            int size = product.getStorageInGigabytes();

            if( size < 5 ) {
                size = 5;
            }
            
            parameters = getProvider().getStandardRdsParameters(getProvider().getContext(), CREATE_DB_INSTANCE);
            parameters.put("DBInstanceIdentifier", id);
            parameters.put("AllocatedStorage", String.valueOf(size));
            parameters.put("DBInstanceClass", product.getProductSize());
            parameters.put("Engine", getEngineString(product.getEngine()));
            parameters.put("EngineVersion", engineVersion);
            parameters.put("MasterUsername", withAdminUser);
            parameters.put("MasterUserPassword", withAdminPassword);
            parameters.put("Port", String.valueOf(hostPort));
            if( !isSQLServer(product.getEngine()) ) {
                String instanceName = toInstanceName(databaseName, product.getEngine());
                parameters.put("DBName", instanceName);
            }

            String ec2Type = getProvider().getDataCenterServices().isRegionEC2VPC(getProvider().getContext().getRegionId());
            if(ec2Type.equals(AWSCloud.PLATFORM_EC2)){
                String securityGroupId = createSecurityGroup(id);
                parameters.put("DBSecurityGroups.member.1", securityGroupId);
            }

            // TODO: refactor into a toLicense() method
            String license = "general-public-license";
            switch (product.getLicenseModel()) {
                case BRING_YOUR_OWN_LICENSE:
                    license = "bring-your-own-license";
                    break;
                case LICENSE_INCLUDED:
                    license = "license-included";
                    break;
                case POSTGRESQL_LICENSE:
                    license = "postgresql-license";
                    break;
            }
            parameters.put("LicenseModel", license);

            if( product.isHighAvailability() ) {
                parameters.put("MultiAZ", "true");
            }
            else if( product.getProviderDataCenterId() != null ) {
                // set az if not empty, otherwise the region's default is used
                parameters.put("AvailabilityZone", product.getProviderDataCenterId());
            }
            method = new EC2Method(SERVICE_ID, getProvider(), parameters);
            try {
                doc = method.invoke();
            }
            catch( EC2Exception e ) {
                throw new CloudException(e);
            }
            blocks = doc.getElementsByTagName("DBInstanceIdentifier");
            if( blocks.getLength() > 0 ) {
                String dbId = blocks.item(0).getFirstChild().getNodeValue().trim();
                
                // Set tags
                ArrayList tags = new ArrayList();
                tags.add(new Tag("Name", databaseName));
               	getProvider().createTags(SERVICE_ID, "arn:aws:rds:" + getProvider().getContext().getRegionId() + ":" + getProvider().getContext().getAccountNumber().replace("-", "") +":db:" + dbId , tags.toArray(new Tag[tags.size()]));   
              	return dbId;
            }
            return null;
        }
        finally {
            APITrace.end();
        }
    }
    
    public String createFromLatest(String databaseName, String providerDatabaseId, String productSize, String providerDataCenterId, int hostPort) throws InternalException, CloudException {
        APITrace.begin(getProvider(), "RDBMS.createFromLatest");
        try {
            Map parameters;
            String id = toIdentifier(databaseName);
            EC2Method method;
            NodeList blocks;
            Document doc;

            parameters = getProvider().getStandardRdsParameters(getProvider().getContext(), RESTORE_DB_INSTANCE_TO_TIME);
            parameters.put("SourceDBInstanceIdentifier", providerDatabaseId);
            parameters.put("UseLatestRestorableTime", "true"); // booleans should be lowercase, as per xsd1.1
            parameters.put("TargetDBInstanceIdentifier", id);
            parameters.put("DBInstanceClass", productSize);
            parameters.put("Port", String.valueOf(hostPort));
            if( providerDataCenterId == null ) {
                parameters.put("MultiAZ", "true");
            }
            else {
                parameters.put("AvailabilityZone", providerDataCenterId);
                parameters.put("MultiAZ", "false");
            }
            method = new EC2Method(SERVICE_ID, getProvider(), parameters);
            try {
                doc = method.invoke();
            }
            catch( EC2Exception e ) {
                throw new CloudException(e);
            }
            blocks = doc.getElementsByTagName("DBInstanceIdentifier");
            if( blocks.getLength() > 0 ) {
            	ArrayList tags = new ArrayList();
                tags.add(new Tag("Name", databaseName));
                getProvider().createTags(SERVICE_ID, "arn:aws:rds:" + getProvider().getContext().getRegionId() + ":" + getProvider().getContext().getAccountNumber().replace("-", "") +":db:" + id, tags.toArray(new Tag[tags.size()]));
                return id;
            }
            return null;
        }
        finally {
            APITrace.end();
        }
    }

    public String createFromSnapshot(String databaseName, String providerDatabaseId, String providerDbSnapshotId, String productSize, String providerDataCenterId, int hostPort) throws CloudException, InternalException {
        APITrace.begin(getProvider(), "RDBMS.createFromSnapshot");
        try {
            Map parameters;
            String id = toIdentifier(databaseName);
            EC2Method method;
            NodeList blocks;
            Document doc;

            parameters = getProvider().getStandardRdsParameters(getProvider().getContext(), RESTORE_DB_INSTANCE_FROM_SNAPSHOT);
            parameters.put("DBSnapshotIdentifier", providerDbSnapshotId);
            parameters.put("DBInstanceIdentifier", id);
            parameters.put("DBInstanceClass", productSize);
            parameters.put("Port", String.valueOf(hostPort));
            if( providerDataCenterId == null ) {
                parameters.put("MultiAZ", "true");
            }
            else {
                parameters.put("AvailabilityZone", providerDataCenterId);
                parameters.put("MultiAZ", "false");
            }
            method = new EC2Method(SERVICE_ID, getProvider(), parameters);
            try {
                doc = method.invoke();
            }
            catch( EC2Exception e ) {
                throw new CloudException(e);
            }
            blocks = doc.getElementsByTagName("DBInstanceIdentifier");
            if( blocks.getLength() > 0 ) {
            	ArrayList tags = new ArrayList();
                tags.add(new Tag("Name", databaseName));
                getProvider().createTags(SERVICE_ID, "arn:aws:rds:" + getProvider().getContext().getRegionId() + ":" + getProvider().getContext().getAccountNumber().replace("-", "") +":db:" + id, tags.toArray(new Tag[tags.size()]));
                return id;
            }
            return null;
        }
        finally {
            APITrace.end();
        }
    }

    public String createFromTimestamp(String databaseName, String providerDatabaseId, long beforeTimestamp, String productSize, String providerDataCenterId, int hostPort) throws InternalException, CloudException {
        APITrace.begin(getProvider(), "RDBMS.createFromTimestamp");
        try {
            Map parameters;
            String id = toIdentifier(databaseName);
            EC2Method method;
            NodeList blocks;
            Document doc;

            parameters = getProvider().getStandardRdsParameters(getProvider().getContext(), RESTORE_DB_INSTANCE_TO_TIME);
            parameters.put("SourceDBInstanceIdentifier", providerDatabaseId);
            parameters.put("RestoreTime", getProvider().getTimestamp(beforeTimestamp, false));
            parameters.put("TargetDBInstanceIdentifier", id);
            parameters.put("DBInstanceClass", productSize);
            parameters.put("Port", String.valueOf(hostPort));
            if( providerDataCenterId == null ) {
                parameters.put("MultiAZ", "true");
            }
            else {
                parameters.put("AvailabilityZone", providerDataCenterId);
                parameters.put("MultiAZ", "false");
            }
            method = new EC2Method(SERVICE_ID, getProvider(), parameters);
            try {
                doc = method.invoke();
            }
            catch( EC2Exception e ) {
                throw new CloudException(e);
            }
            blocks = doc.getElementsByTagName("DBInstanceIdentifier");
            if( blocks.getLength() > 0 ) {
            	ArrayList tags = new ArrayList();
                tags.add(new Tag("Name", databaseName));
                getProvider().createTags(SERVICE_ID, "arn:aws:rds:" + getProvider().getContext().getRegionId() + ":" + getProvider().getContext().getAccountNumber().replace("-", "") +":db:" + id, tags.toArray(new Tag[tags.size()]));
                return id;
            }
            return null;
        }
        finally {
            APITrace.end();
        }
    }

    @Override
    public @Nonnull RelationalDatabaseCapabilities getCapabilities() throws InternalException, CloudException {
        if( capabilities == null ) {
            capabilities = new RDSCapabilities(getProvider());
        }
        return capabilities;
    }

    public DatabaseConfiguration getConfiguration(String providerConfigurationId) throws CloudException, InternalException {
        if( providerConfigurationId == null ) {
            return null;
        }
        PopulatorThread populator;
        final String id = providerConfigurationId;

        getProvider().hold();
        populator = new PopulatorThread(new JiteratorPopulator() {
            public void populate(Jiterator iterator) throws CloudException, InternalException {
                try {
                    populateConfigurationList(id, iterator);
                }
                finally {
                    getProvider().release();
                }
            }
        });
        populator.populate();
        Iterator it = populator.getResult().iterator();
        
        if( it.hasNext() ) {
            return it.next();
        }
        return null;
    }

    public Database getDatabase(String providerDatabaseId) throws CloudException, InternalException {
        APITrace.begin(getProvider(), "RDBMS.getDatabase");
        try {
            if( providerDatabaseId == null ) {
                return null;
            }
            for( Database database : listDatabases(providerDatabaseId) ) {
                if( database.getProviderDatabaseId().equals(providerDatabaseId) ) {
                    return database;
                }
            }
            return null;
        }
        finally {
            APITrace.end();
        }
    }

    static private volatile List engines = null;
    
    @Override
    public Iterable getDatabaseEngines() {
        if( engines == null ) {
            engines = Arrays.asList(
                    DatabaseEngine.MYSQL,
                    DatabaseEngine.ORACLE_EE,
                    DatabaseEngine.ORACLE_SE,
                    DatabaseEngine.ORACLE_SE1,
                    DatabaseEngine.POSTGRES,
                    DatabaseEngine.SQLSERVER_EE,
                    DatabaseEngine.SQLSERVER_EX,
                    DatabaseEngine.SQLSERVER_SE,
                    DatabaseEngine.SQLSERVER_WEB
            );
        }
        return engines;
    }
    
    static private volatile Map defaultVersions = new HashMap();
    static private volatile Map> engineVersions = new HashMap>();
    
    @Override
    public String getDefaultVersion(DatabaseEngine forEngine) throws CloudException, InternalException {
        APITrace.begin(getProvider(), "RDBMS.getDefaultVersion");
        try {
            String version = defaultVersions.get(forEngine);

            if( version == null ) {
                Map parameters = getProvider().getStandardRdsParameters(getProvider().getContext(), DESCRIBE_DB_ENGINE_VERSIONS);
                EC2Method method;
                Document doc;

                parameters.put("Engine", getEngineString(forEngine));
                parameters.put("DefaultOnly", "true");
                method = new EC2Method(SERVICE_ID, getProvider(), parameters);
                try {
                    doc = method.invoke();
                }
                catch( EC2Exception e ) {
                    throw new CloudException(e);
                };
                NodeList blocks = doc.getElementsByTagName("DBEngineVersions");
                for( int i=0; i getSupportedVersions(DatabaseEngine forEngine) throws CloudException, InternalException {
        APITrace.begin(getProvider(), "RDBMS.getSupportedVersions");
        try {
            Collection versions = engineVersions.get(forEngine);

            if( versions == null ) {
                ArrayList list = new ArrayList();
                String marker = null;

                do {
                    Map parameters = getProvider().getStandardRdsParameters(getProvider().getContext(), DESCRIBE_DB_ENGINE_VERSIONS);
                    EC2Method method;
                    Document doc;

                    parameters.put("Engine", getEngineString(forEngine));
                    method = new EC2Method(SERVICE_ID, getProvider(), parameters);
                    try {
                        doc = method.invoke();
                    }
                    catch( EC2Exception e ) {
                        throw new CloudException(e);
                    }
                    marker = null;
                    NodeList blocks;
                    blocks = doc.getElementsByTagName("Marker");
                    if( blocks.getLength() > 0 ) {
                        for( int i=0; i listDatabaseProducts( DatabaseEngine engine ) throws CloudException, InternalException {
        List products = new ArrayList();
        DatabaseProvider databaseProvider = DatabaseProvider.fromFile("/org/dasein/cloud/aws/dbproducts.json", "AWS");

        org.dasein.cloud.aws.model.DatabaseEngine databaseEngine = databaseProvider.findEngine(getEngineString(engine));

        if( databaseEngine != null ) {
            for ( DatabaseRegion region : databaseEngine.getRegions() ) {
                if( region.getName().equalsIgnoreCase( getProvider().getContext().getRegionId()) ) {
                    for( org.dasein.cloud.aws.model.DatabaseProduct databaseProduct : region.getProducts() ) {
                        DatabaseProduct product = new DatabaseProduct(databaseProduct.getName());
                        product.setEngine(engine);
                        product.setHighAvailability(databaseProduct.isHighAvailability());
                        product.setStandardHourlyRate(databaseProduct.getHourlyRate());
                        product.setStandardIoRate(databaseProduct.getIoRate());
                        product.setStandardStorageRate(databaseProduct.getStorageRate());
                        DatabaseLicenseModel lic = GENERAL_PUBLIC_LICENSE;
                        if( "included".equalsIgnoreCase(databaseProduct.getLicense())) {
                            lic = LICENSE_INCLUDED;
                        } else if( "byol".equalsIgnoreCase(databaseProduct.getLicense())) {
                            lic = BRING_YOUR_OWN_LICENSE;
                        } else if( "postgres".equalsIgnoreCase(databaseProduct.getLicense())) {
                            lic = POSTGRESQL_LICENSE;
                        }
                        product.setLicenseModel(lic);
                        product.setCurrency(databaseProduct.getCurrency());
                        DatabaseProductDefinition def = databaseProvider.findProductDefinition(databaseProduct.getName());
                        if( def != null) {
                            product.setName(String.format("%.2fGB RAM, %d CPU, %s Network Performance", def.getMemory(), def.getvCpus(), def.getNetworkPerformance()));
                        }
                        product.setStorageInGigabytes(databaseProduct.getMinStorage());
                        products.add(product);
                    }
                }
            }
        }
        return products;
    }

    private DayOfWeek getDay(String str) {
        if( str.equalsIgnoreCase("Sun") ) {
            return DayOfWeek.SUNDAY;
        }
        else if( str.equalsIgnoreCase("Mon") ) {
            return DayOfWeek.MONDAY;
        }
        else if( str.equalsIgnoreCase("Tue") ) {
            return DayOfWeek.TUESDAY;
        }
        else if( str.equalsIgnoreCase("Wed") ) {
            return DayOfWeek.WEDNESDAY;
        }
        else if( str.equalsIgnoreCase("Thu") ) {
            return DayOfWeek.THURSDAY;
        }
        else if( str.equalsIgnoreCase("Fri") ) {
            return DayOfWeek.FRIDAY;
        }
        else if( str.equalsIgnoreCase("Sat") ) {
            return DayOfWeek.SATURDAY;
        }
        return null;
    }
    
    private TimeWindow getTimeWindow(String start, String end) {
        String[] parts = start.split(":");
        int startHour = 0, endHour = 0;
        int startMinute = 0, endMinute = 0;
        DayOfWeek startDay = null, endDay = null;
        
        if( parts.length < 3 ) {
            if( parts.length < 2 ) {
                try { 
                    startHour = Integer.parseInt(start);
                }
                catch( NumberFormatException ignore ) {
                    // ignore
                }
            }
            else {
                try {
                    startHour = Integer.parseInt(parts[0]);
                }
                catch( NumberFormatException ignore ) {
                    // ignore
                }
                try {
                    startMinute = Integer.parseInt(parts[1]);
                }
                catch( NumberFormatException e ) {
                    // ignore
                }
            }
        }
        else {
            startDay = getDay(parts[0]);
            try {
                startHour = Integer.parseInt(parts[1]);
            }
            catch( NumberFormatException ignore ) {
                // ignore
            }
            try {
                startMinute = Integer.parseInt(parts[2]);
            }
            catch( NumberFormatException e ) {
                // ignore
            }
        }
        parts = end.split(":");
        if( parts.length < 3 ) {
            if( parts.length < 2 ) {
                try { 
                    endHour = Integer.parseInt(start);
                }
                catch( NumberFormatException ignore ) {
                    // ignore
                }
            }
            else {
                try {
                    endHour = Integer.parseInt(parts[0]);
                }
                catch( NumberFormatException ignore ) {
                    // ignore
                }
                try {
                    endMinute = Integer.parseInt(parts[1]);
                }
                catch( NumberFormatException e ) {
                    // ignore
                }
            }
        }
        else {
            endDay = getDay(parts[0]);
            try {
                endHour = Integer.parseInt(parts[1]);
            }
            catch( NumberFormatException ignore ) {
                // ignore
            }
            try {
                endMinute = Integer.parseInt(parts[2]);
            }
            catch( NumberFormatException e ) {
                // ignore
            }
        }
        TimeWindow window = new TimeWindow();
        
        window.setStartDayOfWeek(startDay);
        window.setStartHour(startHour);
        window.setStartMinute(startMinute);
        window.setEndDayOfWeek(endDay);
        window.setEndHour(endHour);
        window.setEndMinute(endMinute);
        return window;
    }

    /**
     * Get Amazon-specific engine name
     * @param engine database engine
     * @return Amazon-spefic engine name, returns 'MySQL' if engine was null.
     */
    private String getEngineString(@Nullable DatabaseEngine engine) {
        if( engine == null ) {
            return AWS_ENGINE_MYSQL;
        }
        switch( engine ) {
            case ORACLE_SE1: return AWS_ENGINE_ORACLE_SE1;
            case ORACLE_SE: return AWS_ENGINE_ORACLE_SE;
            case ORACLE_EE: return AWS_ENGINE_ORACLE_EE;
            case SQLSERVER_SE: return AWS_ENGINE_SQLSERVER_SE;
            case SQLSERVER_EE: return AWS_ENGINE_SQLSERVER_EE;
            case SQLSERVER_EX: return AWS_ENGINE_SQLSERVER_EX;
            case SQLSERVER_WEB: return AWS_ENGINE_SQLSERVER_WEB;
            case POSTGRES: return AWS_ENGINE_POSTGRES;
            case MYSQL:
            default: return AWS_ENGINE_MYSQL;
        }
    }

    @Deprecated
    public String getProviderTermForDatabase(Locale locale) {
        try {
            return getCapabilities().getProviderTermForDatabase(locale);
        } catch( InternalException e ) {
        } catch( CloudException e ) {
        }
        return "database"; // legacy
    }
    
    @Deprecated
    public String getProviderTermForSnapshot(Locale locale) {
        try {
            return getCapabilities().getProviderTermForSnapshot(locale);
        } catch( InternalException e ) {
        } catch( CloudException e ) {
        }
        return "snapshot"; // legacy
    }
    
    
    private String getRDSUrl() throws InternalException, CloudException {
        //noinspection ConstantConditions
        return ("https://rds." + getProvider().getContext().getRegionId() + ".amazonaws.com");
    }
    
    private Iterable getSecurityGroups(String databaseId) throws CloudException, InternalException {
        PopulatorThread populator;
        final String dbId = databaseId;

        getProvider().hold();
        populator = new PopulatorThread(new JiteratorPopulator() {
            public void populate(Jiterator iterator) throws CloudException, InternalException {
                try {
                    populateSecurityGroupIds(dbId, iterator);
                }
                finally {
                    getProvider().release();
                }
            }
        });
        populator.populate();
        return populator.getResult();
    }
    
    public DatabaseSnapshot getSnapshot(String providerDbSnapshotId) throws CloudException, InternalException {
        if( providerDbSnapshotId == null ) {
            return null;
        }
        PopulatorThread populator;
        final String id = providerDbSnapshotId;

        getProvider().hold();
        populator = new PopulatorThread(new JiteratorPopulator() {
            public void populate(Jiterator iterator) throws CloudException, InternalException {
                try {
                    populateSnapshotList(id, null, iterator);
                }
                finally {
                    getProvider().release();
                }
            }
        });
        populator.populate();
        Iterator it = populator.getResult().iterator();
        
        if( it.hasNext() ) {
            return it.next();
        }
        return null;
    }
    
    public boolean isSubscribed() throws CloudException, InternalException {
        APITrace.begin(getProvider(), "RDBMS.isSubscribed");
        try {
            Map parameters = getProvider().getStandardRdsParameters(getProvider().getContext(), DESCRIBE_DB_INSTANCES);
            EC2Method method = new EC2Method(SERVICE_ID, getProvider(), parameters);

            try {
                method.invoke();
                return true;
            }
            catch( EC2Exception e ) {
                if( e.getStatus() == HttpServletResponse.SC_UNAUTHORIZED || e.getStatus() == HttpServletResponse.SC_FORBIDDEN ) {
                    return false;
                }
                String code = e.getCode();

                if( code != null && (code.equals("SubscriptionCheckFailed") || code.equals("AuthFailure") || code.equals("SignatureDoesNotMatch") || code.equals("InvalidClientTokenId") || code.equals("OptInRequired")) ) {
                    return false;
                }
                logger.warn(e.getSummary());
                if( logger.isDebugEnabled() ) {
                    e.printStackTrace();
                }
                throw new CloudException(e);
            }
        }
        finally {
            APITrace.end();
        }
    }

    public Iterable listAccess(String toProviderDatabaseId) throws CloudException, InternalException {
        PopulatorThread idPopulator, accessPopulator;
        final String dbId = toProviderDatabaseId;

        getProvider().hold();
        idPopulator = new PopulatorThread(new JiteratorPopulator() {
            public void populate(Jiterator iterator) throws CloudException, InternalException {
                try {
                    populateSecurityGroupIds(dbId, iterator);
                }
                finally {
                    getProvider().release();
                }
            }
        });
        idPopulator.populate();

        final Iterable ids = idPopulator.getResult();

        String ec2Type = getProvider().getDataCenterServices().isRegionEC2VPC(getProvider().getContext().getRegionId());
        if(ec2Type.equals(AWSCloud.PLATFORM_EC2)) {
            getProvider().hold();
            accessPopulator = new PopulatorThread(new JiteratorPopulator() {
                public void populate(Jiterator iterator) throws CloudException, InternalException {
                    try {
                        for( String id : ids ) {
                            populateAccess(id, iterator);
                        }
                    }
                    finally {
                        getProvider().release();
                    }
                }
            });
            accessPopulator.populate();
            return accessPopulator.getResult();
        }
        else {
            List cidrs = new ArrayList();
            if( getProvider().hasNetworkServices() && getProvider().getNetworkServices().hasFirewallSupport() ) {
                for( String id : ids ) {
                    for( FirewallRule rule : getProvider().getNetworkServices().getFirewallSupport().getRules(id) ) {
                        // FIXME: We need to be able to include GLOBAL rule targets too, but they don't have the CIDR
                        if( rule.getDirection().equals(Direction.INGRESS) && rule.getSourceEndpoint().getRuleTargetType().equals(RuleTargetType.CIDR) ) {
                            cidrs.add(rule.getSourceEndpoint().getCidr());
                        }
                    }
                }
            }
            return cidrs;
        }
    }
    
    public Iterable listConfigurations() throws CloudException, InternalException {
        PopulatorThread populator;

        populator = new PopulatorThread(new JiteratorPopulator() {
            public void populate(Jiterator iterator) throws CloudException, InternalException {
                populateConfigurationList(null, iterator);
            }
        });
        populator.populate();
        return populator.getResult();
    }

    @Override
    public @Nonnull Iterable listDatabaseStatus() throws CloudException, InternalException {
        APITrace.begin(getProvider(), "RDBMS.listDatabaseStatus");
        try {
            ArrayList list = new ArrayList();
            String marker = null;

            do {
                Map parameters = getProvider().getStandardRdsParameters(getProvider().getContext(), DESCRIBE_DB_INSTANCES);
                EC2Method method;
                NodeList blocks;
                Document doc;

                if( marker != null ) {
                    parameters.put("Marker", marker);
                }
                method = new EC2Method(SERVICE_ID, getProvider(), parameters);
                try {
                    doc = method.invoke();
                }
                catch( EC2Exception e ) {
                    throw new CloudException(e);
                }
                marker = null;
                blocks = doc.getElementsByTagName("Marker");
                if( blocks.getLength() > 0 ) {
                    for( int i=0; i listDatabases() throws CloudException, InternalException {
        return listDatabases(null);
    }
    
    private Iterable listDatabases(String targetId) throws CloudException, InternalException {
        APITrace.begin(getProvider(), "RDBMS.listDatabases");
        try {
            ArrayList list = new ArrayList();
            String marker = null;

            do {
                Map parameters = getProvider().getStandardRdsParameters(getProvider().getContext(), DESCRIBE_DB_INSTANCES);
                EC2Method method;
                NodeList blocks;
                Document doc;

                if( marker != null ) {
                    parameters.put("Marker", marker);
                }
                if( targetId != null ) {
                    parameters.put("DBInstanceIdentifier", targetId);
                }
                method = new EC2Method(SERVICE_ID, getProvider(), parameters);
                try {
                    doc = method.invoke();
                }
                catch( EC2Exception e ) {
                    if( targetId != null ) {
                        String code = e.getCode();

                        if( code != null && code.equals("DBInstanceNotFound") || code.equals("InvalidParameterValue") ) {
                            return list;
                        }
                    }
                    throw new CloudException(e);
                }
                marker = null;
                blocks = doc.getElementsByTagName("Marker");
                if( blocks.getLength() > 0 ) {
                    for( int i=0; i listParameters(String forProviderConfigurationId) throws CloudException, InternalException {
        PopulatorThread populator;
        final String id = forProviderConfigurationId;

        getProvider().hold();
        populator = new PopulatorThread(new JiteratorPopulator() {
            public void populate(Jiterator iterator) throws CloudException, InternalException {
                try {
                    populateParameterList(id, null, iterator);
                }
                finally {
                    getProvider().release();
                }
            }
        });
        populator.populate();
        return populator.getResult();
    }
    
    public Collection listDefaultParameters(DatabaseEngine engine) throws CloudException, InternalException {
        PopulatorThread populator;
        final DatabaseEngine dbEngine = engine;

        getProvider().hold();
        populator = new PopulatorThread(new JiteratorPopulator() {
            public void populate(Jiterator iterator) throws CloudException, InternalException {
                try {
                    populateParameterList(null, dbEngine, iterator);
                }
                finally {
                    getProvider().release();
                }
            }
        });
        populator.populate();
        return populator.getResult();
    }
    
    public Iterable listSnapshots(String forOptionalProviderDatabaseId) throws CloudException, InternalException {
        PopulatorThread populator;

        getProvider().hold();
        final String id = (forOptionalProviderDatabaseId == null ? null : forOptionalProviderDatabaseId);
        populator = new PopulatorThread(new JiteratorPopulator() {
            public void populate(Jiterator iterator) throws CloudException, InternalException {
                try {
                    populateSnapshotList(null, id, iterator);
                }
                finally {
                    getProvider().release();
                }
            }
        });
        populator.populate();
        return populator.getResult();
    }

    @Override
    public @Nonnull String[] mapServiceAction(@Nonnull ServiceAction action) {
        return new String[0];     // TODO: implement me
    }

    private void populateAccess(String securityGroupId, Jiterator iterator) throws CloudException, InternalException {
        APITrace.begin(getProvider(), "RDBMS.populateDBSGAccess");
        try {
            Map parameters = getProvider().getStandardRdsParameters(getProvider().getContext(), DESCRIBE_DB_SECURITY_GROUPS);
            EC2Method method;
            NodeList blocks;
            Document doc;

            parameters.put("DBSecurityGroupName", securityGroupId);
            method = new EC2Method(SERVICE_ID, getProvider(), parameters);
            try {
                doc = method.invoke();
            }
            catch( EC2Exception e ) {
                throw new CloudException(e);
            }
            blocks = doc.getElementsByTagName("DBSecurityGroups");
            for( int i=0; i iterator) throws CloudException, InternalException {
        APITrace.begin(getProvider(), "RDBMS.populateConfigurationList");
        try {
            String marker = null;

            do {
                Map parameters = getProvider().getStandardRdsParameters(getProvider().getContext(), DESCRIBE_DB_PARAMETER_GROUPS);
                EC2Method method;
                NodeList blocks;
                Document doc;

                if( marker != null ) {
                    parameters.put("Marker", marker);
                }
                if( targetId != null ) {
                    parameters.put("DBParameterGroupName", targetId);
                }
                method = new EC2Method(SERVICE_ID, getProvider(), parameters);
                try {
                    doc = method.invoke();
                }
                catch( EC2Exception e ) {
                    throw new CloudException(e);
                }
                marker = null;
                blocks = doc.getElementsByTagName("Marker");
                if( blocks.getLength() > 0 ) {
                    for( int i=0; i iterator) throws CloudException, InternalException {
        APITrace.begin(getProvider(), "RDBMS.populateParameterList");
        try {
            String marker = null;

            do {
                Map parameters;
                EC2Method method;
                NodeList blocks;
                Document doc;

                if( cfgId != null ) {
                    parameters = getProvider().getStandardRdsParameters(getProvider().getContext(), DESCRIBE_DB_PARAMETERS);
                    parameters.put("DBParameterGroupName", cfgId);
                }
                else {
                    parameters = getProvider().getStandardRdsParameters(getProvider().getContext(), DESCRIBE_ENGINE_DEFAULT_PARAMETERS);
                    parameters.put("Engine", getEngineString(engine));
                }
                if( marker != null ) {
                    parameters.put("Marker", marker);
                }
                method = new EC2Method(SERVICE_ID, getProvider(), parameters);
                try {
                    doc = method.invoke();
                }
                catch( EC2Exception e ) {
                    throw new CloudException(e);
                }
                marker = null;
                blocks = doc.getElementsByTagName("Marker");
                if( blocks.getLength() > 0 ) {
                    for( int i=0; i iterator) throws CloudException, InternalException {
        APITrace.begin(getProvider(), "RDBMS.populateDBSecurityGroups");
        try {
            Map parameters = getProvider().getStandardRdsParameters(getProvider().getContext(), DESCRIBE_DB_INSTANCES);
            EC2Method method;
            NodeList blocks;
            Document doc;

            parameters.put("DBInstanceIdentifier", providerDatabaseId);
            method = new EC2Method(SERVICE_ID, getProvider(), parameters);
            try {
                doc = method.invoke();
            }
            catch( EC2Exception e ) {
                throw new CloudException(e);
            }
            blocks = doc.getElementsByTagName("DBInstances");
            for( int i=0; i iterator) throws CloudException, InternalException {
        APITrace.begin(getProvider(), "RDBMS.populateDBSnapshotList");
        try {
            String marker = null;

            do {
                Map parameters = getProvider().getStandardRdsParameters(getProvider().getContext(), DESCRIBE_DB_SNAPSHOTS);
                EC2Method method;
                NodeList blocks;
                Document doc;

                if( marker != null ) {
                    parameters.put("Marker", marker);
                }
                if( snapshotId != null ) {
                    parameters.put("DBSnapshotIdentifier", snapshotId);
                }
                if( databaseId != null ) {
                    parameters.put("DBInstanceIdentifier", databaseId);
                }
                method = new EC2Method(SERVICE_ID, getProvider(), parameters);
                try {
                    doc = method.invoke();
                }
                catch( EC2Exception e ) {
                    String code = e.getCode();

                    if( code != null && code.equals("DBSnapshotNotFound") ) {
                        return;
                    }
                    throw new CloudException(e);
                }
                marker = null;
                blocks = doc.getElementsByTagName("Marker");
                if( blocks.getLength() > 0 ) {
                    for( int i=0; i parameters = getProvider().getStandardRdsParameters(getProvider().getContext(), DELETE_DB_PARAMETER_GROUP);
            EC2Method method;

            parameters.put("DBParameterGroupName", providerConfigurationId);
            method = new EC2Method(SERVICE_ID, getProvider(), parameters);
            try {
                method.invoke();
            }
            catch( EC2Exception e ) {
                throw new CloudException(e);
            }
        }
        finally {
            APITrace.end();
        }
    }
    
    private void removeSecurityGroup(String securityGroupId) throws CloudException, InternalException {
        APITrace.begin(getProvider(), "RDBMS.removeSecurityGroup");
        try {
            Map parameters = getProvider().getStandardRdsParameters(getProvider().getContext(), DELETE_DB_SECURITY_GROUP);
            EC2Method method;

            parameters.put("DBSecurityGroupName", securityGroupId);
            method = new EC2Method(SERVICE_ID, getProvider(), parameters);
            try {
                method.invoke();
            }
            catch( EC2Exception e ) {
                throw e;
            }
        }
        finally {
            APITrace.end();
        }
    }
    
    public void removeDatabase(String providerDatabaseId) throws CloudException, InternalException {
        APITrace.begin(getProvider(), "RDBMS.removeDatabase");
        try {
            long timeout = System.currentTimeMillis() + (CalendarWrapper.MINUTE*10L);
            Database db = getDatabase(providerDatabaseId);

            while( timeout > System.currentTimeMillis() ) {
                if( db == null || DatabaseState.DELETED.equals(db.getCurrentState()) ) {
                    return;
                }
                if( DatabaseState.AVAILABLE.equals(db.getCurrentState()) ) {
                    break;
                }
                try { Thread.sleep(15000L); }
                catch( InterruptedException ignore ) { }
                try { db = getDatabase(providerDatabaseId); }
                catch( Throwable ignore ) { }
            }
            Iterable securityGroups = getSecurityGroups(providerDatabaseId);

            Map parameters = getProvider().getStandardRdsParameters(getProvider().getContext(), DELETE_DB_INSTANCE);
            EC2Method method;

            parameters.put("DBInstanceIdentifier", providerDatabaseId);
            parameters.put("FinalDBSnapshotIdentifier", providerDatabaseId + "-FINAL-" + System.currentTimeMillis());
            method = new EC2Method(SERVICE_ID, getProvider(), parameters);
            try {
                method.invoke();
            }
            catch( EC2Exception e ) {
                parameters = getProvider().getStandardRdsParameters(getProvider().getContext(), DELETE_DB_INSTANCE);
                parameters.put("DBInstanceIdentifier", providerDatabaseId);
                parameters.put("SkipFinalSnapshot", "true");
                method = new EC2Method(SERVICE_ID, getProvider(), parameters);
                try {
                    method.invoke();
                }
                catch( EC2Exception again ) {
                    throw new CloudException(e);
                }
            }
            try {
            	for( String securityGroupId : securityGroups ) {
            		if( securityGroupId.equals(providerDatabaseId) ) {
            			for( int i=0; i<3; i++ ) {
            				try {
            					removeSecurityGroup(securityGroupId);
            					break;
            				}
            				catch( EC2Exception e ) {
            					if (e.getProviderCode().equalsIgnoreCase("InvalidDBSecurityGroupState")) {
            						try { Thread.sleep(6000L); }
            						catch( InterruptedException ie ) { }
            						// ignore this because it means it is a shared security group
            					}
            					else throw new CloudException(e);
            				}
            			}
            		}
            	}
            }
            catch( Throwable t ) {
                t.printStackTrace();
            }
        }
        finally {
            APITrace.end();
        }
    }
    
    public void removeSnapshot(String providerSnapshotId) throws CloudException, InternalException {
        APITrace.begin(getProvider(), "RDBMS.removeSnapshot");
        try {
            Map parameters = getProvider().getStandardRdsParameters(getProvider().getContext(), DELETE_DB_SNAPSHOT);
            EC2Method method;

            parameters.put("DBSnapshotIdentifier", providerSnapshotId);
            method = new EC2Method(SERVICE_ID, getProvider(), parameters);
            try {
                method.invoke();
            }
            catch( EC2Exception e ) {
                throw new CloudException(e);
            }
        }
        finally {
            APITrace.end();
        }
    }
    
    public void resetConfiguration(String providerConfigurationId, String ... params) throws CloudException, InternalException {
        APITrace.begin(getProvider(), "RDBMS.resetConfiguration");
        try {
            Map parameters = getProvider().getStandardRdsParameters(getProvider().getContext(), RESET_DB_PARAMETER_GROUP);
            EC2Method method;

            parameters.put("DBParameterGroupName", providerConfigurationId);
            if( params == null || params.length < 1 ) {
                parameters.put("ResetAllParameters", "True");
            }
            else {
                int i = 0;

                parameters.put("ResetAllParameters", "False");
                for( String param : params ) {
                    i++;
                    parameters.put("Parameters.member." + i + ".ParameterName", param);
                    parameters.put("Parameters.member." + i + ".ApplyMethod", "pending-reboot");
                }
            }
            method = new EC2Method(SERVICE_ID, getProvider(), parameters);
            try {
                method.invoke();
            }
            catch( EC2Exception e ) {
                throw new CloudException(e);
            }
        }
        finally {
            APITrace.end();
        }
    }
    
    public void restart(String providerDatabaseId, boolean blockUntilDone) throws CloudException, InternalException {
        APITrace.begin(getProvider(), "RDBMS.restart");
        try {
            Map parameters = getProvider().getStandardRdsParameters(getProvider().getContext(), REBOOT_DB_INSTANCE);
            EC2Method method;

            parameters.put("DBInstanceIdentifier", providerDatabaseId);
            method = new EC2Method(SERVICE_ID, getProvider(), parameters);
            try {
                method.invoke();
            }
            catch( EC2Exception e ) {
                throw new CloudException(e);
            }
        }
        finally {
            APITrace.end();
        }
    }

    /**
     * Use this to revoke access of security groups in EC2-Classic
     * @param groupName
     * @param sourceCidr
     * @throws CloudException
     * @throws InternalException
     */
    private void revokeClassicDbSecurityGroup(String groupName, String sourceCidr) throws CloudException, InternalException {
        Map parameters = getProvider().getStandardRdsParameters(getProvider().getContext(), REVOKE_DB_SECURITY_GROUP_INGRESS);

        parameters.put("CIDRIP", sourceCidr);
        parameters.put("DBSecurityGroupName", groupName);
        EC2Method method = new EC2Method(SERVICE_ID, getProvider(), parameters);
        method.invoke();
    }

    public void revokeAccess(String providerDatabaseId, String sourceCidr) throws CloudException, InternalException {
        APITrace.begin(getProvider(), "RDBMS.revokeAccess");
        try {
            EC2Exception error = null;
            Database db = getDatabase(providerDatabaseId);
            for( String securityGroup : getSecurityGroups(providerDatabaseId) ) {
                try {
                    String ec2Type = getProvider().getDataCenterServices().isRegionEC2VPC(getProvider().getContext().getRegionId());
                    if( ec2Type.equals(AWSCloud.PLATFORM_EC2) ) {
                        revokeClassicDbSecurityGroup(securityGroup, sourceCidr);
                    }
                    else if( getProvider().hasNetworkServices() && getProvider().getNetworkServices().hasFirewallSupport() ) {
                        FirewallSupport firewallSupport = getProvider().getNetworkServices().getFirewallSupport();
                        firewallSupport.revoke(securityGroup, sourceCidr, Protocol.TCP, db.getHostPort(), db.getHostPort());
                    }
                }
                catch( EC2Exception e ) {
                    error = e;
                }
            }
            if( error != null ) {
                throw new CloudException(error);
            }
        }
        finally {
            APITrace.end();
        }
    }
    
    public void updateConfiguration(String providerConfigurationId, ConfigurationParameter ... params) throws CloudException, InternalException {
        APITrace.begin(getProvider(), "RDBMS.updateConfiguration");
        try {
            Map parameters = getProvider().getStandardRdsParameters(getProvider().getContext(), MODIFY_DB_PARAMETER_GROUP);
            EC2Method method;

            parameters.put("DBParameterGroupName", providerConfigurationId);
            int i = 0;
            for( ConfigurationParameter param : params ) {
                i++;
                parameters.put("Parameters.member." + i + ".ParameterName", param.getKey());
                parameters.put("Parameters.member." + i + ".ParameterValue", param.getParameter().toString());
                parameters.put("Parameters.member." + i + ".ApplyMethod", param.isApplyImmediately() ? "immediate" : "pending-reboot");
                if( i >= 20 ) {
                    break;
                }
            }
            method = new EC2Method(SERVICE_ID, getProvider(), parameters);
            try {
                method.invoke();
            }
            catch( EC2Exception e ) {
                throw new CloudException(e);
            }
            if( params.length > 20 ) {
                ConfigurationParameter[] repeat = new ConfigurationParameter[params.length-20];

                i = 0;
                for( ; i parameters = getProvider().getStandardRdsParameters(getProvider().getContext(), MODIFY_DB_INSTANCE);
            EC2Method method;

            parameters.put("DBInstanceIdentifier", id);
            parameters.put("ApplyImmediately", "true");
            String ec2Type = getProvider().getDataCenterServices().isRegionEC2VPC(getProvider().getContext().getRegionId());
            if(ec2Type.equals(AWSCloud.PLATFORM_EC2)){
                parameters.put("DBSecurityGroups.member.1", securityGroupId);
            }
            else {
                parameters.put("VpcSecurityGroupIds.member.1", securityGroupId);
            }
            method = new EC2Method(SERVICE_ID, getProvider(), parameters);
            try {
                method.invoke();
            }
            catch( EC2Exception e ) {
                throw new CloudException(e);
            }
        }
        finally {
            APITrace.end();
        }
    }
    
    public DatabaseSnapshot snapshot(String providerDatabaseId, String name) throws CloudException, InternalException {
        APITrace.begin(getProvider(), "RDBMS.snapshot");
        try {
            Map parameters = getProvider().getStandardRdsParameters(getProvider().getContext(), CREATE_DB_SNAPSHOT);
            String id = toIdentifier(name);
            EC2Method method;

            parameters.put("DBSnapshotIdentifier", id);
            parameters.put("DBInstanceIdentifier", providerDatabaseId);
            method = new EC2Method(SERVICE_ID, getProvider(), parameters);
            try {
                method.invoke();
            }
            catch( EC2Exception e ) {
                throw new CloudException(e);
            }
            return getSnapshot(id);
        }
        finally {
            APITrace.end();
        }
    }

    private DatabaseConfiguration toConfiguration(Node cfgNode) throws CloudException {
        String id = null, cfgName = null, description = null;
        DatabaseEngine engine = DatabaseEngine.MYSQL; //default
        NodeList attrs = cfgNode.getChildNodes();

        for( int i=0; i maxLength ) {
            rawName = rawName.substring(0, maxLength);
        }
        if( rawName.length() < 1 ) {
            return "x";
        }
        return rawName;
    }

    private String toIdentifier(String rawName) {
        StringBuilder str = new StringBuilder();
        
        if( rawName.length() < 1 ) {
            return "x";
        }
        if( !Character.isLetter(rawName.charAt(0)) ) {
            rawName = "db-" + rawName;
        }
        char last = '\0';
        for( int i=0; i 63 ) {
            rawName = rawName.substring(0,63);
        }
        while( rawName.charAt(rawName.length()-1) == '-' ) {
            rawName = rawName.substring(0,rawName.length()-1);
        }
        if( rawName.length() < 1 ) {
            return "x";
        }
        return rawName;
    }
    
    private ConfigurationParameter toParameter(Node pNode) throws CloudException {
        ConfigurationParameter param = new ConfigurationParameter();
        NodeList attrs = pNode.getChildNodes();
        
        param.setModifiable(false);
        param.setApplyImmediately(false);
        for( int i=0; i




© 2015 - 2024 Weber Informatics LLC | Privacy Policy