mirror of
https://github.com/gravitational/teleport.git
synced 2026-11-03 07:40:28 +08:00
194 lines
8.0 KiB
Go
194 lines
8.0 KiB
Go
/*
|
|
Copyright 2020 Gravitational, Inc.
|
|
|
|
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 dynamo
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"strings"
|
|
|
|
"github.com/aws/aws-sdk-go/aws"
|
|
"github.com/aws/aws-sdk-go/service/applicationautoscaling"
|
|
"github.com/aws/aws-sdk-go/service/dynamodb"
|
|
"github.com/aws/aws-sdk-go/service/dynamodb/dynamodbiface"
|
|
)
|
|
|
|
// SetContinuousBackups enables continuous backups.
|
|
func SetContinuousBackups(ctx context.Context, svc dynamodbiface.DynamoDBAPI, tableName string) error {
|
|
// Make request to AWS to update continuous backups settings.
|
|
_, err := svc.UpdateContinuousBackupsWithContext(ctx, &dynamodb.UpdateContinuousBackupsInput{
|
|
PointInTimeRecoverySpecification: &dynamodb.PointInTimeRecoverySpecification{
|
|
PointInTimeRecoveryEnabled: aws.Bool(true),
|
|
},
|
|
TableName: aws.String(tableName),
|
|
})
|
|
if err != nil {
|
|
return convertError(err)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// AutoScalingParams defines auto scaling parameters for DynamoDB.
|
|
type AutoScalingParams struct {
|
|
// ReadMaxCapacity is the maximum provisioned read capacity.
|
|
ReadMaxCapacity int64
|
|
// ReadMinCapacity is the minimum provisioned read capacity.
|
|
ReadMinCapacity int64
|
|
// ReadTargetValue is the ratio of consumed read to provisioned capacity.
|
|
ReadTargetValue float64
|
|
// WriteMaxCapacity is the maximum provisioned write capacity.
|
|
WriteMaxCapacity int64
|
|
// WriteMinCapacity is the minimum provisioned write capacity.
|
|
WriteMinCapacity int64
|
|
// WriteTargetValue is the ratio of consumed write to provisioned capacity.
|
|
WriteTargetValue float64
|
|
}
|
|
|
|
// SetAutoScaling enables auto-scaling for the specified table with given configuration.
|
|
func SetAutoScaling(ctx context.Context, svc *applicationautoscaling.ApplicationAutoScaling, resourceID string, params AutoScalingParams) error {
|
|
readDimension := applicationautoscaling.ScalableDimensionDynamodbTableReadCapacityUnits
|
|
writeDimension := applicationautoscaling.ScalableDimensionDynamodbTableWriteCapacityUnits
|
|
|
|
// Check if the resource ID refers to an index - those IDs have the following form:
|
|
// 'table/<tableName>/index/<indexName>'
|
|
//
|
|
// Indices use a slightly different scaling dimension than tables
|
|
if strings.Contains(resourceID, "/index/") {
|
|
readDimension = applicationautoscaling.ScalableDimensionDynamodbIndexReadCapacityUnits
|
|
writeDimension = applicationautoscaling.ScalableDimensionDynamodbIndexWriteCapacityUnits
|
|
}
|
|
|
|
// Define scaling targets. Defines minimum and maximum {read,write} capacity.
|
|
if _, err := svc.RegisterScalableTargetWithContext(ctx, &applicationautoscaling.RegisterScalableTargetInput{
|
|
MinCapacity: aws.Int64(params.ReadMinCapacity),
|
|
MaxCapacity: aws.Int64(params.ReadMaxCapacity),
|
|
ResourceId: aws.String(resourceID),
|
|
ScalableDimension: aws.String(readDimension),
|
|
ServiceNamespace: aws.String(applicationautoscaling.ServiceNamespaceDynamodb),
|
|
}); err != nil {
|
|
return convertError(err)
|
|
}
|
|
if _, err := svc.RegisterScalableTargetWithContext(ctx, &applicationautoscaling.RegisterScalableTargetInput{
|
|
MinCapacity: aws.Int64(params.WriteMinCapacity),
|
|
MaxCapacity: aws.Int64(params.WriteMaxCapacity),
|
|
ResourceId: aws.String(resourceID),
|
|
ScalableDimension: aws.String(writeDimension),
|
|
ServiceNamespace: aws.String(applicationautoscaling.ServiceNamespaceDynamodb),
|
|
}); err != nil {
|
|
return convertError(err)
|
|
}
|
|
|
|
// Define scaling policy. Defines the ratio of {read,write} consumed capacity to
|
|
// provisioned capacity DynamoDB will try and maintain.
|
|
if _, err := svc.PutScalingPolicyWithContext(ctx, &applicationautoscaling.PutScalingPolicyInput{
|
|
PolicyName: aws.String(getReadScalingPolicyName(resourceID)),
|
|
PolicyType: aws.String(applicationautoscaling.PolicyTypeTargetTrackingScaling),
|
|
ResourceId: aws.String(resourceID),
|
|
ScalableDimension: aws.String(readDimension),
|
|
ServiceNamespace: aws.String(applicationautoscaling.ServiceNamespaceDynamodb),
|
|
TargetTrackingScalingPolicyConfiguration: &applicationautoscaling.TargetTrackingScalingPolicyConfiguration{
|
|
PredefinedMetricSpecification: &applicationautoscaling.PredefinedMetricSpecification{
|
|
PredefinedMetricType: aws.String(applicationautoscaling.MetricTypeDynamoDbreadCapacityUtilization),
|
|
},
|
|
TargetValue: aws.Float64(params.ReadTargetValue),
|
|
},
|
|
}); err != nil {
|
|
return convertError(err)
|
|
}
|
|
if _, err := svc.PutScalingPolicyWithContext(ctx, &applicationautoscaling.PutScalingPolicyInput{
|
|
PolicyName: aws.String(getWriteScalingPolicyName(resourceID)),
|
|
PolicyType: aws.String(applicationautoscaling.PolicyTypeTargetTrackingScaling),
|
|
ResourceId: aws.String(resourceID),
|
|
ScalableDimension: aws.String(writeDimension),
|
|
ServiceNamespace: aws.String(applicationautoscaling.ServiceNamespaceDynamodb),
|
|
TargetTrackingScalingPolicyConfiguration: &applicationautoscaling.TargetTrackingScalingPolicyConfiguration{
|
|
PredefinedMetricSpecification: &applicationautoscaling.PredefinedMetricSpecification{
|
|
PredefinedMetricType: aws.String(applicationautoscaling.MetricTypeDynamoDbwriteCapacityUtilization),
|
|
},
|
|
TargetValue: aws.Float64(params.WriteTargetValue),
|
|
},
|
|
}); err != nil {
|
|
return convertError(err)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// GetTableID returns the resourceID of a table based on its table name
|
|
func GetTableID(tableName string) string {
|
|
return fmt.Sprintf("table/%s", tableName)
|
|
}
|
|
|
|
// GetIndexID returns the resourceID of an index, based on the table & index name
|
|
func GetIndexID(tableName, indexName string) string {
|
|
return fmt.Sprintf("table/%s/index/%s", tableName, indexName)
|
|
}
|
|
|
|
// getWriteScalingPolicyName returns the policy name for our write scaling policy
|
|
func getWriteScalingPolicyName(resourceID string) string {
|
|
// We're trimming the "table/" prefix since policies before 6.1.0 didn't contain it. By referencing an existing
|
|
// policy name in 'PutScalingPolicy', AWS will update that one instead of creating a new resource.
|
|
return fmt.Sprintf("%s-write-target-tracking-scaling-policy", strings.TrimPrefix(resourceID, "table/"))
|
|
}
|
|
|
|
// getWriteScalingPolicyName returns the policy name for our read scaling policy
|
|
func getReadScalingPolicyName(resourceID string) string {
|
|
return fmt.Sprintf("%s-read-target-tracking-scaling-policy", strings.TrimPrefix(resourceID, "table/"))
|
|
}
|
|
|
|
func TurnOnTimeToLive(ctx context.Context, svc dynamodbiface.DynamoDBAPI, tableName string, ttlKey string) error {
|
|
status, err := svc.DescribeTimeToLiveWithContext(ctx, &dynamodb.DescribeTimeToLiveInput{
|
|
TableName: aws.String(tableName),
|
|
})
|
|
if err != nil {
|
|
return convertError(err)
|
|
}
|
|
switch aws.StringValue(status.TimeToLiveDescription.TimeToLiveStatus) {
|
|
case dynamodb.TimeToLiveStatusEnabled, dynamodb.TimeToLiveStatusEnabling:
|
|
return nil
|
|
}
|
|
_, err = svc.UpdateTimeToLiveWithContext(ctx, &dynamodb.UpdateTimeToLiveInput{
|
|
TableName: aws.String(tableName),
|
|
TimeToLiveSpecification: &dynamodb.TimeToLiveSpecification{
|
|
AttributeName: aws.String(ttlKey),
|
|
Enabled: aws.Bool(true),
|
|
},
|
|
})
|
|
return convertError(err)
|
|
}
|
|
|
|
func TurnOnStreams(ctx context.Context, svc dynamodbiface.DynamoDBAPI, tableName string) error {
|
|
status, err := svc.DescribeTableWithContext(ctx, &dynamodb.DescribeTableInput{
|
|
TableName: aws.String(tableName),
|
|
})
|
|
if err != nil {
|
|
return convertError(err)
|
|
}
|
|
if status.Table.StreamSpecification != nil && aws.BoolValue(status.Table.StreamSpecification.StreamEnabled) {
|
|
return nil
|
|
}
|
|
_, err = svc.UpdateTableWithContext(ctx, &dynamodb.UpdateTableInput{
|
|
TableName: aws.String(tableName),
|
|
StreamSpecification: &dynamodb.StreamSpecification{
|
|
StreamEnabled: aws.Bool(true),
|
|
StreamViewType: aws.String(dynamodb.StreamViewTypeNewImage),
|
|
},
|
|
})
|
|
return convertError(err)
|
|
}
|