Skip to content

Commit

Permalink
[AWS/RDS] Feat: adding RDS Support (#12)
Browse files Browse the repository at this point in the history
Former-commit-id: fc24b83
  • Loading branch information
deven96 committed Jan 31, 2021
1 parent 2e7c8c1 commit 5061c2d
Show file tree
Hide file tree
Showing 6 changed files with 219 additions and 0 deletions.
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 10,7 @@ require (
github.com/aws/aws-sdk-go-v2/feature/s3/manager v0.2.0
github.com/aws/aws-sdk-go-v2/service/ec2 v0.31.0
github.com/aws/aws-sdk-go-v2/service/eks v0.31.0
github.com/aws/aws-sdk-go-v2/service/rds v0.31.0
github.com/aws/aws-sdk-go-v2/service/s3 v0.31.0
github.com/gin-gonic/gin v1.6.3
github.com/go-co-op/gocron v0.5.0
Expand Down
10 changes: 10 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 104,8 @@ github.com/aws/aws-sdk-go v1.36.1 h1:rDgSL20giXXu48Ycx6Qa4vWaNTVTltUl6vA73ObCSVk
github.com/aws/aws-sdk-go v1.36.1/go.mod h1:hcU610XS61/ aQV88ixoOzUoG7v3b31pl2zKMmprdro=
github.com/aws/aws-sdk-go-v2 v0.31.0 h1:TNTDsz Xq80nYzZPUFS4a2Oyjz9jKHKcTuNAXtcW8b8=
github.com/aws/aws-sdk-go-v2 v0.31.0/go.mod h1:IQw4KL7QIoaNDT3WoEBV1fDlVRhp/WTRteoaplV3SHo=
github.com/aws/aws-sdk-go-v2 v1.1.0 h1:sKP6QWxdN1oRYjl k6S3bpgBI XUx/0mqVOLIw4lR/Q=
github.com/aws/aws-sdk-go-v2 v1.1.0/go.mod h1:smfAbmpW tcRVuNUjo3MOArSZmW72t62rkCzc2i0TWM=
github.com/aws/aws-sdk-go-v2/config v0.4.0 h1:16lwnZRhleaPbDesZgEJbHxuOv4wy12A372mkhmiktc=
github.com/aws/aws-sdk-go-v2/config v0.4.0/go.mod h1:5uxQPUBCF TwwWYo2xau4N rSOS47ZH QvLbae1Cckc=
github.com/aws/aws-sdk-go-v2/credentials v0.2.0 h1:YDv/0/8BzaZtpS4jfptcyIPh5zlhmIhbM2RtNscn/bo=
Expand All @@ -120,14 122,22 @@ github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v0.4.0 h1:osjGuGbk
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v0.4.0/go.mod h1:Pjv1Z nRaluwWCMuB6OQeqGRyiGk2WTrKG8RHs5wZug=
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v0.2.0 h1:xeqwfWQGg3hjLMs61PlixdxhU qqrd7S50j/3kV1j/0=
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v0.2.0/go.mod h1:Ef71w/O9Ulhxj8gD9Pq2S0lXMvyNzFLMRuIxWpDRQxk=
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.0.1 h1:E7zGGgca12s7jA3VqirtaltXj5Wwe5eUIsUlNl1v d8=
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.0.1/go.mod h1:PISaKWylTYAyruocNk4Lr9miOOJjOcVBd7twCPbydDk=
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v0.4.0 h1:OiRO8lneLP7wJ80dqAwHpIRcMInUO04HzcQUVtPwk3U=
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v0.4.0/go.mod h1:fMsE4Rr6OkxQUmZxi4Amj8LS0BakLZw05Rog0jYStQM=
github.com/aws/aws-sdk-go-v2/service/rds v0.31.0 h1:9QnLjHZGNMR73qWhWQjbLd3Rg1b/UE9XmWNRWpcoypk=
github.com/aws/aws-sdk-go-v2/service/rds v0.31.0/go.mod h1:QR1y6Z2xttVeN5/Ka1qI5nNy5QNh3iMHBEx97R EP3w=
github.com/aws/aws-sdk-go-v2/service/rds v1.1.0 h1:asQWwI3ADdNRXOudrc4aovt8rj6jeN4j8Gl0DN8vff0=
github.com/aws/aws-sdk-go-v2/service/rds v1.1.0/go.mod h1:K8Jjo24XKpMqykQxNEljYHRSLVNDiGpxt067mJqzQ6s=
github.com/aws/aws-sdk-go-v2/service/s3 v0.31.0 h1:KDBpodyszhL8F83QYv36qBzDj99oPlt1coZNGSFKTXU=
github.com/aws/aws-sdk-go-v2/service/s3 v0.31.0/go.mod h1:KnvsmhsdHaJJZatMeNscBKaEmz0V5oXe1N5ZaLmGDBs=
github.com/aws/aws-sdk-go-v2/service/sts v0.31.0 h1:iJwlIyswoW4VM8RUmhC3397jdGa6QhMUtUf5daX /a0=
github.com/aws/aws-sdk-go-v2/service/sts v0.31.0/go.mod h1:gliVu4/DZsKINvBoEcMIlxMIQft/yPYQhnSLxwiWqFM=
github.com/aws/smithy-go v0.5.0 h1:ArsdWUrb1n6/V/REXhuwq2TZv kuqOBpMlGBd2EkDYM=
github.com/aws/smithy-go v0.5.0/go.mod h1:EzMw8dbp/YJL4A5/sbhGddag NPT7q084agLbB9LgIw=
github.com/aws/smithy-go v1.0.0 h1:hkhcRKG9rJ4Fn RbfXY7Tz7b3ITLDyolBnLLBhwbg/c=
github.com/aws/smithy-go v1.0.0/go.mod h1:EzMw8dbp/YJL4A5/sbhGddag NPT7q084agLbB9LgIw=
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue 5NUziq4I4S80YR8gNf3Q=
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh CedLV8=
github.com/bgentry/speakeasy v0.1.0/go.mod h1: zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
Expand Down
2 changes: 2 additions & 0 deletions provider/aws/aws.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 44,7 @@ func NewProvider() (*types.Provider, error) {
ebsManager := newEbsManager(cfg, aws.LogPath)
eipManager := newEipManager(cfg, aws.LogPath)
amiManager := newAmiManager(cfg, aws.LogPath)
rdsManager := newRDSManager(cfg, aws.LogPath)

resourceManagers = map[string]*resource.Manager{
ec2Manager.Name: &ec2Manager,
Expand All @@ -52,6 53,7 @@ func NewProvider() (*types.Provider, error) {
ebsManager.Name: &ebsManager,
eipManager.Name: &eipManager,
amiManager.Name: &amiManager,
rdsManager.Name: &rdsManager,
}

aws.Managers = resourceManagers
Expand Down
142 changes: 142 additions & 0 deletions provider/aws/rds.go
Original file line number Diff line number Diff line change
@@ -0,0 1,142 @@
package aws

import (
"context"
"fmt"

"github.com/aws/aws-sdk-go-v2/aws"
"github.com/aws/aws-sdk-go-v2/service/rds"
"github.com/mensaah/reka/provider/aws/utils"

"github.com/mensaah/reka/resource"
)

// returns only instance IDs of unprotected rds instances
func getrdsInstanceDetails(svc *rds.Client, output *rds.DescribeDBClustersOutput, region string) ([]*resource.Resource, error) {
var rdsInstances []*resource.Resource
rdsLogger.Debug("Fetching RDS Details")
for _, instance := range output.DBClusters {
tags := make(resource.Tags)
for _, t := range instance.TagList {
tags[*t.Key] = *t.Value
}
tags["creation-date"] = (*instance.ClusterCreateTime).String()
rds := NewResource(*instance.DBClusterIdentifier, rdsName)
rds.Region = region
// Get CreationDate by getting LaunchTime of attached Volume
rds.CreationDate = *instance.ClusterCreateTime
rds.Tags = tags
rds.Status = utils.GetRDSStatus(*instance.Status)
rdsInstances = append(rdsInstances, rds)
}

return rdsInstances, nil
}

// GetAllRDSInstances Get all instances
func GetAllRDSInstances(cfg aws.Config) ([]*resource.Resource, error) {
rdsLogger.Debug("Fetching RDS Clusters")

svc := rds.NewFromConfig(cfg)
params := &rds.DescribeDBClustersInput{}

// Build the request with its input parameters
resp, err := svc.DescribeDBClusters(context.TODO(), params)

if err != nil {
return nil, err
}
instances, err := getrdsInstanceDetails(svc, resp, cfg.Region)
if err != nil {
return nil, err
}
rdsLogger.Debugf("Found %d RDS clusters", len(instances))
return instances, nil
}

// StopRDSInstances Stop Running Instances
func StopRDSInstances(cfg aws.Config, instances []*resource.Resource) error {
svc := rds.NewFromConfig(cfg)
var instanceIds []rds.StopDBClusterInput

for _, instance := range instances {
if instance.IsActive() {
instanceIds = append(instanceIds, rds.StopDBClusterInput{
DBClusterIdentifier: &instance.UUID,
})
}
}

if len(instanceIds) <= 0 {
return nil
}

for _, instance := range instanceIds {
rdsLogger.Debug("Stopping RDS Clusters ", instance.DBClusterIdentifier, " ...")
resp, err := svc.StopDBCluster(context.TODO(), &instance)
// TODO Attach error to specific instance where the error occurred if possible
if err != nil {
fmt.Println(resp, err)
}
return err
}
return nil
}

// ResumeRDSInstances Resume Stopped instances
func ResumeRDSInstances(cfg aws.Config, instances []*resource.Resource) error {
svc := rds.NewFromConfig(cfg)
var instanceIds []*rds.StartDBClusterInput

for _, instance := range instances {
if instance.IsStopped() {
instanceIds = append(instanceIds, &rds.StartDBClusterInput{
DBClusterIdentifier: &instance.UUID,
})
}
}

if len(instanceIds) <= 0 {
return nil
}

for _, instance := range instanceIds {
rdsLogger.Debug("Starting RDS Cluster ", instance.DBClusterIdentifier, " ...")
resp, err := svc.StartDBCluster(context.TODO(), instance)
// TODO Attach error to specific instance where the error occurred if possible
if err != nil {
fmt.Println(resp, err)
}
return err
}
return nil
}

// TerminateRDSInstances Shutdown instances
func TerminateRDSInstances(cfg aws.Config, instances []*resource.Resource) error {
svc := rds.NewFromConfig(cfg)
var instanceIds []*rds.DeleteDBClusterInput

for _, instance := range instances {
if instance.IsStopped() || instance.IsActive() {
instanceIds = append(instanceIds, &rds.DeleteDBClusterInput{
DBClusterIdentifier: &instance.UUID,
})
}
}

if len(instanceIds) <= 0 {
return nil
}

for _, instance := range instanceIds {
rdsLogger.Debug("Terminating RDS Cluster ", instance.DBClusterIdentifier, " ...")
resp, err := svc.DeleteDBCluster(context.TODO(), instance)
// TODO Attach error to specific instance where the error occurred if possible
if err != nil {
fmt.Println(resp, err)
}
return err
}
return nil
}
46 changes: 46 additions & 0 deletions provider/aws/rds_types.go
Original file line number Diff line number Diff line change
@@ -0,0 1,46 @@
package aws

import (
log "github.com/sirupsen/logrus"

"github.com/mensaah/reka/config"
"github.com/mensaah/reka/resource"
)

// Manages RDS instances on the AWS.
// RDS resources support stopping/resuming and terminating instances.

var rdsManager resource.Manager

const (
// Name of resource
rdsName = "rds"
// LongName descriptive name for resource
rdsLongName = "Relational Database Service"
)

var rdsLogger *log.Entry

func newRDSManager(cfg *config.Config, logPath string) resource.Manager {
rdsLogger = config.GetLogger(rdsName, logPath)

rdsManager = resource.Manager{
Name: rdsName,
LongName: rdsLongName,
Config: cfg,
Logger: logger,
GetAll: func() ([]*resource.Resource, error) {
return GetAllRDSInstances(*cfg.Aws)
},
Destroy: func(resources []*resource.Resource) error {
return TerminateRDSInstances(*cfg.Aws, resources)
},
Stop: func(resources []*resource.Resource) error {
return StopRDSInstances(*cfg.Aws, resources)
},
Resume: func(resources []*resource.Resource) error {
return ResumeRDSInstances(*cfg.Aws, resources)
},
}
return rdsManager
}
18 changes: 18 additions & 0 deletions provider/aws/utils/state.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 7,24 @@ import (
"github.com/mensaah/reka/state"
)

// GetRDSStatus Get current status of an RDS DBInstance
func GetRDSStatus(f string) resource.Status {
switch f {
case "creating", "modifying", "upgrading":
return resource.Pending
case "stopped":
return resource.Stopped
case "stopping":
return resource.Stopping
case "deleting":
return resource.ShuttingDown
case "failed":
return resource.Destroyed
default:
return resource.Running
}
}

// GetResourceStatus Get the current status of Resource: Pending, Running, ... Stopped
func GetResourceStatus(s int32) resource.Status {
switch s {
Expand Down

0 comments on commit 5061c2d

Please sign in to comment.