Skip to content
This repository was archived by the owner on Oct 10, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ Global Flags:

```
$ check_cloud_aws s3 bucket -C ~/.aws/credentials -w 100mb -c 200mb
OK - 2 Buckets: 0 Critical - 0 Warning - 2 Ok
OK - 2 Buckets: 0 Critical - 0 Warning - 2 OK
\_[OK] my-aws-test-bucket1 - value: 50MiB
\_[OK] my-aws-test-bucket2 - value: 20MiB | my-aws-test-bucket1=50MB;100;200 my-aws-test-bucket2=60MB;100;200
```
Expand Down Expand Up @@ -149,7 +149,7 @@ Global Flags:

````
$ check_cloud_aws s3 object -C ~/.aws/credentials --perfdata --prefix 'test'
OK - 2 Objects: 0 Critical - 0 Warning - 3 Ok
OK - 2 Objects: 0 Critical - 0 Warning - 3 OK
\_[y-aws-testbucket1]:
\_[OK] test-file4.txt: 20MiB
\_[y-aws-testbucket2]:
Expand Down
4 changes: 2 additions & 2 deletions cmd/ec2.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,11 @@ var ec2Cmd = &cobra.Command{
Run: Help,
}

func RequireEC2Client() *ec2.Client {
func RequireEC2Client() *ec2.EC2Client {
session, err := common.CreateSession(CredentialsFile, Profile, Region)
if err != nil {
check.ExitError(fmt.Errorf("could not setup AWS API session: %w", err))
}

return ec2.NewClient(session)
return ec2.NewEC2Client(session)
}
2 changes: 0 additions & 2 deletions cmd/s3.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,6 @@ import (
"github.com/spf13/cobra"
)

var BucketNames []string

var s3Cmd = &cobra.Command{
Use: "s3",
Short: "Checks in the S3 context",
Expand Down
36 changes: 28 additions & 8 deletions cmd/s3_buckets.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
package cmd

import (
"errors"
"fmt"
"github.com/NETWAYS/check_cloud_aws/internal"
b "github.com/NETWAYS/check_cloud_aws/internal/s3"
s3i "github.com/NETWAYS/check_cloud_aws/internal/s3"
"github.com/NETWAYS/go-check"
"github.com/NETWAYS/go-check/perfdata"
"github.com/NETWAYS/go-check/result"
Expand All @@ -15,22 +16,24 @@ import (
var (
CriticalBucketSize string
WarningBucketSize string
BucketNames []string
EmptyOK bool
)

var s3BucketCmd = &cobra.Command{
Use: "bucket",
Short: "Checks the size of a single bucket or multiple buckets",
Example: `
check_cloud_aws s3 bucket
OK - 1 Buckets: 0 Critical - 0 Warning - 1 Ok
OK - 1 Buckets: 0 Critical - 0 Warning - 1 OK
\_[OK] my-bucket - value: 100MiB | my-bucket=100MB;10240;20480

check_cloud_aws s3 bucket --crit-bucket-size 10
CRITICAL - 1 Buckets: 1 Critical - 0 Warning - 0 Ok
CRITICAL - 1 Buckets: 1 Critical - 0 Warning - 0 OK
\_[CRITICAL] my-bucket - value: 100MiB | my-bucket=100MB;10240;10

check_cloud_aws s3 bucket --crit-bucket-size 5GB
CRITICAL - 1 Buckets: 1 Critical - 0 Warning - 0 Ok
CRITICAL - 1 Buckets: 1 Critical - 0 Warning - 0 OK
\_[CRITICAL] my-bucket - value: 100MiB | my-bucket=100MB;10240;10`,
Run: func(cmd *cobra.Command, args []string) {
var (
Expand All @@ -46,23 +49,38 @@ var s3BucketCmd = &cobra.Command{
)

buckets := s3.ListBucketsOutput{}
objectsOutput := b.V2Output{}
objectsOutput := s3i.V2Output{}

client := RequireS3Client()

if BucketNames == nil {
// Load all buckets of if no buckets are speficied
if len(BucketNames) == 0 {
bk, err := client.LoadAllBuckets()
if err != nil {
check.ExitError(err)
}

buckets = *bk
} else {
// Load specific buckets
for _, bucketName := range BucketNames {
buckets.Buckets = append(buckets.Buckets, client.LoadBucketByName(bucketName))
b, err := client.LoadBucketByName(bucketName)
// Requested bucket does not exist, skip
if errors.Is(err, s3i.ErrBucketNotFound) {
continue
}
buckets.Buckets = append(buckets.Buckets, b)
}
}

if len(buckets.Buckets) == 0 && EmptyOK {
check.ExitRaw(check.OK, "No buckets available")
}

if len(buckets.Buckets) == 0 {
check.ExitError(fmt.Errorf("No buckets available"))
}

critical, err := internal.ParseThreshold(CriticalBucketSize)
if err != nil {
check.ExitError(err)
Expand Down Expand Up @@ -121,7 +139,7 @@ var s3BucketCmd = &cobra.Command{
perf.Add(&p)
}

summary += fmt.Sprintf("%d Buckets: %d Critical - %d Warning - %d Ok\n", len(buckets.Buckets), totalCrit, totalWarn, totalOk)
summary += fmt.Sprintf("%d Buckets: %d Critical - %d Warning - %d OK\n", len(buckets.Buckets), totalCrit, totalWarn, totalOk)

check.ExitRaw(result.WorstState(states...), summary+output, "|", perf.String())
},
Expand All @@ -139,6 +157,8 @@ func init() {
s3BucketFlags.StringVarP(&WarningBucketSize, "warn-bucket-size", "w", "10Gb",
"Warning threshold for the size of the specified bucket. Alerts if the size is greater than the warning threshold.\n"+
"Possible units are MB, GB or TB (defaults to MB if none is specified).")
s3BucketFlags.BoolVar(&EmptyOK, "empty-ok", false,
"Return OK if there are no buckets")

s3BucketFlags.SortFlags = false
}
50 changes: 36 additions & 14 deletions cmd/s3_objects.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
package cmd

import (
"errors"
"fmt"
"github.com/NETWAYS/check_cloud_aws/internal"
b "github.com/NETWAYS/check_cloud_aws/internal/s3"
s3i "github.com/NETWAYS/check_cloud_aws/internal/s3"
"github.com/NETWAYS/go-check"
"github.com/NETWAYS/go-check/perfdata"
"github.com/NETWAYS/go-check/result"
Expand All @@ -17,28 +18,32 @@ var (
WarningObjectSize string
ShowPerfdata bool
ObjectPrefix string
ObjectBucketNames []string
ObjectEmptyOK bool
)

var s3ObjectCmd = &cobra.Command{
Use: "object",
Short: "Checks the size of objects, stored in a single bucket or multiple buckets",
Example: `
check_cloud_aws s3 object
OK - 2 Objects: 0 Critical - 0 Warning - 2 Ok
OK - 2 Objects: 0 Critical - 0 Warning - 2 OK
\_[my-bucket]:
\_[OK] foo.fs: 100MiB
\_[OK] bar.fs: 100MiB

check_cloud_aws s3 object --prefix file
OK - 3 Objects: 0 Critical - 0 Warning - 3 Ok
OK - 3 Objects: 0 Critical - 0 Warning - 3 OK
\_[my-bucket]:
\_[OK] file_1.fs: 10MiB
\_[OK] file_2.fs: 20MiB
\_[OK] file_3.fs: 30MiB

check_cloud_aws s3 object --crit-object-size 10KB
CRITICAL - 1 Objects: 1 Critical - 0 Warning - 0 Ok
\_[my-bucket]:
check_cloud_aws s3 object --crit-object-size 10KB --buckets foo --buckets bar
CRITICAL - 2 Objects: 2 Critical - 0 Warning - 0 OK
\_[foo]:
\_[CRITICAL] file.fs: 100MiB
\_[bar]:
\_[CRITICAL] file.fs: 100MiB`,
Run: func(cmd *cobra.Command, args []string) {
var (
Expand All @@ -55,23 +60,38 @@ var s3ObjectCmd = &cobra.Command{
)

buckets := s3.ListBucketsOutput{}
objectsOutput := b.V2Output{}
objectsOutput := s3i.V2Output{}

client := RequireS3Client()

if BucketNames == nil {
// Load all buckets of if no buckets are speficied
if len(ObjectBucketNames) == 0 {
bk, err := client.LoadAllBuckets()
if err != nil {
check.ExitError(err)
}

buckets = *bk
} else {
for _, bucketName := range BucketNames {
buckets.Buckets = append(buckets.Buckets, client.LoadBucketByName(bucketName))
// Load specific buckets
for _, bucketName := range ObjectBucketNames {
b, err := client.LoadBucketByName(bucketName)
// Requested bucket does not exist, skip
if errors.Is(err, s3i.ErrBucketNotFound) {
continue
}
buckets.Buckets = append(buckets.Buckets, b)
}
}

if len(buckets.Buckets) == 0 && ObjectEmptyOK {
check.ExitRaw(check.OK, "No buckets available")
}

if len(buckets.Buckets) == 0 {
check.ExitError(fmt.Errorf("No buckets available"))
}

critical, err := internal.ParseThreshold(CriticalObjectSize)
if err != nil {
check.ExitError(err)
Expand Down Expand Up @@ -130,21 +150,21 @@ var s3ObjectCmd = &cobra.Command{
}
}

summary += fmt.Sprintf("%d Objects: %d Critical - %d Warning - %d Ok\n", totalObjects, totalCrit, totalWarn, totalOk)
summary += fmt.Sprintf("%d Objects: %d Critical - %d Warning - %d OK\n", totalObjects, totalCrit, totalWarn, totalOk)

if ShowPerfdata {
check.ExitRaw(result.WorstState(states...), summary+output, "|", perf.String())
} else {
check.ExitRaw(result.WorstState(states...), summary+output)
}

check.ExitRaw(result.WorstState(states...), summary+output)
},
}

func init() {
s3Cmd.AddCommand(s3ObjectCmd)

s3ObjectFlags := s3ObjectCmd.Flags()
s3ObjectFlags.StringSliceVarP(&BucketNames, "buckets", "b", nil,
s3ObjectFlags.StringSliceVarP(&ObjectBucketNames, "buckets", "b", nil,
"Name of one or multiple S3 buckets. If '--buckets' is empty, all buckets will be evaluated.")
s3ObjectFlags.StringVar(&ObjectPrefix, "prefix", "",
"Limits the response to keys that begin with the specified prefix, e.G. '--prefix test' filters all objects which starts with 'test'.\n"+
Expand All @@ -157,6 +177,8 @@ func init() {
"Possible units are MB, GB or TB (defaults to MB if none is specified).")
s3ObjectFlags.BoolVarP(&ShowPerfdata, "perfdata", "p", false,
"Displays perfdata and lists all objects in the specified bucket.")
s3ObjectFlags.BoolVar(&ObjectEmptyOK, "empty-ok", false,
"Return OK if there are no buckets")

s3ObjectFlags.SortFlags = false
}
16 changes: 14 additions & 2 deletions cmd/status.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,26 @@ package cmd
import (
"encoding/xml"
"fmt"
"github.com/NETWAYS/check_cloud_aws/internal/status"
"github.com/NETWAYS/go-check"
"github.com/spf13/cobra"
"net/http"
"net/url"
"strings"
)

type rss struct {
Channel struct {
Title string `xml:"title"`
Link string `xml:"link"`
Desc string `xml:"description"`
Items []item `xml:"item"`
} `xml:"channel"`
}

type item struct {
Title string `xml:"title"`
}

// To store the CLI parameters
type StatusConfig struct {
Url string
Expand Down Expand Up @@ -47,7 +59,7 @@ var statusCmd = &cobra.Command{
CRITICAL - WARNING - Information available for iam (Global)`,
Run: func(cmd *cobra.Command, args []string) {
var (
feed status.Rss
feed rss
rc int
output string
feedUrl string
Expand Down
26 changes: 13 additions & 13 deletions internal/ec2/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,25 +6,25 @@ import (
"github.com/aws/aws-sdk-go/service/ec2"
)

// Client implementation to offer various load functions for getting data from the API
type Client struct {
Client *ec2.EC2
// EC2Client implementation to offer various load functions for getting data from the API
type EC2Client struct {
EC2Client *ec2.EC2
}

// NewClient sets up a Client with a AWS session.Session
func NewClient(session *session.Session) *Client {
return &Client{ec2.New(session)}
func NewEC2Client(session *session.Session) *EC2Client {
return &EC2Client{ec2.New(session)}
}

// LoadInstance returns a single Instance looking for its id
func (c *Client) LoadInstance(id string) (instance *Instance, err error) {
func (c *EC2Client) LoadInstance(id string) (instance *Instance, err error) {
return c.LoadInstanceByFilter(DescribeInstancesInput(Filter("instance-id", id)))
}

// LoadInstanceByName returns a single Instance looking for a name
//
// Name is not required to be unique, but our interface expects it is.
func (c *Client) LoadInstanceByName(name string) (instance *Instance, err error) {
func (c *EC2Client) LoadInstanceByName(name string) (instance *Instance, err error) {
return c.LoadInstanceByFilter(DescribeInstancesInput(Filter("tag:Name", name)))
}

Expand All @@ -33,8 +33,8 @@ func (c *Client) LoadInstanceByName(name string) (instance *Instance, err error)
// The function expects the result to have exactly one match.
//
// Also see our Filter and DescribeInstancesInput
func (c *Client) LoadInstanceByFilter(filter *ec2.DescribeInstancesInput) (instance *Instance, err error) {
instances, err := c.Client.DescribeInstances(filter)
func (c *EC2Client) LoadInstanceByFilter(filter *ec2.DescribeInstancesInput) (instance *Instance, err error) {
instances, err := c.EC2Client.DescribeInstances(filter)

if err != nil {
err = fmt.Errorf("could not load instances: %w", err)
Expand Down Expand Up @@ -69,8 +69,8 @@ func (c *Client) LoadInstanceByFilter(filter *ec2.DescribeInstancesInput) (insta
}

// LoadInstanceStatus returns the ec2.Instance for an id
func (c *Client) LoadInstanceStatus(id string) (status *ec2.InstanceStatus, err error) {
d, err := c.Client.DescribeInstanceStatus(&ec2.DescribeInstanceStatusInput{
func (c *EC2Client) LoadInstanceStatus(id string) (status *ec2.InstanceStatus, err error) {
d, err := c.EC2Client.DescribeInstanceStatus(&ec2.DescribeInstanceStatusInput{
InstanceIds: []*string{&id},
})
if err != nil {
Expand All @@ -94,8 +94,8 @@ func (c *Client) LoadInstanceStatus(id string) (status *ec2.InstanceStatus, err
// LoadAllInstancesByFilter returns Instances with a list of Instance to work with
//
// Also see our Filter and DescribeInstancesInput
func (c *Client) LoadAllInstancesByFilter(filter *ec2.DescribeInstancesInput) (instances *Instances, err error) {
d, err := c.Client.DescribeInstances(filter)
func (c *EC2Client) LoadAllInstancesByFilter(filter *ec2.DescribeInstancesInput) (instances *Instances, err error) {
d, err := c.EC2Client.DescribeInstances(filter)
if err != nil {
err = fmt.Errorf("could not load instances: %w", err)
return nil, err
Expand Down
4 changes: 2 additions & 2 deletions internal/ec2/client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ import (
"testing"
)

func createTestClient() (*ec2.Client, func()) {
return ec2.NewClient(common.CreateTestSession(TestRegion)), enableMocking()
func createTestClient() (*ec2.EC2Client, func()) {
return ec2.NewEC2Client(common.CreateTestSession(TestRegion)), enableMocking()
}

func TestClient_LoadInstance(t *testing.T) {
Expand Down
Loading