Skip to content

Commit

Permalink
Initial implementation.
Browse files Browse the repository at this point in the history
Signed-off-by: viktor-kurchenko <[email protected]>
  • Loading branch information
viktor-kurchenko committed Mar 27, 2023
1 parent d2de2c2 commit cd6cbf9
Show file tree
Hide file tree
Showing 18 changed files with 708 additions and 2 deletions.
36 changes: 36 additions & 0 deletions .github/workflows/lint-build.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
name: Go Lint and Build

on:
push:
pull_request:

jobs:

lint:
name: Lint
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- name: Check out code
uses: actions/checkout@24cb9080177205b6e8c946b17badbe402adc938f # v3.4.0

- name: Lint
uses: reviewdog/action-golangci-lint@53f8eabb87b40b1a2c63ec75b0d418bd0f4aa919 # v2.2.2

build:
name: Build
runs-on: ubuntu-latest
timeout-minutes: 15
needs: [ lint ]
steps:
- name: Check out code
uses: actions/checkout@24cb9080177205b6e8c946b17badbe402adc938f # v3.4.0

- name: Install Go
uses: actions/setup-go@4d34df0c2316fe8122ab82dc22947d607c0c91f9 # v4.0.0
with:
go-version: 1.18.x
id: go

- name: Build tool
run: go build -v .
21 changes: 21 additions & 0 deletions .github/workflows/release.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
name: Release C7N helper

on:
release:
types: [created]

jobs:

release-linux-amd64:
name: release linux/amd64
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@24cb9080177205b6e8c946b17badbe402adc938f # v3.4.0
- uses: wangyoucao577/go-release-action@b98909985b9c1fd7b0aaa4c51257a7ba49995781 # v1.37
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
goos: linux
goarch: amd64
goversion: 1.18
binary_name: c7n-helper
extra_files: LICENSE README.md
18 changes: 18 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
SHELL := /bin/zsh

define PROJECT_HELP_MSG
Usage:
make help:\t show this message
make lint:\t run go linter
make compile:\t compile c7n-helper binary
endef
export PROJECT_HELP_MSG

help:
echo -e $$PROJECT_HELP_MSG

lint:
golangci-lint run

compile:
go build .
59 changes: 57 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,57 @@
# cloud-custodian-helper
Cloud Custodian helper tool.
# c7n-helper

The tool helps to work with Cloud Custodian generated reports.

## Installation

To install the latest `c7n-helper` release run:

```console
$ go install github.com/isovalent/cloud-custodian-helper@latest
```

## Lint

To lint `c7n-helper` sources please run the following locally:

```console
$ make lint
```

## Build

To build `c7n-helper` from source please run the following locally:

```console
$ make compile
```

## Usage

* Help:

```console
$ c7n-helper --help
```

* Parse C7N output directory into JSON file:

```console
$ c7n-helper parse -d <c7n-report-dir> -p <c7n-policy-name> -t <resource-type> -r <resource-file>
```

* Send Slack notification:

```console
$ c7n-helper slack -r <resource-file> -u <slack-webhook-url> -t "<message-title>"
```

* Clean resources:

```console
$ c7n-helper clean -r <resource-file>
```

## License

Apache-2.0
30 changes: 30 additions & 0 deletions cmd/clean.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package cmd

import (
"c7n-helper/pkg/cleaner"
"github.com/spf13/cobra"
"log"
)

var cleanCmd = &cobra.Command{
Use: "clean",
Short: "Clean all resources from resource file",
Aliases: []string{"c"},
Args: cobra.ExactArgs(0),
Run: clean,
}

var cleanFile *string

func init() {
cleanFile = cleanCmd.Flags().StringP("resource-file", "r", "", "Resource JSON file")
_ = cleanCmd.MarkFlagRequired("resource-file")
_ = cleanCmd.MarkFlagFilename("resource-file")
rootCmd.AddCommand(cleanCmd)
}

func clean(_ *cobra.Command, _ []string) {
if err := cleaner.Clean(*cleanFile); err != nil {
log.Fatal(err.Error())
}
}
36 changes: 36 additions & 0 deletions cmd/parser.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package cmd

import (
"c7n-helper/pkg/parser"
"github.com/spf13/cobra"
"log"
)

var parserCmd = &cobra.Command{
Use: "parse",
Short: "Parse C7N report directory and save result in resource JSON file",
Aliases: []string{"p"},
Args: cobra.ExactArgs(0),
Run: parse,
}

var parseType, parseDir, parsePolicy, parseResult *string

func init() {
parseType = parserCmd.Flags().StringP("type", "t", "", "Cloud resource type (eks, ec2, gke, gce)")
_ = parserCmd.MarkFlagRequired("type")
parseDir = parserCmd.Flags().StringP("report-dir", "d", "", "C7N report directory")
_ = parserCmd.MarkFlagRequired("report-dir")
_ = parserCmd.MarkFlagDirname("report-dir")
parsePolicy = parserCmd.Flags().StringP("policy", "p", "", "C7N policy name")
_ = parserCmd.MarkFlagRequired("policy")
parseResult = parserCmd.Flags().StringP("resource-file", "r", "resources.json", "Resource JSON file")
_ = parserCmd.MarkFlagFilename("resource-file")
rootCmd.AddCommand(parserCmd)
}

func parse(_ *cobra.Command, _ []string) {
if err := parser.Parse(*parseType, *parseDir, *parsePolicy, *parseResult); err != nil {
log.Fatal(err.Error())
}
}
19 changes: 19 additions & 0 deletions cmd/root.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package cmd

import (
"os"

"github.com/spf13/cobra"
)

var rootCmd = &cobra.Command{
Use: "c7n-helper",
Short: "Cloud Custodian helper tool",
}

func Execute() {
err := rootCmd.Execute()
if err != nil {
os.Exit(1)
}
}
32 changes: 32 additions & 0 deletions cmd/slack.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package cmd

import (
"c7n-helper/pkg/slack"
"github.com/spf13/cobra"
"log"
)

var slackCmd = &cobra.Command{
Use: "slack",
Short: "Send Slack notification (via webhook) with information from resource JSON file",
Aliases: []string{"s"},
Args: cobra.ExactArgs(0),
Run: notify,
}

var slackFile, slackURL, slackTitle *string

func init() {
slackFile = slackCmd.Flags().StringP("resource-file", "r", "resources.json", "Resource JSON file")
_ = slackCmd.MarkFlagFilename("resource-file")
slackURL = slackCmd.Flags().StringP("url", "u", "", "Slack webhook URL")
_ = slackCmd.MarkFlagRequired("url")
slackTitle = slackCmd.Flags().StringP("title", "t", "", "Slack notification title")
rootCmd.AddCommand(slackCmd)
}

func notify(_ *cobra.Command, _ []string) {
if err := slack.Notify(*slackFile, *slackURL, *slackTitle); err != nil {
log.Fatal(err.Error())
}
}
17 changes: 17 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
module c7n-helper

go 1.20

require (
github.com/lensesio/tableprinter v0.0.0-20201125135848-89e81fc956e7
github.com/spf13/cobra v1.6.1
)

require (
github.com/dustin/go-humanize v1.0.1 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/kataras/tablewriter v0.0.0-20180708051242-e063d29b7c23 // indirect
github.com/mattn/go-runewidth v0.0.14 // indirect
github.com/rivo/uniseg v0.2.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect
)
21 changes: 21 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
github.com/inconshreveable/mousetrap v1.0.1/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
github.com/kataras/tablewriter v0.0.0-20180708051242-e063d29b7c23 h1:M8exrBzuhWcU6aoHJlHWPe4qFjVKzkMGRal78f5jRRU=
github.com/kataras/tablewriter v0.0.0-20180708051242-e063d29b7c23/go.mod h1:kBSna6b0/RzsOcOZf515vAXwSsXYusl2U7SA0XP09yI=
github.com/lensesio/tableprinter v0.0.0-20201125135848-89e81fc956e7 h1:k/1ku0yehLCPqERCHkIHMDqDg1R02AcCScRuHbamU3s=
github.com/lensesio/tableprinter v0.0.0-20201125135848-89e81fc956e7/go.mod h1:YR/zYthNdWfO8+0IOyHDcIDBBBS2JMnYUIwSsnwmRqU=
github.com/mattn/go-runewidth v0.0.14 h1:+xnbZSEeDbOIg5/mE6JF0w6n9duR1l3/WmbinWVwUuU=
github.com/mattn/go-runewidth v0.0.14/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/spf13/cobra v1.6.1 h1:o94oiPyS4KD1mPy2fmcYYHHfCxLqYjJOhGsCHFZtEzA=
github.com/spf13/cobra v1.6.1/go.mod h1:IOw/AERYS7UzyrGinqmz6HLUo219MORXGxhbaJUqzrY=
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
7 changes: 7 additions & 0 deletions main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package main

import "c7n-helper/cmd"

func main() {
cmd.Execute()
}
22 changes: 22 additions & 0 deletions pkg/cleaner/cleaner.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package cleaner

import (
"c7n-helper/pkg/dto"
"log"
"strings"
)

func Clean(resourceFile string) error {
log.Println("Reading resource file...")
var report dto.PolicyReport
if err := report.ReadFromFile(resourceFile); err != nil {
return err
}
for _, account := range report.Accounts {
for region, resources := range account.RegionResources {
log.Printf("Cleaning %s [%d] in %s [%s] ...\n", strings.ToUpper(report.ResourceType), len(resources), account.Name, region)
//TODO: implement me
}
}
return nil
}
58 changes: 58 additions & 0 deletions pkg/cloud/aws.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package cloud

import (
"c7n-helper/pkg/converter"
"c7n-helper/pkg/dto"
"encoding/json"
"fmt"
"time"
)

type EKS struct {
Name string `converter:"name"`
CreatedAt time.Time `converter:"createdAt"`
}

type EC2 struct {
InstanceId string `converter:"InstanceId"`
LaunchTime time.Time `converter:"LaunchTime"`
InstanceType string `converter:"InstanceType"`
}

func EksFromFile(file string) ([]dto.Resource, error) {
content, err := converter.JsonToBytes(file)
if err != nil {
return nil, err
}
var clusters []EKS
if err := json.Unmarshal(content, &clusters); err != nil {
return nil, err
}
result := make([]dto.Resource, 0, len(clusters))
for _, cluster := range clusters {
result = append(result, dto.Resource{
Name: cluster.Name,
Created: cluster.CreatedAt,
})
}
return result, nil
}

func Ec2FromFile(file string) ([]dto.Resource, error) {
content, err := converter.JsonToBytes(file)
if err != nil {
return nil, err
}
var vms []EC2
if err := json.Unmarshal(content, &vms); err != nil {
return nil, err
}
result := make([]dto.Resource, 0, len(vms))
for _, ec2 := range vms {
result = append(result, dto.Resource{
Name: fmt.Sprintf("%s [%s]", ec2.InstanceId, ec2.InstanceType),
Created: ec2.LaunchTime,
})
}
return result, nil
}
Loading

0 comments on commit cd6cbf9

Please sign in to comment.