func waitForAppRunning(c *cli.Context, app string) error { timeout := time.After(30 * time.Minute) tick := time.Tick(5 * time.Second) failed := false for { select { case <-tick: a, err := rackClient(c).GetApp(app) if err != nil { return err } switch a.Status { case "failed", "running": if failed { stdcli.Writef("<ok>DONE</ok>\n") return fmt.Errorf("Update rolled back") } return nil case "rollback": if !failed { failed = true stdcli.Writef("<fail>FAILED</fail>\n") stdcli.Startf("Rolling back") } } case <-timeout: return fmt.Errorf("timeout") } } return nil }
func diagnose(d Diagnosis) { stdcli.Spinner.Stop() time.Sleep(100 * time.Millisecond) print("\033[K") stdcli.Writef(d.String()) if d.Kind == "fail" { os.Exit(1) } }
func cmdRackUpdate(c *cli.Context) error { vs, err := version.All() if err != nil { return stdcli.Error(err) } target, err := vs.Latest() if err != nil { return stdcli.Error(err) } if len(c.Args()) > 0 { t, err := vs.Find(c.Args()[0]) if err != nil { return stdcli.Error(err) } target = t } system, err := rackClient(c).GetSystem() if err != nil { return stdcli.Error(err) } nv, err := vs.Next(system.Version) if err != nil && strings.HasSuffix(err.Error(), "is latest") { nv = target.Version } else if err != nil { return stdcli.Error(err) } next, err := vs.Find(nv) if err != nil { return stdcli.Error(err) } // stop at a required release if necessary if next.Version < target.Version { stdcli.Writef("WARNING: Required update found.\nPlease run `convox rack update` again once this update completes.\n") target = next } stdcli.Startf("Updating to <release>%s</release>", target.Version) _, err = rackClient(c).UpdateSystem(target.Version) if err != nil { return stdcli.Error(err) } stdcli.Wait("UPDATING") if c.Bool("wait") { stdcli.Startf("Waiting for completion") // give the rack a few seconds to start updating time.Sleep(5 * time.Second) if err := waitForRackRunning(c); err != nil { return stdcli.Error(err) } stdcli.OK() } return nil }
func cmdDoctor(c *cli.Context) error { docContext = c stdcli.Writef("### Setup\n") for _, check := range setupChecks { if err := check(); err != nil { return stdcli.Error(err) } } stdcli.Writef("\n\n### Build: Image\n") for _, check := range buildImageChecks { if err := check(); err != nil { return stdcli.Error(err) } } stdcli.Writef("\n\n### Build: Service\n") startCheck("<file>docker-compose.yml</file> found") _, err := os.Stat("docker-compose.yml") if err != nil { diagnose(Diagnosis{ Title: "<file>docker-compose.yml</file> found", Description: "<fail>A docker-compose.yml file is required to define Services</fail>", Kind: "fail", DocsLink: "https://convox.com/guide/services/", }) } else { diagnose(Diagnosis{ Title: "<file>docker-compose.yml</file> found", Kind: "success", }) } m, err := manifest.LoadFile("docker-compose.yml") checkManifestValid(m, err) for _, check := range buildServiceChecks { if err := check(m); err != nil { return stdcli.Error(err) } } stdcli.Writef("\n\n### Build: Environment\n") for _, check := range buildEnvironmentChecks { if err := check(m); err != nil { return stdcli.Error(err) } } stdcli.Writef("\n\n### Run: Balancer\n") for _, check := range runBalancerChecks { if err := check(m); err != nil { return stdcli.Error(err) } } stdcli.Writef("\n\n### Run: Database\n") for _, check := range runDatabaseChecks { if err := check(m); err != nil { return stdcli.Error(err) } } stdcli.Writef("\n\n### Run: Link\n") for _, check := range runLinkChecks { if err := check(m); err != nil { return stdcli.Error(err) } } stdcli.Writef("\n\n### Development: Reloading\n") for _, check := range runReloadingChecks { if err := check(m); err != nil { return stdcli.Error(err) } } stdcli.Writef("\n\n### Development: Commands\n") for _, check := range runCommandChecks { if err := check(m); err != nil { return stdcli.Error(err) } } stdcli.Writef("\n\n<success>Success:</success> Your app looks ready for development. \nRun it with `convox start`.\n\n") return nil }