Skip to content

Commit 74ff6d8

Browse files
authored
Merge pull request #64 from SumoLogic/222461-installation-logs
Add collection and upload of installation script logs
2 parents 4138166 + 42cd587 commit 74ff6d8

File tree

10 files changed

+254
-50
lines changed

10 files changed

+254
-50
lines changed

install-script/install.ps1

Lines changed: 61 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,14 @@ param (
3030
# The API URL used to communicate with the SumoLogic backend
3131
[string] $Api,
3232

33+
# DisableInstallationTelemetry is used to disable reporting the installation
34+
# to Sumologic.
35+
[bool] $DisableInstallationTelemetry,
36+
37+
# InstallationLogfileEndpoint is used to configure the endpoint where
38+
# installation logs will be sent.
39+
[string] $InstallationLogfileEndpoint,
40+
3341
# The OpAmp Endpoint used to communicate with the OpAmp backend
3442
[string] $OpAmpApi
3543
)
@@ -399,19 +407,48 @@ function Get-BinaryFromUri {
399407
Write-Host "Downloaded ${Path}"
400408
}
401409

410+
function Send-Installation-Logs {
411+
param (
412+
[Parameter(Mandatory, Position=0)]
413+
[HttpClient] $HttpClient,
414+
415+
[Parameter(Mandatory, Position=1)]
416+
[string] $Endpoint,
417+
418+
[Parameter(Mandatory, Position=2)]
419+
[string] $Path
420+
)
421+
422+
$Content = Get-Content -Path $Path
423+
$StringContent = [System.Net.Http.StringContent]::new($Content)
424+
425+
$response = $HttpClient.PostAsync($Endpoint, $StringContent).GetAwaiter().GetResult()
426+
if (!($response.IsSuccessStatusCode)) {
427+
$statusCode = [int]$response.StatusCode
428+
$reasonPhrase = $response.StatusCode.ToString()
429+
$errMsg = "${statusCode} ${reasonPhrase}"
430+
431+
if ($response.Content -ne $null) {
432+
$content = $response.Content.ReadAsStringAsync().GetAwaiter().GetResult()
433+
$errMsg += ": ${content}"
434+
}
435+
436+
Write-Error $errMsg -ErrorAction Stop
437+
}
438+
}
439+
402440
##
403441
# Main code
404442
##
405443

406444
try {
407-
if ($InstallationToken -eq $null -or $InstallationToken -eq "") {
408-
Write-Error "Installation token has not been provided. Please set the SUMOLOGIC_INSTALLATION_TOKEN environment variable." -ErrorAction Stop
445+
$InstallationLogFile = New-TemporaryFile
446+
447+
if ($InstallationLogFileEndpoint -eq "") {
448+
$InstallationLogFileEndpoint = "https://open-events.sumologic.net/api/v1/collector/installation/logs"
409449
}
410450

411-
$osName = Get-OSName
412-
$archName = Get-ArchName
413-
Write-Host "Detected OS type:`t${osName}"
414-
Write-Host "Detected architecture:`t${archName}"
451+
Start-Transcript $InstallationLogFile | Out-Null
415452

416453
$handler = New-Object HttpClientHandler
417454
$handler.AllowAutoRedirect = $true
@@ -423,6 +460,15 @@ try {
423460
# set http client timeout to 30 seconds
424461
$httpClient.Timeout = New-Object System.TimeSpan(0, 0, 30)
425462

463+
if ($InstallationToken -eq $null -or $InstallationToken -eq "") {
464+
Write-Error "Installation token has not been provided. Please set the SUMOLOGIC_INSTALLATION_TOKEN environment variable." -ErrorAction Stop
465+
}
466+
467+
$osName = Get-OSName
468+
$archName = Get-ArchName
469+
Write-Host "Detected OS type:`t${osName}"
470+
Write-Host "Detected architecture:`t${archName}"
471+
426472
if ($Fips -eq $true) {
427473
if ($osName -ne "Win32NT" -or $archName -ne "x64") {
428474
Write-Error "Error: The FIPS-approved binary is only available for windows/amd64"
@@ -533,4 +579,12 @@ try {
533579
msiexec.exe /i "$msiPath" /passive $msiProperties
534580
} catch [HttpRequestException] {
535581
Write-Error $_.Exception.InnerException.Message
536-
}
582+
} finally {
583+
Stop-Transcript | Out-Null
584+
585+
if ($DisableInstallationTelemetry -eq $false) {
586+
Send-Installation-Logs -Endpoint $InstallationLogFileEndpoint -Path $InstallationLogFile -HttpClient $httpClient
587+
}
588+
589+
Remove-Item $InstallationLogFile
590+
}

install-script/install.sh

Lines changed: 37 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,10 @@ ARG_SHORT_EPHEMERAL='E'
5252
ARG_LONG_EPHEMERAL='ephemeral'
5353
ARG_SHORT_TIMEOUT='m'
5454
ARG_LONG_TIMEOUT='download-timeout'
55+
ARG_SHORT_DISABLE_INSTALLATION_TELEMETRY='S'
56+
ARG_LONG_DISABLE_INSTALLATION_TELEMETRY='disable-installation-telemetry'
57+
ARG_SHORT_INSTALLATION_LOGFILE_ENDPOINT='l'
58+
ARG_LONG_INSTALLATION_LOGFILE_ENDPOINT='installation-logfile-endpoint'
5559

5660
PACKAGE_GITHUB_ORG="SumoLogic"
5761
PACKAGE_GITHUB_REPO="sumologic-otel-collector-packaging"
@@ -67,6 +71,8 @@ readonly ARG_SHORT_INSTALL_HOSTMETRICS ARG_LONG_INSTALL_HOSTMETRICS
6771
readonly ARG_SHORT_REMOTELY_MANAGED ARG_LONG_REMOTELY_MANAGED
6872
readonly ARG_SHORT_EPHEMERAL ARG_LONG_EPHEMERAL
6973
readonly ARG_SHORT_TIMEOUT ARG_LONG_TIMEOUT
74+
readonly ARG_SHORT_DISABLE_INSTALLATION_TELEMETRY ARG_LONG_DISABLE_INSTALLATION_TELEMETRY
75+
readonly ARG_SHORT_INSTALLATION_LOGFILE_ENDPOINT ARG_LONG_INSTALLATION_LOGFILE_ENDPOINT
7076
readonly DEPRECATED_ARG_LONG_TOKEN DEPRECATED_ENV_TOKEN DEPRECATED_ARG_LONG_SKIP_TOKEN
7177
readonly PACKAGE_GITHUB_ORG PACKAGE_GITHUB_REPO
7278

@@ -131,6 +137,10 @@ CURL_MAX_TIME=1800
131137
# set by check_dependencies therefore cannot be set by set_defaults
132138
SYSTEMD_DISABLED=false
133139

140+
DISABLE_INSTALLATION_TELEMETRY=false
141+
INSTALLATION_LOGFILE="${TMPDIR:=/tmp}/sumologic-otel-collector_installation.log"
142+
INSTALLATION_LOGFILE_ENDPOINT='https://open-events.sumologic.net/api/v1/collector/installation/logs'
143+
134144
############################ Functions
135145

136146
function usage() {
@@ -164,6 +174,7 @@ Supported arguments:
164174
-${ARG_SHORT_EPHEMERAL}, --${ARG_LONG_EPHEMERAL} Delete the collector from Sumo Logic after 12 hours of inactivity.
165175
-${ARG_SHORT_TIMEOUT}, --${ARG_LONG_TIMEOUT} <timeout> Timeout in seconds after which download will fail. Default is ${CURL_MAX_TIME}.
166176
-${ARG_SHORT_YES}, --${ARG_LONG_YES} Disable confirmation asks.
177+
-${ARG_SHORT_DISABLE_INSTALLATION_TELEMETRY}, --${ARG_LONG_DISABLE_INSTALLATION_TELEMETRY} Do not report installation logs to Sumologic.
167178
168179
-${ARG_SHORT_HELP}, --${ARG_LONG_HELP} Prints this help and usage.
169180
@@ -172,6 +183,18 @@ Supported env variables:
172183
EOF
173184
}
174185

186+
# shellcheck disable=SC2317 # Don't warn about unreachable commands in this function
187+
# ShellCheck may incorrectly believe that code is unreachable if it's invoked in
188+
# a trap, like the reporter function.
189+
function reporter {
190+
if ! $DISABLE_INSTALLATION_TELEMETRY; then
191+
echo "SUMOLOGIC_INSTALLATION_TOKEN=${SUMOLOGIC_INSTALLATION_TOKEN}" >> "$INSTALLATION_LOGFILE"
192+
curl --silent --location -X POST --data-binary @"${INSTALLATION_LOGFILE}" "${INSTALLATION_LOGFILE_ENDPOINT}"
193+
rm -f "${INSTALLATION_LOGFILE}"
194+
fi
195+
}
196+
trap reporter EXIT
197+
175198
function set_defaults() {
176199
HOME_DIRECTORY="/var/lib/otelcol-sumo"
177200
FILE_STORAGE="${HOME_DIRECTORY}/file_storage"
@@ -269,7 +292,7 @@ function parse_options() {
269292
"--${ARG_LONG_TIMEOUT}")
270293
set -- "$@" "-${ARG_SHORT_TIMEOUT}"
271294
;;
272-
"-${ARG_SHORT_TOKEN}"|"-${ARG_SHORT_HELP}"|"-${ARG_SHORT_API}"|"-${ARG_SHORT_OPAMP_API}"|"-${ARG_SHORT_TAG}"|"-${ARG_SHORT_SKIP_CONFIG}"|"-${ARG_SHORT_VERSION}"|"-${ARG_SHORT_FIPS}"|"-${ARG_SHORT_YES}"|"-${ARG_SHORT_SKIP_SYSTEMD}"|"-${ARG_SHORT_UNINSTALL}"|"-${ARG_SHORT_PURGE}"|"-${ARG_SHORT_SKIP_TOKEN}"|"-${ARG_SHORT_DOWNLOAD}"|"-${ARG_SHORT_CONFIG_BRANCH}"|"-${ARG_SHORT_BINARY_BRANCH}"|"-${ARG_SHORT_BRANCH}"|"-${ARG_SHORT_KEEP_DOWNLOADS}"|"-${ARG_SHORT_TIMEOUT}"|"-${ARG_SHORT_INSTALL_HOSTMETRICS}"|"-${ARG_SHORT_REMOTELY_MANAGED}"|"-${ARG_SHORT_EPHEMERAL}")
295+
"-${ARG_SHORT_TOKEN}"|"-${ARG_SHORT_HELP}"|"-${ARG_SHORT_API}"|"-${ARG_SHORT_OPAMP_API}"|"-${ARG_SHORT_TAG}"|"-${ARG_SHORT_SKIP_CONFIG}"|"-${ARG_SHORT_VERSION}"|"-${ARG_SHORT_FIPS}"|"-${ARG_SHORT_YES}"|"-${ARG_SHORT_SKIP_SYSTEMD}"|"-${ARG_SHORT_UNINSTALL}"|"-${ARG_SHORT_PURGE}"|"-${ARG_SHORT_SKIP_TOKEN}"|"-${ARG_SHORT_DOWNLOAD}"|"-${ARG_SHORT_CONFIG_BRANCH}"|"-${ARG_SHORT_BINARY_BRANCH}"|"-${ARG_SHORT_BRANCH}"|"-${ARG_SHORT_KEEP_DOWNLOADS}"|"-${ARG_SHORT_TIMEOUT}"|"-${ARG_SHORT_INSTALL_HOSTMETRICS}"|"-${ARG_SHORT_REMOTELY_MANAGED}"|"-${ARG_SHORT_EPHEMERAL}"|"-${ARG_SHORT_DISABLE_INSTALLATION_TELEMETRY}"|"-${ARG_SHORT_INSTALLATION_LOGFILE_ENDPOINT}")
273296
set -- "$@" "${arg}"
274297
;;
275298
"--${ARG_LONG_INSTALL_HOSTMETRICS}")
@@ -281,6 +304,12 @@ function parse_options() {
281304
"--${ARG_LONG_EPHEMERAL}")
282305
set -- "$@" "-${ARG_SHORT_EPHEMERAL}"
283306
;;
307+
"--${ARG_LONG_DISABLE_INSTALLATION_TELEMETRY}")
308+
set -- "$@" "-${ARG_SHORT_DISABLE_INSTALLATION_TELEMETRY}"
309+
;;
310+
"--${ARG_LONG_INSTALLATION_LOGFILE_ENDPOINT}")
311+
set -- "$@" "-${ARG_SHORT_INSTALLATION_LOGFILE_ENDPOINT}"
312+
;;
284313
-*)
285314
echo "Unknown option ${arg}"; usage; exit 1 ;;
286315
*)
@@ -293,7 +322,7 @@ function parse_options() {
293322

294323
while true; do
295324
set +e
296-
getopts "${ARG_SHORT_HELP}${ARG_SHORT_TOKEN}:${ARG_SHORT_API}:${ARG_SHORT_OPAMP_API}:${ARG_SHORT_TAG}:${ARG_SHORT_VERSION}:${ARG_SHORT_FIPS}${ARG_SHORT_YES}${ARG_SHORT_SKIP_SYSTEMD}${ARG_SHORT_UNINSTALL}${ARG_SHORT_PURGE}${ARG_SHORT_SKIP_TOKEN}${ARG_SHORT_SKIP_CONFIG}${ARG_SHORT_DOWNLOAD}${ARG_SHORT_KEEP_DOWNLOADS}${ARG_SHORT_CONFIG_BRANCH}:${ARG_SHORT_BINARY_BRANCH}:${ARG_SHORT_BRANCH}:${ARG_SHORT_EPHEMERAL}${ARG_SHORT_REMOTELY_MANAGED}${ARG_SHORT_INSTALL_HOSTMETRICS}${ARG_SHORT_TIMEOUT}:" opt
325+
getopts "${ARG_SHORT_HELP}${ARG_SHORT_TOKEN}:${ARG_SHORT_API}:${ARG_SHORT_OPAMP_API}:${ARG_SHORT_TAG}:${ARG_SHORT_VERSION}:${ARG_SHORT_FIPS}${ARG_SHORT_YES}${ARG_SHORT_SKIP_SYSTEMD}${ARG_SHORT_UNINSTALL}${ARG_SHORT_PURGE}${ARG_SHORT_SKIP_TOKEN}${ARG_SHORT_SKIP_CONFIG}${ARG_SHORT_DOWNLOAD}${ARG_SHORT_KEEP_DOWNLOADS}${ARG_SHORT_CONFIG_BRANCH}:${ARG_SHORT_BINARY_BRANCH}:${ARG_SHORT_BRANCH}:${ARG_SHORT_EPHEMERAL}${ARG_SHORT_REMOTELY_MANAGED}${ARG_SHORT_INSTALL_HOSTMETRICS}${ARG_SHORT_TIMEOUT}:${ARG_SHORT_DISABLE_INSTALLATION_TELEMETRY}${ARG_SHORT_INSTALLATION_LOGFILE_ENDPOINT}:" opt
297326
set -e
298327

299328
# Invalid argument catched, print and exit
@@ -305,7 +334,7 @@ function parse_options() {
305334

306335
# Validate opt and set arguments
307336
case "$opt" in
308-
"${ARG_SHORT_HELP}") usage; exit 0 ;;
337+
"${ARG_SHORT_HELP}") usage; DISABLE_INSTALLATION_TELEMETRY=true exit 0 ;;
309338
"${ARG_SHORT_TOKEN}") SUMOLOGIC_INSTALLATION_TOKEN="${OPTARG}" ;;
310339
"${ARG_SHORT_API}") API_BASE_URL="${OPTARG}" ;;
311340
"${ARG_SHORT_OPAMP_API}") OPAMP_API_URL="${OPTARG}" ;;
@@ -332,6 +361,8 @@ function parse_options() {
332361
"${ARG_SHORT_EPHEMERAL}") EPHEMERAL=true ;;
333362
"${ARG_SHORT_KEEP_DOWNLOADS}") KEEP_DOWNLOADS=true ;;
334363
"${ARG_SHORT_TIMEOUT}") CURL_MAX_TIME="${OPTARG}" ;;
364+
"${ARG_SHORT_DISABLE_INSTALLATION_TELEMETRY}") DISABLE_INSTALLATION_TELEMETRY=true ;;
365+
"${ARG_SHORT_INSTALLATION_LOGFILE_ENDPOINT}") INSTALLATION_LOGFILE_ENDPOINT="${OPTARG}" ;;
335366
"${ARG_SHORT_TAG}")
336367
if [[ "${OPTARG}" != ?*"="* ]]; then
337368
echo "Invalid tag: '${OPTARG}'. Should be in 'key=value' format"
@@ -1746,6 +1777,9 @@ function plutil_replace_key() {
17461777

17471778
############################ Main code
17481779

1780+
# Redirect a copy of stdout and stderr into $INSTALLATION_LOGFILE
1781+
exec > >(tee "${INSTALLATION_LOGFILE}") 2>&1
1782+
17491783
OS_TYPE="$(get_os_type)"
17501784
ARCH_TYPE="$(get_arch_type)"
17511785
readonly OS_TYPE ARCH_TYPE

install-script/test/check.go

Lines changed: 55 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
package sumologic_scripts_tests
22

33
import (
4+
"context"
45
"io/fs"
6+
"net"
7+
"net/http"
58
"os"
69
"os/exec"
710
"path/filepath"
@@ -10,14 +13,20 @@ import (
1013
"github.com/stretchr/testify/require"
1114
)
1215

16+
type mockInstallationLogsEndpoint struct {
17+
server *http.Server
18+
receivedData bool
19+
}
20+
1321
type check struct {
14-
test *testing.T
15-
installOptions installOptions
16-
code int
17-
err error
18-
expectedInstallCode int
19-
output []string
20-
errorOutput []string
22+
test *testing.T
23+
installationLogsEndpoint *mockInstallationLogsEndpoint
24+
installOptions installOptions
25+
code int
26+
err error
27+
expectedInstallCode int
28+
output []string
29+
errorOutput []string
2130
}
2231

2332
type condCheckFunc func(check) bool
@@ -228,3 +237,42 @@ func PathHasUserACL(t *testing.T, path string, ownerName string, perms string) {
228237
require.NoError(t, err, "error while checking "+path+" acl")
229238
require.Contains(t, string(output), "user:"+ownerName+":"+perms)
230239
}
240+
241+
func preActionStartInstallationLogsMockReceiver(c check) {
242+
c.test.Log("Starting mock installation logs endpoint")
243+
244+
mux := http.NewServeMux()
245+
mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
246+
if r.Method == http.MethodPost && r.ContentLength >= 1 {
247+
c.installationLogsEndpoint.receivedData = true
248+
}
249+
})
250+
251+
listener, err := net.Listen("tcp", ":4444")
252+
require.NoError(c.test, err)
253+
254+
c.installationLogsEndpoint.server = &http.Server{
255+
Handler: mux,
256+
}
257+
258+
go func() {
259+
err := c.installationLogsEndpoint.server.Serve(listener)
260+
if err != nil && err != http.ErrServerClosed {
261+
require.NoError(c.test, err)
262+
}
263+
}()
264+
}
265+
266+
func checkInstallationLogsReceived(c check) {
267+
require.Equal(c.test, true, c.installationLogsEndpoint.receivedData, "mock installation logs endpoint should have received data but didn't")
268+
269+
c.test.Log("Stopping mock installation logs endpoint")
270+
require.NoError(c.test, c.installationLogsEndpoint.server.Shutdown(context.Background()))
271+
}
272+
273+
func checkInstallationLogsNotReceived(c check) {
274+
require.Equal(c.test, false, c.installationLogsEndpoint.receivedData, "mock installation logs endpoint received data but shouldn't have")
275+
276+
c.test.Log("Stopping mock installation logs endpoint")
277+
require.NoError(c.test, c.installationLogsEndpoint.server.Shutdown(context.Background()))
278+
}

install-script/test/command_unix.go

Lines changed: 31 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -14,25 +14,27 @@ import (
1414
)
1515

1616
type installOptions struct {
17-
installToken string
18-
autoconfirm bool
19-
skipSystemd bool
20-
tags map[string]string
21-
skipConfig bool
22-
skipInstallToken bool
23-
fips bool
24-
envs map[string]string
25-
uninstall bool
26-
purge bool
27-
apiBaseURL string
28-
configBranch string
29-
downloadOnly bool
30-
dontKeepDownloads bool
31-
installHostmetrics bool
32-
remotelyManaged bool
33-
ephemeral bool
34-
timeout float64
35-
opampEndpoint string
17+
installToken string
18+
autoconfirm bool
19+
skipSystemd bool
20+
tags map[string]string
21+
skipConfig bool
22+
skipInstallToken bool
23+
fips bool
24+
envs map[string]string
25+
uninstall bool
26+
purge bool
27+
apiBaseURL string
28+
configBranch string
29+
downloadOnly bool
30+
dontKeepDownloads bool
31+
installHostmetrics bool
32+
remotelyManaged bool
33+
ephemeral bool
34+
timeout float64
35+
opampEndpoint string
36+
disableInstallationTelemetry bool
37+
installationLogfileEndpoint string
3638
}
3739

3840
func (io *installOptions) string() []string {
@@ -106,6 +108,16 @@ func (io *installOptions) string() []string {
106108
opts = append(opts, "--download-timeout", fmt.Sprintf("%f", io.timeout))
107109
}
108110

111+
if io.disableInstallationTelemetry {
112+
opts = append(opts, "--disable-installation-telemetry")
113+
}
114+
115+
if io.installationLogfileEndpoint == "" {
116+
opts = append(opts, "--installation-logfile-endpoint", StagingInstallationLogfileEndpoint)
117+
} else {
118+
opts = append(opts, "--installation-logfile-endpoint", io.installationLogfileEndpoint)
119+
}
120+
109121
if io.opampEndpoint != "" {
110122
opts = append(opts, "--opamp-api", io.opampEndpoint)
111123
}

0 commit comments

Comments
 (0)