ekristen/gcp-nuke

View on GitHub
docs/resources.md

Summary

Maintainability
Test Coverage
# Resources

Resources are the core of the tool, they are what is used to list and remove resources from gcp. The resources are
broken down into separate files. 

When creating a resource there's the base resource type, then there's the `Lister` type that returns a list of resources
that it discovers. Those resources are then filtered by any filtering criteria on the resource itself.

## Anatomy of a Resource

The anatomy of a resource is fairly simple, it's broken down into a few parts:

- `Resource` - This is the base resource type that is used to define the resource.
- `Lister` - This is the type that is used to list the resources.

### Resource

The resource must have the `func Remove() error` method defined on it, this is what is used to remove the resource.

It can optionally have the following methods defined:

- `func Filter() error` - This is used to pre-filter resources, usually based on internal criteria, like system defaults.
- `func String() string` - This is used to print the resource in a human-readable format.
- `func Properties() types.Properties` - This is used to print the resource in a human-readable format.

```go
package resources

import (
    "context"
    
    "github.com/ekristen/libnuke/pkg/resource"
    "github.com/ekristen/libnuke/pkg/types"

    "github.com/ekristen/gcp-nuke/pkg/nuke"
)

type ExampleResource struct {
    ID *string
}

func (r *ExampleResource) Remove(_ context.Context) error {
    // remove the resource, an error will put the resource in failed state
    // resources in failed state are retried a number of times
    return nil
}

func (r *ExampleResource) Filter() error {
    // filter the resource, this is useful for built-in resources that cannot
    // be removed, like a gcp managed resource, return an error here to filter
    // it before it even gets to the user supplied filters.
    return nil
}

func (r *ExampleResource) String() string {
    // return a string representation of the resource, this is legacy, but still
    // used for a number of reasons.
    return *r.ID
}
```

## Lister

The lister must have the `func List(ctx context.Context, o interface{}) ([]resource.Resource, error)` method defined on it.

```go
package resources

import (
    "context"

    "github.com/ekristen/libnuke/pkg/resource"

    "github.com/ekristen/gcp-nuke/pkg/nuke"
)

type ExampleResourceLister struct{}

func (l *ExampleResourceLister) List(_ context.Context, o interface{}) ([]resource.Resource, error) {
    opts := o.(*nuke.ListerOpts)

    var resources []resource.Resource
    
    // list the resources and add to resources slice

    return resources, nil
}
```

### Example

```go
package resources

import (
    "context"
    
    "github.com/ekristen/libnuke/pkg/resource"
    "github.com/ekristen/libnuke/pkg/types"

    "github.com/ekristen/gcp-nuke/pkg/nuke"
)

type ExampleResourceLister struct{}

func (l *ExampleResourceLister) List(_ context.Context, o interface{}) ([]resource.Resource, error) {
    opts := o.(*nuke.ListerOpts)

    var resources []resource.Resource
    
    // list the resources and add to resources slice

    return resources, nil
}

// -----------------------------------------------------------------------------

type ExampleResource struct {
    ID *string
}

func (r *ExampleResource) Remove(_ context.Context) error {
    // remove the resource, an error will put the resource in failed state
    // resources in failed state are retried a number of times
    return nil
}

func (r *ExampleResource) Filter() error {
    // filter the resource, this is useful for built-in resources that cannot
    // be removed, like an gcp managed resource, return an error here to filter
    // it before it even gets to the user supplied filters.
    return nil
}

func (r *ExampleResource) String() string {
    // return a string representation of the resource, this is legacy, but still
    // used for a number of reasons.
    return *r.ID
}

func (r *ExampleResource) Properties() types.Properties {
    // return a properties representation of the resource
    props := types.NewProperties()
    props.Set("ID", r.ID)
    return props
}
```

## Creating a new resource

Creating a new resources is fairly straightforward and a template is provided for you, along with a tool to help you
generate the boilerplate code.

Currently, the code is generated using a tool that is located in `tools/create-resource/main.go` and can be run like so:

!!! note
    At present, the tool does not check if the service or the resource type is valid, this is purely a helper tool to
    generate the boilerplate code.

```bash
go run tools/create-resource/main.go <service> <resource-type>
```

This will output the boilerplate code to stdout, so you can copy and paste it into the appropriate file or you can
redirect to a file like so:

```bash
go run tools/create-resource/main.go <service> <resource-type> > resources/<resource-type>.go
```