diff --git a/go.mod b/go.mod index a6e634f..7232196 100644 --- a/go.mod +++ b/go.mod @@ -4,10 +4,10 @@ go 1.18 require ( github.com/gin-gonic/gin v1.8.1 + github.com/hashicorp/go-version v1.6.0 github.com/hexops/gotextdiff v1.0.3 github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 github.com/sirupsen/logrus v1.9.0 - github.com/toqueteos/webbrowser v1.2.0 gopkg.in/yaml.v3 v3.0.1 helm.sh/helm/v3 v3.9.4 k8s.io/apimachinery v0.25.0-alpha.2 diff --git a/go.sum b/go.sum index 552ac51..dd64460 100644 --- a/go.sum +++ b/go.sum @@ -31,6 +31,8 @@ github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeN github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek= +github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM= github.com/hexops/gotextdiff v1.0.3/go.mod h1:pSWU5MAI3yDq+fZBTazCSJysOMbxWL1BSow5/V2vxeg= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= @@ -78,8 +80,6 @@ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= -github.com/toqueteos/webbrowser v1.2.0 h1:tVP/gpK69Fx+qMJKsLE7TD8LuGWPnEV71wBN9rrstGQ= -github.com/toqueteos/webbrowser v1.2.0/go.mod h1:XWoZq4cyp9WeUeak7w7LXRUQf1F1ATJMir8RTqb4ayM= github.com/ugorji/go v1.2.7/go.mod h1:nF9osbDWLy6bDVv/Rtoh6QgnvNDpmCalQV5urGCCS6M= github.com/ugorji/go/codec v1.2.7 h1:YPXUKf7fYbp/y8xloBqZOw2qaVggbfwMlI8WM3wZUJ0= github.com/ugorji/go/codec v1.2.7/go.mod h1:WGN1fab3R1fzQlVQTkfxVtIBhWDRqOviHU95kRgeqEY= diff --git a/pkg/dashboard/api.go b/pkg/dashboard/api.go index 931af84..6f75830 100644 --- a/pkg/dashboard/api.go +++ b/pkg/dashboard/api.go @@ -44,7 +44,7 @@ func contextSetter(data *subproc.DataLayer) gin.HandlerFunc { } } -func NewRouter(abortWeb utils.ControlChan, data *subproc.DataLayer, version string) *gin.Engine { +func NewRouter(abortWeb utils.ControlChan, data *subproc.DataLayer) *gin.Engine { var api *gin.Engine if os.Getenv("DEBUG") == "" { api = gin.New() @@ -58,12 +58,12 @@ func NewRouter(abortWeb utils.ControlChan, data *subproc.DataLayer, version stri api.Use(errorHandler) configureStatic(api) - configureRoutes(abortWeb, data, api, version) + configureRoutes(abortWeb, data, api) return api } -func configureRoutes(abortWeb utils.ControlChan, data *subproc.DataLayer, api *gin.Engine, version string) { +func configureRoutes(abortWeb utils.ControlChan, data *subproc.DataLayer, api *gin.Engine) { // server shutdown handler api.DELETE("/", func(c *gin.Context) { abortWeb <- struct{}{} @@ -71,7 +71,7 @@ func configureRoutes(abortWeb utils.ControlChan, data *subproc.DataLayer, api *g }) api.GET("/status", func(c *gin.Context) { - c.String(http.StatusOK, version) + c.IndentedJSON(http.StatusOK, data.VersionInfo) }) configureHelms(api.Group("/api/helm"), data) diff --git a/pkg/dashboard/server.go b/pkg/dashboard/server.go index 6bf596c..2f239c8 100644 --- a/pkg/dashboard/server.go +++ b/pkg/dashboard/server.go @@ -2,13 +2,16 @@ package dashboard import ( "context" + "encoding/json" "github.com/gin-gonic/gin" + "github.com/hashicorp/go-version" "github.com/komodorio/helm-dashboard/pkg/dashboard/scanners" "github.com/komodorio/helm-dashboard/pkg/dashboard/subproc" "github.com/komodorio/helm-dashboard/pkg/dashboard/utils" log "github.com/sirupsen/logrus" "net/http" "os" + "time" ) func StartServer(version string) (string, utils.ControlChan) { @@ -19,6 +22,9 @@ func StartServer(version string) (string, utils.ControlChan) { os.Exit(1) // TODO: propagate error instead? } + data.VersionInfo = &subproc.VersionInfo{CurVer: version} + go checkUpgrade(data.VersionInfo) + discoverScanners(&data) address := os.Getenv("HD_BIND") @@ -33,7 +39,7 @@ func StartServer(version string) (string, utils.ControlChan) { } abort := make(utils.ControlChan) - api := NewRouter(abort, &data, version) + api := NewRouter(abort, &data) done := startBackgroundServer(address, api, abort) return "http://" + address, done @@ -75,3 +81,44 @@ func discoverScanners(data *subproc.DataLayer) { } } } + +func checkUpgrade(d *subproc.VersionInfo) { + url := "https://api.github.com/repos/komodorio/helm-dashboard/releases/latest" + type GHRelease struct { + Name string `json:"name"` + } + + var myClient = &http.Client{Timeout: 5 * time.Second} + r, err := myClient.Get(url) + if err != nil { + log.Warnf("Failed to check for new version: %s", err) + return + } + defer r.Body.Close() + + target := new(GHRelease) + err = json.NewDecoder(r.Body).Decode(target) + if err != nil { + log.Warnf("Failed to decode new release version: %s", err) + return + } + d.LatestVer = target.Name + + v1, err := version.NewVersion(d.CurVer) + if err != nil { + log.Warnf("Failed to parse version: %s", err) + v1 = &version.Version{} + } + + v2, err := version.NewVersion(d.LatestVer) + if err != nil { + log.Warnf("Failed to parse version: %s", err) + } else { + if v1.LessThan(v2) { + log.Warnf("Newer Helm Dashboard version is available: %s", d.LatestVer) + log.Warnf("Upgrade instructions: https://github.com/komodorio/helm-dashboard#installing") + } else { + log.Debugf("Got latest version from GH: %s", d.LatestVer) + } + } +} diff --git a/pkg/dashboard/static/datadog.js b/pkg/dashboard/static/datadog.js index ecba853..ff4fe6d 100644 --- a/pkg/dashboard/static/datadog.js +++ b/pkg/dashboard/static/datadog.js @@ -5,8 +5,8 @@ })(window,document,'script','https://www.datadoghq-browser-agent.com/datadog-rum-v4.js','DD_RUM') DD_RUM.onReady(function() { const xhr = new XMLHttpRequest(); - xhr.onreadystatechange = function() { - const version = xhr.responseText; + xhr.onload = function() { + const version = JSON.parse(xhr.responseText).VerCur; if (xhr.readyState === XMLHttpRequest.DONE && version!=="dev") { DD_RUM.init({ clientToken: 'pub16d64cd1c00cf073ce85af914333bf72', diff --git a/pkg/dashboard/static/index.html b/pkg/dashboard/static/index.html index a1e0607..a9d84ef 100644 --- a/pkg/dashboard/static/index.html +++ b/pkg/dashboard/static/index.html @@ -54,8 +54,11 @@ Repository