-
Notifications
You must be signed in to change notification settings - Fork 2
feat: cleanup bootstrapped infra #185
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
OliverTrautvetter
wants to merge
35
commits into
main
Choose a base branch
from
cleanup_bootstrapped_infra
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
35 commits
Select commit
Hold shift + click to select a range
9f1eee8
feat: add cleanup command to bootstrap
OliverTrautvetter f1a09cb
feat: update cleanup command
OliverTrautvetter 539a590
Merge branch 'main' into cleanup_bootstrapped_infra
OliverTrautvetter 382e896
ref: mockery
OliverTrautvetter 9cfbd1e
chore(docs): Auto-update docs and licenses
OliverTrautvetter f20991b
test: add tests for new cleanup
OliverTrautvetter 5b7220f
Merge branch 'cleanup_bootstrapped_infra' of https://github.com/codes…
OliverTrautvetter 5508d73
ref: enhance cleanup command with dependency injection and error hand…
OliverTrautvetter 4f32c3f
ref: add utility functions for OMS-managed label checks and DNS recor…
OliverTrautvetter ec12723
ref: enhance GCP cleanup command with project ID handling
OliverTrautvetter bb57d56
chore(docs): Auto-update docs and licenses
OliverTrautvetter 3e923af
ref: remove redundant file existence check in cleanup command
OliverTrautvetter f362c2a
fix: error handling in EnableAPIs method for GCPClient
OliverTrautvetter 8f23960
ref: streamline GCP cleanup process with improved infra file handling…
OliverTrautvetter 22df9dd
ref: improve error messages for GCP infra file handling
OliverTrautvetter e2e1117
Merge branch 'main' into cleanup_bootstrapped_infra
OliverTrautvetter 424cb1e
chore(docs): Auto-update docs and licenses
OliverTrautvetter af14d9c
fix: improve cleanup to revoke set permissions
OliverTrautvetter 84adde4
feat: enhance GCP cleanup command with DNS settings and error handlin…
OliverTrautvetter 6c12790
Merge remote-tracking branch 'origin/main' into cleanup_bootstrapped_…
OliverTrautvetter bd05188
fix: merge error
OliverTrautvetter deef455
chore(docs): Auto-update docs and licenses
OliverTrautvetter ca4b2c3
ref: consolidate infrastructure file loading into a single function
OliverTrautvetter 9d89e67
Merge branch 'cleanup_bootstrapped_infra' of https://github.com/codes…
OliverTrautvetter 8c95a6c
fix: add DNSProjectID option for GCP cleanup command
OliverTrautvetter 285b82a
chore(docs): Auto-update docs and licenses
OliverTrautvetter 11efdea
Merge branch 'main' into cleanup_bootstrapped_infra
OliverTrautvetter 328063a
fix: typo
OliverTrautvetter 92a9b24
chore(docs): Auto-update docs and licenses
OliverTrautvetter ae0cca0
Update cli/cmd/bootstrap_gcp_cleanup.go
OliverTrautvetter 94a8952
Update cli/cmd/bootstrap_gcp_cleanup.go
OliverTrautvetter 91018a9
Update internal/bootstrap/gcp/gcp_client_cleanup_test.go
OliverTrautvetter 37b4390
Update cli/cmd/bootstrap_gcp_cleanup_test.go
OliverTrautvetter 8dd311b
fix: cleanup
OliverTrautvetter a528af5
chore(docs): Auto-update docs and licenses
OliverTrautvetter File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,222 @@ | ||
| // Copyright (c) Codesphere Inc. | ||
| // SPDX-License-Identifier: Apache-2.0 | ||
|
|
||
| package cmd | ||
|
|
||
| import ( | ||
| "bufio" | ||
| "fmt" | ||
| "io" | ||
| "log" | ||
| "os" | ||
| "strings" | ||
|
|
||
| csio "github.com/codesphere-cloud/cs-go/pkg/io" | ||
| "github.com/codesphere-cloud/oms/internal/bootstrap" | ||
| "github.com/codesphere-cloud/oms/internal/bootstrap/gcp" | ||
| "github.com/codesphere-cloud/oms/internal/util" | ||
| "github.com/spf13/cobra" | ||
| ) | ||
|
|
||
| type BootstrapGcpCleanupCmd struct { | ||
| cmd *cobra.Command | ||
| Opts *BootstrapGcpCleanupOpts | ||
| } | ||
|
|
||
| type BootstrapGcpCleanupOpts struct { | ||
| *GlobalOptions | ||
| ProjectID string | ||
| Force bool | ||
| SkipDNSCleanup bool | ||
| BaseDomain string | ||
| DNSZoneName string | ||
| DNSProjectID string | ||
| } | ||
|
|
||
| type CleanupDeps struct { | ||
| GCPClient gcp.GCPClientManager | ||
| FileIO util.FileIO | ||
| StepLogger *bootstrap.StepLogger | ||
| ConfirmReader io.Reader | ||
| InfraFilePath string | ||
| } | ||
|
|
||
| func (c *BootstrapGcpCleanupCmd) RunE(_ *cobra.Command, args []string) error { | ||
| ctx := c.cmd.Context() | ||
| stlog := bootstrap.NewStepLogger(false) | ||
| gcpClient := gcp.NewGCPClient(ctx, stlog, os.Getenv("GOOGLE_APPLICATION_CREDENTIALS")) | ||
| fw := util.NewFilesystemWriter() | ||
|
|
||
| deps := &CleanupDeps{ | ||
| GCPClient: gcpClient, | ||
| FileIO: fw, | ||
| StepLogger: stlog, | ||
| ConfirmReader: os.Stdin, | ||
| InfraFilePath: gcp.GetInfraFilePath(), | ||
| } | ||
|
|
||
| return c.ExecuteCleanup(deps) | ||
OliverTrautvetter marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| } | ||
|
|
||
| func (c *BootstrapGcpCleanupCmd) confirmDeletion(deps *CleanupDeps, projectID string) error { | ||
| log.Printf("WARNING: This will permanently delete the GCP project '%s' and all its resources.", projectID) | ||
| log.Printf("This action cannot be undone.\n") | ||
| log.Println("Type the project ID to confirm deletion: ") | ||
|
|
||
| reader := bufio.NewReader(deps.ConfirmReader) | ||
| confirmation, err := reader.ReadString('\n') | ||
| if err != nil { | ||
| return fmt.Errorf("failed to read confirmation: %w", err) | ||
| } | ||
| if strings.TrimSpace(confirmation) != projectID { | ||
| return fmt.Errorf("confirmation did not match project ID, aborting cleanup") | ||
| } | ||
| return nil | ||
| } | ||
|
|
||
| // ExecuteCleanup performs the cleanup operation with the provided dependencies. | ||
| func (c *BootstrapGcpCleanupCmd) ExecuteCleanup(deps *CleanupDeps) error { | ||
| projectID := c.Opts.ProjectID | ||
| infraFileLoaded := false | ||
| infraFileExists := false | ||
| var infraEnv gcp.CodesphereEnvironment | ||
|
|
||
| // Only load infra file if we need information from it (project ID or DNS info) | ||
| missingDNSInfo := c.Opts.BaseDomain == "" || c.Opts.DNSZoneName == "" || c.Opts.DNSProjectID == "" | ||
| needsInfraFile := projectID == "" || (!c.Opts.SkipDNSCleanup && missingDNSInfo) | ||
| if needsInfraFile { | ||
| var err error | ||
| infraEnv, infraFileExists, err = gcp.LoadInfraFile(deps.FileIO, deps.InfraFilePath) | ||
| if err != nil { | ||
| if projectID == "" { | ||
| return fmt.Errorf("failed to load infra file: %w", err) | ||
| } | ||
| log.Printf("Warning: %v", err) | ||
| infraEnv = gcp.CodesphereEnvironment{} | ||
| } else if infraEnv.ProjectID != "" { | ||
| infraFileLoaded = true | ||
| } | ||
| } | ||
|
|
||
| // Determine project ID to use | ||
| if projectID == "" { | ||
OliverTrautvetter marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| if infraFileExists && infraEnv.ProjectID == "" { | ||
| return fmt.Errorf("infra file at %s contains empty project ID", deps.InfraFilePath) | ||
| } | ||
| if infraEnv.ProjectID == "" { | ||
| return fmt.Errorf("no project ID provided and no infra file found at %s", deps.InfraFilePath) | ||
| } | ||
| projectID = infraEnv.ProjectID | ||
| log.Printf("Using project ID from infra file: %s", projectID) | ||
| } else if infraFileLoaded && infraEnv.ProjectID != projectID { | ||
| log.Printf("Warning: infra file contains project ID '%s' but deleting '%s'; ignoring infra file for DNS cleanup", infraEnv.ProjectID, projectID) | ||
| infraEnv = gcp.CodesphereEnvironment{} | ||
| infraFileLoaded = false | ||
| } | ||
|
|
||
| // Apply command-line overrides for DNS settings | ||
| baseDomain := c.Opts.BaseDomain | ||
| if baseDomain == "" { | ||
| baseDomain = infraEnv.BaseDomain | ||
| } | ||
| dnsZoneName := c.Opts.DNSZoneName | ||
| if dnsZoneName == "" { | ||
| dnsZoneName = infraEnv.DNSZoneName | ||
| } | ||
|
|
||
| // Verify project is OMS-managed | ||
| if c.Opts.Force { | ||
| log.Printf("Skipping OMS-managed verification and deletion confirmation (--force flag used)") | ||
| } else { | ||
| isOMSManaged, err := deps.GCPClient.IsOMSManagedProject(projectID) | ||
| if err != nil { | ||
| return fmt.Errorf("failed to verify project: %w", err) | ||
| } | ||
| if !isOMSManaged { | ||
| return fmt.Errorf("project %s was not bootstrapped by OMS (missing 'oms-managed' label). Use --force to override this check", projectID) | ||
| } | ||
|
|
||
| if err := c.confirmDeletion(deps, projectID); err != nil { | ||
| return fmt.Errorf("deletion confirmation failed: %w", err) | ||
| } | ||
| } | ||
|
|
||
| // Clean up DNS records | ||
| if !c.Opts.SkipDNSCleanup && baseDomain != "" && dnsZoneName != "" { | ||
| dnsProjectID := c.Opts.DNSProjectID | ||
| if dnsProjectID == "" { | ||
| dnsProjectID = infraEnv.DNSProjectID | ||
| } | ||
| if dnsProjectID == "" { | ||
| dnsProjectID = projectID | ||
| } | ||
| if err := deps.StepLogger.Step("Cleaning up DNS records", func() error { | ||
| return deps.GCPClient.DeleteDNSRecordSets(dnsProjectID, dnsZoneName, baseDomain) | ||
| }); err != nil { | ||
| log.Printf("Warning: failed to clean up DNS records: %v", err) | ||
| log.Printf("You may need to manually delete DNS records for %s in project %s", baseDomain, dnsProjectID) | ||
| } | ||
| } else if !c.Opts.SkipDNSCleanup && baseDomain == "" { | ||
| log.Printf("Skipping DNS cleanup: no base domain available (provide --base-domain or infra file, or use --skip-dns-cleanup)") | ||
| } | ||
|
|
||
| // Delete the project | ||
| if err := deps.StepLogger.Step("Deleting GCP project", func() error { | ||
| return deps.GCPClient.DeleteProject(projectID) | ||
| }); err != nil { | ||
| return fmt.Errorf("failed to delete project: %w", err) | ||
| } | ||
OliverTrautvetter marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| // Clean up local infra file only if it matches the deleted project | ||
| if infraFileLoaded && infraEnv.ProjectID == projectID { | ||
| if err := deps.FileIO.Remove(deps.InfraFilePath); err != nil { | ||
| log.Printf("Warning: failed to remove local infra file: %v", err) | ||
| } else { | ||
| log.Printf("Removed local infra file: %s", deps.InfraFilePath) | ||
| } | ||
OliverTrautvetter marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| } | ||
|
|
||
| log.Println("\nGCP project cleanup completed successfully!") | ||
| log.Printf("Project '%s' has been scheduled for deletion.", projectID) | ||
| log.Printf("Note: GCP projects are retained for 30 days before permanent deletion. You can restore the project within this period from the GCP Console.") | ||
|
|
||
| return nil | ||
| } | ||
|
|
||
| func AddBootstrapGcpCleanupCmd(bootstrapGcp *cobra.Command, opts *GlobalOptions) { | ||
| cleanup := BootstrapGcpCleanupCmd{ | ||
| cmd: &cobra.Command{ | ||
| Use: "cleanup", | ||
| Short: "Clean up GCP infrastructure created by bootstrap-gcp", | ||
| Long: csio.Long(`Deletes a GCP project that was previously created using the bootstrap-gcp command.`), | ||
| Example: ` # Clean up using project ID from the local infra file | ||
| oms-cli beta bootstrap-gcp cleanup | ||
|
|
||
| # Clean up a specific project | ||
| oms-cli beta bootstrap-gcp cleanup --project-id my-project-abc123 | ||
|
|
||
| # Force cleanup without confirmation (skips OMS-managed check) | ||
| oms-cli beta bootstrap-gcp cleanup --project-id my-project-abc123 --force | ||
|
|
||
| # Skip DNS record cleanup | ||
| oms-cli beta bootstrap-gcp cleanup --skip-dns-cleanup | ||
|
|
||
| # Clean up with manual DNS settings (when infra file is not available) | ||
| oms-cli beta bootstrap-gcp cleanup --project-id my-project --base-domain example.com --dns-zone-name my-zone --dns-project-id dns-project`, | ||
| }, | ||
| Opts: &BootstrapGcpCleanupOpts{ | ||
| GlobalOptions: opts, | ||
| }, | ||
| } | ||
|
|
||
| flags := cleanup.cmd.Flags() | ||
| flags.StringVar(&cleanup.Opts.ProjectID, "project-id", "", "GCP Project ID to delete (optional, will use infra file if not provided)") | ||
| flags.BoolVar(&cleanup.Opts.Force, "force", false, "Skip confirmation prompt and OMS-managed check") | ||
| flags.BoolVar(&cleanup.Opts.SkipDNSCleanup, "skip-dns-cleanup", false, "Skip cleaning up DNS records") | ||
| flags.StringVar(&cleanup.Opts.BaseDomain, "base-domain", "", "Base domain for DNS cleanup (optional, will use infra file if not provided)") | ||
| flags.StringVar(&cleanup.Opts.DNSZoneName, "dns-zone-name", "", "DNS zone name for DNS cleanup (optional, will use infra file if not provided)") | ||
| flags.StringVar(&cleanup.Opts.DNSProjectID, "dns-project-id", "", "GCP Project ID for DNS zone (optional, will use infra file if not provided)") | ||
|
|
||
| cleanup.cmd.RunE = cleanup.RunE | ||
| bootstrapGcp.AddCommand(cleanup.cmd) | ||
| } | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.