github.com/darmach/terratest@v0.34.8-0.20210517103231-80931f95e3ff/modules/aws/rds.go (about)

     1  package aws
     2  
     3  import (
     4  	"database/sql"
     5  	"fmt"
     6  
     7  	"github.com/aws/aws-sdk-go/aws"
     8  	"github.com/aws/aws-sdk-go/service/rds"
     9  	_ "github.com/go-sql-driver/mysql"
    10  	"github.com/gruntwork-io/terratest/modules/testing"
    11  	"github.com/stretchr/testify/require"
    12  )
    13  
    14  // GetAddressOfRdsInstance gets the address of the given RDS Instance in the given region.
    15  func GetAddressOfRdsInstance(t testing.TestingT, dbInstanceID string, awsRegion string) string {
    16  	address, err := GetAddressOfRdsInstanceE(t, dbInstanceID, awsRegion)
    17  	if err != nil {
    18  		t.Fatal(err)
    19  	}
    20  	return address
    21  }
    22  
    23  // GetAddressOfRdsInstanceE gets the address of the given RDS Instance in the given region.
    24  func GetAddressOfRdsInstanceE(t testing.TestingT, dbInstanceID string, awsRegion string) (string, error) {
    25  	dbInstance, err := GetRdsInstanceDetailsE(t, dbInstanceID, awsRegion)
    26  	if err != nil {
    27  		return "", err
    28  	}
    29  
    30  	return aws.StringValue(dbInstance.Endpoint.Address), nil
    31  }
    32  
    33  // GetPortOfRdsInstance gets the address of the given RDS Instance in the given region.
    34  func GetPortOfRdsInstance(t testing.TestingT, dbInstanceID string, awsRegion string) int64 {
    35  	port, err := GetPortOfRdsInstanceE(t, dbInstanceID, awsRegion)
    36  	if err != nil {
    37  		t.Fatal(err)
    38  	}
    39  	return port
    40  }
    41  
    42  // GetPortOfRdsInstanceE gets the address of the given RDS Instance in the given region.
    43  func GetPortOfRdsInstanceE(t testing.TestingT, dbInstanceID string, awsRegion string) (int64, error) {
    44  	dbInstance, err := GetRdsInstanceDetailsE(t, dbInstanceID, awsRegion)
    45  	if err != nil {
    46  		return -1, err
    47  	}
    48  
    49  	return *dbInstance.Endpoint.Port, nil
    50  }
    51  
    52  // GetWhetherSchemaExistsInRdsMySqlInstance checks whether the specified schema/table name exists in the RDS instance
    53  func GetWhetherSchemaExistsInRdsMySqlInstance(t testing.TestingT, dbUrl string, dbPort int64, dbUsername string, dbPassword string, expectedSchemaName string) bool {
    54  	output, err := GetWhetherSchemaExistsInRdsMySqlInstanceE(t, dbUrl, dbPort, dbUsername, dbPassword, expectedSchemaName)
    55  	if err != nil {
    56  		t.Fatal(err)
    57  	}
    58  	return output
    59  }
    60  
    61  // GetWhetherSchemaExistsInRdsMySqlInstanceE checks whether the specified schema/table name exists in the RDS instance
    62  func GetWhetherSchemaExistsInRdsMySqlInstanceE(t testing.TestingT, dbUrl string, dbPort int64, dbUsername string, dbPassword string, expectedSchemaName string) (bool, error) {
    63  	connectionString := fmt.Sprintf("%s:%s@tcp(%s:%d)/", dbUsername, dbPassword, dbUrl, dbPort)
    64  	db, connErr := sql.Open("mysql", connectionString)
    65  	if connErr != nil {
    66  		return false, connErr
    67  	}
    68  	defer db.Close()
    69  	var (
    70  		schemaName string
    71  	)
    72  	sqlStatement := "SELECT SCHEMA_NAME FROM INFORMATION_SCHEMA.SCHEMATA WHERE SCHEMA_NAME=?;"
    73  	row := db.QueryRow(sqlStatement, expectedSchemaName)
    74  	scanErr := row.Scan(&schemaName)
    75  	if scanErr != nil {
    76  		return false, scanErr
    77  	}
    78  	return true, nil
    79  }
    80  
    81  // GetParameterValueForParameterOfRdsInstance gets the value of the parameter name specified for the RDS instance in the given region.
    82  func GetParameterValueForParameterOfRdsInstance(t testing.TestingT, parameterName string, dbInstanceID string, awsRegion string) string {
    83  	parameterValue, err := GetParameterValueForParameterOfRdsInstanceE(t, parameterName, dbInstanceID, awsRegion)
    84  	if err != nil {
    85  		t.Fatal(err)
    86  	}
    87  	return parameterValue
    88  }
    89  
    90  // GetParameterValueForParameterOfRdsInstanceE gets the value of the parameter name specified for the RDS instance in the given region.
    91  func GetParameterValueForParameterOfRdsInstanceE(t testing.TestingT, parameterName string, dbInstanceID string, awsRegion string) (string, error) {
    92  	output := GetAllParametersOfRdsInstance(t, dbInstanceID, awsRegion)
    93  	for _, parameter := range output {
    94  		if aws.StringValue(parameter.ParameterName) == parameterName {
    95  			return aws.StringValue(parameter.ParameterValue), nil
    96  		}
    97  	}
    98  	return "", ParameterForDbInstanceNotFound{ParameterName: parameterName, DbInstanceID: dbInstanceID, AwsRegion: awsRegion}
    99  }
   100  
   101  // GetOptionSettingForOfRdsInstance gets the value of the option name in the option group specified for the RDS instance in the given region.
   102  func GetOptionSettingForOfRdsInstance(t testing.TestingT, optionName string, optionSettingName string, dbInstanceID, awsRegion string) string {
   103  	optionValue, err := GetOptionSettingForOfRdsInstanceE(t, optionName, optionSettingName, dbInstanceID, awsRegion)
   104  	if err != nil {
   105  		t.Fatal(err)
   106  	}
   107  	return optionValue
   108  }
   109  
   110  // GetOptionSettingForOfRdsInstanceE gets the value of the option name in the option group specified for the RDS instance in the given region.
   111  func GetOptionSettingForOfRdsInstanceE(t testing.TestingT, optionName string, optionSettingName string, dbInstanceID, awsRegion string) (string, error) {
   112  	optionGroupName := GetOptionGroupNameOfRdsInstance(t, dbInstanceID, awsRegion)
   113  	options := GetOptionsOfOptionGroup(t, optionGroupName, awsRegion)
   114  	for _, option := range options {
   115  		if aws.StringValue(option.OptionName) == optionName {
   116  			for _, optionSetting := range option.OptionSettings {
   117  				if aws.StringValue(optionSetting.Name) == optionSettingName {
   118  					return aws.StringValue(optionSetting.Value), nil
   119  				}
   120  			}
   121  		}
   122  	}
   123  	return "", OptionGroupOptionSettingForDbInstanceNotFound{OptionName: optionName, OptionSettingName: optionSettingName, DbInstanceID: dbInstanceID, AwsRegion: awsRegion}
   124  }
   125  
   126  // GetOptionGroupNameOfRdsInstance gets the name of the option group associated with the RDS instance
   127  func GetOptionGroupNameOfRdsInstance(t testing.TestingT, dbInstanceID string, awsRegion string) string {
   128  	dbInstance, err := GetOptionGroupNameOfRdsInstanceE(t, dbInstanceID, awsRegion)
   129  	if err != nil {
   130  		t.Fatal(err)
   131  	}
   132  	return dbInstance
   133  }
   134  
   135  // GetOptionGroupNameOfRdsInstanceE gets the name of the option group associated with the RDS instance
   136  func GetOptionGroupNameOfRdsInstanceE(t testing.TestingT, dbInstanceID string, awsRegion string) (string, error) {
   137  	dbInstance, err := GetRdsInstanceDetailsE(t, dbInstanceID, awsRegion)
   138  	if err != nil {
   139  		return "", err
   140  	}
   141  	return aws.StringValue(dbInstance.OptionGroupMemberships[0].OptionGroupName), nil
   142  }
   143  
   144  // GetOptionsOfOptionGroup gets the options of the option group specified
   145  func GetOptionsOfOptionGroup(t testing.TestingT, optionGroupName string, awsRegion string) []*rds.Option {
   146  	output, err := GetOptionsOfOptionGroupE(t, optionGroupName, awsRegion)
   147  	if err != nil {
   148  		t.Fatal(err)
   149  	}
   150  	return output
   151  }
   152  
   153  // GetOptionsOfOptionGroupE gets the options of the option group specified
   154  func GetOptionsOfOptionGroupE(t testing.TestingT, optionGroupName string, awsRegion string) ([]*rds.Option, error) {
   155  	rdsClient := NewRdsClient(t, awsRegion)
   156  	input := rds.DescribeOptionGroupsInput{OptionGroupName: aws.String(optionGroupName)}
   157  	output, err := rdsClient.DescribeOptionGroups(&input)
   158  	if err != nil {
   159  		return []*rds.Option{}, err
   160  	}
   161  	return output.OptionGroupsList[0].Options, nil
   162  }
   163  
   164  // GetAllParametersOfRdsInstance gets all the parameters defined in the parameter group for the RDS instance in the given region.
   165  func GetAllParametersOfRdsInstance(t testing.TestingT, dbInstanceID string, awsRegion string) []*rds.Parameter {
   166  	parameters, err := GetAllParametersOfRdsInstanceE(t, dbInstanceID, awsRegion)
   167  	if err != nil {
   168  		t.Fatal(err)
   169  	}
   170  	return parameters
   171  }
   172  
   173  // GetAllParametersOfRdsInstanceE gets all the parameters defined in the parameter group for the RDS instance in the given region.
   174  func GetAllParametersOfRdsInstanceE(t testing.TestingT, dbInstanceID string, awsRegion string) ([]*rds.Parameter, error) {
   175  	dbInstance, dbInstanceErr := GetRdsInstanceDetailsE(t, dbInstanceID, awsRegion)
   176  	if dbInstanceErr != nil {
   177  		return []*rds.Parameter{}, dbInstanceErr
   178  	}
   179  	parameterGroupName := aws.StringValue(dbInstance.DBParameterGroups[0].DBParameterGroupName)
   180  
   181  	rdsClient := NewRdsClient(t, awsRegion)
   182  	input := rds.DescribeDBParametersInput{DBParameterGroupName: aws.String(parameterGroupName)}
   183  	output, err := rdsClient.DescribeDBParameters(&input)
   184  
   185  	if err != nil {
   186  		return []*rds.Parameter{}, err
   187  	}
   188  	return output.Parameters, nil
   189  }
   190  
   191  // GetRdsInstanceDetailsE gets the details of a single DB instance whose identifier is passed.
   192  func GetRdsInstanceDetailsE(t testing.TestingT, dbInstanceID string, awsRegion string) (*rds.DBInstance, error) {
   193  	rdsClient := NewRdsClient(t, awsRegion)
   194  	input := rds.DescribeDBInstancesInput{DBInstanceIdentifier: aws.String(dbInstanceID)}
   195  	output, err := rdsClient.DescribeDBInstances(&input)
   196  	if err != nil {
   197  		return nil, err
   198  	}
   199  	return output.DBInstances[0], nil
   200  }
   201  
   202  // NewRdsClient creates an RDS client.
   203  func NewRdsClient(t testing.TestingT, region string) *rds.RDS {
   204  	client, err := NewRdsClientE(t, region)
   205  	if err != nil {
   206  		t.Fatal(err)
   207  	}
   208  	return client
   209  }
   210  
   211  // NewRdsClientE creates an RDS client.
   212  func NewRdsClientE(t testing.TestingT, region string) (*rds.RDS, error) {
   213  	sess, err := NewAuthenticatedSession(region)
   214  	if err != nil {
   215  		return nil, err
   216  	}
   217  
   218  	return rds.New(sess), nil
   219  }
   220  
   221  // GetRecommendedRdsInstanceType takes in a list of RDS instance types (e.g., "db.t2.micro", "db.t3.micro") and returns the
   222  // first instance type in the list that is available in the given region and for the given database engine type.
   223  // If none of the instances provided are avaiable for your combination of region and database engine, this function will exit with an error.
   224  func GetRecommendedRdsInstanceType(t testing.TestingT, region string, engine string, engineVersion string, instanceTypeOptions []string) string {
   225  	out, err := GetRecommendedRdsInstanceTypeE(t, region, engine, engineVersion, instanceTypeOptions)
   226  	require.NoError(t, err)
   227  	return out
   228  }
   229  
   230  // GetRecommendedRdsInstanceTypeE takes in a list of RDS instance types (e.g., "db.t2.micro", "db.t3.micro") and returns the
   231  // first instance type in the list that is available in the given region and for the given database engine type.
   232  // If none of the instances provided are avaiable for your combination of region and database engine, this function will return an error.
   233  func GetRecommendedRdsInstanceTypeE(t testing.TestingT, region string, engine string, engineVersion string, instanceTypeOptions []string) (string, error) {
   234  	client, err := NewRdsClientE(t, region)
   235  	if err != nil {
   236  		return "", err
   237  	}
   238  	return GetRecommendedRdsInstanceTypeWithClientE(t, client, engine, engineVersion, instanceTypeOptions)
   239  }
   240  
   241  // GetRecommendedRdsInstanceTypeWithClientE takes in a list of RDS instance types (e.g., "db.t2.micro", "db.t3.micro") and returns the
   242  // first instance type in the list that is available in the given region and for the given database engine type.
   243  // If none of the instances provided are avaiable for your combination of region and database engine, this function will return an error.
   244  // This function expects an authenticated RDS client from the AWS SDK Go library.
   245  func GetRecommendedRdsInstanceTypeWithClientE(t testing.TestingT, rdsClient *rds.RDS, engine string, engineVersion string, instanceTypeOptions []string) (string, error) {
   246  	for _, instanceTypeOption := range instanceTypeOptions {
   247  		instanceTypeExists, err := instanceTypeExistsForEngineAndRegionE(rdsClient, engine, engineVersion, instanceTypeOption)
   248  		if err != nil {
   249  			return "", err
   250  		}
   251  
   252  		if instanceTypeExists {
   253  			return instanceTypeOption, nil
   254  		}
   255  	}
   256  	return "", NoRdsInstanceTypeError{InstanceTypeOptions: instanceTypeOptions, DatabaseEngine: engine, DatabaseEngineVersion: engineVersion}
   257  }
   258  
   259  // instanceTypeExistsForEngineAndRegionE returns a boolean that represents whether the provided instance type (e.g. db.t2.micro) exists for the given region and db engine type
   260  // This function will return an error if the RDS AWS SDK call fails.
   261  func instanceTypeExistsForEngineAndRegionE(client *rds.RDS, engine string, engineVersion string, instanceType string) (bool, error) {
   262  	input := rds.DescribeOrderableDBInstanceOptionsInput{
   263  		Engine:          aws.String(engine),
   264  		EngineVersion:   aws.String(engineVersion),
   265  		DBInstanceClass: aws.String(instanceType),
   266  	}
   267  
   268  	out, err := client.DescribeOrderableDBInstanceOptions(&input)
   269  	if err != nil {
   270  		return false, err
   271  	}
   272  
   273  	if len(out.OrderableDBInstanceOptions) > 0 {
   274  		return true, nil
   275  	}
   276  
   277  	return false, nil
   278  }
   279  
   280  // ParameterForDbInstanceNotFound is an error that occurs when the parameter group specified is not found for the DB instance
   281  type ParameterForDbInstanceNotFound struct {
   282  	ParameterName string
   283  	DbInstanceID  string
   284  	AwsRegion     string
   285  }
   286  
   287  func (err ParameterForDbInstanceNotFound) Error() string {
   288  	return fmt.Sprintf("Could not find a parameter %s in parameter group of database %s in %s", err.ParameterName, err.DbInstanceID, err.AwsRegion)
   289  }
   290  
   291  // OptionGroupOptionSettingForDbInstanceNotFound is an error that occurs when the option setting specified is not found in the option group of the DB instance
   292  type OptionGroupOptionSettingForDbInstanceNotFound struct {
   293  	OptionName        string
   294  	OptionSettingName string
   295  	DbInstanceID      string
   296  	AwsRegion         string
   297  }
   298  
   299  func (err OptionGroupOptionSettingForDbInstanceNotFound) Error() string {
   300  	return fmt.Sprintf("Could not find a option setting %s in option name %s of database %s in %s", err.OptionName, err.OptionSettingName, err.DbInstanceID, err.AwsRegion)
   301  }