Browse Source

telemetry first draft

main
forest 1 month ago
parent
commit
11b0f8513b
6 changed files with 132 additions and 21 deletions
  1. +1
    -0
      child-process-service/child_process_service.go
  2. +1
    -0
      config_service.go
  3. +1
    -1
      go.mod
  4. +2
    -0
      go.sum
  5. +76
    -20
      main.go
  6. +51
    -0
      telemetry.go

+ 1
- 0
child-process-service/child_process_service.go View File

@ -446,6 +446,7 @@ func (service *ChildProcessService) readPidFile() (int, error) {
return pid, nil
}
// https://stackoverflow.com/questions/20010199/how-to-determine-if-a-process-runs-inside-lxc-docker
func (service *ChildProcessService) isInsideDockerContainer() bool {
if service.insideDockerContainer == nil {
bytez, err := ioutil.ReadFile("/proc/1/cgroup")


+ 1
- 0
config_service.go View File

@ -132,6 +132,7 @@ type ConfigService struct {
CaddyAdminClient *http.Client
EmailAddress string
UseUnixSockets bool
TelemetryID string
}
// TODO make these configurable?


+ 1
- 1
go.mod View File

@ -5,7 +5,7 @@ go 1.16
require (
git.sequentialread.com/forest/easypki.git v1.1.3-0.20210825184937-473ebf3609b4
git.sequentialread.com/forest/go-netstat v0.0.0-20210914205413-73fdb805ec95
git.sequentialread.com/forest/greenhouse-daemon/child-process-service v0.0.0-20211015153025-b6e24775fe15
git.sequentialread.com/forest/greenhouse-daemon/child-process-service v0.0.0-20211018201724-fe222bad16d7
git.sequentialread.com/forest/greenhouse/pki v0.0.0-20210825185315-cbbdc0e93a3e
git.sequentialread.com/forest/pkg-errors v0.9.2
)

+ 2
- 0
go.sum View File

@ -34,6 +34,8 @@ git.sequentialread.com/forest/greenhouse-daemon/child-process-service v0.0.0-202
git.sequentialread.com/forest/greenhouse-daemon/child-process-service v0.0.0-20211014173006-315e67eacb09/go.mod h1:Q/NOXcXUvoWtfMHl1x34aL7mEhT2S99Nx013Jjm6pis=
git.sequentialread.com/forest/greenhouse-daemon/child-process-service v0.0.0-20211015153025-b6e24775fe15 h1:+0HOoq/wHMaMDzj1RE+gml54nNpsDH1dPrfy2iAiiA0=
git.sequentialread.com/forest/greenhouse-daemon/child-process-service v0.0.0-20211015153025-b6e24775fe15/go.mod h1:Q/NOXcXUvoWtfMHl1x34aL7mEhT2S99Nx013Jjm6pis=
git.sequentialread.com/forest/greenhouse-daemon/child-process-service v0.0.0-20211018201724-fe222bad16d7 h1:KqrkHGp9rtc5b+YxF+TylRzkzmU+aqGRETa1gZ9rjPU=
git.sequentialread.com/forest/greenhouse-daemon/child-process-service v0.0.0-20211018201724-fe222bad16d7/go.mod h1:Q/NOXcXUvoWtfMHl1x34aL7mEhT2S99Nx013Jjm6pis=
git.sequentialread.com/forest/greenhouse/pki v0.0.0-20210825185315-cbbdc0e93a3e h1:FL2uGlCqEGam18N++w2CaN75XScVCs38Ic6XOIaJEPU=
git.sequentialread.com/forest/greenhouse/pki v0.0.0-20210825185315-cbbdc0e93a3e/go.mod h1:Z69GF72qss9LA4h1vdzxxZlvIASQpZUx6qFl+4601s8=
git.sequentialread.com/forest/lumberjack v0.0.0-20210825181050-880244457f2e h1:4Jqvham9nIkxx34Ou0KKEE3AXPwXYJLLw1zWTuqbISY=


+ 76
- 20
main.go View File

@ -2,6 +2,7 @@ package main
import (
"context"
"crypto/rand"
"crypto/sha256"
"crypto/tls"
"crypto/x509"
@ -55,6 +56,8 @@ type DaemonAPI struct {
ApplyConfigStatuses []string
ApplyConfigStatusIndex int
ApplyConfigStatusError string
TelemetryID string
}
type ThresholdConfig struct {
@ -87,6 +90,7 @@ type Status struct {
ServerName string `json:"server_name"`
GUITunnels []GUITunnel `json:"tunnels"`
UpdateTenantInfoMessage string `json:"update_tenant_info_message"`
DaemonTelemetryID string `json:"daemon_telemetry_id"`
}
type TenantInfo struct {
@ -195,6 +199,8 @@ const caddyAdminSocketFile = "/var/run/greenhouse-daemon-caddy-admin.sock"
const mainCAName = "greenhouse_daemon_localhost_ca"
var log child.LogManager
var daemonTelemetryId string
var daemonTelemetryAccount string
func main() {
@ -214,7 +220,7 @@ func main() {
daemonExecutablePath = filepath.Dir(executableLocation)
}
} else {
log.Fatalf("can't start the greenhouse-daemon because operating system '%s' is not supported yet\n\n", runtime.GOOS)
fatalfWithTelemetry("can't start the greenhouse-daemon because operating system '%s' is not supported yet\n\n", runtime.GOOS)
}
}
@ -246,7 +252,7 @@ func main() {
caddyExecutable = filepath.Join(daemonExecutablePath, caddyExecutable)
caddyConfigAbsPath, err := filepath.Abs("caddy-config.json")
if err != nil {
log.Fatalf("can't start the greenhouse-daemon because can't resolve absolute path of \"caddy-config.json\": %+v\n\n", err)
fatalfWithTelemetry("can't start the greenhouse-daemon because can't resolve absolute path of \"caddy-config.json\": %+v\n\n", err)
return
}
caddyArguments := []string{"run", "-config", caddyConfigAbsPath}
@ -258,14 +264,26 @@ func main() {
fmt.Sprintf("XDG_CONFIG_HOME=%s", filepath.Join(daemonPath, "caddyConfig")),
}
daemonTelemetryIdBytes, err := ioutil.ReadFile(filepath.Join(daemonPath, "daemon-telemetry-id.txt"))
if err == nil {
daemonTelemetryId = string(daemonTelemetryIdBytes)
} else {
buffer := make([]byte, 4)
n, err := rand.Read(buffer)
if n != 4 || err != nil {
fatalfWithTelemetry("can't start the greenhouse-daemon, can't read 4 random bytes: read: %d err: %+v", n, err)
}
daemonTelemetryId = fmt.Sprintf("%x", buffer)
ioutil.WriteFile(filepath.Join(daemonPath, "daemon-telemetry-id.txt"), []byte(daemonTelemetryId), 0755)
}
var daemonConfig DaemonConfig
daemonConfigBytes, err := ioutil.ReadFile(filepath.Join(daemonPath, "daemon-config.json"))
// if the file doesn't exist, just skip it.
if err == nil {
err = json.Unmarshal(daemonConfigBytes, &daemonConfig)
if err != nil {
log.Fatalf("can't start the greenhouse-daemon, can't parse daemon-config.json %+v", err)
os.Exit(1)
fatalfWithTelemetry("can't start the greenhouse-daemon, can't parse daemon-config.json %+v", err)
}
}
@ -275,9 +293,10 @@ func main() {
if err == nil {
err = json.Unmarshal(tenantInfoBytes, &tenantInfo)
if err != nil {
log.Fatalf("can't start the greenhouse-daemon, can't parse daemon-tenant-info.json %+v", err)
fatalfWithTelemetry("can't start the greenhouse-daemon, can't parse daemon-tenant-info.json %+v", err)
}
}
daemonTelemetryAccount = tenantInfo.EmailAddress
var thresholdConfig ThresholdConfig
thresholdConfigBytes, err := ioutil.ReadFile(filepath.Join(daemonPath, "threshold-config.json"))
@ -285,7 +304,7 @@ func main() {
if err == nil {
err = json.Unmarshal(thresholdConfigBytes, &thresholdConfig)
if err != nil {
log.Fatalf("can't start the greenhouse-daemon, can't parse threshold-config.json %+v", err)
fatalfWithTelemetry("can't start the greenhouse-daemon, can't parse threshold-config.json %+v", err)
}
}
@ -332,7 +351,8 @@ func main() {
daemonConfig.TunnelsEnabled,
child.NewDaemonLogManager(daemonPath, thresholdExecutable),
),
LogManager: log,
LogManager: log,
TelemetryID: daemonTelemetryId,
}
go daemonAPIInstance.ThresholdService.MainLoop()
@ -355,7 +375,7 @@ func main() {
if missingAnyCertsOrKeys && !useUnixSockets {
err = GenerateTLSCertificatesAndKeys(daemonPath)
if err != nil {
log.Fatalf("can't start the greenhouse-daemon because GenerateTLSCertificatesAndKeys returned %+v", err)
fatalfWithTelemetry("can't start the greenhouse-daemon because GenerateTLSCertificatesAndKeys returned %+v", err)
}
}
@ -368,11 +388,11 @@ func main() {
// the unix socket will only be used if useUnixSockets == true
thresholdClient, err := daemonAPIInstance.MakeServiceClient(thresholdAdminSocketFile)
if err != nil {
log.Fatalf("can't start the greenhouse-daemon because can't make threshold client: %+v", err)
fatalfWithTelemetry("can't start the greenhouse-daemon because can't make threshold client: %+v", err)
}
caddyAdminClient, err := daemonAPIInstance.MakeServiceClient(caddyAdminSocketFile)
if err != nil {
log.Fatalf("can't start the greenhouse-daemon because can't make caddy admin client: %+v", err)
fatalfWithTelemetry("can't start the greenhouse-daemon because can't make caddy admin client: %+v", err)
}
thresholdAdminURL := fmt.Sprintf("https://127.0.0.1:%d", thresholdAdminPort)
caddyAdminURL := fmt.Sprintf("https://127.0.0.1:%d", caddyAdminPort)
@ -389,6 +409,7 @@ func main() {
CaddyAdminBaseURL: caddyAdminURL,
ThresholdClient: thresholdClient,
CaddyAdminClient: caddyAdminClient,
TelemetryID: daemonTelemetryId,
}
if daemonAPIInstance.Config.TunnelsEnabled && len(daemonAPIInstance.Config.GUITunnels) > 0 {
@ -402,7 +423,7 @@ func main() {
thresholdConfig, caddyConfig, err := daemonAPIInstance.ConfigService.PrepareConfigs(daemonAPIInstance.Config.GUITunnels)
if err != nil {
log.Fatalf("can't start the greenhouse-daemon because daemon-config.json is invalid: %+v", err)
fatalfWithTelemetry("can't start the greenhouse-daemon because daemon-config.json is invalid: %+v", err)
}
completionChannel := make(chan bool)
@ -421,12 +442,12 @@ func main() {
listenAddress, err := net.ResolveUnixAddr("unix", daemonSocketFile)
if err != nil {
panic(fmt.Sprintf("can't start the greenhouse-daemon because net.ResolveUnixAddr() returned %+v", err))
fatalfWithTelemetry("can't start the greenhouse-daemon because net.ResolveUnixAddr() returned %+v", err)
}
listener, err = net.ListenUnix("unix", listenAddress)
if err != nil {
panic(fmt.Sprintf("can't start the greenhouse-daemon because net.ListenUnix(\"unix\", \"%s\") returned %+v", listenAddress, err))
fatalfWithTelemetry("can't start the greenhouse-daemon because net.ListenUnix(\"unix\", \"%s\") returned %+v", listenAddress, err)
}
log.Printf("greenhouse-daemon about to start listening at http://%s 😈\n", daemonSocketFile)
@ -435,18 +456,18 @@ func main() {
addrString := fmt.Sprintf("127.0.0.1:%d", daemonAdminPort)
addr, err := net.ResolveTCPAddr("tcp", addrString)
if err != nil {
panic(fmt.Sprintf("can't start the greenhouse-daemon because net.ResolveTCPAddr(%s) returned %+v", addrString, err))
fatalfWithTelemetry("can't start the greenhouse-daemon because net.ResolveTCPAddr(%s) returned %+v", addrString, err)
}
tcpListener, err := net.ListenTCP("tcp", addr)
if err != nil {
panic(fmt.Sprintf("can't start the greenhouse-daemon because net.ListenTCP(%s) returned %+v", addrString, err))
fatalfWithTelemetry("can't start the greenhouse-daemon because net.ListenTCP(%s) returned %+v", addrString, err)
}
tlsCert, err := tls.LoadX509KeyPair(daemonAPIInstance.TLSCertFile, daemonAPIInstance.TLSKeyFile)
if err != nil {
panic(fmt.Sprintf(
fatalfWithTelemetry(
"can't start the greenhouse-daemon because tls.LoadX509KeyPair(%s,%s) returned %+v",
daemonAPIInstance.TLSCertFile, daemonAPIInstance.TLSKeyFile, err,
))
)
}
tlsConfig := &tls.Config{
@ -456,6 +477,7 @@ func main() {
listener = tls.NewListener(tcpListener, tlsConfig)
go postTelemetry("daemon-started", daemonTelemetryAccount, daemonTelemetryId, "success!!")
log.Printf("greenhouse-daemon about to start listening at https://%s 😈\n", addrString)
}
@ -467,7 +489,7 @@ func main() {
go (func() {
err = server.Serve(listener)
log.Fatalf("server.Serve returned %+v", err)
fatalfWithTelemetry("server.Serve returned %+v", err)
})()
sigs := child.GetSignalChannelOSIndependent()
@ -475,6 +497,7 @@ func main() {
go func() {
sig := <-sigs
log.Printf("Greenhouse daemon recieved signal: %s\n", sig)
go postTelemetry("daemon-signal", daemonTelemetryAccount, daemonTelemetryId, sig.String())
daemonAPIInstance.CaddyService.Enabled = false
daemonAPIInstance.ThresholdService.Enabled = false
@ -494,6 +517,7 @@ func main() {
return
}
}
postTelemetry("daemon-timed-out-waiting-threshold-and-caddy", daemonTelemetryAccount, daemonTelemetryId, "oof")
done <- true
}()
@ -548,6 +572,7 @@ func (daemon *DaemonAPI) ServeHTTP(responseWriter http.ResponseWriter, request *
if err != nil {
errorMessage := fmt.Sprintf("greenhouse-daemon: 500 internal server error: failed to open log iterator")
go postTelemetry("daemon-logs", daemonTelemetryAccount, daemonTelemetryId, fmt.Sprintf("%s: %s\n", errorMessage, err))
log.Printf("%s: %+v\n", errorMessage, err)
http.Error(responseWriter, errorMessage, http.StatusInternalServerError)
return
@ -558,6 +583,7 @@ func (daemon *DaemonAPI) ServeHTTP(responseWriter http.ResponseWriter, request *
logs, err := child.Joinerate(logIterators, count)
if err != nil {
errorMessage := "greenhouse-daemon: 500 internal server error: failed to read log file(s)"
go postTelemetry("daemon-logs", daemonTelemetryAccount, daemonTelemetryId, fmt.Sprintf("%s: %s\n", errorMessage, err))
log.Printf("%s: %+v\n", errorMessage, err)
http.Error(responseWriter, errorMessage, http.StatusInternalServerError)
return
@ -566,6 +592,7 @@ func (daemon *DaemonAPI) ServeHTTP(responseWriter http.ResponseWriter, request *
logBytes, err := json.Marshal(logs)
if err != nil {
errorMessage := "greenhouse-daemon: 500 internal server error: json serialization failed"
go postTelemetry("daemon-logs", daemonTelemetryAccount, daemonTelemetryId, fmt.Sprintf("%s: %s\n", errorMessage, err))
log.Printf("%s: %+v\n", errorMessage, err)
http.Error(responseWriter, errorMessage, http.StatusInternalServerError)
return
@ -590,6 +617,7 @@ func (daemon *DaemonAPI) ServeHTTP(responseWriter http.ResponseWriter, request *
fmt.Printf("greenhouse-daemon can't get your account info: greenhouse returned HTTP %d: %s\n", statusCode, errorMessage)
} else {
daemon.TenantInfo = tenantInfo
daemonTelemetryAccount = tenantInfo.EmailAddress
daemon.ConfigService.EmailAddress = tenantInfo.EmailAddress
updateTenantInfoMessage = "success"
}
@ -608,12 +636,14 @@ func (daemon *DaemonAPI) ServeHTTP(responseWriter http.ResponseWriter, request *
ApplyConfigStatuses: daemon.ApplyConfigStatuses,
ApplyConfigStatusIndex: daemon.ApplyConfigStatusIndex,
ApplyConfigStatusError: daemon.ApplyConfigStatusError,
DaemonTelemetryID: daemon.TelemetryID,
}
statusBytes, err := json.MarshalIndent(status, "", " ")
//log.Printf("statusBytes: %s\n\n", statusBytes)
if err != nil {
errorMessage := "greenhouse-daemon: 500 internal server error: json serialization failed"
go postTelemetry("daemon-get-status", daemonTelemetryAccount, daemonTelemetryId, fmt.Sprintf("%s: %s\n", errorMessage, err))
http.Error(responseWriter, errorMessage, http.StatusInternalServerError)
return
}
@ -643,6 +673,7 @@ func (daemon *DaemonAPI) ServeHTTP(responseWriter http.ResponseWriter, request *
if tenantInfo.ClientStates[serverName].CurrentState == "ClientConnected" {
errorMessage := fmt.Sprintf("greenhouse-daemon: 409 conflict, you already have a connected server named '%s'", serverName)
go postTelemetry("daemon-register", daemonTelemetryAccount, daemonTelemetryId, errorMessage)
http.Error(responseWriter, errorMessage, http.StatusConflict)
return
}
@ -656,19 +687,23 @@ func (daemon *DaemonAPI) ServeHTTP(responseWriter http.ResponseWriter, request *
if err != nil || statusCode != 200 {
errorMessage := fmt.Sprintf("greenhouse-daemon failed to get tenant info: %d %s", statusCode, errorMessage)
go postTelemetry("daemon-register", daemonTelemetryAccount, daemonTelemetryId, fmt.Sprintf("%s: HTTP %d err: %s\n", errorMessage, statusCode, err))
log.Printf("%s:\n%+v\n", errorMessage, err)
http.Error(responseWriter, errorMessage, statusCode)
return
}
daemon.TenantInfo = tenantInfo
daemonTelemetryAccount = tenantInfo.EmailAddress
daemon.ConfigService.EmailAddress = tenantInfo.EmailAddress
go postTelemetry("daemon-register", daemonTelemetryAccount, daemonTelemetryId, daemonTelemetryAccount)
// TODO real greenhouse API url
registerURL := fmt.Sprintf("%s/api/client_config?serverName=%s", daemon.CloudURL, serverName)
configRequest, err := http.NewRequest("POST", registerURL, nil)
if err != nil {
errorMessage := "greenhouse-daemon: 500 internal server error"
go postTelemetry("daemon-register", daemonTelemetryAccount, daemonTelemetryId, fmt.Sprintf("%s: %s\n", errorMessage, err))
log.Printf("%s:\n%+v\n", errorMessage, err)
http.Error(responseWriter, errorMessage, http.StatusInternalServerError)
return
@ -678,6 +713,7 @@ func (daemon *DaemonAPI) ServeHTTP(responseWriter http.ResponseWriter, request *
configResponse, err := daemon.HTTPClient.Do(configRequest)
if err != nil {
errorMessage := fmt.Sprintf("greenhouse-daemon: 503 bad gateway, can't reach greenhouse cloud at %s", registerURL)
go postTelemetry("daemon-register", daemonTelemetryAccount, daemonTelemetryId, fmt.Sprintf("%s: %s\n", errorMessage, err))
log.Printf("%s:\n%+v\n", errorMessage, err)
http.Error(responseWriter, errorMessage, http.StatusBadGateway)
return
@ -687,6 +723,7 @@ func (daemon *DaemonAPI) ServeHTTP(responseWriter http.ResponseWriter, request *
"greenhouse-daemon: %d %s, the server at %s returned HTTP %d",
configResponse.StatusCode, configResponse.Status, registerURL, configResponse.StatusCode,
)
go postTelemetry("daemon-register", daemonTelemetryAccount, daemonTelemetryId, fmt.Sprintf("%s: %s\n", errorMessage, err))
log.Printf("%s:\n%+v\n", errorMessage, err)
http.Error(responseWriter, errorMessage, configResponse.StatusCode)
return
@ -695,6 +732,7 @@ func (daemon *DaemonAPI) ServeHTTP(responseWriter http.ResponseWriter, request *
configBytes, err := ioutil.ReadAll(configResponse.Body)
if err != nil {
errorMessage := fmt.Sprintf("greenhouse-daemon: 503 bad gateway, read error on %s. please try again", registerURL)
go postTelemetry("daemon-register", daemonTelemetryAccount, daemonTelemetryId, fmt.Sprintf("%s: %s\n", errorMessage, err))
log.Printf("%s:\n%+v\n", errorMessage, err)
http.Error(responseWriter, errorMessage, http.StatusBadGateway)
return
@ -704,6 +742,7 @@ func (daemon *DaemonAPI) ServeHTTP(responseWriter http.ResponseWriter, request *
err = json.Unmarshal(configBytes, &thresholdConfig)
if err != nil {
errorMessage := fmt.Sprintf("greenhouse-daemon: 500 internal server error, %s did not return json", registerURL)
go postTelemetry("daemon-register", daemonTelemetryAccount, daemonTelemetryId, fmt.Sprintf("%s: %s\n", errorMessage, err))
log.Printf("%s:\n%+v\n", errorMessage, err)
http.Error(responseWriter, errorMessage, http.StatusInternalServerError)
return
@ -724,6 +763,7 @@ func (daemon *DaemonAPI) ServeHTTP(responseWriter http.ResponseWriter, request *
configBytesToWrite, err := json.MarshalIndent(thresholdConfig, "", " ")
if err != nil {
errorMessage := "greenhouse-daemon: 500 internal server error: json serialization failed"
go postTelemetry("daemon-register", daemonTelemetryAccount, daemonTelemetryId, fmt.Sprintf("%s: %s\n", errorMessage, err))
log.Printf("%s:\n%+v\n", errorMessage, err)
http.Error(responseWriter, errorMessage, http.StatusInternalServerError)
return
@ -731,6 +771,7 @@ func (daemon *DaemonAPI) ServeHTTP(responseWriter http.ResponseWriter, request *
err = ioutil.WriteFile(filepath.Join(daemon.DaemonPath, "threshold-config.json"), configBytesToWrite, 0600)
if err != nil {
errorMessage := "greenhouse-daemon: 500 internal server error: write threshold config file failed"
go postTelemetry("daemon-register", daemonTelemetryAccount, daemonTelemetryId, fmt.Sprintf("%s: %s\n", errorMessage, err))
log.Printf("%s:\n%+v\n", errorMessage, err)
http.Error(responseWriter, errorMessage, http.StatusInternalServerError)
return
@ -739,15 +780,16 @@ func (daemon *DaemonAPI) ServeHTTP(responseWriter http.ResponseWriter, request *
err = daemon.writeDaemonConfigJSON()
if err != nil {
errorMessage := "greenhouse-daemon: 500 internal server error: writeDaemonConfigJSON failed"
go postTelemetry("daemon-register", daemonTelemetryAccount, daemonTelemetryId, fmt.Sprintf("%s: %s\n", errorMessage, err))
log.Printf("%s:\n%+v\n", errorMessage, err)
http.Error(responseWriter, errorMessage, http.StatusInternalServerError)
return
}
go postTelemetry("daemon-register", daemonTelemetryAccount, daemonTelemetryId, "success!!")
responseWriter.Write([]byte("OK"))
case "/unregister":
os.Remove(filepath.Join(daemon.DaemonPath, "threshold-config.json"))
os.Remove(filepath.Join(daemon.DaemonPath, "daemon-config.json"))
os.Remove(filepath.Join(daemon.DaemonPath, "daemon-tenant-info.json"))
@ -758,12 +800,15 @@ func (daemon *DaemonAPI) ServeHTTP(responseWriter http.ResponseWriter, request *
daemon.Config.APIToken = ""
daemon.Config.ServerName = ""
go postTelemetry("daemon-unregister", daemonTelemetryAccount, daemonTelemetryId, "success!!")
responseWriter.Write([]byte("OK"))
case "/apply_config":
requestBytes, err := ioutil.ReadAll(request.Body)
if err != nil {
errorMessage := "greenhouse-daemon: 500 apply_config failed: http read error"
go postTelemetry("daemon-apply-config", daemonTelemetryAccount, daemonTelemetryId, fmt.Sprintf("%s: %s\n", errorMessage, err))
log.Printf("%s:\n%+v\n", errorMessage, err)
http.Error(responseWriter, errorMessage, http.StatusInternalServerError)
return
@ -774,7 +819,8 @@ func (daemon *DaemonAPI) ServeHTTP(responseWriter http.ResponseWriter, request *
var tunnels []GUITunnel
err = json.Unmarshal(requestBytes, &tunnels)
if err != nil {
errorMessage := fmt.Sprintf("greenhouse-daemon: 400 bad request: invalid json: %s", err)
errorMessage := "greenhouse-daemon: 400 bad request: invalid json:"
go postTelemetry("daemon-apply-config", daemonTelemetryAccount, daemonTelemetryId, fmt.Sprintf("%s: %s\n", errorMessage, err))
log.Printf("%s:\n%+v\n", errorMessage, err)
http.Error(responseWriter, errorMessage, http.StatusBadRequest)
return
@ -790,6 +836,7 @@ func (daemon *DaemonAPI) ServeHTTP(responseWriter http.ResponseWriter, request *
thresholdConfig, caddyConfig, err := daemon.ConfigService.PrepareConfigs(tunnels)
if err != nil {
errorMessage := fmt.Sprintf("greenhouse-daemon: 400 bad request: %s", err)
go postTelemetry("daemon-apply-config", daemonTelemetryAccount, daemonTelemetryId, fmt.Sprintf("%s: %s\n", errorMessage, err))
log.Printf("%s:\n%+v\n", errorMessage, err)
http.Error(responseWriter, errorMessage, http.StatusBadRequest)
return
@ -803,16 +850,22 @@ func (daemon *DaemonAPI) ServeHTTP(responseWriter http.ResponseWriter, request *
err = daemon.writeDaemonConfigJSON()
if err != nil {
errorMessage := "greenhouse-daemon: 500 internal server error: writeDaemonConfigJSON failed"
go postTelemetry("daemon-apply-config", daemonTelemetryAccount, daemonTelemetryId, fmt.Sprintf("%s: %s\n", errorMessage, err))
log.Printf("%s:\n%+v\n", errorMessage, err)
http.Error(responseWriter, errorMessage, http.StatusInternalServerError)
return
}
go postTelemetry("daemon-apply-config", daemonTelemetryAccount, daemonTelemetryId, "started...")
completionChannel := make(chan bool)
go daemon.applyConfigAsync(tunnels, thresholdConfig, caddyConfig, completionChannel)
go (func() {
<-completionChannel
go postTelemetry("daemon-apply-config", daemonTelemetryAccount, daemonTelemetryId, fmt.Sprintf(
"completed: ApplyConfigStatusIndex: %d, error: '%s'", daemon.ApplyConfigStatusIndex, daemon.ApplyConfigStatusError,
))
log.Printf("/apply_config releasing ConfigurationMutex lock\n")
daemon.ConfigurationMutex.Unlock()
})()
@ -823,6 +876,7 @@ func (daemon *DaemonAPI) ServeHTTP(responseWriter http.ResponseWriter, request *
})
if err != nil {
errorMessage := "greenhouse-daemon: 500 internal server error: netstat.TCPSocks failed"
go postTelemetry("daemon-netstat", daemonTelemetryAccount, daemonTelemetryId, fmt.Sprintf("%s: %s\n", errorMessage, err))
log.Printf("%s:\n%+v\n", errorMessage, err)
http.Error(responseWriter, errorMessage, http.StatusInternalServerError)
return
@ -855,6 +909,7 @@ func (daemon *DaemonAPI) ServeHTTP(responseWriter http.ResponseWriter, request *
if err != nil {
errorMessage := "greenhouse-daemon: 500 internal server error: json serialization failed"
go postTelemetry("daemon-netstat", daemonTelemetryAccount, daemonTelemetryId, fmt.Sprintf("%s: %s\n", errorMessage, err))
log.Printf("%s:\n%+v\n", errorMessage, err)
http.Error(responseWriter, errorMessage, http.StatusInternalServerError)
return
@ -1042,6 +1097,7 @@ func (daemon *DaemonAPI) UpdateTenantInfo(tenantInfo *TenantInfo) (error, int, s
if err != nil || statusCode != 200 {
return err, statusCode, statusString, nil
}
daemonTelemetryAccount = tenantInfo.EmailAddress
}
tenantInfoBytesToWrite, err := json.MarshalIndent(daemon.TenantInfo, "", " ")


+ 51
- 0
telemetry.go View File

@ -0,0 +1,51 @@
package main
import (
"bytes"
"fmt"
"io/ioutil"
"net/http"
"strings"
"time"
)
var telemetryClient *http.Client
func postTelemetry(tyype string, account string, daemonId string, content string) {
if account != "" {
account = fmt.Sprintf("&account=%s", account)
}
if daemonId != "" {
daemonId = fmt.Sprintf("&daemon=%s", daemonId)
}
response, err := getTelemetryClient().Post(
fmt.Sprintf("https://telemetry.greenhouse-alpha.server.garden/?type=%s&ip=auto%s%s", tyype, account, daemonId),
"text/plain",
bytes.NewBufferString(content),
)
if err != nil {
log.Printf("postTelemetry: %s\n", err)
} else if response.StatusCode > 299 {
responseString := "<read error>"
responseBytes, err := ioutil.ReadAll(response.Body)
if err == nil {
responseString = string(responseBytes)
}
log.Printf("postTelemetry: HTTP %d: %s\n", response.StatusCode, responseString)
}
}
func getTelemetryClient() *http.Client {
if telemetryClient == nil {
telemetryClient = &http.Client{
Timeout: time.Second * 10,
}
}
return telemetryClient
}
func fatalfWithTelemetry(format string, args ...interface{}) {
formatWithoutStackTraces := strings.ReplaceAll(format, "%+v", "%s")
postTelemetry("daemon-crashed", daemonTelemetryAccount, daemonTelemetryId, fmt.Sprintf(formatWithoutStackTraces, args...))
log.Fatalf(format, args...)
}

Loading…
Cancel
Save