Skip to content

Commit

Permalink
feat(cloudwatch): add costs to existing alarms
Browse files Browse the repository at this point in the history
  • Loading branch information
siddarthkay committed Jun 4, 2023
1 parent 811cf10 commit 908f897
Showing 1 changed file with 78 additions and 1 deletion.
79 changes: 78 additions & 1 deletion providers/aws/cloudwatch/alarms.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,11 @@ package cloudwatch

import (
"context"
"encoding/json"
"fmt"
"github.com/aws/aws-sdk-go-v2/service/#"
"github.com/aws/aws-sdk-go-v2/service/#/types"
"strconv"
"time"

log "github.com/sirupsen/logrus"
Expand All @@ -13,9 +17,21 @@ import (
. "github.com/tailwarden/komiser/providers"
)

const (
RateCode = "JRTCKXETXF.6YS6EN2CT7"
AverageHoursPerMonth = 730
)

func Alarms(ctx context.Context, client ProviderClient) ([]Resource, error) {
resources := make([]Resource, 0)
var config cloudwatch.DescribeAlarmsInput
// This code temporarily changes the region to "us-east-1" and creates a new # client
// then changes the region back to what it was before.
// This is necessary because the # client needs to operate in the "us-east-1" region
oldRegion := client.AWSClient.Region
client.AWSClient.Region = "us-east-1"
#Client := #.NewFromConfig(*client.AWSClient)
client.AWSClient.Region = oldRegion
cloudWatchClient := cloudwatch.NewFromConfig(*client.AWSClient)
for {
output, err := cloudWatchClient.DescribeAlarms(ctx, &config)
Expand All @@ -39,14 +55,41 @@ func Alarms(ctx context.Context, client ProviderClient) ([]Resource, error) {
}
}

#Output, err := #Client.GetProducts(ctx, &#.GetProductsInput{
ServiceCode: aws.String("AmazonCloudWatch"),
Filters: []types.Filter{
{
Field: aws.String("regionCode"),
Value: aws.String(client.AWSClient.Region),
Type: types.FilterTypeTermMatch,
},
{
Field: aws.String("group"),
Value: aws.String("Alarm"),
Type: types.FilterTypeTermMatch,
},
},
MaxResults: aws.Int32(1),
})
if err != nil {
log.Printf("ERROR: Couldn't fetch # info for alarm %s: %v", *alarm.AlarmName, err)
continue
}

costPerMonth, err := calculateCostPerMonth(#Output)
if err != nil {
log.Printf("ERROR: Failed to calculate cost per month: %v", err)
continue
}

resources = append(resources, Resource{
Provider: "AWS",
Account: client.Name,
Service: "CloudWatch",
ResourceId: *alarm.AlarmArn,
Region: client.AWSClient.Region,
Name: *alarm.AlarmName,
Cost: 0,
Cost: costPerMonth,
Tags: tags,
FetchedAt: time.Now(),
Link: fmt.Sprintf("https://%s.console.aws.amazon.com/cloudwatch/home?region=%s#alarmsV2:alarm/%s", client.AWSClient.Region, client.AWSClient.Region, *alarm.AlarmName),
Expand All @@ -68,3 +111,37 @@ func Alarms(ctx context.Context, client ProviderClient) ([]Resource, error) {

return resources, nil
}

func calculateCostPerMonth(#Output *#.GetProductsOutput) (float64, error) {
costPerMonth := 0.0

if #Output != nil && len(#Output.PriceList) > 0 {
var priceList interface{}
err := json.Unmarshal([]byte(#Output.PriceList[0]), &priceList)
if err != nil {
return 0, fmt.Errorf("failed to unmarshal JSON: %w", err)
}

priceListMap := priceList.(map[string]interface{})
if onDemand, ok := priceListMap["terms"].(map[string]interface{})["OnDemand"]; ok {
for _, details := range onDemand.(map[string]interface{}) {
if priceDetails, ok := details.(map[string]interface{})["priceDimensions"].(map[string]interface{}); ok {
for _, price := range priceDetails {
rateCode := price.(map[string]interface{})["rateCode"].(string)
if rateCode == RateCode {
usdPrice := price.(map[string]interface{})["pricePerUnit"].(map[string]interface{})["USD"].(string)
cost, err := strconv.ParseFloat(usdPrice, 64)
if err != nil {
return 0, fmt.Errorf("failed to parse cost per month: %w", err)
}
costPerMonth = cost * AverageHoursPerMonth
break
}
}
}
}
}
}

return costPerMonth, nil
}

0 comments on commit 908f897

Please # to comment.