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 }