Skip to content

Commit 6e2ae90

Browse files
committed
improve the main function for launching on GCP app engine; fix an unintended spamming issue coming from supervisor
1 parent 40501c6 commit 6e2ae90

File tree

6 files changed

+80
-17
lines changed

6 files changed

+80
-17
lines changed

.gcloudignore

+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
# This file specifies files that are *not* uploaded to Google Cloud Platform
2+
# using gcloud. It follows the same syntax as .gitignore, with the addition of
3+
# "#!include" directives (which insert the entries of the given .gitignore-style
4+
# file at that point).
5+
#
6+
# For more information, run:
7+
# $ gcloud topic gcloudignore
8+
#
9+
.gcloudignore
10+
# If you would like to upload your .git directory, .gitignore file or files
11+
# from your .gitignore file, remove the corresponding line
12+
# below:
13+
.git
14+
.gitignore
15+
16+
# Binaries for programs and plugins
17+
*.exe
18+
*.exe~
19+
*.dll
20+
*.so
21+
*.dylib
22+
# Test binary, build with `go test -c`
23+
*.test
24+
# Output of the go coverage tool, specifically when used with LiteIDE
25+
*.out

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -19,3 +19,4 @@ laitos.exe
1919
nohup.out
2020
pass
2121
tags
22+
gcp_appengine_data/

app.yaml

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
runtime: go114
2+
includes:
3+
- gcp_appengine_data/appeng-environment.yaml

launcher/supervisor.go

+6-10
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ const (
4343
*/
4444
FailureThresholdSec = 20 * 60
4545
// StartAttemptIntervalSec is the amount of time to wait between supervisor's attempts to start main program.
46-
StartAttemptIntervalSec = 10
46+
StartAttemptIntervalSec = 30
4747
// MemoriseOutputCapacity is the size of laitos main program output to memorise for notification purpose.
4848
MemoriseOutputCapacity = 4 * 1024
4949
)
@@ -254,31 +254,27 @@ func (sup *Supervisor) Start() {
254254
mainProgram.Stderr = sup.mainStderr
255255
if err := FeedDecryptionPasswordToStdinAndStart(misc.ProgramDataDecryptionPassword, mainProgram); err != nil {
256256
sup.logger.Warning("Start", strconv.Itoa(paramChoice), err, "failed to start main program")
257-
time.Sleep(1 * time.Second)
257+
// Avoid incidentally overwhelming the user with notification emails
258+
time.Sleep(StartAttemptIntervalSec * time.Second)
258259
sup.notifyFailure(cliFlags, err)
259260
if time.Now().Unix()-lastAttemptTime < FailureThresholdSec {
260261
paramChoice++
261262
}
262-
time.Sleep(StartAttemptIntervalSec * time.Second)
263263
continue
264264
}
265265
lastAttemptTime = time.Now().Unix()
266266
if err := mainProgram.Wait(); err != nil {
267267
sup.logger.Warning("Start", strconv.Itoa(paramChoice), err, "main program has crashed")
268-
/*
269-
Unsure what's going on - the main program crashes, the buffer storing latest stderr content just barely
270-
catches the beginning of a panic message and never the full stack trace. The full panic message
271-
including stack trace shows up properly in system journal. Let's see if a delay of a second will help.
272-
*/
273-
time.Sleep(1 * time.Second)
268+
// Avoid incidentally overwhelming the user with notification emails
269+
time.Sleep(StartAttemptIntervalSec * time.Second)
274270
sup.notifyFailure(cliFlags, err)
275271
if time.Now().Unix()-lastAttemptTime < FailureThresholdSec {
276272
paramChoice++
277273
}
278274
time.Sleep(StartAttemptIntervalSec * time.Second)
279275
continue
280276
}
281-
// laitos main program is not supposed to exit, therefore, restart it in the next iteration even if it exits normally.
277+
// The main function is not supposed to exit while it is running under supervision. Restart the program in the next iteration of this loop.
282278
}
283279
}
284280

main.go

+42-6
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import (
2424
"net/http"
2525
"net/http/pprof"
2626
"os"
27+
"path"
2728
"path/filepath"
2829
"regexp"
2930
"runtime"
@@ -46,6 +47,12 @@ import (
4647
"github.com/aws/aws-xray-sdk-go/xraylog"
4748
)
4849

50+
const (
51+
// AppEngineDataDir is the relative path to a data directory that contains config files and data files required for launching laitos program
52+
// on GCP app engine.
53+
AppEngineDataDir = "./gcp_appengine_data"
54+
)
55+
4956
var (
5057
// pprofHTTPPort is the localhost port to listen on for serving pprof profiling data over HTTP.
5158
// The port number must differ from those used with regular HTTP and HTTPS servers.
@@ -126,15 +133,21 @@ func main() {
126133
var gomaxprocs int
127134
flag.StringVar(&misc.ConfigFilePath, launcher.ConfigFlagName, "", "(Mandatory) path to configuration file in JSON syntax")
128135
flag.StringVar(&daemonList, launcher.DaemonsFlagName, "", "(Mandatory) comma-separated list of daemon names to start (autounlock, dnsd, httpd, httpproxy, insecurehttpd, maintenance, passwdrpc, phonehome, plainsocket, serialport, simpleipsvcd, smtpd, snmpd, sockd, telegram)")
129-
flag.BoolVar(&disableConflicts, "disableconflicts", false, "(Optional) automatically stop and disable other daemon programs that may cause port usage conflicts")
130136
flag.BoolVar(&awsLambda, launcher.LambdaFlagName, false, "(Optional) run AWS Lambda handler to proxy HTTP requests to laitos web server")
137+
// Internal supervisor flag
138+
var isSupervisor = true
139+
flag.BoolVar(&isSupervisor, launcher.SupervisorFlagName, true, "(Internal use only) launch a supervisor process to auto-restart laitos main process in case of crash")
140+
// Auxiliary features
141+
flag.BoolVar(&disableConflicts, "disableconflicts", false, "(Optional) automatically stop and disable other daemon programs that may cause port usage conflicts")
142+
flag.StringVar(&passwordUnlockServers, "passwordunlockservers", "", "(Optional) comma-separated list of server:port combos that offer password unlocking service (daemon \"passwdrpc\") over gRPC")
143+
// Optional integration features
131144
flag.BoolVar(&misc.EnableAWSIntegration, "awsinteg", false, "(Optional) activate all points of integration with various AWS services such as sending warning log entries to SQS")
132145
flag.BoolVar(&misc.EnablePrometheusIntegration, "prominteg", false, "(Optional) activate all points of integration with Prometheus such as collecting performance metrics and serving them over HTTP")
146+
// Diagnosis features
133147
flag.BoolVar(&debug, "debug", false, "(Optional) print goroutine stack traces upon receiving interrupt signal")
134148
flag.IntVar(&pprofHTTPPort, "profhttpport", pprofHTTPPort, "(Optional) serve program profiling data (pprof) over HTTP on this port at localhost")
135149
flag.IntVar(&gomaxprocs, "gomaxprocs", 0, "(Optional) set gomaxprocs")
136-
flag.StringVar(&passwordUnlockServers, "passwordunlockservers", "", "(Optional) comma-separated list of server:port combos that offer password unlocking service (daemon \"passwdrpc\") over gRPC")
137-
// Data unlocker (password input server) flags
150+
// Decryption password collector (password input server) flags
138151
var pwdServer bool
139152
var pwdServerPort int
140153
var pwdServerURL string
@@ -145,12 +158,35 @@ func main() {
145158
var dataUtil, dataUtilFile string
146159
flag.StringVar(&dataUtil, "datautil", "", "(Optional) program data encryption utility: encrypt|decrypt")
147160
flag.StringVar(&dataUtilFile, "datautilfile", "", "(Optional) program data encryption utility: encrypt/decrypt file location")
148-
// Internal supervisor flag
149-
var isSupervisor = true
150-
flag.BoolVar(&isSupervisor, launcher.SupervisorFlagName, true, "(Internal use only) launch a supervisor process to auto-restart laitos main process in case of crash")
151161

152162
flag.Parse()
153163

164+
logger.Info("main", "", nil, "program is starting, here is a summary of the runtime environment:\n%s", platform.GetProgramStatusSummary(false))
165+
// FIXME: TODO: this main function is way too long >:-|
166+
if os.Getenv("GAE_ENV") == "standard" {
167+
// Change working directory to the data directory (if not done yet).
168+
// All program config files and data files are expected to reside in the data directory.
169+
cwd, err := os.Getwd()
170+
if err != nil {
171+
logger.Abort("main", "", err, "failed to determine current working directory")
172+
}
173+
if path.Base(cwd) != path.Base(AppEngineDataDir) {
174+
if err := os.Chdir(AppEngineDataDir); err != nil {
175+
logger.Abort("main", "", err, "failed to change directory to %s", AppEngineDataDir)
176+
return
177+
}
178+
}
179+
// Read the value of CLI parameter "-daemons" from a text file
180+
daemonListContent, err := ioutil.ReadFile("daemonList")
181+
if err != nil {
182+
logger.Abort("main", "", err, "failed to read daemonList")
183+
return
184+
}
185+
// Find program configuration data (encrypted or otherwise) in "config.json"
186+
misc.ConfigFilePath = "config.json"
187+
daemonList = string(daemonListContent)
188+
}
189+
154190
// Common diagnosis and security practices
155191
platform.LockMemory()
156192
ReseedPseudoRandAndInBackground()

platform/os_config.go

+3-1
Original file line numberDiff line numberDiff line change
@@ -558,7 +558,9 @@ func GetRedactedEnviron() []string {
558558
ret := make([]string, 0, len(environ))
559559
for _, keyValue := range environ {
560560
redacted := false
561-
for _, keyToRedact := range []string{"AWS_SESSION_TOKEN", "AWS_ACCESS_KEY_ID", "AWS_SECRET_ACCESS_KEY", misc.EnvironmentDecryptionPassword} {
561+
for _, keyToRedact := range []string{
562+
"AWS_SESSION_TOKEN", "AWS_ACCESS_KEY_ID", "AWS_SECRET_ACCESS_KEY", "S2A_ACCESS_TOKEN",
563+
misc.EnvironmentDecryptionPassword} {
562564
if strings.HasPrefix(keyValue, keyToRedact+"=") {
563565
ret = append(ret, keyToRedact+"=REDACTED")
564566
redacted = true

0 commit comments

Comments
 (0)