func GetConfigureAlertHandler(client alert.PrometheusAlertClient) func(c echo.Context) error {
	return func(c echo.Context) error {
		defer glog.Flush()
		rule, err := decodeRulePostRequest(c)
		if err != nil {
			return echo.NewHTTPError(http.StatusBadRequest, err.Error())
		}
		tenantID := c.Get(tenantIDParam).(string)
		glog.Infof("Configure Alert: Tenant: %s, %+v", tenantID, rule)
		err = alert.ValidateRule(rule)
		if err != nil {
			return echo.NewHTTPError(http.StatusBadRequest, err.Error())
		}
		if client.RuleExists(tenantID, rule.Alert) {
			return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Rule '%s' already exists", rule.Alert))
		}
		err = client.WriteRule(tenantID, rule)
		if err != nil {
			return echo.NewHTTPError(http.StatusInternalServerError, err.Error())
		}
		err = client.ReloadPrometheus()
		if err != nil {
			return echo.NewHTTPError(http.StatusInternalServerError, err.Error())
		}
		return c.NoContent(http.StatusOK)
	}
}
GetConfigureAlertHandler returns a handler that calls the client method WriteAlert() to
write the alert configuration from the body of this request
package handlers
import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"github.com/facebookincubator/prometheus-configmanager/prometheus/alert"
	"github.com/golang/glog"
	"github.com/labstack/echo"
	"github.com/prometheus/prometheus/pkg/rulefmt"
)
const (
	v0rootPath        = "/:tenant_id"
	v0alertPath       = "/alert"
	v0alertUpdatePath = v0alertPath + "/:" + ruleNameParam
	v0alertBulkPath   = v0alertPath + "/bulk"
	ruleNameParam = "alert_name"
	tenantIDParam = "tenant_id"
	v1rootPath       = "/v1"
	v1TenantRootPath = v1rootPath + "/:tenant_id"
	v1alertPath     = "/alert"
	v1alertBulkPath = v1alertPath + "/bulk"
	v1alertNamePath = v1alertPath + "/:" + ruleNameParam
	v1TenancyPath   = "/tenancy"
)
func statusHandler(c echo.Context) error {
	return c.String(http.StatusOK, "Prometheus Config server")
}
func RegisterBaseHandlers(e *echo.Echo) {
	e.GET("/", statusHandler)
}
func RegisterV0Handlers(e *echo.Echo, alertClient alert.PrometheusAlertClient) {
	v0 := e.Group(v0rootPath)
	v0.Use(tenancyMiddlewareProvider(pathTenantProvider))
	v0.POST(v0alertPath, GetConfigureAlertHandler(alertClient))
	v0.GET(v0alertPath, GetRetrieveAlertHandler(alertClient))
	v0.DELETE(v0alertPath, GetDeleteAlertHandler(alertClient, queryAlertNameProvider))
	v0.PUT(v0alertUpdatePath, GetUpdateAlertHandler(alertClient))
	v0.PUT(v0alertBulkPath, GetBulkAlertUpdateHandler(alertClient))
}
func RegisterV1Handlers(e *echo.Echo, alertClient alert.PrometheusAlertClient) {
	v1 := e.Group(v1rootPath)
	v1.GET(v1TenancyPath, GetGetTenancyHandler(alertClient))
	v1Tenant := e.Group(v1TenantRootPath)
	v1Tenant.Use(tenancyMiddlewareProvider(pathTenantProvider))
	v1Tenant.POST(v1alertPath, GetConfigureAlertHandler(alertClient))
	v1Tenant.GET(v1alertPath, GetRetrieveAlertHandler(alertClient))
	v1Tenant.DELETE(v1alertNamePath, GetDeleteAlertHandler(alertClient, pathAlertNameProvider))
	v1Tenant.PUT(v1alertNamePath, GetUpdateAlertHandler(alertClient))
	v1Tenant.GET(v1alertNamePath, GetRetrieveAlertHandler(alertClient))
	v1Tenant.POST(v1alertBulkPath, GetBulkAlertUpdateHandler(alertClient))
}
func tenancyMiddlewareProvider(getTenantID paramProvider) echo.MiddlewareFunc {
	return func(next echo.HandlerFunc) echo.HandlerFunc {
		return func(c echo.Context) error {
			providedTenantID := getTenantID(c)
			if providedTenantID == "" {
				return echo.NewHTTPError(http.StatusBadRequest, "Must provide tenant_id parameter")
			}
			c.Set(tenantIDParam, providedTenantID)
			return next(c)
		}
	}
}
type paramProvider func(c echo.Context) string
var pathTenantProvider = func(c echo.Context) string {
	return c.Param(tenantIDParam)
}
var pathAlertNameProvider = func(c echo.Context) string {
	return c.Param(ruleNameParam)
}
var queryAlertNameProvider = func(c echo.Context) string {
	return c.QueryParam(ruleNameParam)
}