Пример #1
0
// 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
}
Пример #2
0
// 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
}
Пример #3
0
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
	}
}
Пример #4
0
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))
	}
}
Пример #5
0
// Stop stops Reaper's schedule
func (r *Reaper) Stop() {
	log.Debug("Stopping Reaper")
	reaperevents.Cleanup()
	r.Cron.Stop()
}