Skip to content

Commit fce13d3

Browse files
committed
Initial review commit for redshift - go
1 parent be90fca commit fce13d3

File tree

11 files changed

+1197
-0
lines changed

11 files changed

+1197
-0
lines changed
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
package actions
2+
3+
import (
4+
"context"
5+
"errors"
6+
"github.com/aws/aws-sdk-go-v2/aws"
7+
"github.com/aws/aws-sdk-go-v2/service/redshift"
8+
"github.com/aws/aws-sdk-go-v2/service/redshift/types"
9+
"log"
10+
)
11+
12+
// RedshiftActions wraps Redshift service actions.
13+
type RedshiftActions struct {
14+
RedshiftClient *redshift.Client
15+
}
16+
17+
// snippet-start:[gov2.redshift.CreateCluster]
18+
19+
// CreateCluster sends a request to create a cluster with the given clusterId using the provided credentials.
20+
func (actor RedshiftActions) CreateCluster(ctx context.Context, clusterId string, userName string, userPassword string, nodeType string, clusterType string, publiclyAccessible bool) (*redshift.CreateClusterOutput, error) {
21+
// Create a new Redshift cluster
22+
input := &redshift.CreateClusterInput{
23+
ClusterIdentifier: aws.String(clusterId),
24+
MasterUserPassword: aws.String(userPassword),
25+
MasterUsername: aws.String(userName),
26+
NodeType: aws.String(nodeType),
27+
ClusterType: aws.String(clusterType),
28+
PubliclyAccessible: aws.Bool(publiclyAccessible),
29+
}
30+
31+
var opErr *types.ClusterAlreadyExistsFault
32+
output, err := actor.RedshiftClient.CreateCluster(ctx, input)
33+
if err != nil && errors.As(err, &opErr) {
34+
log.Println("Cluster already exists")
35+
return nil, nil
36+
} else if err != nil {
37+
log.Printf("Failed to create Redshift cluster: %v\n", err)
38+
return nil, err
39+
}
40+
41+
log.Printf("Created cluster %s\n", *output.Cluster.ClusterIdentifier)
42+
return output, nil
43+
}
44+
45+
// snippet-end:[gov2.redshift.CreateCluster]
46+
47+
// snippet-start:[gov2.redshift.ModifyCluster]
48+
49+
// ModifyCluster sets the preferred maintenance window for the given cluster.
50+
func (actor RedshiftActions) ModifyCluster(ctx context.Context, clusterId string, maintenanceWindow string) *redshift.ModifyClusterOutput {
51+
// Modify the cluster's maintenance window
52+
input := &redshift.ModifyClusterInput{
53+
ClusterIdentifier: aws.String(clusterId),
54+
PreferredMaintenanceWindow: aws.String(maintenanceWindow),
55+
}
56+
57+
output, err := actor.RedshiftClient.ModifyCluster(ctx, input)
58+
if err != nil {
59+
log.Printf("Failed to modify Redshift cluster: %v\n", err)
60+
return nil
61+
}
62+
63+
log.Printf("The cluster was successfully modified and now has %s as the maintenance window\n", *output.Cluster.PreferredMaintenanceWindow)
64+
return output
65+
}
66+
67+
// snippet-end:[gov2.redshift.ModifyCluster]
68+
69+
// snippet-start:[gov2.redshift.DeleteCluster]
70+
71+
// DeleteCluster deletes the given cluster.
72+
func (actor RedshiftActions) DeleteCluster(ctx context.Context, clusterId string) (bool, error) {
73+
// Delete the specified Redshift cluster
74+
input := &redshift.DeleteClusterInput{
75+
ClusterIdentifier: aws.String(clusterId),
76+
SkipFinalClusterSnapshot: aws.Bool(true),
77+
}
78+
_, err := actor.RedshiftClient.DeleteCluster(ctx, input)
79+
if err != nil {
80+
log.Printf("Failed to delete Redshift cluster: %v\n", err)
81+
return false, err
82+
}
83+
log.Printf("The %s was deleted\n", clusterId)
84+
return true, nil
85+
}
86+
87+
// snippet-end:[gov2.redshift.DeleteCluster]
Lines changed: 207 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,207 @@
1+
package actions
2+
3+
import (
4+
"context"
5+
"errors"
6+
"github.com/aws/aws-sdk-go-v2/aws"
7+
"github.com/aws/aws-sdk-go-v2/service/redshiftdata"
8+
"github.com/awsdocs/aws-doc-sdk-examples/gov2/demotools"
9+
"log"
10+
)
11+
12+
// RedshiftDataActions wraps RedshiftData actions.
13+
type RedshiftDataActions struct {
14+
RedshiftDataClient *redshiftdata.Client
15+
}
16+
17+
// snippet-start:[gov2.redshift.RedshiftQuery.struct]
18+
19+
// RedshiftQuery makes it easier to deal with RedshiftQuery objects.
20+
type RedshiftQuery struct {
21+
Result interface{}
22+
Input redshiftdata.DescribeStatementInput
23+
Context context.Context
24+
}
25+
26+
// snippet-end:[gov2.redshift.RedshiftQuery.struct]
27+
28+
// snippet-start:[gov2.redshift.ExecuteStatement
29+
30+
// ExecuteStatement calls the ExecuteStatement operation from the RedshiftDataClient
31+
func (actor RedshiftDataActions) ExecuteStatement(ctx context.Context, input redshiftdata.ExecuteStatementInput) (*redshiftdata.ExecuteStatementOutput, error) {
32+
33+
return actor.RedshiftDataClient.ExecuteStatement(ctx, &input)
34+
35+
}
36+
37+
// snippet-end:[gov2.redshift.ExecuteStatement
38+
39+
// snippet-start:[gov2.redshift.ExecuteBatchStatement
40+
41+
// ExecuteBatchStatement calls the BatchExecuteStatement operation from the RedshiftDataClient
42+
func (actor RedshiftDataActions) ExecuteBatchStatement(ctx context.Context, input redshiftdata.BatchExecuteStatementInput) (*redshiftdata.BatchExecuteStatementOutput, error) {
43+
return actor.RedshiftDataClient.BatchExecuteStatement(ctx, &input)
44+
}
45+
46+
// snippet-end:[gov2.redshift.ExecuteBatchStatement
47+
48+
// snippet-start:[gov2.redshift.ListDatabases]
49+
50+
// ListDatabases lists all databases in the given cluster.
51+
func (actor RedshiftDataActions) ListDatabases(ctx context.Context, clusterId string, databaseName string, userName string) error {
52+
input := redshiftdata.ListDatabasesInput{
53+
ClusterIdentifier: aws.String(clusterId),
54+
Database: aws.String(databaseName),
55+
DbUser: aws.String(userName),
56+
}
57+
58+
output, err := actor.RedshiftDataClient.ListDatabases(ctx, &input)
59+
if err != nil {
60+
log.Printf("Failed to list databases: %v\n", err)
61+
return err
62+
}
63+
64+
for _, database := range output.Databases {
65+
log.Printf("The database name is : %s\n", database)
66+
}
67+
return nil
68+
}
69+
70+
// snippet-end:[gov2.redshift.ListDatabases]
71+
72+
// snippet-start:[gov2.redshift.CreateTable]
73+
74+
// CreateTable creates a table named <tableName> in the <databaseName> database with the given arguments.
75+
func (actor RedshiftDataActions) CreateTable(ctx context.Context, clusterId string, databaseName string, tableName string, userName string, args []string) error {
76+
sql := "CREATE TABLE " + tableName + " (" +
77+
"id bigint identity(1, 1), " +
78+
"PRIMARY KEY (id)"
79+
for _, value := range args {
80+
sql += ", " + value
81+
}
82+
sql += ");"
83+
createTableInput := &redshiftdata.ExecuteStatementInput{
84+
ClusterIdentifier: aws.String(clusterId),
85+
Database: aws.String(databaseName),
86+
DbUser: aws.String(userName),
87+
Sql: aws.String(sql),
88+
}
89+
90+
output, err := actor.RedshiftDataClient.ExecuteStatement(ctx, createTableInput)
91+
if err != nil {
92+
log.Printf("Failed to create table: %v\n", err)
93+
return err
94+
}
95+
96+
log.Println("Table created:", *output.Id)
97+
return nil
98+
}
99+
100+
// snippet-end:[gov2.redshift.CreateTable]
101+
102+
// snippet-start:[gov2.redshift.DeleteTable]
103+
104+
// DeleteTable drops the table named <tableName> from the <databaseName> database.
105+
func (actor RedshiftDataActions) DeleteTable(ctx context.Context, clusterId string, databaseName string, tableName string, userName string) (bool, error) {
106+
sql := "DROP TABLE " + tableName
107+
deleteTableInput := &redshiftdata.ExecuteStatementInput{
108+
ClusterIdentifier: aws.String(clusterId),
109+
Database: aws.String(databaseName),
110+
DbUser: aws.String(userName),
111+
Sql: aws.String(sql),
112+
}
113+
114+
output, err := actor.RedshiftDataClient.ExecuteStatement(ctx, deleteTableInput)
115+
if err != nil {
116+
log.Printf("Failed to delete table "+tableName+" from "+databaseName+" database: %v\n", err)
117+
return false, err
118+
}
119+
120+
log.Println(tableName+" table deleted from "+databaseName+" database:", *output.Id)
121+
return true, nil
122+
}
123+
124+
// snippet-end:[gov2.redshift.DeleteTable]
125+
126+
// snippet-start:[gov2.redshift.DeleteRows]
127+
128+
// DeleteDataRows deletes all rows from the given table.
129+
func (actor RedshiftDataActions) DeleteDataRows(ctx context.Context, clusterId string, databaseName string, tableName string, userName string, pauser demotools.IPausable) (bool, error) {
130+
deleteRows := &redshiftdata.ExecuteStatementInput{
131+
ClusterIdentifier: aws.String(clusterId),
132+
Database: aws.String(databaseName),
133+
DbUser: aws.String(userName),
134+
Sql: aws.String("DELETE FROM " + tableName + ";"),
135+
}
136+
137+
result, err := actor.RedshiftDataClient.ExecuteStatement(ctx, deleteRows)
138+
if err != nil {
139+
log.Printf("Failed to execute batch statement: %v\n", err)
140+
return false, err
141+
}
142+
describeInput := redshiftdata.DescribeStatementInput{
143+
Id: result.Id,
144+
}
145+
query := RedshiftQuery{
146+
Context: ctx,
147+
Result: result,
148+
Input: describeInput,
149+
}
150+
err = actor.WaitForQueryStatus(query, pauser, true)
151+
if err != nil {
152+
log.Printf("Failed to execute delete query: %v\n", err)
153+
return false, err
154+
}
155+
156+
log.Printf("Successfully executed delete statement\n")
157+
return true, nil
158+
}
159+
160+
// snippet-end:[gov2.redshift.DeleteRows]
161+
162+
// snippet-start:[gov2.redshift.WaitForQueryStatus]
163+
164+
// WaitForQueryStatus waits until the given RedshiftQuery object has succeeded or failed.
165+
func (actor RedshiftDataActions) WaitForQueryStatus(query RedshiftQuery, pauser demotools.IPausable, showProgress bool) error {
166+
done := false
167+
attempts := 0
168+
maxWaitCycles := 30
169+
for done == false {
170+
describeOutput, err := actor.RedshiftDataClient.DescribeStatement(query.Context, &query.Input)
171+
if err != nil {
172+
return err
173+
}
174+
if describeOutput.Status == "FAILED" {
175+
return errors.New("failed to describe statement")
176+
}
177+
if attempts >= maxWaitCycles {
178+
return errors.New("timed out waiting for statement")
179+
}
180+
if showProgress {
181+
log.Print(".")
182+
}
183+
if describeOutput.Status == "FINISHED" {
184+
done = true
185+
}
186+
attempts++
187+
pauser.Pause(attempts)
188+
}
189+
return nil
190+
}
191+
192+
// snippet-end:[gov2.redshift.WaitForQueryStatus]
193+
194+
// snippet-start:[gov2.redshift.GetStatementResult]
195+
196+
// GetStatementResult returns the result of the statement with the given id.
197+
func (actor RedshiftDataActions) GetStatementResult(ctx context.Context, statementId string) (*redshiftdata.GetStatementResultOutput, error) {
198+
getStatementResultOutput, err := actor.RedshiftDataClient.GetStatementResult(ctx, &redshiftdata.GetStatementResultInput{
199+
Id: aws.String(statementId),
200+
})
201+
if err != nil {
202+
return nil, err
203+
}
204+
return getStatementResultOutput, nil
205+
}
206+
207+
// snippet-end:[gov2.redshift.GetStatementResult]

gov2/redshift/cmd/main.go

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
package main
5+
6+
import (
7+
"context"
8+
"flag"
9+
"fmt"
10+
"github.com/awsdocs/aws-doc-sdk-examples/gov2/demotools"
11+
"github.com/awsdocs/aws-doc-sdk-examples/gov2/redshift/scenarios"
12+
"log"
13+
"math/rand"
14+
"time"
15+
16+
"github.com/aws/aws-sdk-go-v2/aws"
17+
"github.com/aws/aws-sdk-go-v2/config"
18+
)
19+
20+
// main loads default AWS credentials and configuration from the ~/.aws folder and runs
21+
// a scenario specified by the `-scenario` flag.
22+
//
23+
// `-scenario` can be one of the following:
24+
//
25+
// - `getstarted` - Runs the interactive get started scenario that shows you how to use
26+
// Amazon Simple Storage Service (Amazon S3) actions to work with
27+
// S3 buckets and objects.
28+
func main() {
29+
scenarioMap := map[string]func(sdkConfig aws.Config, helper scenarios.IScenarioHelper){
30+
"basics": runRedshiftBasicsScenario,
31+
}
32+
choices := make([]string, len(scenarioMap))
33+
choiceIndex := 0
34+
for choice := range scenarioMap {
35+
choices[choiceIndex] = choice
36+
choiceIndex++
37+
}
38+
scenario := flag.String(
39+
"scenario", "",
40+
fmt.Sprintf("The scenario to run. Must be one of %v.", choices))
41+
flag.Parse()
42+
43+
if runScenario, ok := scenarioMap[*scenario]; !ok {
44+
fmt.Printf("'%v' is not a valid scenario.\n", *scenario)
45+
flag.Usage()
46+
} else {
47+
sdkConfig, err := config.LoadDefaultConfig(context.TODO())
48+
if err != nil {
49+
log.Fatalf("unable to load SDK config, %v", err)
50+
}
51+
52+
log.SetFlags(0)
53+
helper := scenarios.ScenarioHelper{
54+
Prefix: "redshift_basics",
55+
Random: rand.New(rand.NewSource(time.Now().UnixNano())),
56+
}
57+
runScenario(sdkConfig, helper)
58+
}
59+
}
60+
61+
func runRedshiftBasicsScenario(sdkConfig aws.Config, helper scenarios.IScenarioHelper) {
62+
pauser := demotools.Pauser{}
63+
scenario := scenarios.RedshiftBasics(sdkConfig, demotools.NewQuestioner(), pauser, demotools.NewStandardFileSystem(), helper)
64+
scenario.Run()
65+
}

gov2/redshift/go.mod

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
module github.com/awsdocs/aws-doc-sdk-examples/gov2/redshift
2+
3+
go 1.21
4+
5+
require (
6+
github.com/aws/aws-sdk-go-v2 v1.30.5
7+
github.com/aws/aws-sdk-go-v2/config v1.27.33
8+
github.com/aws/aws-sdk-go-v2/service/redshift v1.46.8
9+
github.com/aws/aws-sdk-go-v2/service/redshiftdata v1.28.2
10+
github.com/awsdocs/aws-doc-sdk-examples/gov2/demotools v0.0.0-20240911175713-48a391575470
11+
github.com/awsdocs/aws-doc-sdk-examples/gov2/testtools v0.0.0-20240911175713-48a391575470
12+
)
13+
14+
require (
15+
github.com/aws/aws-sdk-go-v2/credentials v1.17.32 // indirect
16+
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.13 // indirect
17+
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.17 // indirect
18+
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.17 // indirect
19+
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.1 // indirect
20+
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.4 // indirect
21+
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.19 // indirect
22+
github.com/aws/aws-sdk-go-v2/service/sso v1.22.7 // indirect
23+
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.26.7 // indirect
24+
github.com/aws/aws-sdk-go-v2/service/sts v1.30.7 // indirect
25+
github.com/aws/smithy-go v1.20.4 // indirect
26+
github.com/jmespath/go-jmespath v0.4.0 // indirect
27+
golang.org/x/sys v0.25.0 // indirect
28+
golang.org/x/term v0.24.0 // indirect
29+
)

0 commit comments

Comments
 (0)