Skip to content

Commit

Permalink
add --all flag to plural destroy (#359)
Browse files Browse the repository at this point in the history
* add `--all` flag to plural destroy

This will make a full cluster destroy require an implicit invocation which can prevent mistyping

* try to enable services when some are missing

* Add ability to ignore preflight checks
  • Loading branch information
michaeljguarino authored Mar 6, 2023
1 parent 2a39f5c commit 557968d
Show file tree
Hide file tree
Showing 7 changed files with 70 additions and 15 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/e2e.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ jobs:
- run: go test -v -race ./pkg/test/e2e/... -tags="e2e"
- run: |
cd $HOME/test
plural destroy --force --commit=""
plural destroy --force --all --commit=""
env:
PLURAL_DESTROY_CONFIRM: true
PLURAL_DESTROY_AFFIRM_UNINSTALL_APPS: true
4 changes: 3 additions & 1 deletion cmd/plural/deploy.go
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,6 @@ func (p *Plural) build(c *cli.Context) error {
}

func (p *Plural) doBuild(installation *api.Installation, force bool) error {
p.InitPluralClient()
repoName := installation.Repository.Name
fmt.Printf("Building workspace for %s\n", repoName)

Expand Down Expand Up @@ -360,13 +359,16 @@ func (p *Plural) destroy(c *cli.Context) error {
repoName := c.Args().Get(0)
repoRoot, err := git.Root()
force := c.Bool("force")
all := c.Bool("all")
if err != nil {
return err
}

infix := "this workspace"
if repoName != "" {
infix = repoName
} else if !all {
return fmt.Errorf("you must either specify an individual application or `--all` to destroy the entire workspace")
}

if !force && !confirm(fmt.Sprintf("Are you sure you want to destroy %s?", infix), "PLURAL_DESTROY_CONFIRM") {
Expand Down
2 changes: 1 addition & 1 deletion cmd/plural/init.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ func (p *Plural) handleInit(c *cli.Context) error {
}

prov, err := runPreflights()
if err != nil {
if err != nil && !c.Bool("ignore-preflights") {
return err
}

Expand Down
8 changes: 8 additions & 0 deletions cmd/plural/plural.go
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,10 @@ func (p *Plural) getCommands() []cli.Command {
Name: "force",
Usage: "use force push when pushing to git",
},
cli.BoolFlag{
Name: "all",
Usage: "tear down the entire cluster gracefully in one go",
},
},
Action: tracked(latestVersion(owned(upstreamSynced(p.destroy))), "cli.destroy"),
},
Expand All @@ -250,6 +254,10 @@ func (p *Plural) getCommands() []cli.Command {
Name: "service-account",
Usage: "email for the service account you'd like to use for this workspace",
},
cli.BoolFlag{
Name: "ignore-preflights",
Usage: "whether to ignore preflight check failures prior to init",
},
},
Action: tracked(latestVersion(p.handleInit), "cli.init"),
},
Expand Down
43 changes: 31 additions & 12 deletions pkg/provider/gcp.go
Original file line number Diff line number Diff line change
Expand Up @@ -364,32 +364,51 @@ func (gcp *GCPProvider) validateEnabled() error {
return errEnabled
}

wrapped := func(name string) string {
return fmt.Sprintf("projects/%s/services/%s", proj.ProjectId, name)
}
services := algorithms.Map([]string{
"serviceusage.googleapis.com",
"cloudresourcemanager.googleapis.com",
"container.googleapis.com",
}, func(name string) string { return fmt.Sprintf("projects/%s/services/%s", proj.ProjectId, name) })
parent := fmt.Sprintf("projects/%s", proj.ProjectId)
req := &serviceusagepb.BatchGetServicesRequest{
Parent: fmt.Sprintf("projects/%s", proj.ProjectId),
Names: []string{
wrapped("serviceusage.googleapis.com"),
wrapped("cloudresourcemanager.googleapis.com"),
wrapped("container.googleapis.com"),
},
Parent: parent,
Names: services,
}
resp, err := c.BatchGetServices(ctx, req)
if err != nil {
utils.LogError().Println(err)
return errEnabled
}

for _, svc := range resp.Services {
if svc.State != serviceusagepb.State_ENABLED {
utils.LogError().Printf("the service state %v != %v", svc.State, serviceusagepb.State_ENABLED)
missing := algorithms.Filter(resp.Services, func(svc *serviceusagepb.Service) bool {
return svc.State != serviceusagepb.State_ENABLED
})

if len(missing) > 0 {
services := algorithms.Map(missing, func(svc *serviceusagepb.Service) string { return svc.Name })
enableReq := &serviceusagepb.BatchEnableServicesRequest{
Parent: parent,
ServiceIds: services,
}
utils.LogError().Printf("Attempting to enable services %v", services)
if err := tryToEnableServices(ctx, c, enableReq); err != nil {
return errEnabled
}
}

return nil
}

func tryToEnableServices(ctx context.Context, client *serviceusage.Client, req *serviceusagepb.BatchEnableServicesRequest) (err error) {
op, err := client.BatchEnableServices(ctx, req)
if err != nil {
return
}

_, err = op.Wait(ctx)
return
}

func (gcp *GCPProvider) Permissions() (permissions.Checker, error) {
proj, err := gcp.getProject()
if err != nil {
Expand Down
2 changes: 2 additions & 0 deletions pkg/scaffold/terraform.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import (
"golang.org/x/mod/semver"

"github.com/pluralsh/plural/pkg/api"
"github.com/pluralsh/plural/pkg/config"
"github.com/pluralsh/plural/pkg/template"
"github.com/pluralsh/plural/pkg/utils"
"github.com/pluralsh/plural/pkg/utils/pathing"
Expand Down Expand Up @@ -122,6 +123,7 @@ func (scaffold *Scaffold) handleTerraform(wk *wkspace.Workspace) error {
"Namespace": wk.Config.Namespace(repo.Name),
"Region": wk.Provider.Region(),
"Context": wk.Provider.Context(),
"Config": config.Read(),
"Applications": apps,
}
if err := tmpl.Execute(&buf, values); err != nil {
Expand Down
24 changes: 24 additions & 0 deletions pkg/server/setup.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ import (
"github.com/pluralsh/plural/pkg/provider"
"github.com/pluralsh/plural/pkg/utils"
"github.com/pluralsh/plural/pkg/wkspace"

"github.com/pluralsh/polly/algorithms"
)

func toConfig(setup *SetupRequest) *config.Config {
Expand Down Expand Up @@ -151,6 +153,11 @@ func setupCli(c *gin.Context) error {
if err != nil {
return err
}

if err := runPreflights(prov); err != nil {
return err
}

missing, err := prov.Permissions()
if err != nil {
return err
Expand All @@ -161,3 +168,20 @@ func setupCli(c *gin.Context) error {
c.JSON(http.StatusOK, gin.H{"success": true, "missing": missing})
return nil
}

func runPreflights(prov provider.Provider) error {
// run only relevant preflights
preflights := []*provider.Preflight{}
if prov.Name() == provider.GCP {
preflights = algorithms.Filter(prov.Preflights(), func(pre *provider.Preflight) bool {
return pre.Name == "Enabled Services"
})
}

for _, pre := range preflights {
if err := pre.Validate(); err != nil {
return err
}
}
return nil
}

0 comments on commit 557968d

Please sign in to comment.