func run() error { log := log15.New() if *isTTY { log.SetHandler(log15.StreamHandler(colorable.NewColorableStdout(), log15.TerminalFormat())) } var images map[string]*ct.Artifact if err := json.NewDecoder(os.Stdin).Decode(&images); err != nil { log.Error("error decoding images", "err", err) return err } req, err := http.NewRequest("GET", "http://status-web.discoverd", nil) if err != nil { return err } req.Header = make(http.Header) req.Header.Set("Accept", "application/json") res, err := http.DefaultClient.Do(req) if err != nil { log.Error("error getting cluster status", "err", err) return err } defer res.Body.Close() if res.StatusCode != 200 { log.Error("cluster status is unhealthy", "code", res.StatusCode) return fmt.Errorf("cluster is unhealthy") } var statusWrapper struct { Data struct { Detail map[string]status.Status } } if err := json.NewDecoder(res.Body).Decode(&statusWrapper); err != nil { log.Error("error decoding cluster status JSON", "err", err) return err } statuses := statusWrapper.Data.Detail instances, err := discoverd.GetInstances("controller", 10*time.Second) if err != nil { log.Error("error looking up controller in service discovery", "err", err) return err } client, err := controller.NewClient("", instances[0].Meta["AUTH_KEY"]) if err != nil { log.Error("error creating controller client", "err", err) return err } log.Info("validating images") for _, app := range updater.SystemApps { if v := version.Parse(statuses[app.Name].Version); !v.Dev && app.MinVersion != "" && v.Before(version.Parse(app.MinVersion)) { log.Info( "not updating image of system app, can't upgrade from running version", "app", app.Name, "version", v, ) continue } if _, ok := images[app.Name]; !ok { err := fmt.Errorf("missing image: %s", app.Name) log.Error(err.Error()) return err } } log.Info("creating new image artifacts") redisImage = images["redis"] if err := client.CreateArtifact(redisImage); err != nil { log.Error("error creating redis image artifact", "err", err) return err } slugRunner = images["slugrunner"] if err := client.CreateArtifact(slugRunner); err != nil { log.Error("error creating slugrunner image artifact", "err", err) return err } slugBuilder = images["slugbuilder"] if err := client.CreateArtifact(slugBuilder); err != nil { log.Error("error creating slugbuilder image artifact", "err", err) return err } // deploy system apps in order first for _, appInfo := range updater.SystemApps { if appInfo.ImageOnly { continue // skip ImageOnly updates } log := log.New("name", appInfo.Name) log.Info("starting deploy of system app") app, err := client.GetApp(appInfo.Name) if err == controller.ErrNotFound && appInfo.Optional { log.Info( "skipped deploy of system app", "reason", "optional app not present", "app", appInfo.Name, ) continue } else if err != nil { log.Error("error getting app", "err", err) return err } if err := deployApp(client, app, images[appInfo.Name], appInfo.UpdateRelease, log); err != nil { if e, ok := err.(errDeploySkipped); ok { log.Info( "skipped deploy of system app", "reason", e.reason, "app", appInfo.Name, ) continue } return err } log.Info("finished deploy of system app") } // deploy all other apps (including provisioned Redis apps) apps, err := client.AppList() if err != nil { log.Error("error getting apps", "err", err) return err } for _, app := range apps { log := log.New("name", app.Name) if app.RedisAppliance() { log.Info("starting deploy of Redis app") if err := deployApp(client, app, redisImage, nil, log); err != nil { if e, ok := err.(errDeploySkipped); ok { log.Info("skipped deploy of Redis app", "reason", e.reason) continue } return err } log.Info("finished deploy of Redis app") continue } if app.System() { continue } log.Info("starting deploy of app to update slugrunner") if err := deployApp(client, app, slugRunner, nil, log); err != nil { if e, ok := err.(errDeploySkipped); ok { log.Info("skipped deploy of app", "reason", e.reason) continue } return err } log.Info("finished deploy of app") } return nil }
func run() error { log := log15.New() if *isTTY { log.SetHandler(log15.StreamHandler(colorable.NewColorableStdout(), log15.TerminalFormat())) } var images map[string]string if err := json.NewDecoder(os.Stdin).Decode(&images); err != nil { log.Error("error decoding images", "err", err) return err } instances, err := discoverd.GetInstances("flynn-controller", 10*time.Second) if err != nil { log.Error("error looking up controller in service discovery", "err", err) return err } client, err := controller.NewClient("", instances[0].Meta["AUTH_KEY"]) if err != nil { log.Error("error creating controller client", "err", err) return err } log.Info("validating images") uris := make(map[string]string, len(updater.SystemApps)+2) for _, name := range append(updater.SystemApps, "slugbuilder", "slugrunner") { image := "flynn/" + name if name == "gitreceive" { image = "flynn/receiver" } else if name == "postgres" { image = "flynn/postgresql" } uri, ok := images[image] if !ok { err := fmt.Errorf("missing image: %s", image) log.Error(err.Error()) return err } uris[name] = uri } slugbuilderURI = uris["slugbuilder"] slugrunnerURI = uris["slugrunner"] // deploy system apps in order first for _, name := range updater.SystemApps { log := log.New("name", name) log.Info("starting deploy of system app") app, err := client.GetApp(name) if err != nil { log.Error("error getting app", "err", err) return err } if err := deployApp(client, app, uris[name], log); err != nil { if e, ok := err.(errDeploySkipped); ok { log.Info("skipped deploy of system app", "reason", e.reason) continue } return err } log.Info("finished deploy of system app") } // deploy all other apps apps, err := client.AppList() if err != nil { log.Error("error getting apps", "err", err) return err } for _, app := range apps { if app.System() { continue } log := log.New("name", app.Name) log.Info("starting deploy of app to update slugrunner") if err := deployApp(client, app, slugrunnerURI, log); err != nil { if e, ok := err.(errDeploySkipped); ok { log.Info("skipped deploy of app", "reason", e.reason) continue } return err } log.Info("finished deploy of app") } return nil }