forked from genevieve/leftovers
/
leftovers.go
136 lines (110 loc) · 4 KB
/
leftovers.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
package azure
import (
"errors"
"fmt"
"github.com/Azure/azure-sdk-for-go/services/network/mgmt/2019-04-01/network"
"github.com/Azure/azure-sdk-for-go/services/resources/mgmt/2018-05-01/resources"
"github.com/Azure/go-autorest/autorest"
"github.com/Azure/go-autorest/autorest/adal"
azurelib "github.com/Azure/go-autorest/autorest/azure"
"github.com/fatih/color"
multierror "github.com/hashicorp/go-multierror"
"github.com/notrepo05/leftovers/common"
)
type resource interface {
List(filter string, regex bool) ([]common.Deletable, error)
Type() string
}
type Leftovers struct {
logger logger
resource resource
}
// List will print all of the resources that match the provided filter.
func (l Leftovers) List(filter string, regex bool) {
l.logger.NoConfirm()
list, err := l.resource.List(filter, regex)
if err != nil {
l.logger.Println(color.YellowString(err.Error()))
}
for _, r := range list {
l.logger.Println(fmt.Sprintf("[%s: %s]", r.Type(), r.Name()))
}
}
// ListByType defaults to List as there is only one resource type.
func (l Leftovers) ListByType(filter, rType string, regex bool) {
l.List(filter, regex)
}
// Types will print all the resource types that can
// be deleted on this IaaS.
func (l Leftovers) Types() {
l.logger.Println(l.resource.Type())
}
// Delete will collect all resources that contain
// the provided filter in the resource's identifier, prompt
// you to confirm deletion (if enabled), and delete those
// that are selected.
func (l Leftovers) Delete(filter string, regex bool) error {
var (
deletables []common.Deletable
result *multierror.Error
)
// TODO: If they say no to the Resource Group, prompt for individual resources.
deletables, err := l.resource.List(filter, regex)
if err != nil {
l.logger.Println(color.YellowString(err.Error()))
}
for _, d := range deletables {
l.logger.Println(fmt.Sprintf("[%s: %s] Deleting...", d.Type(), d.Name()))
err := d.Delete()
if err != nil {
err = fmt.Errorf("[%s: %s] %s", d.Type(), d.Name(), color.YellowString(err.Error()))
result = multierror.Append(result, err)
l.logger.Println(err.Error())
} else {
l.logger.Println(fmt.Sprintf("[%s: %s] %s", d.Type(), d.Name(), color.GreenString("Deleted!")))
}
}
return result.ErrorOrNil()
}
// DeleteByType will collect all resources of the provied type that contain
// the provided filter in the resource's identifier, prompt
// you to confirm deletion (if enabled), and delete those
// that are selected.
// TODO: rType isn't used here? Is this an error? @ciriarte
func (l Leftovers) DeleteByType(filter, rType string, regex bool) error {
return l.Delete(filter, regex)
}
// NewLeftovers returns a new Leftovers for Azure that can be used to list resources,
// list types, or delete resources for the provided account. It returns an error
// if the credentials provided are invalid.
func NewLeftovers(logger logger, clientId, clientSecret, subscriptionId, tenantId string) (Leftovers, error) {
if clientId == "" {
return Leftovers{}, errors.New("Missing client id.")
}
if clientSecret == "" {
return Leftovers{}, errors.New("Missing client secret.")
}
if subscriptionId == "" {
return Leftovers{}, errors.New("Missing subscription id.")
}
if tenantId == "" {
return Leftovers{}, errors.New("Missing tenant id.")
}
oauthConfig, err := adal.NewOAuthConfig(azurelib.PublicCloud.ActiveDirectoryEndpoint, tenantId)
if err != nil {
return Leftovers{}, fmt.Errorf("Creating oauth config: %s\n", err)
}
token, err := adal.NewServicePrincipalToken(*oauthConfig, clientId, clientSecret, azurelib.PublicCloud.ResourceManagerEndpoint)
if err != nil {
return Leftovers{}, fmt.Errorf("Creating service principal token: %s\n", err)
}
rg := resources.NewGroupsClient(subscriptionId)
rg.Authorizer = autorest.NewBearerAuthorizer(token)
sg := network.NewApplicationSecurityGroupsClient(subscriptionId)
sg.Authorizer = autorest.NewBearerAuthorizer(token)
client := NewClient(rg, sg)
return Leftovers{
logger: logger,
resource: NewGroups(client, logger),
}, nil
}