Skip to content

Commit

Permalink
Remove legacy HTTP API
Browse files Browse the repository at this point in the history
Signed-off-by: beorn7 <beorn@soundcloud.com>
  • Loading branch information
beorn7 committed Dec 4, 2018
1 parent 949c831 commit 4c1bf91
Show file tree
Hide file tree
Showing 4 changed files with 0 additions and 226 deletions.
39 changes: 0 additions & 39 deletions handler/delete.go
Expand Up @@ -66,42 +66,3 @@ func Delete(ms storage.MetricStore) func(http.ResponseWriter, *http.Request, htt
instrumentedHandler.ServeHTTP(w, r)
}
}

// LegacyDelete returns a handler that accepts delete requests. It deals with
// the deprecated API.
//
// The returned handler is already instrumented for Prometheus.
func LegacyDelete(ms storage.MetricStore) func(http.ResponseWriter, *http.Request, httprouter.Params) {
var ps httprouter.Params
var mtx sync.Mutex // Protects ps.

instrumentedHandler := promhttp.InstrumentHandlerCounter(
httpCnt.MustCurryWith(prometheus.Labels{"handler": "legacy_delete"}),
http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
job := ps.ByName("job")
instance := ps.ByName("instance")
mtx.Unlock()

if job == "" {
http.Error(w, "job name is required", http.StatusBadRequest)
log.Debug("job name is required")
return
}
labels := map[string]string{"job": job}
if instance != "" {
labels["instance"] = instance
}
ms.SubmitWriteRequest(storage.WriteRequest{
Labels: labels,
Timestamp: time.Now(),
})
w.WriteHeader(http.StatusAccepted)
}),
)

return func(w http.ResponseWriter, r *http.Request, params httprouter.Params) {
mtx.Lock()
ps = params
instrumentedHandler.ServeHTTP(w, r)
}
}
81 changes: 0 additions & 81 deletions handler/handler_test.go
Expand Up @@ -80,7 +80,6 @@ func TestHealthyReady(t *testing.T) {
func TestPush(t *testing.T) {
mms := MockMetricStore{}
handler := Push(&mms, false)
legacyHandler := LegacyPush(&mms, false)
req, err := http.NewRequest("POST", "http://example.org/", &bytes.Buffer{})
if err != nil {
t.Fatal(err)
Expand Down Expand Up @@ -113,23 +112,6 @@ func TestPush(t *testing.T) {
t.Errorf("Wanted instance %v, got %v.", expected, got)
}

// With job name, but no instance name and no content, legacy handler.
mms.lastWriteRequest = storage.WriteRequest{}
w = httptest.NewRecorder()
legacyHandler(w, req, httprouter.Params{httprouter.Param{Key: "job", Value: "testjob"}})
if expected, got := http.StatusAccepted, w.Code; expected != got {
t.Errorf("Wanted status code %v, got %v.", expected, got)
}
if mms.lastWriteRequest.Timestamp.IsZero() {
t.Errorf("Write request timestamp not set: %#v", mms.lastWriteRequest)
}
if expected, got := "testjob", mms.lastWriteRequest.Labels["job"]; expected != got {
t.Errorf("Wanted job %v, got %v.", expected, got)
}
if expected, got := "localhost", mms.lastWriteRequest.Labels["instance"]; expected != got {
t.Errorf("Wanted instance %v, got %v.", expected, got)
}

// With job name and instance name and invalid text content.
mms.lastWriteRequest = storage.WriteRequest{}
req, err = http.NewRequest(
Expand Down Expand Up @@ -252,69 +234,6 @@ func TestPush(t *testing.T) {
t.Errorf("Write request timestamp unexpectedly set: %#v", mms.lastWriteRequest)
}

// With job name and instance name and text content, legacy handler.
mms.lastWriteRequest = storage.WriteRequest{}
req, err = http.NewRequest(
"POST", "http://example.org/",
bytes.NewBufferString("some_metric 3.14\nanother_metric 42\n"),
)
if err != nil {
t.Fatal(err)
}
w = httptest.NewRecorder()
legacyHandler(
w, req,
httprouter.Params{
httprouter.Param{Key: "job", Value: "testjob"},
httprouter.Param{Key: "instance", Value: "testinstance"},
},
)
if expected, got := http.StatusAccepted, w.Code; expected != got {
t.Errorf("Wanted status code %v, got %v.", expected, got)
}
if mms.lastWriteRequest.Timestamp.IsZero() {
t.Errorf("Write request timestamp not set: %#v", mms.lastWriteRequest)
}
if expected, got := "testjob", mms.lastWriteRequest.Labels["job"]; expected != got {
t.Errorf("Wanted job %v, got %v.", expected, got)
}
if expected, got := "testinstance", mms.lastWriteRequest.Labels["instance"]; expected != got {
t.Errorf("Wanted instance %v, got %v.", expected, got)
}
if expected, got := `name:"some_metric" type:UNTYPED metric:<label:<name:"instance" value:"testinstance" > label:<name:"job" value:"testjob" > untyped:<value:3.14 > > `, mms.lastWriteRequest.MetricFamilies["some_metric"].String(); expected != got {
t.Errorf("Wanted metric family %v, got %v.", expected, got)
}
if expected, got := `name:"another_metric" type:UNTYPED metric:<label:<name:"instance" value:"testinstance" > label:<name:"job" value:"testjob" > untyped:<value:42 > > `, mms.lastWriteRequest.MetricFamilies["another_metric"].String(); expected != got {
t.Errorf("Wanted metric family %v, got %v.", expected, got)
}
if _, ok := mms.lastWriteRequest.MetricFamilies["push_time_seconds"]; !ok {
t.Errorf("Wanted metric family push_time_seconds missing.")
}

// With job name and instance name and timestamp, legacy handler.
mms.lastWriteRequest = storage.WriteRequest{}
req, err = http.NewRequest(
"POST", "http://example.org/",
bytes.NewBufferString("a 1\nb 1 1000\n"),
)
if err != nil {
t.Fatal(err)
}
w = httptest.NewRecorder()
legacyHandler(
w, req,
httprouter.Params{
httprouter.Param{Key: "job", Value: "testjob"},
httprouter.Param{Key: "instance", Value: "testinstance"},
},
)
if expected, got := http.StatusBadRequest, w.Code; expected != got {
t.Errorf("Wanted status code %v, got %v.", expected, got)
}
if !mms.lastWriteRequest.Timestamp.IsZero() {
t.Errorf("Write request timestamp unexpectedly set: %#v", mms.lastWriteRequest)
}

// With job name and instance name and text content and job and instance labels.
mms.lastWriteRequest = storage.WriteRequest{}
req, err = http.NewRequest(
Expand Down
98 changes: 0 additions & 98 deletions handler/push.go
Expand Up @@ -17,7 +17,6 @@ import (
"fmt"
"io"
"mime"
"net"
"net/http"
"sort"
"strings"
Expand Down Expand Up @@ -137,103 +136,6 @@ func Push(
}
}

// LegacyPush returns an http.Handler which accepts samples over HTTP and stores
// them in the MetricStore. It uses the deprecated API (expecting a 'job'
// parameter and an optional 'instance' parameter). If replace is true, all
// metrics for the job and instance given by the request are deleted before new
// ones are stored.
//
// The returned handler is already instrumented for Prometheus.
func LegacyPush(
ms storage.MetricStore, replace bool,
) func(http.ResponseWriter, *http.Request, httprouter.Params) {
var ps httprouter.Params
var mtx sync.Mutex // Protects ps.

handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
job := ps.ByName("job")
instance := ps.ByName("instance")
mtx.Unlock()

var err error
if job == "" {
http.Error(w, "job name is required", http.StatusBadRequest)
log.Debug("job name is required")
return
}
if instance == "" {
// Remote IP number (without port).
instance, _, err = net.SplitHostPort(r.RemoteAddr)
if err != nil || instance == "" {
instance = "localhost"
}
}
labels := map[string]string{"job": job, "instance": instance}
if replace {
ms.SubmitWriteRequest(storage.WriteRequest{
Labels: labels,
Timestamp: time.Now(),
})
}

var metricFamilies map[string]*dto.MetricFamily
ctMediatype, ctParams, ctErr := mime.ParseMediaType(r.Header.Get("Content-Type"))
if ctErr == nil && ctMediatype == "application/vnd.google.protobuf" &&
ctParams["encoding"] == "delimited" &&
ctParams["proto"] == "io.prometheus.client.MetricFamily" {
metricFamilies = map[string]*dto.MetricFamily{}
for {
mf := &dto.MetricFamily{}
if _, err = pbutil.ReadDelimited(r.Body, mf); err != nil {
if err == io.EOF {
err = nil
}
break
}
metricFamilies[mf.GetName()] = mf
}
} else {
// We could do further content-type checks here, but the
// fallback for now will anyway be the text format
// version 0.0.4, so just go for it and see if it works.
var parser expfmt.TextParser
metricFamilies, err = parser.TextToMetricFamilies(r.Body)
}
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
log.Debugf("Error parsing request body, %v", err.Error())
return
}
if timestampsPresent(metricFamilies) {
http.Error(w, "pushed metrics must not have timestamps", http.StatusBadRequest)
log.Debug("pushed metrics must not have timestamps")
return
}
now := time.Now()
addPushTimestamp(metricFamilies, now)
sanitizeLabels(metricFamilies, labels)
ms.SubmitWriteRequest(storage.WriteRequest{
Labels: labels,
Timestamp: now,
MetricFamilies: metricFamilies,
})
w.WriteHeader(http.StatusAccepted)
})

instrumentedHandler := promhttp.InstrumentHandlerRequestSize(
httpPushSize, promhttp.InstrumentHandlerDuration(
httpPushDuration, promhttp.InstrumentHandlerCounter(
httpCnt.MustCurryWith(prometheus.Labels{"handler": "legacy_push"}),
handler,
)))

return func(w http.ResponseWriter, r *http.Request, params httprouter.Params) {
mtx.Lock()
ps = params
instrumentedHandler.ServeHTTP(w, r)
}
}

// sanitizeLabels ensures that all the labels in groupingLabels and the
// `instance` label are present in each MetricFamily in metricFamilies. The
// label values from groupingLabels are set in each MetricFamily, no matter
Expand Down
8 changes: 0 additions & 8 deletions main.go
Expand Up @@ -96,14 +96,6 @@ func main() {
r.POST(pushAPIPath+"/job/:job", handler.Push(ms, false))
r.DELETE(pushAPIPath+"/job/:job", handler.Delete(ms))

// Handlers for the deprecated API.
r.PUT(pushAPIPath+"/jobs/:job/instances/:instance", handler.LegacyPush(ms, true))
r.POST(pushAPIPath+"/jobs/:job/instances/:instance", handler.LegacyPush(ms, false))
r.DELETE(pushAPIPath+"/jobs/:job/instances/:instance", handler.LegacyDelete(ms))
r.PUT(pushAPIPath+"/jobs/:job", handler.LegacyPush(ms, true))
r.POST(pushAPIPath+"/jobs/:job", handler.LegacyPush(ms, false))
r.DELETE(pushAPIPath+"/jobs/:job", handler.LegacyDelete(ms))

r.Handler("GET", *routePrefix+"/static/*filepath", handler.Static(asset.Assets))

statusHandler := handler.Status(ms, asset.Assets, flags)
Expand Down

0 comments on commit 4c1bf91

Please sign in to comment.