Skip to content

Commit

Permalink
migrate-to-v2: enter troubleshooting on failed migration. theming(?!)
Browse files Browse the repository at this point in the history
  • Loading branch information
alichay committed Jun 7, 2023
1 parent a242164 commit 2b69f1b
Show file tree
Hide file tree
Showing 2 changed files with 91 additions and 18 deletions.
36 changes: 33 additions & 3 deletions internal/command/migrate_to_v2/migrate_to_v2.go
Expand Up @@ -426,9 +426,39 @@ func (m *v2PlatformMigrator) Migrate(ctx context.Context) (err error) {
header = "(!) An error has occurred. Attempting to rollback changes..."
}
fmt.Fprintf(m.io.ErrOut, "failed while migrating: %v\n", err)
recoveryBlock := render.NewTextBlock(ctx, header)
if recoveryErr := m.rollback(ctx, recoveryBlock); recoveryErr != nil {
fmt.Fprintf(m.io.ErrOut, "failed while rolling back application: %v\n", recoveryErr)

enterTroubleshooting := false
if !flag.GetYes(ctx) && err != abortedErr && m.io.IsInteractive() {
askErr := survey.AskOne(&survey.Confirm{
Message: "Would you like to enter interactive troubleshooting mode? If not, the migration will be rolled back.",
Default: true,
}, &enterTroubleshooting)
if askErr != nil {
enterTroubleshooting = false
}
}

if enterTroubleshooting {

migrateErr := func() error {
t, err := newTroubleshooter(ctx, m.appCompact.Name)
if err != nil {
return err
}

return t.run(ctx)
}()
if migrateErr != nil {
fmt.Fprintf(m.io.ErrOut, "failed while troubleshooting: %v\n", err)
} else {
err = nil // Printing an error message below a successful troubleshooting run is confusing
}

} else {
recoveryBlock := render.NewTextBlock(ctx, header)
if recoveryErr := m.rollback(ctx, recoveryBlock); recoveryErr != nil {
fmt.Fprintf(m.io.ErrOut, "failed while rolling back application: %v\n", recoveryErr)
}
}
}
}()
Expand Down
73 changes: 58 additions & 15 deletions internal/command/migrate_to_v2/troubleshoot.go
Expand Up @@ -24,6 +24,26 @@ import (
"github.com/superfly/flyctl/iostreams"
)

const (
yellowBrickRoad = `
Oops! We ran into issues migrating your app.
We're constantly working to improve the migration and squash bugs, but for
now please let this debug wizard guide you down a yellow brick road
of potential solutions...
,,,,,
,,.,,,,,,,,, .
.,,,,,,,
,,,,,,,,,.,,
,,,,,,,,,,,,,,,,,,,
,,,,,,,,,,,,,,,,,,,,
,,,,,,,,,,,,,,,,,,,,,
,,,,,,,,,,,,,,,,,,,,,,,
,,,,,,,,,,,,,,,,,,,,,,,,,,,,.
, ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
`
)

func newTroubleshoot() *cobra.Command {
const (
usage = `troubleshoot`
Expand All @@ -43,14 +63,18 @@ func newTroubleshoot() *cobra.Command {
return cmd
}

func runTroubleshoot(ctx context.Context) error {
func runTroubleshoot(ctx context.Context) (err error) {
var (
appName = appconfig.NameFromContext(ctx)

appName = appconfig.NameFromContext(ctx)
flapsClient *flaps.Client
err error
)

defer func() {
if err != nil {
err = wrapTroubleshootingErrWithSuggestions(err)
}
}()

flapsClient, err = flaps.NewFromAppName(ctx, appName)
if err != nil {
return fmt.Errorf("could not create flaps client: %w", err)
Expand All @@ -66,6 +90,10 @@ func runTroubleshoot(ctx context.Context) error {
return t.run(ctx)
}

func wrapTroubleshootingErrWithSuggestions(err error) error {
return fmt.Errorf("%w\nplease try running `fly migrate-to-v2 troubleshoot` later, or contact hello@fly.io\n", err)
}

type troubleshooter struct {
app *api.AppCompact
machines []*api.Machine
Expand Down Expand Up @@ -160,14 +188,33 @@ func (t *troubleshooter) hasMigrated(ctx context.Context) bool {
func (t *troubleshooter) run(ctx context.Context) error {
io := iostreams.FromContext(ctx)

if t.app.PlatformVersion == appconfig.MachinesPlatform && len(t.allocs) == 0 {

fmt.Fprintf(io.Out, "No issues detected.\n")
}

// From here on out we know that we're either
// * not on the machines platform, or
// * we have at least one nomad alloc
// (meaning: we've got issues)

fmt.Fprint(io.Out, yellowBrickRoad)

if t.app.PlatformVersion != appconfig.MachinesPlatform {
err := t.unsuspend(ctx)
if err != nil {
return fmt.Errorf("could not unsuspend app: %w", err)
}
}

if t.app.PlatformVersion == appconfig.DetachedPlatform {
switch t.app.PlatformVersion {
case appconfig.NomadPlatform:
// Already handled in newTroubleshooter by the hasMigrated check
return nil
case appconfig.MachinesPlatform:
fmt.Fprintf(io.Out, "Detected Nomad VMs running on V2 app, cleaning up.\n")
return t.cleanupNomadSwitchToMachines(ctx)
case appconfig.DetachedPlatform:
fmt.Fprintf(io.Out, `The app's platform version is 'detached'
This means that the app is stuck in a half-migrated state, and wasn't able to
be fully recovered during the migration error rollback process.
Expand All @@ -178,16 +225,7 @@ Please use these tools to troubleshoot and attempt to repair the app.
return t.detachedInteractiveTroubleshoot(ctx)
}

if t.app.PlatformVersion == appconfig.MachinesPlatform {
if len(t.allocs) != 0 {
fmt.Fprintf(io.Out, "Detected Nomad VMs running on V2 app, cleaning up.\n")
return t.cleanupNomadSwitchToMachines(ctx)
}
}

fmt.Fprintf(io.Out, "No issues detected.\n")

return nil
return fmt.Errorf("unknown platform version: %s", t.app.PlatformVersion)
}

const timedOutErr = "timed out"
Expand Down Expand Up @@ -355,6 +393,11 @@ func (t *troubleshooter) detachedInteractiveTroubleshoot(ctx context.Context) er
return t.setPlatformVersion(ctx, appconfig.MachinesPlatform)
}

if !io.IsInteractive() {
fmt.Fprintf(io.Out, "Troubleshooting mode is intended for interactive use.\nOutput of autodiagnose:\n%s\n", t.detachedAutodiagnose(ctx))
return nil
}

const (
Autodiagnose = "Autodiagnose issues"
PrintNomad = "List Nomad VMs"
Expand Down

0 comments on commit 2b69f1b

Please sign in to comment.