// Stop by region, id, calls a Reapable's own Stop method func Stop(region reapable.Region, id reapable.ID) error { reapable, err := reapables.Get(region, id) if err != nil { return err } _, err = reapable.Stop() if err != nil { log.Error(fmt.Sprintf("Could not stop resource with region: %s and id: %s. Error: %s", region, id, err.Error())) return err } log.Debug("Stop ", reapable.ReapableDescriptionShort()) return nil }
// Serve should be run in a goroutine func (h *HTTPApi) Serve() (e error) { h.ln, e = net.Listen("tcp", h.conf.Listen) if e != nil { return } mux := http.NewServeMux() mux.HandleFunc("/", processToken(h)) mux.HandleFunc("/__heartbeat__", heartbeat(h)) mux.HandleFunc("/__lbheartbeat__", heartbeat(h)) h.server = &http.Server{Handler: mux} log.Debug("Starting HTTP server: %s", h.conf.Listen) go h.server.Serve(h.ln) return nil }
func init() { configFile := flag.String("config", "", "path to config file") withoutCloudformationResources := flag.Bool("withoutCloudformationResources", false, "disables dependency checking for Cloudformations (which is slow!)") useMozlog := flag.Bool("useMozlog", true, "set to false to disable mozlog output") flag.Parse() if *useMozlog { log.EnableMozlog() } // if no config file -> exit with error if *configFile == "" { log.Error("Config file is a required Argument. Specify with -config='filename'") os.Exit(1) } // if config file path specified, attempt to load it if c, err := reaper.LoadConfig(*configFile); err == nil { // catches panics loading config defer func() { if r := recover(); r != nil { log.Error("Invalid config ", r) os.Exit(1) } }() config = *c log.Info(fmt.Sprintf("Configuration loaded from %s", *configFile)) } else { // config not successfully loaded -> exit with error log.Error("toml", err) os.Exit(1) } // if log file path specified, attempt to load it if config.LogFile != "" { log.AddLogFile(config.LogFile) } // if DatadogStatistics EventReporter is enabled if config.Events.DatadogStatistics.Enabled { log.Info("DatadogStatistics EventReporter enabled.") eventReporters = append(eventReporters, reaperevents.NewDatadogStatistics(&config.Events.DatadogStatistics)) } // if DatadogEvents EventReporter is enabled if config.Events.DatadogEvents.Enabled { log.Info("DatadogEvents EventReporter enabled.") eventReporters = append(eventReporters, reaperevents.NewDatadogEvents(&config.Events.DatadogEvents)) } // if Email EventReporter is enabled if config.Events.Email.Enabled { log.Info("Email EventReporter enabled.") eventReporters = append(eventReporters, reaperevents.NewMailer(&config.Events.Email)) // these methods have pointer receivers log.Debug("SMTP Config: %s", &config.Events.Email) log.Debug("SMTP From: %s", &config.Events.Email.From) } // if Tagger EventReporter is enabled if config.Events.Tagger.Enabled { log.Info("Tagger EventReporter enabled.") eventReporters = append(eventReporters, reaperevents.NewTagger(&config.Events.Tagger)) } // if Reaper EventReporter is enabled if config.Events.Reaper.Enabled { log.Info("Reaper EventReporter enabled.") eventReporters = append(eventReporters, reaperevents.NewReaperEvent(&config.Events.Reaper)) } // if WhitelistTag is not set if config.WhitelistTag == "" { log.Error("WhitelistTag is empty, exiting") os.Exit(1) } else { log.Info("Using WhitelistTag '%s'", config.WhitelistTag) } if *withoutCloudformationResources { config.AWS.WithoutCloudformationResources = true } }
func processToken(h *HTTPApi) func(http.ResponseWriter, *http.Request) { return func(w http.ResponseWriter, req *http.Request) { if err := req.ParseForm(); err != nil { writeResponse(w, http.StatusBadRequest, "Bad query string") return } userToken := req.Form.Get(h.conf.Token) if userToken == "" { writeResponse(w, http.StatusBadRequest, "Token Missing") return } if u, err := url.QueryUnescape(userToken); err == nil { userToken = u } else { writeResponse(w, http.StatusBadRequest, "Invalid Token, could not decode data") return } job, err := token.Untokenize(h.conf.TokenSecret, userToken) if err != nil { writeResponse(w, http.StatusBadRequest, "Invalid Token, Could not untokenize") return } if job.Expired() == true { writeResponse(w, http.StatusBadRequest, "Token expired") return } // find reapable associated with the job r, err := reapables.Get(reapable.Region(job.Region), reapable.ID(job.ID)) if err != nil { writeResponse(w, http.StatusInternalServerError, err.Error()) return } switch job.Action { case token.J_DELAY: log.Debug("Delay request received for %s in region %s until %s", job.ID, job.Region, job.IgnoreUntil.String()) s := r.ReaperState() ok, err := r.Save(state.NewStateWithUntilAndState(s.Until.Add(job.IgnoreUntil), s.State)) if err != nil { writeResponse(w, http.StatusInternalServerError, err.Error()) return } if !ok { writeResponse(w, http.StatusInternalServerError, fmt.Sprintf("Delay failed for %s.", r.ReapableDescriptionTiny())) return } reaperevents.NewEvent("Reaper: Delay Request Received", fmt.Sprintf("Delay for %s in region %s until %s", job.ID, job.Region, job.IgnoreUntil.String()), nil, []string{}, ) reaperevents.NewCountStatistic("reaper.reapables.requests", []string{"type:delay"}) case token.J_TERMINATE: log.Debug("Terminate request received for %s in region %s.", job.ID, job.Region) ok, err := r.Terminate() if err != nil { writeResponse(w, http.StatusInternalServerError, err.Error()) return } if !ok { writeResponse(w, http.StatusInternalServerError, fmt.Sprintf("Terminate failed for %s.", r.ReapableDescriptionTiny())) return } reaperevents.NewEvent("Reaper: Terminate Request Received", r.ReapableDescriptionShort(), nil, []string{}) reaperevents.NewCountStatistic("reaper.reapables.requests", []string{"type:terminate"}) case token.J_WHITELIST: log.Debug("Whitelist request received for %s in region %s", job.ID, job.Region) ok, err := r.Whitelist() if err != nil { writeResponse(w, http.StatusInternalServerError, err.Error()) return } if !ok { writeResponse(w, http.StatusInternalServerError, fmt.Sprintf("Whitelist failed for %s.", r.ReapableDescriptionTiny())) return } reaperevents.NewEvent("Reaper: Whitelist Request Received", r.ReapableDescriptionShort(), nil, []string{}) reaperevents.NewCountStatistic("reaper.reapables.requests", []string{"type:whitelist"}) case token.J_STOP: log.Debug("Stop request received for %s in region %s", job.ID, job.Region) ok, err := r.Stop() if err != nil { writeResponse(w, http.StatusInternalServerError, err.Error()) return } if !ok { writeResponse(w, http.StatusInternalServerError, fmt.Sprintf("Stop failed for %s.", r.ReapableDescriptionTiny())) return } reaperevents.NewEvent("Reaper: Stop Request Received", r.ReapableDescriptionShort(), nil, []string{}) reaperevents.NewCountStatistic("reaper.reapables.requests", []string{"type:stop"}) default: log.Error("Unrecognized job token received.") writeResponse(w, http.StatusInternalServerError, "Unrecognized job token.") return } var consoleURL *url.URL switch t := r.(type) { case *reaperaws.Instance: consoleURL = t.AWSConsoleURL() case *reaperaws.AutoScalingGroup: consoleURL = t.AWSConsoleURL() default: log.Error("No AWSConsoleURL") } writeResponse(w, http.StatusOK, fmt.Sprintf("Success. Check %s out on the <a href=\"%s\">AWS Console.</a>", r.ReapableDescriptionTiny(), consoleURL)) } }
// Stop stops Reaper's schedule func (r *Reaper) Stop() { log.Debug("Stopping Reaper") reaperevents.Cleanup() r.Cron.Stop() }