Skip to content

Commit b66fc33

Browse files
Brett LoganBrett Logan
Brett Logan
authored and
Brett Logan
committed
[FAB-15814] Add endpoint for versioning metadata
Adds a /version endpoint to the operations server that serves the Version and CommitSHA from the common/metadata package Change-Id: Ic16e044f989bf9bdf827637412217fb07a8394e3 Signed-off-by: Brett Logan <[email protected]>
1 parent 5d23cfa commit b66fc33

File tree

4 files changed

+114
-0
lines changed

4 files changed

+114
-0
lines changed

core/operations/system.go

+10
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import (
1919
"github.com/hyperledger/fabric-lib-go/healthz"
2020
"github.com/hyperledger/fabric/common/flogging"
2121
"github.com/hyperledger/fabric/common/flogging/httpadmin"
22+
"github.com/hyperledger/fabric/common/metadata"
2223
"github.com/hyperledger/fabric/common/metrics"
2324
"github.com/hyperledger/fabric/common/metrics/disabled"
2425
"github.com/hyperledger/fabric/common/metrics/prometheus"
@@ -86,6 +87,7 @@ func NewSystem(o Options) *System {
8687
system.initializeHealthCheckHandler()
8788
system.initializeLoggingHandler()
8889
system.initializeMetricsProvider()
90+
system.initializeVersionInfoHandler()
8991

9092
return system
9193
}
@@ -201,6 +203,14 @@ func (s *System) initializeHealthCheckHandler() {
201203
s.mux.Handle("/healthz", s.handlerChain(s.healthHandler, false))
202204
}
203205

206+
func (s *System) initializeVersionInfoHandler() {
207+
versionInfo := &VersionInfoHandler{
208+
CommitSHA: metadata.CommitSHA,
209+
Version: metadata.Version,
210+
}
211+
s.mux.Handle("/version", s.handlerChain(versionInfo, false))
212+
}
213+
204214
func (s *System) startMetricsTickers() error {
205215
m := s.options.Metrics
206216
if s.statsd != nil {

core/operations/system_test.go

+11
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,17 @@ var _ = Describe("System", func() {
7878
}
7979
})
8080

81+
It("hosts an unsecured endpoint for the version information", func() {
82+
err := system.Start()
83+
Expect(err).NotTo(HaveOccurred())
84+
85+
versionURL := fmt.Sprintf("https://%s/version", system.Addr())
86+
resp, err := client.Get(versionURL)
87+
Expect(err).NotTo(HaveOccurred())
88+
Expect(resp.StatusCode).To(Equal(http.StatusOK))
89+
resp.Body.Close()
90+
})
91+
8192
It("hosts a secure endpoint for logging", func() {
8293
err := system.Start()
8394
Expect(err).NotTo(HaveOccurred())

core/operations/version.go

+50
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
/*
2+
Copyright IBM Corp All Rights Reserved.
3+
4+
SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
package operations
8+
9+
import (
10+
"encoding/json"
11+
"fmt"
12+
"net/http"
13+
14+
"github.com/hyperledger/fabric/common/flogging"
15+
)
16+
17+
type VersionInfoHandler struct {
18+
CommitSHA string `json:"CommitSHA,omitempty"`
19+
Version string `json:"Version,omitempty"`
20+
}
21+
22+
func (m *VersionInfoHandler) ServeHTTP(resp http.ResponseWriter, req *http.Request) {
23+
switch req.Method {
24+
case http.MethodGet:
25+
m.sendResponse(resp, http.StatusOK, m)
26+
default:
27+
err := fmt.Errorf("invalid request method: %s", req.Method)
28+
m.sendResponse(resp, http.StatusBadRequest, err)
29+
}
30+
}
31+
32+
type errorResponse struct {
33+
Error string `json:"Error"`
34+
}
35+
36+
func (m *VersionInfoHandler) sendResponse(resp http.ResponseWriter, code int, payload interface{}) {
37+
if err, ok := payload.(error); ok {
38+
payload = &errorResponse{Error: err.Error()}
39+
}
40+
js, err := json.Marshal(payload)
41+
if err != nil {
42+
logger := flogging.MustGetLogger("operations.runner")
43+
logger.Errorw("failed to encode payload", "error", err)
44+
resp.WriteHeader(http.StatusInternalServerError)
45+
} else {
46+
resp.WriteHeader(code)
47+
resp.Header().Set("Content-Type", "application/json")
48+
resp.Write(js)
49+
}
50+
}

core/operations/version_test.go

+43
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
/*
2+
Copyright IBM Corp All Rights Reserved.
3+
4+
SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
package operations
8+
9+
import (
10+
"net/http"
11+
"net/http/httptest"
12+
13+
. "github.com/onsi/ginkgo"
14+
. "github.com/onsi/gomega"
15+
)
16+
17+
var _ = Describe("Version", func() {
18+
It("returns 200 if the method is GET", func() {
19+
resp := httptest.NewRecorder()
20+
21+
versionInfoHandler := &VersionInfoHandler{Version: "latest"}
22+
versionInfoHandler.ServeHTTP(resp, &http.Request{Method: http.MethodGet})
23+
Expect(resp.Result().StatusCode).To(Equal(http.StatusOK))
24+
Expect(resp.Body).To(MatchJSON(`{"Version": "latest"}`))
25+
})
26+
27+
It("returns 400 when an unsupported method is used", func() {
28+
resp := httptest.NewRecorder()
29+
30+
versionInfoHandler := &VersionInfoHandler{}
31+
versionInfoHandler.ServeHTTP(resp, &http.Request{Method: http.MethodPut})
32+
Expect(resp.Result().StatusCode).To(Equal(http.StatusBadRequest))
33+
Expect(resp.Body).To(MatchJSON(`{"Error": "invalid request method: PUT"}`))
34+
})
35+
36+
It("returns 500 when the payload is invalid JSON", func() {
37+
resp := httptest.NewRecorder()
38+
39+
versionInfoHandler := &VersionInfoHandler{}
40+
versionInfoHandler.sendResponse(resp, 200, make(chan int))
41+
Expect(resp.Result().StatusCode).To(Equal(http.StatusInternalServerError))
42+
})
43+
})

0 commit comments

Comments
 (0)