Files
steampipe/pluginmanager/pluginupdate.go

179 lines
4.9 KiB
Go

package pluginmanager
import (
"encoding/json"
"fmt"
"io/ioutil"
"log"
"net/url"
"strings"
"time"
"github.com/turbot/steampipe/ociinstaller"
"github.com/turbot/steampipe/ociinstaller/versionfile"
"github.com/turbot/steampipe/utils"
)
// GetPluginUpdateReport :: looks up and reports the updated version of plugins which are listed in versions.json
func GetPluginUpdateReport(installationID string) map[string]VersionCheckReport {
pvc := new(PluginVersionChecker)
pvc.signature = installationID
return pvc.reportPluginUpdates()
}
// VersionCheckReport ::
type VersionCheckReport struct {
Plugin *versionfile.InstalledVersion
CheckResponse versionCheckPayload
CheckRequest versionCheckPayload
}
// versionCheckPayload :: the payload that travels to-and-fro between steampipe and the server
type versionCheckPayload struct {
Org string `json:"org"`
Name string `json:"name"`
Stream string `json:"stream"`
Version string `json:"version"`
Digest string `json:"digest"`
}
// PluginVersionChecker :: wrapper struct over the plugin version check utilities
type PluginVersionChecker struct {
signature string
}
// CheckAndReportPluginUpdates ::
func (pvc *PluginVersionChecker) reportPluginUpdates() map[string]VersionCheckReport {
versionFileData, err := versionfile.Load()
if err != nil {
log.Println("[TRACE]", "CheckAndReportPluginUpdates", "could not load versionfile")
return nil
}
if versionFileData.Plugins == nil {
versionFileData.Plugins = make(map[string](*versionfile.InstalledVersion))
}
pluginsToCheck := pvc.filterPluginsToCheck(versionFileData.Plugins)
if len(pluginsToCheck) == 0 {
// there's no plugin installed. no point continuing
return nil
}
reports := pvc.getLatestVersionsForPlugins(pluginsToCheck)
// update the version file
for _, plugin := range pluginsToCheck {
versionFileData.Plugins[plugin.Name].LastCheckedDate = versionfile.FormatTime(time.Now())
}
versionFileData.Save()
return reports
}
func (pvc *PluginVersionChecker) filterPluginsToCheck(plugins map[string]*versionfile.InstalledVersion) map[string]*versionfile.InstalledVersion {
pluginsToCheck := map[string]*versionfile.InstalledVersion{}
for k, v := range plugins {
if strings.HasPrefix(k, ociinstaller.DefaultImageRepoDisplayURL) {
pluginsToCheck[k] = v
}
}
return pluginsToCheck
}
func (pvc *PluginVersionChecker) getLatestVersionsForPlugins(plugins map[string]*versionfile.InstalledVersion) map[string]VersionCheckReport {
getMapKey := func(thisPayload versionCheckPayload) string {
return fmt.Sprintf("%s/%s/%s", thisPayload.Org, thisPayload.Name, thisPayload.Stream)
}
requestPayload := []versionCheckPayload{}
reports := map[string]VersionCheckReport{}
for _, ref := range plugins {
thisPayload := pvc.getPayloadFromInstalledData(ref)
requestPayload = append(requestPayload, thisPayload)
reports[getMapKey(thisPayload)] = VersionCheckReport{
Plugin: ref,
CheckRequest: thisPayload,
}
}
serverResponse := pvc.requestServerForLatest(requestPayload)
if serverResponse == nil {
// return a blank map
return map[string]VersionCheckReport{}
}
for _, rD := range serverResponse {
r := reports[getMapKey(rD)]
r.CheckResponse = rD
reports[getMapKey(rD)] = r
}
return reports
}
func (pvc *PluginVersionChecker) getPayloadFromInstalledData(plugin *versionfile.InstalledVersion) versionCheckPayload {
ref := ociinstaller.NewSteampipeImageRef(plugin.Name)
org, name, stream := ref.GetOrgNameAndStream()
payload := versionCheckPayload{
Org: org,
Name: name,
Stream: stream,
Version: plugin.Version,
Digest: plugin.ImageDigest,
}
return payload
}
func (pvc *PluginVersionChecker) getVersionCheckURL() url.URL {
var u url.URL
//https://hub-steampipe-io-git-development.turbot.vercel.app/api/plugin/version
u.Scheme = "https"
u.Host = "hub.steampipe.io"
u.Path = "api/plugin/version"
return u
}
func (pvc *PluginVersionChecker) requestServerForLatest(payload []versionCheckPayload) []versionCheckPayload {
// Set a default timeout of 3 sec for the check request (in milliseconds)
sendRequestTo := pvc.getVersionCheckURL()
requestBody := utils.BuildRequestPayload(pvc.signature, map[string]interface{}{
"plugins": payload,
})
resp, err := utils.SendRequest(pvc.signature, "POST", sendRequestTo, requestBody)
if err != nil {
log.Printf("[DEBUG] Could not send request")
return nil
}
if resp.StatusCode == 204 {
log.Println("[DEBUG] Got 204")
return nil
}
if resp.StatusCode != 200 {
log.Printf("[DEBUG] Unknown response during version check: %d\n", resp.StatusCode)
return nil
}
bodyBytes, err := ioutil.ReadAll(resp.Body)
if err != nil {
fmt.Printf("[DEBUG] Error reading body stream")
return nil
}
defer resp.Body.Close()
responseData := []versionCheckPayload{}
err = json.Unmarshal(bodyBytes, &responseData)
if err != nil {
fmt.Println("[DEBUG] Error in unmarshalling response", err)
return nil
}
return responseData
}