func (r rctlParams) RollingUpdate(oldID, newID string, want, need int, pagerdutyServiceKey string) { if want < need { r.logger.WithFields(logrus.Fields{ "want": want, "need": need, }).Fatalln("Cannot run update with desired replicas less than minimum replicas") } sessions := make(chan string) quit := make(chan struct{}) go consulutil.SessionManager(api.SessionEntry{ Name: SessionName(), LockDelay: 5 * time.Second, Behavior: api.SessionBehaviorDelete, TTL: "15s", }, r.baseClient, sessions, quit, r.logger) sessionID := <-sessions if sessionID == "" { r.logger.NoFields().Fatalln("Could not acquire session") } session := r.kps.NewUnmanagedSession(sessionID, "") alerter := alerting.NewNop() if pagerdutyServiceKey != "" { var err error alerter, err = alerting.NewPagerduty(pagerdutyServiceKey, r.httpClient) if err != nil { r.logger.WithError(err).Fatalln("Could not initialize pagerduty alerter") } } result := make(chan bool, 1) go func() { result <- roll.NewUpdate(roll_fields.Update{ OldRC: rc_fields.ID(oldID), NewRC: rc_fields.ID(newID), DesiredReplicas: want, MinimumReplicas: need, }, r.kps, r.rcs, r.hcheck, r.labeler, r.sched, r.logger, session, alerter).Run(quit) close(result) }() signals := make(chan os.Signal, 2) signal.Notify(signals, syscall.SIGTERM, os.Interrupt) LOOP: for { select { case <-signals: // try to clean up locks on ^C close(quit) // do not exit right away - the session and result channels will be // closed after the quit is requested, ensuring that the locks held // by the farm were released. r.logger.NoFields().Errorln("Got signal, exiting") case <-sessions: r.logger.NoFields().Fatalln("Lost session") case res := <-result: // done, either due to ^C (already printed message above) or // clean finish if res { r.logger.NoFields().Infoln("Done") } break LOOP } } }
func main() { // Parse custom flags + standard Consul routing options kingpin.Version(version.VERSION) _, opts := flags.ParseWithConsulOptions() // Set up the logger logger := logging.NewLogger(logrus.Fields{}) logger.Logger.Formatter = new(logrus.TextFormatter) if *logLevel != "" { lv, err := logrus.ParseLevel(*logLevel) if err != nil { logger.WithErrorAndFields(err, logrus.Fields{"level": *logLevel}). Fatalln("Could not parse log level") } logger.Logger.Level = lv } // Initialize the myriad of different storage components httpClient := cleanhttp.DefaultClient() client := kp.NewConsulClient(opts) kpStore := kp.NewConsulStore(client) rcStore := rcstore.NewConsul(client, RetryCount) rollStore := rollstore.NewConsul(client, nil) healthChecker := checker.NewConsulHealthChecker(client) labeler := labels.NewConsulApplicator(client, RetryCount) var sched scheduler.Scheduler if *labelEndpoint != "" { endpoint, err := url.Parse(*labelEndpoint) if err != nil { logger.WithErrorAndFields(err, logrus.Fields{ "url": *labelEndpoint, }).Fatalln("Could not parse URL from label endpoint") } httpLabeler, err := labels.NewHttpApplicator(opts.Client, endpoint) if err != nil { logger.WithError(err).Fatalln("Could not create label applicator from endpoint") } sched = scheduler.NewApplicatorScheduler(httpLabeler) } else { sched = scheduler.NewApplicatorScheduler(labeler) } // Start acquiring sessions sessions := make(chan string) go consulutil.SessionManager(api.SessionEntry{ Name: SessionName(), LockDelay: 5 * time.Second, Behavior: api.SessionBehaviorDelete, TTL: "15s", }, client, sessions, nil, logger) pub := stream.NewStringValuePublisher(sessions, "") alerter := alerting.NewNop() if *pagerdutyServiceKey != "" { var err error alerter, err = alerting.NewPagerduty(*pagerdutyServiceKey, httpClient) if err != nil { logger.WithError(err).Fatalln( "Unable to initialize pagerduty alerter", ) } } // Run the farms! go rc.NewFarm( kpStore, rcStore, sched, labeler, pub.Subscribe().Chan(), logger, klabels.Everything(), alerter, ).Start(nil) roll.NewFarm( roll.UpdateFactory{ KPStore: kpStore, RCStore: rcStore, HealthChecker: healthChecker, Labeler: labeler, Scheduler: sched, }, kpStore, rollStore, rcStore, pub.Subscribe().Chan(), logger, labeler, klabels.Everything(), alerter, ).Start(nil) }