HTTP control server /version endpoint

This commit is contained in:
Quentin McGaw
2020-11-04 14:07:04 +00:00
parent b5fb2b849a
commit 3b04677f8f
6 changed files with 55 additions and 21 deletions

View File

@@ -20,6 +20,7 @@ import (
"github.com/qdm12/gluetun/internal/healthcheck" "github.com/qdm12/gluetun/internal/healthcheck"
"github.com/qdm12/gluetun/internal/httpproxy" "github.com/qdm12/gluetun/internal/httpproxy"
gluetunLogging "github.com/qdm12/gluetun/internal/logging" gluetunLogging "github.com/qdm12/gluetun/internal/logging"
"github.com/qdm12/gluetun/internal/models"
"github.com/qdm12/gluetun/internal/openvpn" "github.com/qdm12/gluetun/internal/openvpn"
"github.com/qdm12/gluetun/internal/params" "github.com/qdm12/gluetun/internal/params"
"github.com/qdm12/gluetun/internal/publicip" "github.com/qdm12/gluetun/internal/publicip"
@@ -37,11 +38,11 @@ import (
) )
//nolint:gochecknoglobals //nolint:gochecknoglobals
var ( var buildInfo = models.BuildInformation{
version = "unknown" Version: "unknown",
commit = "unknown" Commit: "unknown",
buildDate = "an unknown date" BuildDate: "an unknown date",
) }
func main() { func main() {
ctx := context.Background() ctx := context.Background()
@@ -86,7 +87,7 @@ func _main(background context.Context, args []string) int { //nolint:gocognit,go
streamMerger := command.NewStreamMerger() streamMerger := command.NewStreamMerger()
paramsReader := params.NewReader(logger, fileManager) paramsReader := params.NewReader(logger, fileManager)
fmt.Println(gluetunLogging.Splash(version, commit, buildDate)) fmt.Println(gluetunLogging.Splash(buildInfo))
printVersions(ctx, logger, map[string]func(ctx context.Context) (string, error){ printVersions(ctx, logger, map[string]func(ctx context.Context) (string, error){
"OpenVPN": ovpnConf.Version, "OpenVPN": ovpnConf.Version,
@@ -262,7 +263,7 @@ func _main(background context.Context, args []string) int { //nolint:gocognit,go
controlServerAddress := fmt.Sprintf("0.0.0.0:%d", allSettings.ControlServer.Port) controlServerAddress := fmt.Sprintf("0.0.0.0:%d", allSettings.ControlServer.Port)
controlServerLogging := allSettings.ControlServer.Log controlServerLogging := allSettings.ControlServer.Log
httpServer := server.New(controlServerAddress, controlServerLogging, httpServer := server.New(controlServerAddress, controlServerLogging,
logger, openvpnLooper, unboundLooper, updaterLooper) logger, buildInfo, openvpnLooper, unboundLooper, updaterLooper)
wg.Add(1) wg.Add(1)
go httpServer.Run(ctx, wg) go httpServer.Run(ctx, wg)
@@ -434,7 +435,7 @@ func routeReadyEvents(ctx context.Context, wg *sync.WaitGroup, tunnelReadyCh, dn
if !versionInformation { if !versionInformation {
break break
} }
message, err := versionpkg.GetMessage(ctx, version, commit, httpClient) message, err := versionpkg.GetMessage(ctx, buildInfo, httpClient)
if err != nil { if err != nil {
logger.Error(err) logger.Error(err)
break break

View File

@@ -7,13 +7,15 @@ import (
"github.com/kyokomi/emoji" "github.com/kyokomi/emoji"
"github.com/qdm12/gluetun/internal/constants" "github.com/qdm12/gluetun/internal/constants"
"github.com/qdm12/gluetun/internal/models"
) )
// Splash returns the welcome spash message. // Splash returns the welcome spash message.
func Splash(version, commit, buildDate string) string { func Splash(buildInfo models.BuildInformation) string {
lines := title() lines := title()
lines = append(lines, "") lines = append(lines, "")
lines = append(lines, fmt.Sprintf("Running version %s built on %s (commit %s)", version, buildDate, commit)) lines = append(lines, fmt.Sprintf("Running version %s built on %s (commit %s)",
buildInfo.Version, buildInfo.BuildDate, buildInfo.Commit))
lines = append(lines, "") lines = append(lines, "")
lines = append(lines, announcement()...) lines = append(lines, announcement()...)
lines = append(lines, "") lines = append(lines, "")

7
internal/models/build.go Normal file
View File

@@ -0,0 +1,7 @@
package models
type BuildInformation struct {
Version string `json:"version"`
Commit string `json:"commit"`
BuildDate string `json:"buildDate"`
}

View File

@@ -3,12 +3,12 @@ package server
import ( import (
"context" "context"
"fmt" "fmt"
"net"
"net/http" "net/http"
"sync" "sync"
"time" "time"
"github.com/qdm12/gluetun/internal/dns" "github.com/qdm12/gluetun/internal/dns"
"github.com/qdm12/gluetun/internal/models"
"github.com/qdm12/gluetun/internal/openvpn" "github.com/qdm12/gluetun/internal/openvpn"
"github.com/qdm12/gluetun/internal/updater" "github.com/qdm12/gluetun/internal/updater"
"github.com/qdm12/golibs/logging" "github.com/qdm12/golibs/logging"
@@ -22,22 +22,22 @@ type server struct {
address string address string
logging bool logging bool
logger logging.Logger logger logging.Logger
buildInfo models.BuildInformation
openvpnLooper openvpn.Looper openvpnLooper openvpn.Looper
unboundLooper dns.Looper unboundLooper dns.Looper
updaterLooper updater.Looper updaterLooper updater.Looper
lookupIP func(host string) ([]net.IP, error)
} }
func New(address string, logging bool, logger logging.Logger, func New(address string, logging bool, logger logging.Logger, buildInfo models.BuildInformation,
openvpnLooper openvpn.Looper, unboundLooper dns.Looper, updaterLooper updater.Looper) Server { openvpnLooper openvpn.Looper, unboundLooper dns.Looper, updaterLooper updater.Looper) Server {
return &server{ return &server{
address: address, address: address,
logging: logging, logging: logging,
logger: logger.WithPrefix("http server: "), logger: logger.WithPrefix("http server: "),
buildInfo: buildInfo,
openvpnLooper: openvpnLooper, openvpnLooper: openvpnLooper,
unboundLooper: unboundLooper, unboundLooper: unboundLooper,
updaterLooper: updaterLooper, updaterLooper: updaterLooper,
lookupIP: net.LookupIP,
} }
} }
@@ -68,6 +68,9 @@ func (s *server) makeHandler() http.HandlerFunc {
switch r.Method { switch r.Method {
case http.MethodGet: case http.MethodGet:
switch r.RequestURI { switch r.RequestURI {
case "/version":
s.handleGetVersion(w)
w.WriteHeader(http.StatusOK)
case "/openvpn/actions/restart": case "/openvpn/actions/restart":
s.openvpnLooper.Restart() s.openvpnLooper.Restart()
w.WriteHeader(http.StatusOK) w.WriteHeader(http.StatusOK)

View File

@@ -0,0 +1,19 @@
package server
import (
"encoding/json"
"net/http"
)
func (s *server) handleGetVersion(w http.ResponseWriter) {
data, err := json.Marshal(s.buildInfo)
if err != nil {
s.logger.Warn(err)
w.WriteHeader(http.StatusInternalServerError)
return
}
if _, err := w.Write(data); err != nil {
s.logger.Warn(err)
w.WriteHeader(http.StatusInternalServerError)
}
}

View File

@@ -7,31 +7,33 @@ import (
"time" "time"
"github.com/qdm12/gluetun/internal/logging" "github.com/qdm12/gluetun/internal/logging"
"github.com/qdm12/gluetun/internal/models"
) )
// GetMessage returns a message for the user describing if there is a newer version // GetMessage returns a message for the user describing if there is a newer version
// available. It should only be called once the tunnel is established. // available. It should only be called once the tunnel is established.
func GetMessage(ctx context.Context, version, commitShort string, client *http.Client) (message string, err error) { func GetMessage(ctx context.Context, buildInfo models.BuildInformation,
if version == "latest" { client *http.Client) (message string, err error) {
if buildInfo.Version == "latest" {
// Find # of commits between current commit and latest commit // Find # of commits between current commit and latest commit
commitsSince, err := getCommitsSince(ctx, client, commitShort) commitsSince, err := getCommitsSince(ctx, client, buildInfo.Commit)
if err != nil { if err != nil {
return "", fmt.Errorf("cannot get version information: %w", err) return "", fmt.Errorf("cannot get version information: %w", err)
} else if commitsSince == 0 { } else if commitsSince == 0 {
return fmt.Sprintf("You are running on the bleeding edge of %s!", version), nil return fmt.Sprintf("You are running on the bleeding edge of %s!", buildInfo.Version), nil
} }
commits := "commits" commits := "commits"
if commitsSince == 1 { if commitsSince == 1 {
commits = "commit" commits = "commit"
} }
return fmt.Sprintf("You are running %d %s behind the most recent %s", commitsSince, commits, version), nil return fmt.Sprintf("You are running %d %s behind the most recent %s", commitsSince, commits, buildInfo.Version), nil
} }
tagName, name, releaseTime, err := getLatestRelease(ctx, client) tagName, name, releaseTime, err := getLatestRelease(ctx, client)
if err != nil { if err != nil {
return "", fmt.Errorf("cannot get version information: %w", err) return "", fmt.Errorf("cannot get version information: %w", err)
} }
if tagName == version { if tagName == buildInfo.Version {
return fmt.Sprintf("You are running the latest release %s", version), nil return fmt.Sprintf("You are running the latest release %s", buildInfo.Version), nil
} }
timeSinceRelease := logging.FormatDuration(time.Since(releaseTime)) timeSinceRelease := logging.FormatDuration(time.Since(releaseTime))
return fmt.Sprintf("There is a new release %s (%s) created %s ago", return fmt.Sprintf("There is a new release %s (%s) created %s ago",