in integration_test/soak_test/cmd/launcher/main.go [107:236]
func mainErr() error {
defer gce.CleanupKeysOrDie()
ctx, cancel := context.WithTimeout(context.Background(), 60*time.Minute)
defer cancel()
// Log to stderr.
logger := log.Default()
if distro == "" {
return errors.New("Env variable DISTRO cannot be empty")
}
if ttl == "" {
return errors.New("Env variable TTL cannot be empty")
}
// Create the VM.
options := gce.VMOptions{
ImageSpec: distro,
TimeToLive: ttl,
Name: vmName,
MachineType: "e2-standard-16",
Metadata: map[string]string{
// This is to avoid Windows updates and reboots (b/295165549), and
// also to avoid throughput blips when the OS Config agent runs
// periodically.
"osconfig-disabled-features": "tasks",
},
ExtraCreateArguments: []string{"--boot-disk-size=4000GB"},
}
vm, err := gce.CreateInstance(ctx, logger, options)
if err != nil {
return err
}
if gce.IsWindows(vm.ImageSpec) {
if _, err := pauseWindowsUpdates(ctx, logger, vm); err != nil {
return err
}
}
debugLogPath := "/tmp/log_generator.log"
// Install the Ops Agent with a config telling it to watch logPath,
// and debugLogPath for debugging.
config := fmt.Sprintf(`logging:
receivers:
mylog_source:
type: files
include_paths:
- %s
generator_debug_logs:
type: files
include_paths:
- %s
exporters:
google:
type: google_cloud_logging
service:
pipelines:
my_pipeline:
receivers:
- mylog_source
- generator_debug_logs
exporters: [google]
`, logPath, debugLogPath)
if err := agents.SetupOpsAgent(ctx, logger, vm, config); err != nil {
return err
}
// Install Python.
// TODO: Consider shipping over a prebuilt binary so that we don't need to
// install Python.
if gce.IsWindows(vm.ImageSpec) {
installPython := `$tempDir = "/tmp"
mkdir $tempDir
$pythonUrl = 'https://www.python.org/ftp/python/3.11.2/python-3.11.2.exe'
$pythonInstallerName = $pythonUrl -replace '.*/'
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
$webClient = New-Object System.Net.WebClient
$webClient.DownloadFile($pythonUrl, "$tempDir\$pythonInstallerName")
$pythonInstallDir = "$env:SystemDrive\Python"
$pythonPath = "$pythonInstallDir\python.exe"
Start-Process "$tempDir\$pythonInstallerName" -Wait -ArgumentList "/quiet TargetDir=$pythonInstallDir InstallAllUsers=1"
`
if _, err := gce.RunRemotely(ctx, logger, vm, installPython); err != nil {
return fmt.Errorf("Could not install Python: %w", err)
}
} else {
if err := agents.InstallPackages(ctx, logger, vm, []string{"python3"}); err != nil {
return err
}
}
// Upload log_generator.py.
if err := gce.UploadContent(ctx, logger, vm, strings.NewReader(logGeneratorSource), logGeneratorPath); err != nil {
return err
}
// Start log_generator.py asynchronously.
var startLogGenerator string
if gce.IsWindows(vm.ImageSpec) {
// The best way I've found to start a process asynchronously. One downside
// is that standard output and standard error are lost.
startLogGenerator = fmt.Sprintf(`Invoke-WmiMethod -ComputerName . -Class Win32_Process -Name Create -ArgumentList "$env:SystemDrive\Python\python.exe %v --log-size-in-bytes=%v --log-rate=%v --log-write-type=file --file-path=%v"`, logGeneratorPath, logSizeInBytes, logRate, logPath)
} else {
startLogGenerator = fmt.Sprintf(`nohup python3 %v \
--log-size-in-bytes="%v" \
--log-rate="%v" \
--log-write-type=file \
--file-path="%v" \
&> %v &
`, logGeneratorPath, logSizeInBytes, logRate, logPath, debugLogPath)
}
if _, err := gce.RunRemotely(ctx, logger, vm, startLogGenerator); err != nil {
return err
}
// Print log_generator log files to debug startup errors.
// These log files are unfortunately not available on Windows.
if !gce.IsWindows(vm.ImageSpec) {
time.Sleep(5 * time.Second)
if _, err := gce.RunRemotely(ctx, logger, vm, "cat "+debugLogPath); err != nil {
return err
}
}
return nil
}