Skip to content

Commit

Permalink
Merge pull request #321 from flanksource/cloudwatch-support
Browse files Browse the repository at this point in the history
feat: add cloudwatch support
  • Loading branch information
moshloop authored Sep 10, 2021
2 parents 7618a69 + 7ebc0e2 commit 2d693d4
Show file tree
Hide file tree
Showing 11 changed files with 459 additions and 27 deletions.
4 changes: 4 additions & 0 deletions api/v1/canary_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ type CanarySpec struct {
EC2 []EC2Check `yaml:"ec2,omitempty" json:"ec2,omitempty"`
Prometheus []PrometheusCheck `yaml:"prometheus,omitempty" json:"prometheus,omitempty"`
MongoDB []MongoDBCheck `yaml:"mongodb,omitempty" json:"mongodb,omitempty"`
CloudWatch []CloudWatchCheck `yaml:"cloudwatch,omitempty" json:"cloudwatch,omitempty"`
// interval (in seconds) to run checks on
// Deprecated in favor of Schedule
Interval uint64 `yaml:"interval,omitempty" json:"interval,omitempty"`
Expand Down Expand Up @@ -144,6 +145,9 @@ func (spec CanarySpec) GetAllChecks() []external.Check {
for _, check := range spec.GCSBucket {
checks = append(checks, check)
}
for _, check := range spec.CloudWatch {
checks = append(checks, check)
}
return checks
}

Expand Down
53 changes: 53 additions & 0 deletions api/v1/checks.go
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,35 @@ func (c S3BucketCheck) GetType() string {
return "s3Bucket"
}

type CloudWatchCheck struct {
Description `yaml:",inline" json:",inline"`
AWSConnection `yaml:",inline" json:",inline"`
Templatable `yaml:",inline" json:",inline"`
Filter CloudWatchFilter `yaml:"filter,omitempty" json:"filter,omitempty"`
}

type CloudWatchFilter struct {
ActionPrefix *string `yaml:"actionPrefix,omitempty" json:"actionPrefix,omitempty"`
AlarmPrefix *string `yaml:"alarmPrefix,omitempty" json:"alarmPrefix,omitempty"`
Alarms []string `yaml:"alarms,omitempty" json:"alarms,omitempty"`
State string `yaml:"state,omitempty" json:"state,omitempty"`
}

func (c CloudWatchCheck) GetEndpoint() string {
endpoint := c.Region
if c.Filter.ActionPrefix != nil {
endpoint += "-" + *c.Filter.ActionPrefix
}
if c.Filter.AlarmPrefix != nil {
endpoint += "-" + *c.Filter.AlarmPrefix
}
return endpoint
}

func (c CloudWatchCheck) GetType() string {
return "cloudwatch"
}

type GCPConnection struct {
Endpoint string `yaml:"endpoint" json:"endpoint,omitempty"`
Credentials *kommons.EnvVar `yaml:"credentials" json:"credentials,omitempty"`
Expand Down Expand Up @@ -975,6 +1004,29 @@ type Smb struct {
SmbCheck `yaml:",inline" json:",inline"`
}

/*
This checks the cloudwatch for all the Active alarm and response with the reason
```yaml
cloudwatch:
- accessKey:
valueFrom:
secretKeyRef:
key: aws
name: access-key
secretKey:
valueFrom:
secretKeyRef:
key: aws
name: secrey-key
region: "us-east-1"
#skipTLSVerify: true
```
*/
type CloudWatch struct {
CloudWatchCheck `yaml:",inline" json:",inline"`
}

type EC2Check struct {
Description `yaml:",inline" json:",inline"`
AWSConnection `yaml:",inline" json:",inline"`
Expand Down Expand Up @@ -1021,4 +1073,5 @@ var AllChecks = []external.Check{
PrometheusCheck{},
GCSBucketCheck{},
MongoDBCheck{},
CloudWatchCheck{},
}
72 changes: 72 additions & 0 deletions api/v1/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions checks/checker.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ var All = []Checker{
&PrometheusChecker{},
&MongoDBChecker{},
&GCSBucketChecker{},
&CloudWatchChecker{},
NewPodChecker(),
NewNamespaceChecker(),
NewTCPChecker(),
Expand Down
68 changes: 68 additions & 0 deletions checks/cloudwatch.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
package checks

import (
"fmt"

"github.com/aws/aws-sdk-go-v2/service/cloudwatch"
"github.com/aws/aws-sdk-go-v2/service/cloudwatch/types"
"github.com/flanksource/canary-checker/api/context"
"github.com/flanksource/canary-checker/api/external"
v1 "github.com/flanksource/canary-checker/api/v1"
"github.com/flanksource/canary-checker/pkg"
awsUtil "github.com/flanksource/canary-checker/pkg/clients/aws"
)

type CloudWatchChecker struct {
}

// Run: Check every entry from config according to Checker interface
// Returns check result and metrics
func (c *CloudWatchChecker) Run(ctx *context.Context) []*pkg.CheckResult {
var results []*pkg.CheckResult
for _, conf := range ctx.Canary.Spec.CloudWatch {
results = append(results, c.Check(ctx, conf))
}
return results
}

// Type: returns checker type
func (c *CloudWatchChecker) Type() string {
return "cloudwatch"
}

func (c *CloudWatchChecker) Check(ctx *context.Context, extConfig external.Check) *pkg.CheckResult {
check := extConfig.(v1.CloudWatchCheck)
result := pkg.Success(check)
cfg, err := awsUtil.NewSession(ctx, check.AWSConnection)
if err != nil {
return result.ErrorMessage(err)
}
client := cloudwatch.NewFromConfig(*cfg)
maxRecords := int32(100)
alarms, err := client.DescribeAlarms(ctx, &cloudwatch.DescribeAlarmsInput{
AlarmNames: check.Filter.Alarms,
AlarmNamePrefix: check.Filter.AlarmPrefix,
ActionPrefix: check.Filter.ActionPrefix,
StateValue: types.StateValue(check.Filter.State),
MaxRecords: &maxRecords,
})
if err != nil {
return result.ErrorMessage(err)
}
result.AddDetails(alarms)
message := ""
for _, alarm := range alarms.MetricAlarms {
if alarm.StateValue == types.StateValueAlarm {
message += fmt.Sprintf("alarm '%s': is in %s state Reason: %s ReasonData: %s\n", *alarm.AlarmName, alarm.StateValue, *alarm.StateReason, *alarm.StateReasonData)
}
}
for _, alarm := range alarms.CompositeAlarms {
if alarm.StateValue == types.StateValueAlarm {
message += fmt.Sprintf("alarm '%s': is in %s state Reason: %s ReasonData: %s\n", *alarm.AlarmName, alarm.StateValue, *alarm.StateReason, *alarm.StateReasonData)
}
}
if message != "" {
return result.Failf(message)
}
return result
}
24 changes: 1 addition & 23 deletions checks/s3_bucket.go
Original file line number Diff line number Diff line change
@@ -1,17 +1,14 @@
package checks

import (
"crypto/tls"
"fmt"
"io/fs"
"net/http"
"strings"
"time"

"github.com/aws/aws-sdk-go-v2/service/s3/types"
"github.com/flanksource/canary-checker/api/context"
"github.com/flanksource/commons/logger"
"github.com/henvic/httpretty"

"github.com/aws/aws-sdk-go-v2/aws"
"github.com/aws/aws-sdk-go-v2/service/s3"
Expand Down Expand Up @@ -150,26 +147,7 @@ func (c *S3BucketChecker) Check(ctx *context.Context, extConfig external.Check)
bucket := extConfig.(v1.S3BucketCheck)
result := pkg.Success(bucket)

var tr http.RoundTripper
tr = &http.Transport{
TLSClientConfig: &tls.Config{InsecureSkipVerify: bucket.AWSConnection.SkipTLSVerify},
}

if ctx.IsTrace() {
logger := &httpretty.Logger{
Time: true,
TLS: true,
RequestHeader: true,
RequestBody: true,
ResponseHeader: true,
ResponseBody: true,
Colors: true, // erase line if you don't like colors
Formatters: []httpretty.Formatter{&httpretty.JSONFormatter{}},
}
tr = logger.RoundTripper(tr)
}

cfg, err := awsUtil.NewSession(ctx, bucket.AWSConnection, tr)
cfg, err := awsUtil.NewSession(ctx, bucket.AWSConnection)
if err != nil {
return result.ErrorMessage(err)
}
Expand Down
Loading

0 comments on commit 2d693d4

Please sign in to comment.