From afe0f0986c394e72b427ec7867f3f9062c62d4d1 Mon Sep 17 00:00:00 2001 From: James Read Date: Mon, 20 Mar 2023 12:47:52 +0000 Subject: [PATCH] feature: sosreport (#132) --- OliveTin.proto | 12 ++++++ cmd/OliveTin/main.go | 6 +++ internal/grpcapi/grpcApi.go | 11 +++++ internal/installationinfo/buildinfo.go | 9 ++++ internal/installationinfo/runtimeinfo.go | 55 ++++++++++++++++++++++++ internal/installationinfo/sosreport.go | 39 +++++++++++++++++ internal/updatecheck/updateCheck.go | 17 ++------ 7 files changed, 136 insertions(+), 13 deletions(-) create mode 100644 internal/installationinfo/buildinfo.go create mode 100644 internal/installationinfo/runtimeinfo.go create mode 100644 internal/installationinfo/sosreport.go diff --git a/OliveTin.proto b/OliveTin.proto index 9931729..38fa1ab 100644 --- a/OliveTin.proto +++ b/OliveTin.proto @@ -93,6 +93,12 @@ message WhoAmIResponse { string authenticatedUser = 1; } +message SosReportRequest {} + +message SosReportResponse { + string alert = 1; +} + service OliveTinApi { rpc GetDashboardComponents(GetDashboardComponentsRequest) returns (GetDashboardComponentsResponse) { option (google.api.http) = { @@ -125,4 +131,10 @@ service OliveTinApi { get: "/api/WhoAmI" }; } + + rpc SosReport(SosReportRequest) returns (SosReportResponse) { + option (google.api.http) = { + get: "/api/sosreport" + }; + } } diff --git a/cmd/OliveTin/main.go b/cmd/OliveTin/main.go index a389bf1..04dfb17 100644 --- a/cmd/OliveTin/main.go +++ b/cmd/OliveTin/main.go @@ -7,6 +7,7 @@ import ( "github.com/OliveTin/OliveTin/internal/executor" grpcapi "github.com/OliveTin/OliveTin/internal/grpcapi" + "github.com/OliveTin/OliveTin/internal/installationinfo" "github.com/OliveTin/OliveTin/internal/oncron" "github.com/OliveTin/OliveTin/internal/onstartup" updatecheck "github.com/OliveTin/OliveTin/internal/updatecheck" @@ -76,6 +77,11 @@ func init() { warnIfPuidGuid() + installationinfo.Config = cfg + installationinfo.Build.Version = version + installationinfo.Build.Commit = commit + installationinfo.Build.Date = date + log.Info("Init complete") } diff --git a/internal/grpcapi/grpcApi.go b/internal/grpcapi/grpcApi.go index 2417ab8..d6f1353 100644 --- a/internal/grpcapi/grpcApi.go +++ b/internal/grpcapi/grpcApi.go @@ -11,6 +11,7 @@ import ( acl "github.com/OliveTin/OliveTin/internal/acl" config "github.com/OliveTin/OliveTin/internal/config" executor "github.com/OliveTin/OliveTin/internal/executor" + installationinfo "github.com/OliveTin/OliveTin/internal/installationinfo" ) var ( @@ -108,6 +109,16 @@ func (api *oliveTinAPI) WhoAmI(ctx ctx.Context, req *pb.WhoAmIRequest) (*pb.WhoA return res, nil } +func (api *oliveTinAPI) SosReport(ctx ctx.Context, req *pb.SosReportRequest) (*pb.SosReportResponse, error) { + res := &pb.SosReportResponse{ + Alert: "Your SOS Report has been logged to OliveTin logs.", + } + + log.Infof("\n" + installationinfo.GetSosReport()) + + return res, nil +} + // Start will start the GRPC API. func Start(globalConfig *config.Config, ex *executor.Executor) { cfg = globalConfig diff --git a/internal/installationinfo/buildinfo.go b/internal/installationinfo/buildinfo.go new file mode 100644 index 0000000..805bf76 --- /dev/null +++ b/internal/installationinfo/buildinfo.go @@ -0,0 +1,9 @@ +package installationinfo + +type buildInfo struct { + Commit string + Version string + Date string +} + +var Build = &buildInfo{} diff --git a/internal/installationinfo/runtimeinfo.go b/internal/installationinfo/runtimeinfo.go new file mode 100644 index 0000000..96d066f --- /dev/null +++ b/internal/installationinfo/runtimeinfo.go @@ -0,0 +1,55 @@ +package installationinfo + +import ( + "bufio" + "errors" + "os" + "runtime" + "strings" +) + +type runtimeInfo struct { + OS string + OSReleasePrettyName string + Arch string + InContainer bool + LastBrowserUserAgent string +} + +func isInContainer() bool { + if _, err := os.Stat("/.dockerenv"); errors.Is(err, os.ErrNotExist) { + return false + } + + return true +} + +func getOsReleasePrettyName() string { + handle, err := os.Open("/etc/os-release") + + if err != nil { + return "" + } + + scanner := bufio.NewScanner(handle) + scanner.Split(bufio.ScanLines) + + for scanner.Scan() { + line := scanner.Text() + + if strings.Contains(line, "PRETTY_NAME") { + return line + } + } + + handle.Close() + + return "notfound" +} + +var Runtime = &runtimeInfo{ + OS: runtime.GOOS, + Arch: runtime.GOARCH, + InContainer: isInContainer(), + OSReleasePrettyName: getOsReleasePrettyName(), +} diff --git a/internal/installationinfo/sosreport.go b/internal/installationinfo/sosreport.go new file mode 100644 index 0000000..3b7d8cd --- /dev/null +++ b/internal/installationinfo/sosreport.go @@ -0,0 +1,39 @@ +package installationinfo + +import ( + "fmt" + config "github.com/OliveTin/OliveTin/internal/config" + "gopkg.in/yaml.v3" +) + +var Config *config.Config + +type sosReportConfig struct { + CountOfActions int + LogLevel string +} + +func configToSosreport(cfg *config.Config) *sosReportConfig { + return &sosReportConfig{ + CountOfActions: len(cfg.Actions), + LogLevel: cfg.LogLevel, + } +} + +func GetSosReport() string { + ret := "" + + ret += "### SOSREPORT START (copy all text to SOSREPORT END)\n" + + out, _ := yaml.Marshal(Build) + ret += fmt.Sprintf("# Build: \n%+v\n", string(out)) + + out, _ = yaml.Marshal(Runtime) + ret += fmt.Sprintf("# Runtime:\n%+v\n", string(out)) + + out, _ = yaml.Marshal(configToSosreport(Config)) + ret += fmt.Sprintf("# Config:\n%+v\n", string(out)) + ret += "### SOSREPORT END (copy all text from SOSREPORT START)\n" + + return ret +} diff --git a/internal/updatecheck/updateCheck.go b/internal/updatecheck/updateCheck.go index 0943902..0da3a1e 100644 --- a/internal/updatecheck/updateCheck.go +++ b/internal/updatecheck/updateCheck.go @@ -3,15 +3,14 @@ package updatecheck import ( "bytes" "encoding/json" - "errors" config "github.com/OliveTin/OliveTin/internal/config" + installationinfo "github.com/OliveTin/OliveTin/internal/installationinfo" "github.com/google/uuid" "github.com/robfig/cron/v3" log "github.com/sirupsen/logrus" "io/ioutil" "net/http" "os" - "runtime" ) type updateRequest struct { @@ -63,14 +62,6 @@ func installationID(filename string) string { return content } -func isInContainer() bool { - if _, err := os.Stat("/.dockerenv"); errors.Is(err, os.ErrNotExist) { - return false - } - - return true -} - // StartUpdateChecker will start a job that runs periodically, checking // for updates. func StartUpdateChecker(currentVersion string, currentCommit string, cfg *config.Config, configDir string) { @@ -84,10 +75,10 @@ func StartUpdateChecker(currentVersion string, currentCommit string, cfg *config payload := updateRequest{ CurrentVersion: currentVersion, CurrentCommit: currentCommit, - OS: runtime.GOOS, - Arch: runtime.GOARCH, + OS: installationinfo.Runtime.OS, + Arch: installationinfo.Runtime.Arch, InstallationID: installationID(configDir + "/installation-id.txt"), - InContainer: isInContainer(), + InContainer: installationinfo.Runtime.InContainer, } s := cron.New(cron.WithSeconds())