-
-
Notifications
You must be signed in to change notification settings - Fork 18
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add support for tagging EBS volumes (#199)
- Loading branch information
Showing
5 changed files
with
278 additions
and
0 deletions.
There are no files selected for viewing
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -8,6 +8,7 @@ | |
*.dll | ||
*.so | ||
*.dylib | ||
awstaghelper | ||
|
||
# Test binary, built with `go test -c` | ||
*.test | ||
|
This file contains 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
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
/* | ||
Copyright © 2023 Cristian Magherusan-Stanciu [email protected] | ||
Copyright © 2020 Maksym Postument [email protected] | ||
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 cmd is the package for the CLI of awstaghelper | ||
package cmd | ||
|
||
import ( | ||
"github.com/aws/aws-sdk-go/service/ec2" | ||
"github.com/mpostument/awstaghelper/pkg" | ||
|
||
"github.com/spf13/cobra" | ||
) | ||
|
||
// ebsCmd represents the ebs command | ||
var ebsCmd = &cobra.Command{ | ||
Use: "ebs", | ||
Short: "Root command for interaction with AWS EBS volumes", | ||
Long: `Root command for interaction with AWS EBS volumes,`, | ||
} | ||
|
||
var getEBSVolumeCmd = &cobra.Command{ | ||
Use: "get-ebs-tags", | ||
Short: "Write EBS volume IDs and required tags to CSV", | ||
Long: `Write to csv data with EBS volume IDs and required tags to CSV. This CSV can be used with tag-ebs command to tag AWS environment. Specify list of tags which should be read using tags flag: --tags Name,Env,Project. Csv filename can be specified with flag filename.`, | ||
Run: func(cmd *cobra.Command, args []string) { | ||
tags, _ := cmd.Flags().GetString("tags") | ||
filename, _ := cmd.Flags().GetString("filename") | ||
profile, _ := cmd.Flags().GetString("profile") | ||
region, _ := cmd.Flags().GetString("region") | ||
sess := pkg.GetSession(region, profile) | ||
client := ec2.New(sess) | ||
pkg.WriteCsv(pkg.ParseEBSVolumeTags(tags, client), filename) | ||
}, | ||
} | ||
|
||
var tagEBSVolumeCmd = &cobra.Command{ | ||
Use: "tag-ebs", | ||
Short: "Read CSV and tag EBS volumes with CSV data", | ||
Long: `Read CSV generated with get-ebs-tags command and tag EBS volumes with tags from CSV.`, | ||
Run: func(cmd *cobra.Command, args []string) { | ||
filename, _ := cmd.Flags().GetString("filename") | ||
profile, _ := cmd.Flags().GetString("profile") | ||
region, _ := cmd.Flags().GetString("region") | ||
sess := pkg.GetSession(region, profile) | ||
csvData := pkg.ReadCsv(filename) | ||
client := ec2.New(sess) | ||
pkg.TagEBSVolumes(csvData, client) | ||
}, | ||
} | ||
|
||
func init() { | ||
rootCmd.AddCommand(ebsCmd) | ||
ebsCmd.AddCommand(getEBSVolumeCmd) | ||
ebsCmd.AddCommand(tagEBSVolumeCmd) | ||
} |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,82 @@ | ||
/* | ||
Copyright © 2023 Cristian Magherusan-Stanciu [email protected] | ||
Copyright © 2020 Maksym Postument [email protected] | ||
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 pkg | ||
|
||
import ( | ||
"log" | ||
|
||
"github.com/aws/aws-sdk-go/aws" | ||
"github.com/aws/aws-sdk-go/service/ec2" | ||
"github.com/aws/aws-sdk-go/service/ec2/ec2iface" | ||
) | ||
|
||
// getEBSVolumes returns all EBS volumes from specified region | ||
func getEBSVolumes(client ec2iface.EC2API) []*ec2.Volume { | ||
input := &ec2.DescribeVolumesInput{} | ||
|
||
var result []*ec2.Volume | ||
|
||
err := client.DescribeVolumesPages(input, | ||
func(page *ec2.DescribeVolumesOutput, lastPage bool) bool { | ||
result = append(result, page.Volumes...) | ||
return !lastPage | ||
}) | ||
if err != nil { | ||
log.Fatal("Not able to get EBS volumes ", err) | ||
} | ||
return result | ||
} | ||
|
||
// ParseEBSVolumeTags parse output from getEBSVolumes and return volume ID and specified tags. | ||
func ParseEBSVolumeTags(tagsToRead string, client ec2iface.EC2API) [][]string { | ||
volumesOutput := getEBSVolumes(client) | ||
rows := addHeadersToCsv(tagsToRead, "VolumeId") | ||
for _, volume := range volumesOutput { | ||
tags := map[string]string{} | ||
for _, tag := range volume.Tags { | ||
tags[*tag.Key] = *tag.Value | ||
} | ||
rows = addTagsToCsv(tagsToRead, tags, rows, *volume.VolumeId) | ||
} | ||
return rows | ||
} | ||
|
||
// TagEBSVolumes tag EBS volumes. Take as input data from csv file. Where first column is volume ID. | ||
func TagEBSVolumes(csvData [][]string, client ec2iface.EC2API) { | ||
for r := 1; r < len(csvData); r++ { | ||
var tags []*ec2.Tag | ||
for c := 1; c < len(csvData[0]); c++ { | ||
tags = append(tags, &ec2.Tag{ | ||
Key: &csvData[0][c], | ||
Value: &csvData[r][c], | ||
}) | ||
} | ||
|
||
input := &ec2.CreateTagsInput{ | ||
Resources: []*string{ | ||
aws.String(csvData[r][0]), | ||
}, | ||
Tags: tags, | ||
} | ||
|
||
_, err := client.CreateTags(input) | ||
if awsErrorHandle(err) { | ||
return | ||
} | ||
} | ||
} |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,108 @@ | ||
/* | ||
Copyright © 2023 Cristian Magherusan-Stanciu [email protected] | ||
Copyright © 2020 Maksym Postument [email protected] | ||
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 pkg | ||
|
||
import ( | ||
"testing" | ||
|
||
"github.com/aws/aws-sdk-go/aws" | ||
"github.com/aws/aws-sdk-go/service/ec2" | ||
"github.com/aws/aws-sdk-go/service/ec2/ec2iface" | ||
"github.com/stretchr/testify/assert" | ||
) | ||
|
||
type mockedEBS struct { | ||
ec2iface.EC2API | ||
respDescribeVolumes ec2.DescribeVolumesOutput | ||
} | ||
|
||
// AWS Mocks | ||
func (m *mockedEBS) DescribeVolumesPages(input *ec2.DescribeVolumesInput, | ||
pageFunc func(*ec2.DescribeVolumesOutput, bool) bool) error { | ||
pageFunc(&m.respDescribeVolumes, true) | ||
return nil | ||
} | ||
|
||
var ParseEBSVolumeTagsResponse = ec2.DescribeVolumesOutput{ | ||
Volumes: []*ec2.Volume{ | ||
{ | ||
VolumeId: aws.String("vol-1"), | ||
Tags: []*ec2.Tag{ | ||
{ | ||
Key: aws.String("Name"), | ||
Value: aws.String("Volume1"), | ||
}, | ||
{ | ||
Key: aws.String("Environment"), | ||
Value: aws.String("Test"), | ||
}, | ||
}, | ||
}, | ||
{ | ||
VolumeId: aws.String("vol-2"), | ||
Tags: []*ec2.Tag{ | ||
{ | ||
Key: aws.String("Name"), | ||
Value: aws.String("Volume2"), | ||
}, | ||
{ | ||
Key: aws.String("Environment"), | ||
Value: aws.String("Dev"), | ||
}, | ||
}, | ||
}, | ||
}, | ||
} | ||
|
||
func Test_getEBSVolumes(t *testing.T) { | ||
cases := []*mockedEBS{ | ||
{ | ||
respDescribeVolumes: ParseEBSVolumeTagsResponse, | ||
}, | ||
} | ||
|
||
expectedResult := ParseEBSVolumeTagsResponse.Volumes | ||
for _, c := range cases { | ||
t.Run("getEBSVolumes", func(t *testing.T) { | ||
result := getEBSVolumes(c) | ||
assertions := assert.New(t) | ||
assertions.EqualValues(expectedResult, result) | ||
}) | ||
|
||
} | ||
} | ||
|
||
func TestParseEBSVolumeTags(t *testing.T) { | ||
cases := []*mockedEBS{ | ||
{ | ||
respDescribeVolumes: ParseEBSVolumeTagsResponse, | ||
}, | ||
} | ||
expectedResult := [][]string{ | ||
{"VolumeId", "Name", "Environment"}, | ||
{"vol-1", "Volume1", "Test"}, | ||
{"vol-2", "Volume2", "Dev"}, | ||
} | ||
for _, c := range cases { | ||
t.Run("ParseEBSVolumeTags", func(t *testing.T) { | ||
result := ParseEBSVolumeTags("Name,Environment", c) | ||
assertions := assert.New(t) | ||
assertions.EqualValues(expectedResult, result) | ||
}) | ||
} | ||
} |