Skip to content

Commit

Permalink
Added a simple reservation status
Browse files Browse the repository at this point in the history
  • Loading branch information
omerh committed Oct 22, 2020
1 parent 8fa46ce commit 54f46d5
Show file tree
Hide file tree
Showing 5 changed files with 179 additions and 0 deletions.
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,12 @@ Delete old ECR images in a region or in all regions
awsctl delete ecr -r eu-west-2 --keep 20 --yes # This will keep 20 newest images for all repositories in the region
```

Get simple reservation status on all of your regions

```bash
awsctl get ri -r all
```

For any missing action please open an issue for a feature request.

### Contributing
Expand Down
1 change: 1 addition & 0 deletions cmd/awsctl/cmd/get.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,4 +30,5 @@ func init() {
getCmd.AddCommand(getRdsSnapshots)
getCmd.AddCommand(getAcmCertCmd)
getCmd.AddCommand(getCloudwatchAlarmCmd)
getCmd.AddCommand(getRiCmd)
}
57 changes: 57 additions & 0 deletions cmd/awsctl/cmd/get_ri.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package cmd

import (
"fmt"

"github.com/omerh/awsctl/pkg/helpers"
"github.com/spf13/cobra"
)

var (
getRiExample = `
# Get amazon resources
get ri --status active --region us-east-1
`
getRihort = ("Get AWS EC2 Reservation Details")
)

var getRiCmd = &cobra.Command{
Use: "ri",
Short: getRihort,
Example: getRiExample,
Run: func(cmd *cobra.Command, args []string) {
region, _ := cmd.Flags().GetString("region")

if region == "all" {
awsRegions, _ := helpers.GetAllAwsRegions()
for _, r := range awsRegions {
riSummary, ec2Summary := generateRIreport(r)
utilizationReport(riSummary, ec2Summary, r)
}
return
}

if region == "" {
region = helpers.GetDefaultAwsRegion()
}

riSummary, ec2Summary := generateRIreport(region)
utilizationReport(riSummary, ec2Summary, region)
},
}

func generateRIreport(region string) (map[string]int64, map[string]int64) {
riSummary := helpers.GetAllReservations(region, "active")
allEC2 := helpers.GetAllEC2Instances(region, "ondemand", "running")
ec2Summary := helpers.SummeriesEC2Instances(allEC2)
return riSummary, ec2Summary
}

func utilizationReport(ri map[string]int64, ec2 map[string]int64, region string) {
fmt.Printf("Reservation status in %v (Only for running instances)\n", region)
fmt.Println("=================================================================")
for instanceType, instanceCount := range ec2 {
fmt.Printf("- You have %v %v with a resevation of %v\n", instanceCount, instanceType, ri[instanceType])
}
fmt.Println()
}
73 changes: 73 additions & 0 deletions pkg/helpers/ec2.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,3 +71,76 @@ func printEc2Events(ec2evnets []Ec2Event, out string, region string) {
log.Println("==============================================")
}
}

// GetAllEC2Instances get all instances
func GetAllEC2Instances(region string, lifeCycle string, state string) []*ec2.Reservation {
awsSession, _ := InitAwsSession(region)
svc := ec2.New(awsSession)
var filter []*ec2.Filter

if state == "running" {
filter = []*ec2.Filter{
{
Name: aws.String("instance-state-name"),
Values: []*string{
aws.String("running"),
aws.String("pending"),
},
},
}
} else {
filter = []*ec2.Filter{
{
Name: aws.String("instance-state-name"),
Values: []*string{
aws.String("stopped"),
},
},
}
}

input := &ec2.DescribeInstancesInput{
Filters: filter,
}
result, _ := svc.DescribeInstances(input)
ec2Slice := result.Reservations

for result.NextToken != nil {
input := &ec2.DescribeInstancesInput{
NextToken: result.NextToken,
}
result, _ = svc.DescribeInstances(input)
for _, r := range result.Reservations {
ec2Slice = append(ec2Slice, r)
}
}

if lifeCycle == "all" {
return ec2Slice
}

var filteredEC2Slice []*ec2.Reservation
for _, i := range ec2Slice {
if lifeCycle == "spot" {
if i.Instances[0].InstanceLifecycle != nil {
filteredEC2Slice = append(filteredEC2Slice, i)
}
} else {
if i.Instances[0].InstanceLifecycle == nil {
filteredEC2Slice = append(filteredEC2Slice, i)
}
}
}

return filteredEC2Slice
}

// SummeriesEC2Instances summarieses into map instances by type and count them
func SummeriesEC2Instances(ec2Slice []*ec2.Reservation) map[string]int64 {
summary := make(map[string]int64, len(ec2Slice))
for _, i := range ec2Slice {
c := summary[*i.Instances[0].InstanceType]
summary[*i.Instances[0].InstanceType] = c + 1
}
return summary
}
42 changes: 42 additions & 0 deletions pkg/helpers/reservations.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package helpers

import (
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/ec2"
)

type riSummary struct {
instanceType string
instanceCount int
}

// GetAllReservations retrive all reservations
func GetAllReservations(region string, state string) map[string]int64 {
awsSession, _ := InitAwsSession(region)
svc := ec2.New(awsSession)
filter := []*ec2.Filter{
{
Name: aws.String("state"),
Values: []*string{
aws.String(state),
},
},
}

input := &ec2.DescribeReservedInstancesInput{
Filters: filter,
}

result, _ := svc.DescribeReservedInstances(input)
summaryResult := summeriesRI(result)
return summaryResult
}

func summeriesRI(ri *ec2.DescribeReservedInstancesOutput) map[string]int64 {
summary := make(map[string]int64, len(ri.ReservedInstances))
for _, r := range ri.ReservedInstances {
i := summary[*r.InstanceType]
summary[*r.InstanceType] = i + *r.InstanceCount
}
return summary
}

0 comments on commit 54f46d5

Please sign in to comment.