Created
October 17, 2015 17:37
-
-
Save kszarek/e5cc7a95521741951f36 to your computer and use it in GitHub Desktop.
ec2-snapshot-copy.go
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| package main | |
| import ( | |
| "flag" | |
| "fmt" | |
| "os" | |
| "regexp" | |
| "time" | |
| "github.com/aws/aws-sdk-go/aws" | |
| "github.com/aws/aws-sdk-go/aws/awserr" | |
| "github.com/aws/aws-sdk-go/service/ec2" | |
| ) | |
| var ( | |
| Version string | |
| BuildTime string | |
| GitCommit string | |
| ) | |
| // got it from aws console | |
| var awsOwnerID = "763925042285" | |
| // regexp for snapshots from AMI | |
| // we don't need to copy those between regions | |
| var amiRegexp = regexp.MustCompile("^(Created by CreateImage)") | |
| var sourceAwsRegion string | |
| var destinationAwsRegion string | |
| type Tag struct { | |
| Key string | |
| Value string | |
| } | |
| type Snapshot struct { | |
| Id string | |
| Desc string | |
| Tags []*ec2.Tag | |
| } | |
| type AwsRegion struct { | |
| src string | |
| dest string | |
| } | |
| func createTag(svc *ec2.EC2, resouceID string, tags []*ec2.Tag) error { | |
| params := &ec2.CreateTagsInput{ | |
| Resources: []*string{ | |
| aws.String(resouceID), | |
| }, | |
| Tags: tags, | |
| DryRun: aws.Bool(false), | |
| } | |
| // returns {} if successfully | |
| _, err := svc.CreateTags(params) | |
| if err != nil { | |
| // Print the error, cast err to awserr.Error to get the Code and | |
| // Message from an error. | |
| fmt.Fprintln(os.Stderr, err.Error()) | |
| return err | |
| } | |
| fmt.Println("Create Tag", tags, "for", resouceID) | |
| return nil | |
| } | |
| func findSnapshotsToCopy(svc *ec2.EC2) ([]Snapshot, error) { | |
| var snapshotsToCopy []Snapshot | |
| params := &ec2.DescribeSnapshotsInput{ | |
| OwnerIds: []*string{ | |
| aws.String(awsOwnerID), | |
| }, | |
| // Filters: []*ec2.Filter{ | |
| // &ec2.Filter{ | |
| // Name: aws.String("tag:test"), | |
| // Values: []*string{ | |
| // aws.String("true"), | |
| // }, | |
| // }, | |
| // }, | |
| } | |
| resp, err := svc.DescribeSnapshots(params) | |
| if err != nil { | |
| // Print the error, cast err to awserr.Error to get the Code and | |
| // Message from an error. | |
| fmt.Fprintln(os.Stderr, err.Error()) | |
| return snapshotsToCopy, err | |
| } | |
| if len(resp.Snapshots) == 0 { | |
| fmt.Fprintln(os.Stderr, "No snapshots were found") | |
| return snapshotsToCopy, nil | |
| } | |
| // go through all snapshots that we owns on given region | |
| for _, snap := range resp.Snapshots { | |
| // fmt.Println() | |
| // skip snapshots older then 1 day | |
| dayBefore := time.Now().AddDate(0, 0, -1) | |
| if snap.StartTime.Before(dayBefore) { | |
| fmt.Println("Skip old snapshot", *snap.SnapshotId, *snap.Description) | |
| continue | |
| } | |
| // skip snapshots from AMI | |
| m := amiRegexp.FindStringSubmatch(*snap.Description) | |
| doCopy := true | |
| if m == nil { | |
| fmt.Println("Checking tags for", *snap.SnapshotId) | |
| // checks snapshot tags | |
| for _, t := range snap.Tags { | |
| if *t.Key == "RegionCopy" { | |
| fmt.Println(*snap.SnapshotId, "has been already copied to another region") | |
| doCopy = false | |
| break | |
| } | |
| if *t.Key == "OS_Version" { | |
| fmt.Println(*snap.SnapshotId, "is AMI snapshot") | |
| doCopy = false | |
| break | |
| } | |
| } | |
| if doCopy { | |
| fmt.Println("Will copy:", *snap.SnapshotId, *snap.Description) | |
| snapshotsToCopy = append(snapshotsToCopy, Snapshot{Id: *snap.SnapshotId, Desc: *snap.Description, Tags: snap.Tags}) | |
| } | |
| } | |
| } | |
| return snapshotsToCopy, nil | |
| } | |
| func copySnapshot(a AwsRegion, snapshotID string, snapshotDescription string) (*ec2.CopySnapshotOutput, error) { | |
| newDescription := "[Copied " + snapshotID + " from " + a.src + " ] " + snapshotDescription | |
| fmt.Println("Copy snapshot id: " + snapshotID) | |
| // make connection to destination region | |
| svc := ec2.New(&aws.Config{Region: aws.String(a.dest)}) | |
| params := &ec2.CopySnapshotInput{ | |
| SourceRegion: aws.String(a.src), // Required | |
| SourceSnapshotId: aws.String(snapshotID), // Required | |
| Description: aws.String(newDescription), | |
| DestinationRegion: aws.String(a.dest), | |
| DryRun: aws.Bool(false), | |
| } | |
| resp, err := svc.CopySnapshot(params) | |
| if err != nil { | |
| return nil, err | |
| } | |
| // Pretty-print the response data. | |
| fmt.Println("Copy snapshot", resp) | |
| return resp, nil | |
| } | |
| func main() { | |
| // source aws region | |
| sourceAwsRegion = *flag.String("src", "us-east-1", "Source AWS Region") | |
| // destination aws region | |
| destinationAwsRegion := *flag.String("dest", "us-west-2", "Destination AWS Region") | |
| // version | |
| cli_version := flag.Bool("version", false, "Show version") | |
| cli_help := flag.Bool("help", false, "Show help") | |
| flag.Parse() | |
| if *cli_version { | |
| fmt.Println("Application version:", Version) | |
| fmt.Println("UTC Build Time:", BuildTime) | |
| fmt.Println("Git Commit Hash:", GitCommit) | |
| os.Exit(0) | |
| } | |
| if *cli_help { | |
| fmt.Println("Usage: ec2-snapshot-copy -src REGION -dest REGION") | |
| os.Exit(0) | |
| } | |
| a := &AwsRegion{src: sourceAwsRegion, dest: destinationAwsRegion} | |
| // make connection to AWS API | |
| svc := ec2.New(&aws.Config{Region: aws.String(a.src)}) | |
| dest_svc := ec2.New(&aws.Config{Region: aws.String(a.dest)}) | |
| snapshotsToCopy, err := findSnapshotsToCopy(svc) | |
| if err != nil { | |
| panic(err) | |
| } | |
| fmt.Println("Snapshot list to copy", snapshotsToCopy) | |
| for _, snapshot := range snapshotsToCopy { | |
| resp, err := copySnapshot(*a, snapshot.Id, snapshot.Desc) | |
| if err != nil { | |
| if ec2err := err.(awserr.Error); ec2err != nil { | |
| // A service error occurred. | |
| fmt.Println("Error:", ec2err.Code(), ec2err.Message()) | |
| if ec2err.Code() == "ResourceLimitExceeded" { | |
| fmt.Println("Too many snapshot copies in progress. Exit") | |
| os.Exit(0) | |
| } else { | |
| panic(ec2err) | |
| } | |
| } else { | |
| // A non-service error occurred. | |
| panic(err) | |
| } | |
| } else { | |
| var tag ec2.Tag | |
| tag.Key = aws.String("RegionCopy") | |
| tag.Value = aws.String("true") | |
| tags := []*ec2.Tag{&tag} | |
| // Tag{Key: "RegionCopy", Value: "true"} | |
| createTag(svc, snapshot.Id, tags) | |
| if err != nil { | |
| panic(err) | |
| } | |
| createTag(dest_svc, *resp.SnapshotId, snapshot.Tags) | |
| if err != nil { | |
| panic(err) | |
| } | |
| } | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment