Skip to content

Commit 2f4a6b3

Browse files
committed
Initial commit
1 parent 1cdbc96 commit 2f4a6b3

File tree

18 files changed

+1053
-0
lines changed

18 files changed

+1053
-0
lines changed

README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,5 @@
11
# ibmcloud-nuke
22
Delete the resource in the IBM Cloud account
3+
4+
5+
> Note: This is still in alpha phase and not ready for the production usage, not responsible for any data loss.

cmd/root.go

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
package cmd
2+
3+
import (
4+
"fmt"
5+
"github.com/mkumatag/ibmcloud-nuke/internal/app"
6+
"github.com/spf13/cobra"
7+
)
8+
9+
func NewRootCommand() *cobra.Command {
10+
command := &cobra.Command{
11+
Use: "ibmcloud-nuke",
12+
Short: "ibmcloud-nuke removes the mentioned resource from IBM Cloud",
13+
Long: `Tool which removes the specified resource from the IBM Cloud account based on the filters`,
14+
SilenceUsage: true,
15+
}
16+
17+
command.RunE = func(cmd *cobra.Command, args []string) error {
18+
if len(args) != 1 {
19+
return fmt.Errorf("only one argument is expected which is a config file name but provided: %s", args)
20+
}
21+
return app.Run(args[0])
22+
}
23+
return command
24+
}

go.mod

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
module github.com/mkumatag/ibmcloud-nuke
2+
3+
go 1.18
4+
5+
require (
6+
github.com/IBM/go-sdk-core/v5 v5.10.1
7+
github.com/IBM/vpc-go-sdk v0.20.0
8+
github.com/spf13/cobra v1.4.0
9+
gopkg.in/yaml.v2 v2.4.0
10+
k8s.io/apimachinery v0.24.1
11+
)
12+
13+
require (
14+
github.com/asaskevich/govalidator v0.0.0-20200907205600-7a23bdc65eef // indirect
15+
github.com/go-logr/logr v1.2.0 // indirect
16+
github.com/go-openapi/errors v0.19.8 // indirect
17+
github.com/go-openapi/strfmt v0.21.2 // indirect
18+
github.com/go-playground/locales v0.14.0 // indirect
19+
github.com/go-playground/universal-translator v0.18.0 // indirect
20+
github.com/go-stack/stack v1.8.0 // indirect
21+
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
22+
github.com/hashicorp/go-retryablehttp v0.7.1 // indirect
23+
github.com/inconshreveable/mousetrap v1.0.0 // indirect
24+
github.com/leodido/go-urn v1.2.1 // indirect
25+
github.com/mitchellh/mapstructure v1.3.3 // indirect
26+
github.com/oklog/ulid v1.3.1 // indirect
27+
github.com/spf13/pflag v1.0.5 // indirect
28+
go.mongodb.org/mongo-driver v1.7.5 // indirect
29+
gopkg.in/go-playground/validator.v9 v9.31.0 // indirect
30+
k8s.io/klog/v2 v2.60.1 // indirect
31+
k8s.io/utils v0.0.0-20220210201930-3a6ce19ff2f9 // indirect
32+
)

go.sum

Lines changed: 311 additions & 0 deletions
Large diffs are not rendered by default.

internal/app/nuke.go

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
package app
2+
3+
import (
4+
"github.com/mkumatag/ibmcloud-nuke/internal/pkg"
5+
"github.com/mkumatag/ibmcloud-nuke/internal/resources"
6+
"gopkg.in/yaml.v2"
7+
"os"
8+
)
9+
10+
func Run(config string) error {
11+
content, err := os.ReadFile(config)
12+
if err != nil {
13+
return err
14+
}
15+
conf := &pkg.Config{}
16+
if err := yaml.Unmarshal(content, conf); err != nil {
17+
return err
18+
}
19+
//spew.Dump(conf)
20+
for _, r := range conf.Resources {
21+
for _, f := range resources.ResourceFuncs {
22+
n, err := f(*conf, r)
23+
if err != nil {
24+
return err
25+
}
26+
if err := n.NukeIt(); err != nil {
27+
return err
28+
}
29+
}
30+
31+
}
32+
return nil
33+
}

internal/app/resources.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
package app
2+
3+
import (
4+
_ "github.com/mkumatag/ibmcloud-nuke/internal/resources/vpc"
5+
)

internal/pkg/authenticator.go

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
package pkg
2+
3+
import (
4+
"fmt"
5+
"os"
6+
7+
"github.com/IBM/go-sdk-core/v5/core"
8+
)
9+
10+
const (
11+
// APIKeyEnv is environment which contains the IBMCloud API Key
12+
APIKeyEnv = "IBMCLOUD_API_KEY"
13+
)
14+
15+
// GetAuthenticator Returns an authenticator for IBM Cloud
16+
func GetAuthenticator() (core.Authenticator, error) {
17+
apiKey := os.Getenv(APIKeyEnv)
18+
if apiKey == "" {
19+
return nil, fmt.Errorf("please set %s environment, it cannot be empty", APIKeyEnv)
20+
}
21+
22+
auth := &core.IamAuthenticator{
23+
ApiKey: apiKey,
24+
}
25+
return auth, nil
26+
}

internal/pkg/errors.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
package pkg
2+
3+
import "fmt"
4+
5+
var (
6+
ErrorResourceTypeMatch = fmt.Errorf("resource type doesn't match")
7+
8+
ErrorMissingRegion = fmt.Errorf("region is not specified in resouce or globally")
9+
10+
ErrorResourceNotFound = fmt.Errorf("resource not found")
11+
)

internal/pkg/types.go

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
package pkg
2+
3+
type Nuke interface {
4+
NukeIt() error
5+
Validate() error
6+
}
7+
8+
type Filter struct {
9+
Name string `yaml:"name"`
10+
Regex string `yaml:"regex"`
11+
ID string `yaml:"ID"`
12+
}
13+
14+
type Resource struct {
15+
Nuke
16+
17+
Type string `yaml:"type"`
18+
Attributes `yaml:",inline"`
19+
}
20+
21+
type Attributes struct {
22+
Region string `yaml:"region"`
23+
Zone string `yaml:"zone"`
24+
Filter Filter `yaml:"filter"`
25+
}
26+
27+
type Config struct {
28+
Global Attributes `yaml:",inline"`
29+
Resources []Resource `yaml:"resources"`
30+
}
31+
32+
func (c *Config) GetGlobalRegion() string {
33+
return c.Global.Region
34+
}
35+
36+
func (c *Config) GetGlobalZone() string {
37+
return c.Global.Zone
38+
}
39+
40+
func (c *Config) GetGlobalFilter() Filter {
41+
return c.Global.Filter
42+
}

internal/pkg/utils/paging.go

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
package utils
2+
3+
import (
4+
"fmt"
5+
"net/url"
6+
)
7+
8+
// pagingHelper while listing resources, can use this to get the start token for getting the next set of resources for processing
9+
// start token will get fetched from nextUrl returned by f and passed to the func f.
10+
// f should take start as param and return three values isDone bool, nextUrl string, e error.
11+
// isDone - represents no need to iterate for getting next set of resources.
12+
// nextUrl - if nextUrl is present, will try to get the start token and pass it to f for next set of resource processing.
13+
// e - if e is not nil, will break and return the error.
14+
func PagingHelper(f func(string) (bool, string, error)) (err error) {
15+
start := ""
16+
for {
17+
isDone, nextUrl, e := f(start)
18+
19+
if e != nil {
20+
err = e
21+
break
22+
}
23+
24+
if isDone {
25+
break
26+
}
27+
28+
// for paging over next set of resources getting the start token
29+
if nextUrl != "" {
30+
start, err = getStartToken(nextUrl)
31+
if err != nil {
32+
break
33+
}
34+
} else {
35+
break
36+
}
37+
}
38+
39+
return
40+
}
41+
42+
// getStartToken parses the given url string and gets the 'start' query param
43+
func getStartToken(nextUrlS string) (start string, err error) {
44+
nextUrl, err := url.Parse(nextUrlS)
45+
if err != nil || nextUrl == nil {
46+
err = fmt.Errorf("could not parse next url for getting next resources %w", err)
47+
return
48+
}
49+
50+
start = nextUrl.Query().Get("start")
51+
return
52+
}

0 commit comments

Comments
 (0)