package version import ( "context" "encoding/json" "flag" "fmt" "io/ioutil" "net/http" "os" "time" healthcheckPb "github.com/runconduit/conduit/controller/gen/common/healthcheck" pb "github.com/runconduit/conduit/controller/gen/public" "github.com/runconduit/conduit/pkg/healthcheck" log "github.com/sirupsen/logrus" ) // DO NOT EDIT // This var is updated automatically as part of the build process var Version = "undefined" const ( VersionSubsystemName = "conduit-version" CliCheckDescription = "cli is up-to-date" ControlPlaneCheckDescription = "control plane is up-to-date" ) func VersionFlag() *bool { return flag.Bool("version", false, "print version and exit") } func MaybePrintVersionAndExit(printVersion bool) { if printVersion { fmt.Println(Version) os.Exit(0) } log.Infof("running conduit version %s", Version) } var httpClientTimeout = 10 * time.Second type versionStatusChecker struct { version string versionCheckURL string versionOverride string publicApiClient pb.ApiClient httpClient http.Client } func (v versionStatusChecker) SelfCheck() []*healthcheckPb.CheckResult { cliVersion := v.version cliIsUpToDate := &healthcheckPb.CheckResult{ Status: healthcheckPb.CheckStatus_OK, SubsystemName: VersionSubsystemName, CheckDescription: CliCheckDescription, } latestVersion, err := v.getLatestVersion() if err != nil { cliIsUpToDate.Status = healthcheckPb.CheckStatus_ERROR cliIsUpToDate.FriendlyMessageToUser = err.Error() return []*healthcheckPb.CheckResult{cliIsUpToDate} } if cliVersion != latestVersion { cliIsUpToDate.Status = healthcheckPb.CheckStatus_FAIL cliIsUpToDate.FriendlyMessageToUser = fmt.Sprintf("is running version %s but the latest version is %s", cliVersion, latestVersion) } controlPlaneIsUpToDate := &healthcheckPb.CheckResult{ Status: healthcheckPb.CheckStatus_OK, SubsystemName: VersionSubsystemName, CheckDescription: ControlPlaneCheckDescription, } controlPlaneVersion, err := v.getServerVersion() if err != nil { controlPlaneIsUpToDate.Status = healthcheckPb.CheckStatus_ERROR controlPlaneIsUpToDate.FriendlyMessageToUser = err.Error() return []*healthcheckPb.CheckResult{controlPlaneIsUpToDate} } if controlPlaneVersion != latestVersion { controlPlaneIsUpToDate.Status = healthcheckPb.CheckStatus_FAIL controlPlaneIsUpToDate.FriendlyMessageToUser = fmt.Sprintf("is running version %s but the latest version is %s", controlPlaneVersion, latestVersion) } checks := []*healthcheckPb.CheckResult{cliIsUpToDate} checks = append(checks, controlPlaneIsUpToDate) return checks } func (v versionStatusChecker) getServerVersion() (string, error) { ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel() resp, err := v.publicApiClient.Version(ctx, &pb.Empty{}) if err != nil { return "", err } return resp.GetReleaseVersion(), nil } func (v versionStatusChecker) getLatestVersion() (string, error) { if v.versionOverride != "" { return v.versionOverride, nil } resp, err := v.httpClient.Get(v.versionCheckURL) if err != nil { return "", err } defer resp.Body.Close() if resp.StatusCode != 200 { return "", fmt.Errorf("got %d error from %s", resp.StatusCode, v.versionCheckURL) } bodyBytes, err := ioutil.ReadAll(resp.Body) if err != nil { return "", err } var l map[string]string err = json.Unmarshal(bodyBytes, &l) if err != nil { return "", err } return l["version"], nil } func NewVersionStatusChecker(versionCheckURL, versionOverride string, client pb.ApiClient) healthcheck.StatusChecker { return versionStatusChecker{ version: Version, versionCheckURL: versionCheckURL, versionOverride: versionOverride, publicApiClient: client, httpClient: http.Client{Timeout: httpClientTimeout}, } }