Skip to content

Commit

Permalink
Merge pull request #150 from kubefirst/feat-del-s3-on-clean-cmd
Browse files Browse the repository at this point in the history
put-tag-bucket-delete-on-clean
  • Loading branch information
pagottoo committed Jul 25, 2022
2 parents dbe2aea + 84a371f commit a1d4d6f
Show file tree
Hide file tree
Showing 6 changed files with 200 additions and 35 deletions.
33 changes: 27 additions & 6 deletions cmd/clean.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,28 +3,47 @@ package cmd
import (
"bytes"
"fmt"
"log"
"os"
"strings"

"github.com/kubefirst/kubefirst/configs"
"github.com/kubefirst/kubefirst/internal/aws"
"github.com/kubefirst/kubefirst/internal/reports"
"github.com/kubefirst/kubefirst/pkg"
"github.com/spf13/cobra"
"github.com/spf13/viper"
"log"
"os"
"strings"
)

// todo delete the s3 buckets associated with the ~/.kubefirst file
// todo ask for user input to verify deletion?
// todo ask for user input to verify?
// cleanCmd removes all kubefirst resources locally for new execution.
var cleanCmd = &cobra.Command{
Use: "clean",
Short: "removes all kubefirst resources locally for new execution",
Long: `Kubefirst creates files and folders during installation at your local environment. This command removes and
re-create all Kubefirst files.`,
Long: `Kubefirst creates files, folders and cloud buckets during installation at your environment. This command removes and
re-create all Kubefirst files. To destroy cloud resources you need to specify aditional flags (--destroy-buckets)`,
Run: func(cmd *cobra.Command, args []string) {

config := configs.ReadConfig()

destroyBuckets, err := cmd.Flags().GetBool("destroy-buckets")
if err != nil {
log.Println(err)
}
destroyConfirm, err := cmd.Flags().GetBool("destroy-confirm")
if err != nil {
log.Println(err)
}
if destroyBuckets && !destroyConfirm {
destroyConfirm = pkg.AskForConfirmation("This process will delete cloud buckets and all files inside, do you really want to proceed?")
if !destroyConfirm {
os.Exit(130)
}
}

aws.DestroyBucketsInUse(destroyBuckets && destroyConfirm)

// command line flags
rmLogsFolder, err := cmd.Flags().GetBool("rm-logs")
if err != nil {
Expand Down Expand Up @@ -86,4 +105,6 @@ re-create all Kubefirst files.`,
func init() {
rootCmd.AddCommand(cleanCmd)
cleanCmd.Flags().Bool("rm-logs", false, "remove logs folder")
cleanCmd.Flags().Bool("destroy-buckets", false, "destroy buckets created by init cmd")
cleanCmd.Flags().Bool("destroy-confirm", false, "confirm destroy operation (to be used during automation")
}
14 changes: 4 additions & 10 deletions cmd/destroy.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,15 @@ package cmd
import (
"bytes"
"fmt"
"log"
"os/exec"
"syscall"

"github.com/kubefirst/kubefirst/configs"
"github.com/kubefirst/kubefirst/internal/aws"
"github.com/kubefirst/kubefirst/internal/gitlab"
"github.com/kubefirst/kubefirst/internal/k8s"
"github.com/kubefirst/kubefirst/internal/terraform"
"github.com/spf13/cobra"
"log"
"os/exec"
"syscall"
)

// destroyCmd represents the destroy command
Expand Down Expand Up @@ -39,10 +39,6 @@ if the registry has already been deleted.`,
if err != nil {
log.Panic(err)
}
destroyBuckets, err := cmd.Flags().GetBool("destroy-buckets")
if err != nil {
log.Panic(err)
}

var kPortForwardOutb, kPortForwardErrb bytes.Buffer
kPortForward := exec.Command(config.KubectlClientPath, "--kubeconfig", config.KubeConfigPath, "-n", "gitlab", "port-forward", "svc/gitlab-webservice-default", "8888:8080")
Expand Down Expand Up @@ -100,8 +96,6 @@ if the registry has already been deleted.`,
log.Println("terraform destroy base")
terraform.DestroyBaseTerraform(skipBaseTerraform)
log.Println("terraform base destruction complete")
//TODO: move this step to `kubefirst clean` command and empty buckets and delete
aws.DestroyBucketsInUse(destroyBuckets)
fmt.Println("End of execution destroy")
},
}
Expand Down
19 changes: 14 additions & 5 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,14 @@ require (
k8s.io/client-go v0.22.1
)

require (
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.3 // indirect
github.com/aws/aws-sdk-go-v2/internal/v4a v1.0.5 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.9.3 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.9 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.13.8 // indirect
)

replace k8s.io/client-go => k8s.io/client-go v0.22.1

replace k8s.io/apimachinery => k8s.io/apimachinery v0.22.1
Expand All @@ -37,15 +45,16 @@ require (
github.com/acomagu/bufpipe v1.0.3 // indirect
github.com/armon/go-metrics v0.3.10 // indirect
github.com/armon/go-radix v1.0.0 // indirect
github.com/aws/aws-sdk-go-v2 v1.16.5 // indirect
github.com/aws/aws-sdk-go-v2 v1.16.7 // indirect
github.com/aws/aws-sdk-go-v2/credentials v1.12.2 // indirect
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.5 // indirect
github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.12 // indirect
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.6 // indirect
github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.14 // indirect
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.8 // indirect
github.com/aws/aws-sdk-go-v2/internal/ini v1.3.12 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.5 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.8 // indirect
github.com/aws/aws-sdk-go-v2/service/s3 v1.27.1
github.com/aws/aws-sdk-go-v2/service/sso v1.11.5 // indirect
github.com/aws/smithy-go v1.11.3 // indirect
github.com/aws/smithy-go v1.12.0 // indirect
github.com/cenkalti/backoff/v3 v3.0.0 // indirect
github.com/containerd/console v1.0.3 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
Expand Down
22 changes: 22 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,10 @@ github.com/aws/aws-sdk-go v1.44.23/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4
github.com/aws/aws-sdk-go-v2 v1.16.4/go.mod h1:ytwTPBG6fXTZLxxeeCCWj2/EMYp/xDUgX+OET6TLNNU=
github.com/aws/aws-sdk-go-v2 v1.16.5 h1:Ah9h1TZD9E2S1LzHpViBO3Jz9FPL5+rmflmb8hXirtI=
github.com/aws/aws-sdk-go-v2 v1.16.5/go.mod h1:Wh7MEsmEApyL5hrWzpDkba4gwAPc5/piwLVLFnCxp48=
github.com/aws/aws-sdk-go-v2 v1.16.7 h1:zfBwXus3u14OszRxGcqCDS4MfMCv10e8SMJ2r8Xm0Ns=
github.com/aws/aws-sdk-go-v2 v1.16.7/go.mod h1:6CpKuLXg2w7If3ABZCl/qZ6rEgwtjZTn4eAf4RcEyuw=
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.3 h1:S/ZBwevQkr7gv5YxONYpGQxlMFFYSRfz3RMcjsC9Qhk=
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.3/go.mod h1:gNsR5CaXKmQSSzrmGxmwmct/r+ZBfbxorAuXYsj/M5Y=
github.com/aws/aws-sdk-go-v2/config v1.15.7 h1:PrzhYjDpWnGSpjedmEapldQKPW4x8cCNzUI8XOho1CM=
github.com/aws/aws-sdk-go-v2/config v1.15.7/go.mod h1:exERlvqx1OoUHrxQpMgrmfSW0H6B1+r3xziZD3bBXRg=
github.com/aws/aws-sdk-go-v2/credentials v1.12.2 h1:tX4EHQFU4+O9at5QjnwIKb/Qgv7MbgbUNtqTRF0Vu2M=
Expand All @@ -107,22 +111,40 @@ github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.5/go.mod h1:WAPnuhG5IQ/i6DET
github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.11/go.mod h1:tmUB6jakq5DFNcXsXOA/ZQ7/C8VnSKYkx58OI7Fh79g=
github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.12 h1:Zt7DDk5V7SyQULUUwIKzsROtVzp/kVvcz15uQx/Tkow=
github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.12/go.mod h1:Afj/U8svX6sJ77Q+FPWMzabJ9QjbwP32YlopgKALUpg=
github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.14 h1:2C0pYHcUBmdzPj+EKNC4qj97oK6yjrUhc1KoSodglvk=
github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.14/go.mod h1:kdjrMwHwrC3+FsKhNcCMJ7tUVj/8uSD5CZXeQ4wV6fM=
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.5/go.mod h1:fV1AaS2gFc1tM0RCb015FJ0pvWVUfJZANzjwoO4YakM=
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.6 h1:eeXdGVtXEe+2Jc49+/vAzna3FAQnUD4AagAw8tzbmfc=
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.6/go.mod h1:FwpAKI+FBPIELJIdmQzlLtRe8LQSOreMcM2wBsPMvvc=
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.8 h1:2J+jdlBJWEmTyAwC82Ym68xCykIvnSnIN18b8xHGlcc=
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.8/go.mod h1:ZIV8GYoC6WLBW5KGs+o4rsc65/ozd+eQ0L31XF5VDwk=
github.com/aws/aws-sdk-go-v2/internal/ini v1.3.12 h1:j0VqrjtgsY1Bx27tD0ysay36/K4kFMWRp9K3ieO9nLU=
github.com/aws/aws-sdk-go-v2/internal/ini v1.3.12/go.mod h1:00c7+ALdPh4YeEUPXJzyU0Yy01nPGOq2+9rUaz05z9g=
github.com/aws/aws-sdk-go-v2/internal/v4a v1.0.5 h1:tEEHn+PGAxRVqMPEhtU8oCSW/1Ge3zP5nUgPrGQNUPs=
github.com/aws/aws-sdk-go-v2/internal/v4a v1.0.5/go.mod h1:aIwFF3dUk95ocCcA3zfk3nhz0oLkpzHFWuMp8l/4nNs=
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.9.3 h1:4n4KCtv5SUoT5Er5XV41huuzrCqepxlW3SDI9qHQebc=
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.9.3/go.mod h1:gkb2qADY+OHaGLKNTYxMaQNacfeyQpZ4csDTQMeFmcw=
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.9 h1:gVv2vXOMqJeR4ZHHV32K7LElIJIIzyw/RU1b0lSfWTQ=
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.9/go.mod h1:EF5RLnD9l0xvEWwMRcktIS/dI6lF8lU5eV3B13k6sWo=
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.5 h1:gRW1ZisKc93EWEORNJRvy/ZydF3o6xLSveJHdi1Oa0U=
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.5/go.mod h1:ZbkttHXaVn3bBo/wpJbQGiiIWR90eTBUVBrEHUEQlho=
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.8 h1:oKnAXxSF2FUvfgw8uzU/v9OTYorJJZ8eBmWhr9TWVVQ=
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.8/go.mod h1:rDVhIMAX9N2r8nWxDUlbubvvaFMnfsm+3jAV7q+rpM4=
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.13.8 h1:TlN1UC39A0LUNoD51ubO5h32haznA+oVe15jO9O4Lj0=
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.13.8/go.mod h1:JlVwmWtT/1c5W+6oUsjXjAJ0iJZ+hlghdrDy/8JxGCU=
github.com/aws/aws-sdk-go-v2/service/route53 v1.20.5 h1:Vex6D07/CmahT0LIaiRk+j9xyVAsvQxBa8iv38p3Ajc=
github.com/aws/aws-sdk-go-v2/service/route53 v1.20.5/go.mod h1:QZWV7sxHUg/qsPJcAtAI9JyLPKZ78weHmdILmYMCqEE=
github.com/aws/aws-sdk-go-v2/service/s3 v1.27.1 h1:OKQIQ0QhEBmGr2LfT952meIZz3ujrPYnxH+dO/5ldnI=
github.com/aws/aws-sdk-go-v2/service/s3 v1.27.1/go.mod h1:NffjpNsMUFXp6Ok/PahrktAncoekWrywvmIK83Q2raE=
github.com/aws/aws-sdk-go-v2/service/sso v1.11.5 h1:TfJ/zuOYvHnxkvohSwAF3Ppn9KT/SrGZuOZHTPy8Guw=
github.com/aws/aws-sdk-go-v2/service/sso v1.11.5/go.mod h1:TFVe6Rr2joVLsYQ1ABACXgOC6lXip/qpX2x5jWg/A9w=
github.com/aws/aws-sdk-go-v2/service/sts v1.16.6 h1:aYToU0/iazkMY67/BYLt3r6/LT/mUtarLAF5mGof1Kg=
github.com/aws/aws-sdk-go-v2/service/sts v1.16.6/go.mod h1:rP1rEOKAGZoXp4iGDxSXFvODAtXpm34Egf0lL0eshaQ=
github.com/aws/smithy-go v1.11.2/go.mod h1:3xHYmszWVx2c0kIwQeEVf9uSm4fYZt67FBJnwub1bgM=
github.com/aws/smithy-go v1.11.3 h1:DQixirEFM9IaKxX1olZ3ke3nvxRS2xMDteKIDWxozW8=
github.com/aws/smithy-go v1.11.3/go.mod h1:Tg+OJXh4MB2R/uN61Ko2f6hTZwB/ZYGOtib8J3gBHzA=
github.com/aws/smithy-go v1.12.0 h1:gXpeZel/jPoWQ7OEmLIgCUnhkFftqNfwWUwAHSlp1v0=
github.com/aws/smithy-go v1.12.0/go.mod h1:Tg+OJXh4MB2R/uN61Ko2f6hTZwB/ZYGOtib8J3gBHzA=
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/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
Expand Down
125 changes: 111 additions & 14 deletions internal/aws/aws.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,11 @@ import (
"strings"
"time"

awsv2 "github.com/aws/aws-sdk-go-v2/aws"
"github.com/aws/aws-sdk-go-v2/config"
"github.com/aws/aws-sdk-go-v2/service/route53"
"github.com/aws/aws-sdk-go-v2/service/route53/types"
s3v2 "github.com/aws/aws-sdk-go-v2/service/s3"
"github.com/aws/aws-sdk-go-v2/service/sts"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/awserr"
Expand Down Expand Up @@ -80,7 +82,7 @@ func BucketRand(dryRun bool, trackers map[string]*pkg.ActionTracker) {
if err != nil {
log.Panicf("Error putting S3 versioning: %s", err)
}

PutTagKubefirstOnBuckets(bucketName, viper.GetString("cluster-name"))
} else {
log.Printf("[#99] Dry-run mode, bucket creation skipped: %s", bucketName)
}
Expand Down Expand Up @@ -261,11 +263,6 @@ func ReturnHostedZoneId(rawZoneId string) string {
}

func ListBucketsInUse() []string {
//Read flare file
//Iterate over buckets
//check if bucket exist
//buckets := make([]map[string]string, 0)
//var m map[string]string
var bucketsInUse []string
bucketsConfig := viper.AllKeys()
for _, bucketKey := range bucketsConfig {
Expand All @@ -279,7 +276,6 @@ func ListBucketsInUse() []string {
}

func DestroyBucket(bucketName string) {

s3Client := s3.New(GetAWSSession())

log.Printf("Attempt to delete: %s", bucketName)
Expand All @@ -295,21 +291,16 @@ func DestroyBucket(bucketName string) {
log.Println("Bucket Error:", aerr.Error())
}
} else {
// Print the error, cast err to awserr.Error to get the Code and
// Message from an error.
log.Println(errHead.Error())
}
} else {
//if exist, we can delete it
_, err := s3Client.DeleteBucket(&s3.DeleteBucketInput{
Bucket: &bucketName,
})
if err != nil {
log.Panicf("failed to delete bucket "+bucketName, err.Error())
}

}

}

func GetAWSSession() *session.Session {
Expand All @@ -324,9 +315,13 @@ func GetAWSSession() *session.Session {

func DestroyBucketsInUse(destroyBuckets bool) {
if destroyBuckets {
log.Println("Execute: DestroyBucketsInUse")
log.Println("Confirmed: DestroyBucketsInUse")
for _, bucket := range ListBucketsInUse() {
DestroyBucket(bucket)
log.Printf("Deleting versions, objects and bucket: %s:", bucket)
err := DestroyBucketObjectsAndVersions(bucket, viper.GetString("aws.region"))
if err != nil {
log.Panic("Error deleting bucket/objects/version, the resources may have already been removed, please re-run without flag --destroy-buckets and check on console")
}
}
} else {
log.Println("Skip: DestroyBucketsInUse")
Expand Down Expand Up @@ -427,3 +422,105 @@ func DownloadBucket(bucket string, destFolder string) error {
}
return nil
}

func PutTagKubefirstOnBuckets(bucketName, clusterName string) {
log.Printf("tagging bucket... %s:%s", bucketName, clusterName)
svc := s3.New(session.New())
input := &s3.PutBucketTaggingInput{
Bucket: aws.String(bucketName),
Tagging: &s3.Tagging{
TagSet: []*s3.Tag{
{
Key: aws.String("Provisioned-by"),
Value: aws.String("Kubefirst"),
},
{
Key: aws.String("ClusterName"),
Value: aws.String(clusterName),
},
},
},
}

_, err := svc.PutBucketTagging(input)
if err != nil {
if aerr, ok := err.(awserr.Error); ok {
log.Println(aerr.Error())
} else {
log.Println(err.Error())
}
return
}
log.Printf("Bucket: %s tagged successfully", bucketName)
}

func DestroyBucketObjectsAndVersions(bucket, region string) error {
cfg, err := config.LoadDefaultConfig(context.TODO(), config.WithRegion(region))
if err != nil {
log.Printf("Failed to load config: %v", err)
return err
}

client := s3v2.NewFromConfig(cfg)

deleteObject := func(bucket, key, versionId *string) {
log.Printf("Object: %s/%s\n", *key, awsv2.ToString(versionId))
_, err := client.DeleteObject(context.TODO(), &s3v2.DeleteObjectInput{
Bucket: bucket,
Key: key,
VersionId: versionId,
})
if err != nil {
log.Printf("Failed to delete object: %v", err)
}
}

in := &s3v2.ListObjectsV2Input{Bucket: &bucket}
for {
out, err := client.ListObjectsV2(context.TODO(), in)
if err != nil {
log.Printf("Failed to list objects: %v", err)
return err
}

for _, item := range out.Contents {
deleteObject(&bucket, item.Key, nil)
}

if out.IsTruncated {
in.ContinuationToken = out.ContinuationToken
} else {
break
}
}

inVer := &s3v2.ListObjectVersionsInput{Bucket: &bucket}
for {
out, err := client.ListObjectVersions(context.TODO(), inVer)
if err != nil {
log.Printf("Failed to list version objects: %v", err)
return err
}

for _, item := range out.DeleteMarkers {
deleteObject(&bucket, item.Key, item.VersionId)
}

for _, item := range out.Versions {
deleteObject(&bucket, item.Key, item.VersionId)
}

if out.IsTruncated {
inVer.VersionIdMarker = out.NextVersionIdMarker
inVer.KeyMarker = out.NextKeyMarker
} else {
break
}
}

_, err = client.DeleteBucket(context.TODO(), &s3v2.DeleteBucketInput{Bucket: &bucket})
if err != nil {
log.Printf("Failed to delete bucket: %v", err)
}
return nil
}

0 comments on commit a1d4d6f

Please sign in to comment.