msp/terraformcloud: add option to respect existing run mode (#62580)

When using https://github.com/sourcegraph/sourcegraph/pull/62565, we override test environments that are in CLI mode, which can cause infra to be rolled out by surprise via VCS mode on switch - this change adds an option to respect the existing run mode configuration via `-workspace-run-mode=ignore`.

Thread: https://sourcegraph.slack.com/archives/C06JENN2QBF/p1715256898022469?thread_ts=1715251558.736709&cid=C06JENN2QBF

## Test plan

```
sg msp tfc sync -all
👉 Syncing all environments for all services, including setting ALL workspaces to use run mode "vcs" (use '-workspace-run-mode=ignore' to respect the existing run mode) - are you sure? (y/N)  N
 aborting
Projects/sourcegraph/managed-services 1 » sg msp tfc sync -all -workspace-run-mode=ignore
👉 Syncing all environments for all services - are you sure? (y/N)  y
// ...
```
This commit is contained in:
Robert Lin 2024-05-09 14:57:40 -07:00 committed by GitHub
parent b252e2d68a
commit 022b4ad95f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 36 additions and 3 deletions

View File

@ -52,6 +52,9 @@ type WorkspaceRunMode string
const (
WorkspaceRunModeVCS WorkspaceRunMode = "vcs"
WorkspaceRunModeCLI WorkspaceRunMode = "cli"
// WorkspaceRunModeIgnore is used to indicate that the workspace's run mode
// should not be modified.
WorkspaceRunModeIgnore WorkspaceRunMode = "ignore"
)
type WorkspaceConfig struct {
@ -266,6 +269,9 @@ func (c *Client) SyncWorkspaces(ctx context.Context, svc spec.ServiceSpec, env s
// to TFC, hence we need to remove all VCS and working directory override
wantWorkspaceOptions.VCSRepo = nil
wantWorkspaceOptions.WorkingDirectory = nil
case WorkspaceRunModeIgnore:
// We will apply existing configuration later before the
// 'Workspaces.Update' operation
default:
return nil, errors.Errorf("invalid WorkspaceRunModeVCS %q", c.workspaceConfig.RunMode)
}
@ -281,6 +287,11 @@ func (c *Client) SyncWorkspaces(ctx context.Context, svc spec.ServiceSpec, env s
return nil, errors.Wrap(err, "failed to check if workspace exists")
}
if c.workspaceConfig.RunMode == WorkspaceRunModeIgnore {
// Can't ignore a configuration that doesn't exist yet!
return nil, errors.New("cannot create workspace in WorkspaceRunModeIgnore")
}
createdWorkspace, err := c.client.Workspaces.Create(ctx, c.org,
wantWorkspaceOptions.AsCreate(wantWorkspaceTags))
if err != nil {
@ -296,6 +307,19 @@ func (c *Client) SyncWorkspaces(ctx context.Context, svc spec.ServiceSpec, env s
Name: existingWorkspace.Name,
})
// Apply existing config relevant to run mode explicitly
if c.workspaceConfig.RunMode == WorkspaceRunModeIgnore {
if existingWorkspace.VCSRepo != nil {
wantWorkspaceOptions.VCSRepo = &tfe.VCSRepoOptions{
OAuthTokenID: &existingWorkspace.VCSRepo.OAuthTokenID,
Identifier: &existingWorkspace.VCSRepo.Identifier,
Branch: &existingWorkspace.VCSRepo.Branch,
}
}
wantWorkspaceOptions.WorkingDirectory = &existingWorkspace.WorkingDirectory
wantWorkspaceOptions.TriggerPrefixes = existingWorkspace.TriggerPrefixes
}
// VCSRepo must be removed by explicitly using the API - update
// doesn't remove it - if we want to remove the connection.
if existingWorkspace.VCSRepo != nil && wantWorkspaceOptions.VCSRepo == nil {

View File

@ -841,7 +841,7 @@ This command supports completions on services and environments.
},
&cli.StringFlag{
Name: "workspace-run-mode",
Usage: "One of 'vcs', 'cli'",
Usage: "One of 'vcs', 'cli', or 'ignore' (to respect existing configuration)",
Value: "vcs",
},
&cli.BoolFlag{
@ -871,9 +871,10 @@ This command supports completions on services and environments.
return errors.Wrap(err, "get TFC OAuth client ID")
}
runMode := terraformcloud.WorkspaceRunMode(c.String("workspace-run-mode"))
tfcClient, err := terraformcloud.NewClient(tfcAccessToken, tfcOAuthClient,
terraformcloud.WorkspaceConfig{
RunMode: terraformcloud.WorkspaceRunMode(c.String("workspace-run-mode")),
RunMode: runMode,
})
if err != nil {
return errors.Wrap(err, "init Terraform Cloud client")
@ -899,7 +900,15 @@ This command supports completions on services and environments.
return errors.New("cannot delete workspaces for all services")
}
std.Out.Promptf("Syncing all environments for all services - are you sure? (y/N) ")
confirmAction := "Syncing all environments for all services"
if runMode != terraformcloud.WorkspaceRunModeIgnore {
// This action may override custom run mode
// configurations, which may unexpectedly deploy
// new changes
confirmAction = fmt.Sprintf("%s, including setting ALL workspaces to use run mode %q (use '-workspace-run-mode=ignore' to respect the existing run mode)",
confirmAction, runMode)
}
std.Out.Promptf("%s - are you sure? (y/N) ", confirmAction)
var input string
if _, err := fmt.Scan(&input); err != nil {
return err