diff --git a/.github/workflows/pull_requests.yml b/.github/workflows/pull_requests.yml index 0c072aea6e..eeb321898e 100644 --- a/.github/workflows/pull_requests.yml +++ b/.github/workflows/pull_requests.yml @@ -139,6 +139,7 @@ jobs: name: Test Install Script runs-on: ${{ matrix.runs_on }} strategy: + fail-fast: false matrix: include: - arch_os: linux_amd64 diff --git a/pkg/scripts_test/check.go b/pkg/scripts_test/check.go index c29b83576b..5cbf19df45 100644 --- a/pkg/scripts_test/check.go +++ b/pkg/scripts_test/check.go @@ -18,6 +18,7 @@ import ( type check struct { test *testing.T installOptions installOptions + installType installType code int err error expectedInstallCode int @@ -55,6 +56,44 @@ func checkRun(c check) { require.Equal(c.test, c.expectedInstallCode, c.code, "unexpected installation script error code") } +func checkConfigFilesOwnershipAndPermissions(c check) { + ownerName := getConfigFilesOwner(c) + groupName := getConfigFilesGroup(c) + etcPathGlob := filepath.Join(etcPath, "*") + etcPathNestedGlob := filepath.Join(etcPath, "*", "*") + + for _, glob := range []string{etcPathGlob, etcPathNestedGlob} { + paths, err := filepath.Glob(glob) + require.NoError(c.test, err) + for _, path := range paths { + var permissions uint32 + info, err := os.Stat(path) + require.NoError(c.test, err) + if info.IsDir() { + permissions = configPathDirPermissions + } else { + switch path { + case configPath: + // /etc/otelcol-sumo/sumologic.yaml + permissions = configPathFilePermissions + case userConfigPath: + // /etc/otelcol-sumo/conf.d/common.yaml + permissions = commonConfigPathFilePermissions + case tokenEnvFilePath: + // /etc/otelcol-sumo/env/token.env + permissions = commonConfigPathFilePermissions + default: + // /etc/otelcol-sumo/conf.d/**/ + permissions = confDPathFilePermissions + } + } + PathHasPermissions(c.test, path, permissions) + PathHasOwner(c.test, configPath, ownerName, groupName) + } + } + PathHasPermissions(c.test, configPath, configPathFilePermissions) +} + func checkConfigCreated(c check) { require.FileExists(c.test, configPath, "configuration has not been created properly") } @@ -77,6 +116,13 @@ func checkConfigOverrided(c check) { }, "invalid value for installation token") } +func checkHostmetricsOwnershipAndPermissions(c check) { + ownerName := getConfigFilesOwner(c) + groupName := getConfigFilesGroup(c) + PathHasOwner(c.test, hostmetricsConfigPath, ownerName, groupName) + PathHasPermissions(c.test, hostmetricsConfigPath, confDPathFilePermissions) +} + func checkUserConfigCreated(c check) { require.FileExists(c.test, userConfigPath, "user configuration has not been created properly") } @@ -138,75 +184,67 @@ func checkAbortedDueToNoToken(c check) { require.Contains(c.test, c.output[len(c.output)-1], "You can ignore this requirement by adding '--skip-installation-token argument.") } -func preActionMockConfig(c check) { - err := os.MkdirAll(etcPath, fs.FileMode(etcPathPermissions)) - require.NoError(c.test, err) - - f, err := os.Create(configPath) - require.NoError(c.test, err) - - err = f.Chmod(fs.FileMode(configPathFilePermissions)) - require.NoError(c.test, err) -} - -func preActionMockUserConfig(c check) { - err := os.MkdirAll(etcPath, fs.FileMode(etcPathPermissions)) - require.NoError(c.test, err) - - err = os.MkdirAll(confDPath, fs.FileMode(configPathDirPermissions)) - require.NoError(c.test, err) - - f, err := os.Create(userConfigPath) - require.NoError(c.test, err) - - err = f.Chmod(fs.FileMode(commonConfigPathFilePermissions)) - require.NoError(c.test, err) +func getConfigFilesOwner(c check) string { + if c.installOptions.uninstall { + if c.installType&PACKAGE_INSTALL != 0 { + return systemUser + } + return rootUser + } + if c.installOptions.skipSystemd || c.installOptions.skipInstallToken { + return rootUser + } + return systemUser } -func preActionWriteAPIBaseURLToUserConfig(c check) { - conf, err := getConfig(userConfigPath) - require.NoError(c.test, err) - - conf.Extensions.Sumologic.APIBaseURL = c.installOptions.apiBaseURL - err = saveConfig(userConfigPath, conf) - require.NoError(c.test, err) +func getConfigFilesGroup(c check) string { + if c.installOptions.uninstall { + if c.installType&PACKAGE_INSTALL != 0 { + return systemGroup + } + return rootGroup + } + if c.installOptions.skipSystemd || c.installOptions.skipInstallToken { + return rootGroup + } + return systemGroup } -func preActionWriteDifferentAPIBaseURLToUserConfig(c check) { - conf, err := getConfig(userConfigPath) - require.NoError(c.test, err) - - conf.Extensions.Sumologic.APIBaseURL = "different" + c.installOptions.apiBaseURL - err = saveConfig(userConfigPath, conf) - require.NoError(c.test, err) +func preActionInstallPackage(c check) { + c.installOptions.installToken = installToken + c.installOptions.uninstall = false + c.installOptions.purge = false + c.installOptions.apiBaseURL = mockAPIBaseURL + c.code, c.output, c.errorOutput, c.err = runScript(c) } -func preActionWriteDifferentTagsToUserConfig(c check) { - conf, err := getConfig(userConfigPath) - require.NoError(c.test, err) - - conf.Extensions.Sumologic.Tags = map[string]string{ - "some": "tag", +func preActionInstallPackageVersion(version string) checkFunc { + return func(c check) { + c.installOptions.installToken = installToken + c.installOptions.uninstall = false + c.installOptions.purge = false + c.installOptions.version = version + c.installOptions.apiBaseURL = mockAPIBaseURL + c.code, c.output, c.errorOutput, c.err = runScript(c) } - err = saveConfig(userConfigPath, conf) - require.NoError(c.test, err) } -func preActionWriteEmptyUserConfig(c check) { - conf, err := getConfig(userConfigPath) - require.NoError(c.test, err) - - err = saveConfig(userConfigPath, conf) - require.NoError(c.test, err) +func preActionInstallPreviousVersion(c check) { + if c.installType&PACKAGE_INSTALL != 0 { + preActionInstallPackageVersion(previousPackageVersion)(c) + } + preActionInstallVersion(previousBinaryVersion)(c) } -func preActionWriteTagsToUserConfig(c check) { - conf, err := getConfig(userConfigPath) - require.NoError(c.test, err) - - conf.Extensions.Sumologic.Tags = c.installOptions.tags - err = saveConfig(userConfigPath, conf) - require.NoError(c.test, err) +func preActionInstallVersion(version string) checkFunc { + return func(c check) { + c.installOptions.installToken = installToken + c.installOptions.uninstall = false + c.installOptions.purge = false + c.installOptions.version = version + c.installOptions.apiBaseURL = mockAPIBaseURL + c.code, c.output, c.errorOutput, c.err = runScript(c) + } } func checkAbortedDueToDifferentAPIBaseURL(c check) { diff --git a/pkg/scripts_test/check_darwin.go b/pkg/scripts_test/check_darwin.go index d66d801497..1fb356a643 100644 --- a/pkg/scripts_test/check_darwin.go +++ b/pkg/scripts_test/check_darwin.go @@ -3,55 +3,12 @@ package sumologic_scripts_tests import ( "io/fs" "os" - "path/filepath" "regexp" "strings" "github.com/stretchr/testify/require" ) -func checkConfigFilesOwnershipAndPermissions(ownerName string, ownerGroup string) func(c check) { - return func(c check) { - PathHasPermissions(c.test, etcPath, etcPathPermissions) - PathHasOwner(c.test, etcPath, ownerName, ownerGroup) - - etcPathGlob := filepath.Join(etcPath, "*") - etcPathNestedGlob := filepath.Join(etcPath, "*", "*") - - for _, glob := range []string{etcPathGlob, etcPathNestedGlob} { - paths, err := filepath.Glob(glob) - require.NoError(c.test, err) - for _, path := range paths { - var permissions uint32 - info, err := os.Stat(path) - require.NoError(c.test, err) - if info.IsDir() { - if path == etcPath { - permissions = etcPathPermissions - } else { - permissions = configPathDirPermissions - } - } else { - switch path { - case configPath: - // /etc/otelcol-sumo/sumologic.yaml - permissions = configPathFilePermissions - case userConfigPath: - // /etc/otelcol-sumo/conf.d/common.yaml - permissions = commonConfigPathFilePermissions - default: - // /etc/otelcol-sumo/conf.d/* - permissions = confDPathFilePermissions - } - } - PathHasPermissions(c.test, path, permissions) - PathHasOwner(c.test, configPath, ownerName, ownerGroup) - } - } - PathHasPermissions(c.test, configPath, configPathFilePermissions) - } -} - func checkDifferentTokenInLaunchdConfig(c check) { require.NotEmpty(c.test, c.installOptions.installToken, "installation token has not been provided") @@ -71,13 +28,6 @@ func checkGroupNotExists(c check) { require.False(c.test, exists, "group has been created") } -func checkHostmetricsOwnershipAndPermissions(ownerName string, ownerGroup string) func(c check) { - return func(c check) { - PathHasOwner(c.test, hostmetricsConfigPath, ownerName, ownerGroup) - PathHasPermissions(c.test, hostmetricsConfigPath, confDPathFilePermissions) - } -} - func checkLaunchdConfigCreated(c check) { require.FileExists(c.test, launchdPath, "launchd configuration has not been created properly") } @@ -87,7 +37,7 @@ func checkLaunchdConfigNotCreated(c check) { } func checkPackageCreated(c check) { - re, err := regexp.Compile("Package downloaded to: .*/otelcol-sumo.pkg") + re, err := regexp.Compile(`^Package downloaded to: .*/otelcol-sumo-(apple|intel)\.pkg$`) require.NoError(c.test, err) matchedLine := "" @@ -121,10 +71,6 @@ func checkUserNotExists(c check) { require.False(c.test, exists, "user has been created") } -func preActionInstallPackage(c check) { - c.code, c.output, c.errorOutput, c.err = runScript(c) -} - func preActionInstallPackageWithDifferentAPIBaseURL(c check) { c.installOptions.apiBaseURL = "different" + c.installOptions.apiBaseURL c.code, c.output, c.errorOutput, c.err = runScript(c) diff --git a/pkg/scripts_test/check_linux.go b/pkg/scripts_test/check_linux.go index 28a3514623..cf934c6226 100644 --- a/pkg/scripts_test/check_linux.go +++ b/pkg/scripts_test/check_linux.go @@ -4,10 +4,8 @@ import ( "fmt" "io/fs" "os" - "os/exec" "os/user" - "path/filepath" - "strconv" + "regexp" "strings" "testing" @@ -16,42 +14,13 @@ import ( "github.com/stretchr/testify/require" ) -func checkACLAvailability(c check) bool { - return assert.FileExists(&testing.T{}, "/usr/bin/getfacl", "File ACLS is not supported") +func checkAbortedDueToSkipConfigUnsupported(c check) { + require.Greater(c.test, len(c.output), 0) + require.Contains(c.test, c.output[len(c.output)-1], "SKIP_CONFIG is not supported") } -func checkConfigFilesOwnershipAndPermissions(ownerName string, ownerGroup string) func(c check) { - return func(c check) { - etcPathGlob := filepath.Join(etcPath, "*") - etcPathNestedGlob := filepath.Join(etcPath, "*", "*") - - for _, glob := range []string{etcPathGlob, etcPathNestedGlob} { - paths, err := filepath.Glob(glob) - require.NoError(c.test, err) - for _, path := range paths { - var permissions uint32 - info, err := os.Stat(path) - require.NoError(c.test, err) - if info.IsDir() { - permissions = configPathDirPermissions - } else { - permissions = configPathFilePermissions - } - PathHasPermissions(c.test, path, permissions) - PathHasOwner(c.test, configPath, ownerName, ownerGroup) - } - } - PathHasPermissions(c.test, configPath, configPathFilePermissions) - } -} - -func checkDeprecatedTokenInConfig(c check) { - require.NotEmpty(c.test, c.installOptions.deprecatedInstallToken, "installation token has not been provided") - - conf, err := getConfig(userConfigPath) - require.NoError(c.test, err, "error while reading configuration") - - require.Equal(c.test, c.installOptions.deprecatedInstallToken, conf.Extensions.Sumologic.InstallToken, "installation token is different than expected") +func checkACLAvailability(c check) bool { + return assert.FileExists(&testing.T{}, "/usr/bin/getfacl", "File ACLS is not supported") } func checkDifferentTokenInConfig(c check) { @@ -80,11 +49,14 @@ func checkDownloadTimeout(c check) { require.Equal(c.test, 6, count) } -func checkHostmetricsOwnershipAndPermissions(ownerName string, ownerGroup string) func(c check) { - return func(c check) { - PathHasOwner(c.test, hostmetricsConfigPath, ownerName, ownerGroup) - PathHasPermissions(c.test, hostmetricsConfigPath, configPathFilePermissions) - } +func checkGroupExists(c check) { + _, err := user.LookupGroup(systemGroup) + require.NoError(c.test, err, "group has not been created") +} + +func checkGroupNotExists(c check) { + _, err := user.LookupGroup(systemGroup) + require.Error(c.test, err, "group has been created") } func checkOutputUserAddWarnings(c check) { @@ -95,6 +67,22 @@ func checkOutputUserAddWarnings(c check) { require.NotContains(c.test, errOutput, "useradd", "unexpected useradd output") } +func checkPackageCreated(c check) { + re, err := regexp.Compile(`^Package downloaded to: .*/otelcol\-sumo(_|\.).*.(deb|rpm)$`) + require.NoError(c.test, err) + + matchedLine := "" + for _, line := range c.output { + if re.MatchString(line) { + matchedLine = line + } + } + require.NotEmpty(c.test, matchedLine, "package path not in output") + + packagePath := strings.TrimPrefix(matchedLine, "Package downloaded to: ") + require.FileExists(c.test, packagePath, "package has not been created") +} + func checkSystemdAvailability(c check) bool { return assert.DirExists(&testing.T{}, systemdDirectoryPath, "systemd is not supported") } @@ -107,6 +95,12 @@ func checkSystemdConfigNotCreated(c check) { require.NoFileExists(c.test, systemdPath, "systemd configuration has been created") } +func checkSystemdConfigOrBackupCreated(c check) { + if configOrBackupMissing(tokenEnvFilePath) { + c.test.Fatalf("unable to find file: \"%s\"", tokenEnvFilePath) + } +} + func checkSystemdEnvDirExists(c check) { require.DirExists(c.test, etcPath+"/env", "systemd env directory does not exist") } @@ -150,6 +144,12 @@ func checkUninstallationOutput(c check) { require.Contains(c.test, c.output[len(c.output)-1], "Uninstallation completed") } +func checkUserConfigOrBackupCreated(c check) { + if configOrBackupMissing(userConfigPath) { + c.test.Fatalf("unable to find file: \"%s\"", userConfigPath) + } +} + func checkUserExists(c check) { _, err := user.Lookup(systemUser) require.NoError(c.test, err, "user has not been created") @@ -168,32 +168,34 @@ func checkVarLogACL(c check) { PathHasUserACL(c.test, "/var/log", systemUser, "r-x") } +func configOrBackupMissing(p string) bool { + backupPath := fmt.Sprintf("%s.rpmsave", p) + _, cErr := os.Stat(p) + _, bErr := os.Stat(backupPath) + return os.IsNotExist(cErr) && os.IsNotExist(bErr) +} + func preActionCreateHomeDirectory(c check) { err := os.MkdirAll(libPath, fs.FileMode(etcPathPermissions)) require.NoError(c.test, err) } -// preActionCreateUser creates the system user and then set it as owner of configPath -func preActionCreateUser(c check) { - preActionMockUserConfig(c) - - cmd := exec.Command("useradd", systemUser) - _, err := cmd.CombinedOutput() - require.NoError(c.test, err) - - f, err := os.Open(configPath) - require.NoError(c.test, err) - - user, err := user.Lookup(systemUser) - require.NoError(c.test, err) +func preActionInstallPackageWithOptions(o installOptions) checkFunc { + return func(c check) { + o.useNativePackaging = true + c.installOptions = o + c.code, c.output, c.errorOutput, c.err = runScript(c) + } +} - uid, err := strconv.Atoi(user.Uid) +func preActionMockConfig(c check) { + err := os.MkdirAll(etcPath, fs.FileMode(etcPathPermissions)) require.NoError(c.test, err) - gid, err := strconv.Atoi(user.Gid) + f, err := os.Create(configPath) require.NoError(c.test, err) - err = f.Chown(uid, gid) + err = f.Chmod(fs.FileMode(configPathFilePermissions)) require.NoError(c.test, err) } @@ -230,6 +232,29 @@ func preActionMockSystemdStructure(c check) { require.NoError(c.test, err) } +func preActionMockUserConfig(c check) { + err := os.MkdirAll(etcPath, fs.FileMode(etcPathPermissions)) + require.NoError(c.test, err) + + err = os.MkdirAll(confDPath, fs.FileMode(configPathDirPermissions)) + require.NoError(c.test, err) + + f, err := os.Create(userConfigPath) + require.NoError(c.test, err) + + err = f.Chmod(fs.FileMode(commonConfigPathFilePermissions)) + require.NoError(c.test, err) +} + +func preActionWriteAPIBaseURLToUserConfig(c check) { + conf, err := getConfig(userConfigPath) + require.NoError(c.test, err) + + conf.Extensions.Sumologic.APIBaseURL = c.installOptions.apiBaseURL + err = saveConfig(userConfigPath, conf) + require.NoError(c.test, err) +} + func preActionWriteDefaultAPIBaseURLToUserConfig(c check) { conf, err := getConfig(userConfigPath) require.NoError(c.test, err) @@ -239,6 +264,15 @@ func preActionWriteDefaultAPIBaseURLToUserConfig(c check) { require.NoError(c.test, err) } +func preActionWriteDifferentAPIBaseURLToUserConfig(c check) { + conf, err := getConfig(userConfigPath) + require.NoError(c.test, err) + + conf.Extensions.Sumologic.APIBaseURL = "different" + c.installOptions.apiBaseURL + err = saveConfig(userConfigPath, conf) + require.NoError(c.test, err) +} + func preActionWriteDifferentDeprecatedTokenToEnvFile(c check) { preActionMockEnvFiles(c) @@ -247,6 +281,17 @@ func preActionWriteDifferentDeprecatedTokenToEnvFile(c check) { require.NoError(c.test, err) } +func preActionWriteDifferentTagsToUserConfig(c check) { + conf, err := getConfig(userConfigPath) + require.NoError(c.test, err) + + conf.Extensions.Sumologic.Tags = map[string]string{ + "some": "tag", + } + err = saveConfig(userConfigPath, conf) + require.NoError(c.test, err) +} + func preActionWriteDifferentTokenToEnvFile(c check) { preActionMockEnvFiles(c) @@ -264,6 +309,20 @@ func preActionWriteDifferentTokenToUserConfig(c check) { require.NoError(c.test, err) } +func preActionWriteEmptyUserConfig(c check) { + err := saveConfig(userConfigPath, config{}) + require.NoError(c.test, err) +} + +func preActionWriteTagsToUserConfig(c check) { + conf, err := getConfig(userConfigPath) + require.NoError(c.test, err) + + conf.Extensions.Sumologic.Tags = c.installOptions.tags + err = saveConfig(userConfigPath, conf) + require.NoError(c.test, err) +} + func preActionWriteTokenToUserConfig(c check) { conf, err := getConfig(userConfigPath) require.NoError(c.test, err) diff --git a/pkg/scripts_test/command.go b/pkg/scripts_test/command.go index ea2ef5703b..446a72001e 100644 --- a/pkg/scripts_test/command.go +++ b/pkg/scripts_test/command.go @@ -31,6 +31,8 @@ type installOptions struct { dontKeepDownloads bool installHostmetrics bool timeout float64 + useNativePackaging bool + version string } func (io *installOptions) string() []string { @@ -96,6 +98,14 @@ func (io *installOptions) string() []string { opts = append(opts, "--download-timeout", fmt.Sprintf("%f", io.timeout)) } + if io.useNativePackaging { + opts = append(opts, "--use-native-packaging") + } + + if io.version != "" { + opts = append(opts, "--version", io.version) + } + return opts } @@ -114,6 +124,11 @@ func (io *installOptions) buildEnvs() []string { e = append(e, fmt.Sprintf("%s=%s", deprecatedInstallTokenEnv, io.deprecatedInstallToken)) } + // Enable non-interactive deb package installation & force default config + // conflict resolution + e = append(e, "DEBIAN_FRONTEND=noninteractive") + e = append(e, "DPKG_FORCE=confdef") + return e } diff --git a/pkg/scripts_test/common.go b/pkg/scripts_test/common.go index b086ed05f6..63cb12ef2a 100644 --- a/pkg/scripts_test/common.go +++ b/pkg/scripts_test/common.go @@ -3,14 +3,26 @@ package sumologic_scripts_tests import ( + "context" + "io" + "net" + "net/http" "os" "testing" "github.com/stretchr/testify/require" ) +type installType int + +const ( + BINARY_INSTALL installType = 1 << iota + PACKAGE_INSTALL +) + type testSpec struct { name string + installType installType options installOptions preChecks []checkFunc postChecks []checkFunc @@ -19,6 +31,53 @@ type testSpec struct { installCode int } +func NewTestSpecFromTestSpec(old testSpec) testSpec { + options := installOptions{ + installToken: old.options.installToken, + deprecatedInstallToken: old.options.deprecatedInstallToken, + autoconfirm: old.options.autoconfirm, + skipSystemd: old.options.skipSystemd, + tags: make(map[string]string), + skipConfig: old.options.skipConfig, + skipInstallToken: old.options.skipInstallToken, + fips: old.options.fips, + envs: make(map[string]string), + uninstall: old.options.uninstall, + purge: old.options.purge, + apiBaseURL: old.options.apiBaseURL, + configBranch: old.options.configBranch, + downloadOnly: old.options.downloadOnly, + dontKeepDownloads: old.options.dontKeepDownloads, + installHostmetrics: old.options.installHostmetrics, + timeout: old.options.timeout, + useNativePackaging: old.options.useNativePackaging, + version: old.options.version, + } + for k, v := range old.options.tags { + options.tags[k] = v + } + for k, v := range old.options.envs { + options.envs[k] = v + } + + new := testSpec{ + name: old.name, + installType: old.installType, + options: options, + preChecks: []checkFunc{}, + postChecks: []checkFunc{}, + preActions: []checkFunc{}, + conditionalChecks: []condCheckFunc{}, + installCode: old.installCode, + } + new.preChecks = append(new.preChecks, old.preChecks...) + new.postChecks = append(new.postChecks, old.postChecks...) + new.preActions = append(new.preActions, old.preActions...) + new.conditionalChecks = append(new.conditionalChecks, old.conditionalChecks...) + + return new +} + // These checks always have to be true after a script execution var commonPostChecks = []checkFunc{checkNoBakFilesPresent} @@ -31,6 +90,7 @@ func runTest(t *testing.T, spec *testSpec) { ch := check{ test: t, installOptions: spec.options, + installType: spec.installType, expectedInstallCode: spec.installCode, } @@ -43,6 +103,29 @@ func runTest(t *testing.T, spec *testSpec) { defer tearDown(t) + t.Log("Starting HTTP server") + mux := http.NewServeMux() + mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { + _, err := io.WriteString(w, "200 OK\n") + require.NoError(t, err) + }) + + listener, err := net.Listen("tcp", ":3333") + require.NoError(t, err) + + httpServer := &http.Server{ + Handler: mux, + } + go func() { + err := httpServer.Serve(listener) + if err != nil && err != http.ErrServerClosed { + require.NoError(t, err) + } + }() + defer func() { + require.NoError(t, httpServer.Shutdown(context.Background())) + }() + t.Log("Running pre actions") for _, a := range spec.preActions { a(ch) @@ -53,6 +136,7 @@ func runTest(t *testing.T, spec *testSpec) { c(ch) } + t.Log("Running install script") ch.code, ch.output, ch.errorOutput, ch.err = runScript(ch) // Remove cache in case of curl issue diff --git a/pkg/scripts_test/config.go b/pkg/scripts_test/config.go index 2f37aaab3e..539533bf59 100644 --- a/pkg/scripts_test/config.go +++ b/pkg/scripts_test/config.go @@ -39,6 +39,7 @@ func getConfig(path string) (config, error) { return conf, err } +//nolint:unused func saveConfig(path string, conf config) error { out, err := yaml.Marshal(conf) if err != nil { diff --git a/pkg/scripts_test/consts.go b/pkg/scripts_test/consts.go index 1eb155e95f..3db52ec578 100644 --- a/pkg/scripts_test/consts.go +++ b/pkg/scripts_test/consts.go @@ -12,11 +12,27 @@ const ( hostmetricsConfigPath string = confDPath + "/hostmetrics.yaml" cacheDirectory string = "/var/cache/otelcol-sumo/" logDirPath string = "/var/log/otelcol-sumo" + envDirectoryPath string = etcPath + "/env" + tokenEnvFilePath string = envDirectoryPath + "/token.env" installToken string = "token" installTokenEnv string = "SUMOLOGIC_INSTALLATION_TOKEN" deprecatedInstallTokenEnv string = "SUMOLOGIC_INSTALL_TOKEN" apiBaseURL string = "https://open-collectors.sumologic.com" + mockAPIBaseURL string = "http://127.0.0.1:3333" + + // previousBinaryVersion and previousPackageVersion specify a previous + // version to test upgrades from. It is necessary to upgrade from an older + // version as same-version package upgrades can behave differently than + // proper upgrades. + previousBinaryVersion string = "0.82.0-sumo-0" + previousPackageVersion string = "0.83.0-551" curlTimeoutErrorCode int = 28 + + commonConfigPathFilePermissions uint32 = 0660 + configPathDirPermissions uint32 = 0770 + configPathFilePermissions uint32 = 0440 + confDPathFilePermissions uint32 = 0644 + etcPathPermissions uint32 = 0751 ) diff --git a/pkg/scripts_test/consts_darwin.go b/pkg/scripts_test/consts_darwin.go index 095c6c4234..982e3af4d5 100644 --- a/pkg/scripts_test/consts_darwin.go +++ b/pkg/scripts_test/consts_darwin.go @@ -7,14 +7,6 @@ const ( launchdPathFilePermissions uint32 = 0640 uninstallScriptPath string = appSupportDirPath + "/uninstall.sh" - // TODO: fix mismatch between darwin permissions & linux binary install permissions - // common.yaml must be writable as the install scripts mutate it - commonConfigPathFilePermissions uint32 = 0660 - configPathDirPermissions uint32 = 0770 - configPathFilePermissions uint32 = 0440 - confDPathFilePermissions uint32 = 0644 - etcPathPermissions uint32 = 0751 - rootGroup string = "wheel" rootUser string = "root" systemGroup string = "_otelcol-sumo" diff --git a/pkg/scripts_test/consts_linux.go b/pkg/scripts_test/consts_linux.go index 84126e572d..794698b694 100644 --- a/pkg/scripts_test/consts_linux.go +++ b/pkg/scripts_test/consts_linux.go @@ -1,17 +1,9 @@ package sumologic_scripts_tests const ( - envDirectoryPath string = etcPath + "/env" - systemdDirectoryPath string = "/run/systemd/system" - systemdPath string = "/etc/systemd/system/otelcol-sumo.service" - tokenEnvFilePath string = envDirectoryPath + "/token.env" - - // TODO: fix mismatch between package permissions & expected permissions - commonConfigPathFilePermissions uint32 = 0550 - configPathDirPermissions uint32 = 0550 - configPathFilePermissions uint32 = 0440 - confDPathFilePermissions uint32 = 0644 - etcPathPermissions uint32 = 0551 + systemdDirectoryPath string = "/run/systemd/system" + systemdPath string = "/lib/systemd/system/otelcol-sumo.service" + deprecatedSystemdPath string = "/etc/systemd/system/otelcol-sumo.service" rootGroup string = "root" rootUser string = "root" diff --git a/pkg/scripts_test/install_darwin_test.go b/pkg/scripts_test/install_darwin_test.go index 80af459425..81cdd7fa61 100644 --- a/pkg/scripts_test/install_darwin_test.go +++ b/pkg/scripts_test/install_darwin_test.go @@ -3,6 +3,7 @@ package sumologic_scripts_tests import ( + "fmt" "testing" ) @@ -71,16 +72,9 @@ func TestInstallScriptDarwin(t *testing.T) { options: installOptions{ skipInstallToken: true, }, - preChecks: notInstalledChecks, - postChecks: []checkFunc{ - checkBinaryCreated, - checkBinaryIsRunning, - checkConfigCreated, - checkConfigFilesOwnershipAndPermissions(systemUser, systemGroup), - checkUserConfigCreated, - checkLaunchdConfigCreated, - checkHomeDirectoryCreated, - }, + preChecks: notInstalledChecks, + postChecks: notInstalledChecks, + installCode: 1, }, { name: "installation token only", @@ -92,7 +86,7 @@ func TestInstallScriptDarwin(t *testing.T) { checkBinaryCreated, checkBinaryIsRunning, checkConfigCreated, - checkConfigFilesOwnershipAndPermissions(systemUser, systemGroup), + checkConfigFilesOwnershipAndPermissions, checkUserConfigCreated, checkLaunchdConfigCreated, checkTokenInLaunchdConfig, @@ -105,15 +99,16 @@ func TestInstallScriptDarwin(t *testing.T) { { name: "override default config", options: installOptions{ - skipInstallToken: true, - autoconfirm: true, + autoconfirm: true, + }, + preActions: []checkFunc{ + preActionInstallPreviousVersion, }, - preActions: []checkFunc{preActionMockConfig}, preChecks: []checkFunc{ - checkBinaryNotCreated, + checkBinaryCreated, checkConfigCreated, - checkUserConfigNotCreated, - checkUserNotExists, + checkUserConfigCreated, + checkUserExists, }, postChecks: []checkFunc{ checkBinaryCreated, @@ -135,14 +130,14 @@ func TestInstallScriptDarwin(t *testing.T) { checkBinaryCreated, checkBinaryIsRunning, checkConfigCreated, - checkConfigFilesOwnershipAndPermissions(systemUser, systemGroup), + checkConfigFilesOwnershipAndPermissions, checkUserConfigCreated, checkLaunchdConfigCreated, checkTokenInLaunchdConfig, checkUserExists, checkGroupExists, checkHostmetricsConfigCreated, - checkHostmetricsOwnershipAndPermissions(systemUser, systemGroup), + checkHostmetricsOwnershipAndPermissions, checkHomeDirectoryCreated, }, }, @@ -159,7 +154,7 @@ func TestInstallScriptDarwin(t *testing.T) { checkBinaryCreated, checkBinaryIsRunning, checkConfigCreated, - checkConfigFilesOwnershipAndPermissions(systemUser, systemGroup), + checkConfigFilesOwnershipAndPermissions, checkUserConfigCreated, checkLaunchdConfigCreated, checkTokenInLaunchdConfig, @@ -224,11 +219,10 @@ func TestInstallScriptDarwin(t *testing.T) { { name: "same api base url", options: installOptions{ - apiBaseURL: apiBaseURL, - skipInstallToken: true, + apiBaseURL: mockAPIBaseURL, }, preActions: []checkFunc{ - preActionInstallPackage, + preActionInstallPreviousVersion, }, preChecks: []checkFunc{ checkBinaryCreated, @@ -247,8 +241,8 @@ func TestInstallScriptDarwin(t *testing.T) { { name: "different api base url", options: installOptions{ - apiBaseURL: apiBaseURL, - skipInstallToken: true, + apiBaseURL: apiBaseURL, + installToken: installToken, }, preActions: []checkFunc{ preActionInstallPackageWithDifferentAPIBaseURL, @@ -271,10 +265,12 @@ func TestInstallScriptDarwin(t *testing.T) { { name: "adding api base url", options: installOptions{ - apiBaseURL: apiBaseURL, - skipInstallToken: true, + apiBaseURL: apiBaseURL, + installToken: installToken, + }, + preActions: []checkFunc{ + preActionInstallPackageWithNoAPIBaseURL, }, - preActions: []checkFunc{preActionInstallPackageWithNoAPIBaseURL}, preChecks: []checkFunc{ checkBinaryCreated, checkConfigCreated, @@ -291,8 +287,8 @@ func TestInstallScriptDarwin(t *testing.T) { { name: "editing api base url", options: installOptions{ - apiBaseURL: apiBaseURL, - skipInstallToken: true, + apiBaseURL: apiBaseURL, + installToken: installToken, }, preActions: []checkFunc{ preActionInstallPackageWithNoAPIBaseURL, @@ -313,7 +309,7 @@ func TestInstallScriptDarwin(t *testing.T) { { name: "configuration with tags", options: installOptions{ - skipInstallToken: true, + installToken: installToken, tags: map[string]string{ "lorem": "ipsum", "foo": "bar", @@ -327,7 +323,7 @@ func TestInstallScriptDarwin(t *testing.T) { checkBinaryCreated, checkBinaryIsRunning, checkConfigCreated, - checkConfigFilesOwnershipAndPermissions(systemUser, systemGroup), + checkConfigFilesOwnershipAndPermissions, checkTags, checkLaunchdConfigCreated, }, @@ -335,7 +331,6 @@ func TestInstallScriptDarwin(t *testing.T) { { name: "same tags", options: installOptions{ - skipInstallToken: true, tags: map[string]string{ "lorem": "ipsum", "foo": "bar", @@ -365,7 +360,7 @@ func TestInstallScriptDarwin(t *testing.T) { { name: "different tags", options: installOptions{ - skipInstallToken: true, + installToken: installToken, tags: map[string]string{ "lorem": "ipsum", "foo": "bar", @@ -396,7 +391,7 @@ func TestInstallScriptDarwin(t *testing.T) { { name: "editing tags", options: installOptions{ - skipInstallToken: true, + installToken: installToken, tags: map[string]string{ "lorem": "ipsum", "foo": "bar", @@ -423,8 +418,16 @@ func TestInstallScriptDarwin(t *testing.T) { }, }, } { - t.Run(spec.name, func(t *testing.T) { - runTest(t, &spec) - }) + // Always use native packaging on Darwin + spec.installType = PACKAGE_INSTALL + + if spec.installType&PACKAGE_INSTALL != 0 { + spec.name = fmt.Sprintf("native packaging -- %s", spec.name) + spec.options.useNativePackaging = true + + t.Run(spec.name, func(t *testing.T) { + runTest(t, &spec) + }) + } } } diff --git a/pkg/scripts_test/install_unix_test.go b/pkg/scripts_test/install_unix_test.go index bc3d3a78f2..061ba7dffc 100644 --- a/pkg/scripts_test/install_unix_test.go +++ b/pkg/scripts_test/install_unix_test.go @@ -3,28 +3,69 @@ package sumologic_scripts_tests import ( + "fmt" "testing" ) func TestInstallScript(t *testing.T) { + notInstalledChecks := []checkFunc{ + checkBinaryNotCreated, + checkConfigNotCreated, + checkUserConfigNotCreated, + checkUserNotExists, + checkGroupNotExists, + checkUserConfigNotCreated, + checkSystemdConfigNotCreated, + checkTokenEnvFileNotCreated, + checkHostmetricsConfigNotCreated, + } + + installedWithSystemdChecks := []checkFunc{ + checkBinaryCreated, + checkConfigCreated, + checkUserConfigCreated, + checkSystemdConfigCreated, + checkUserExists, + checkGroupExists, + } + for _, spec := range []testSpec{ { name: "no arguments", + installType: BINARY_INSTALL | PACKAGE_INSTALL, options: installOptions{}, - preChecks: []checkFunc{checkBinaryNotCreated, checkConfigNotCreated, checkUserConfigNotCreated, checkUserNotExists}, - postChecks: []checkFunc{checkBinaryNotCreated, checkConfigNotCreated, checkUserConfigNotCreated, checkAbortedDueToNoToken, checkUserNotExists}, + preChecks: notInstalledChecks, + postChecks: append(notInstalledChecks, checkAbortedDueToNoToken), installCode: 1, }, { - name: "download only", + name: "download only", + installType: BINARY_INSTALL, + options: installOptions{ + downloadOnly: true, + }, + preChecks: notInstalledChecks, + postChecks: []checkFunc{ + checkBinaryCreated, + checkConfigNotCreated, + checkUserConfigNotCreated, + checkSystemdConfigNotCreated, + checkUserNotExists, + checkGroupNotExists, + }, + }, + { + name: "download only", + installType: PACKAGE_INSTALL, options: installOptions{ downloadOnly: true, }, - preChecks: []checkFunc{checkBinaryNotCreated, checkConfigNotCreated, checkUserConfigNotCreated, checkUserNotExists}, - postChecks: []checkFunc{checkBinaryCreated, checkConfigNotCreated, checkUserConfigNotCreated, checkSystemdConfigNotCreated, checkUserNotExists}, + preChecks: notInstalledChecks, + postChecks: append(notInstalledChecks, checkPackageCreated), }, { - name: "download only with timeout", + name: "download only with timeout", + installType: BINARY_INSTALL | PACKAGE_INSTALL, options: installOptions{ downloadOnly: true, timeout: 1, @@ -32,58 +73,122 @@ func TestInstallScript(t *testing.T) { }, // Skip this test as getting binary in github actions takes less than one second conditionalChecks: []condCheckFunc{checkSkipTest}, - preChecks: []checkFunc{checkBinaryNotCreated, checkConfigNotCreated, checkUserConfigNotCreated, checkUserNotExists}, - postChecks: []checkFunc{checkBinaryNotCreated, checkConfigNotCreated, checkUserConfigNotCreated, checkSystemdConfigNotCreated, checkUserNotExists, - checkDownloadTimeout}, - installCode: curlTimeoutErrorCode, + preChecks: notInstalledChecks, + postChecks: append(notInstalledChecks, checkDownloadTimeout), + installCode: curlTimeoutErrorCode, }, { - name: "skip config", + name: "skip config", + installType: BINARY_INSTALL, options: installOptions{ skipConfig: true, skipInstallToken: true, }, - preChecks: []checkFunc{checkBinaryNotCreated, checkConfigNotCreated, checkUserConfigNotCreated, checkUserNotExists}, - postChecks: []checkFunc{checkBinaryCreated, checkConfigNotCreated, checkUserConfigNotCreated}, + preChecks: notInstalledChecks, + postChecks: []checkFunc{ + checkBinaryCreated, + checkConfigNotCreated, + checkUserConfigNotCreated, + }, + }, + { + name: "skip config", + installType: PACKAGE_INSTALL, + options: installOptions{ + skipConfig: true, + skipInstallToken: true, + }, + preChecks: notInstalledChecks, + postChecks: append(notInstalledChecks, []checkFunc{ + checkAbortedDueToSkipConfigUnsupported, + }...), + installCode: 1, }, { - name: "skip installation token", + name: "skip installation token", + installType: BINARY_INSTALL, options: installOptions{ skipInstallToken: true, + skipSystemd: true, }, - preChecks: []checkFunc{checkBinaryNotCreated, checkConfigNotCreated, checkUserConfigNotCreated, checkUserNotExists}, + preChecks: notInstalledChecks, postChecks: []checkFunc{ checkBinaryCreated, checkBinaryIsRunning, checkConfigCreated, - checkConfigFilesOwnershipAndPermissions(rootUser, rootGroup), + checkConfigFilesOwnershipAndPermissions, checkUserConfigNotCreated, checkSystemdConfigNotCreated, }, }, { - name: "override default config", + name: "skip installation token", + installType: PACKAGE_INSTALL, + options: installOptions{ + skipInstallToken: true, + }, + preChecks: notInstalledChecks, + postChecks: notInstalledChecks, + installCode: 1, + }, + { + name: "override default config", + installType: BINARY_INSTALL, options: installOptions{ skipInstallToken: true, autoconfirm: true, }, - preActions: []checkFunc{preActionMockConfig}, - preChecks: []checkFunc{checkBinaryNotCreated, checkConfigCreated, checkUserConfigNotCreated, checkUserNotExists}, - postChecks: []checkFunc{checkBinaryCreated, checkBinaryIsRunning, checkConfigCreated, checkConfigOverrided, checkUserConfigNotCreated, - checkSystemdConfigNotCreated}, + preActions: []checkFunc{ + preActionMockConfig, + }, + preChecks: []checkFunc{ + checkBinaryNotCreated, + checkConfigCreated, + checkUserConfigNotCreated, + checkUserNotExists, + }, + postChecks: []checkFunc{ + checkBinaryCreated, + checkBinaryIsRunning, + checkConfigCreated, + checkConfigOverrided, + checkUserConfigNotCreated, + checkSystemdConfigNotCreated, + }, + }, + { + name: "override default config", + installType: PACKAGE_INSTALL, + options: installOptions{ + installToken: installToken, + autoconfirm: true, + }, + preActions: []checkFunc{ + preActionInstallPreviousVersion, + }, + preChecks: installedWithSystemdChecks, + postChecks: []checkFunc{ + checkBinaryCreated, + checkBinaryIsRunning, + checkConfigCreated, + checkConfigOverrided, + checkUserConfigCreated, + checkSystemdConfigCreated, + }, }, { - name: "installation token only", + name: "installation token only", + installType: BINARY_INSTALL, options: installOptions{ skipSystemd: true, installToken: installToken, }, - preChecks: []checkFunc{checkBinaryNotCreated, checkConfigNotCreated, checkUserConfigNotCreated, checkUserNotExists}, + preChecks: notInstalledChecks, postChecks: []checkFunc{ checkBinaryCreated, checkBinaryIsRunning, checkConfigCreated, - checkConfigFilesOwnershipAndPermissions(rootUser, rootGroup), + checkConfigFilesOwnershipAndPermissions, checkUserConfigCreated, checkTokenInConfig, checkSystemdConfigNotCreated, @@ -93,253 +198,846 @@ func TestInstallScript(t *testing.T) { }, }, { - name: "deprecated installation token only", + name: "installation token only", + installType: PACKAGE_INSTALL, + options: installOptions{ + apiBaseURL: mockAPIBaseURL, + installToken: installToken, + }, + preChecks: notInstalledChecks, + postChecks: []checkFunc{ + checkBinaryCreated, + checkBinaryIsRunning, + checkConfigCreated, + checkConfigFilesOwnershipAndPermissions, + checkUserConfigCreated, + checkTokenEnvFileCreated, + checkTokenInEnvFile, + checkSystemdConfigCreated, + checkUserExists, + checkHostmetricsConfigNotCreated, + }, + }, + { + name: "deprecated installation token only", + installType: BINARY_INSTALL, options: installOptions{ skipSystemd: true, deprecatedInstallToken: installToken, }, - preChecks: []checkFunc{checkBinaryNotCreated, checkConfigNotCreated, checkUserConfigNotCreated, checkUserNotExists}, + preChecks: notInstalledChecks, postChecks: []checkFunc{ checkBinaryCreated, checkBinaryIsRunning, checkConfigCreated, - checkConfigFilesOwnershipAndPermissions(rootUser, rootGroup), + checkConfigFilesOwnershipAndPermissions, checkUserConfigCreated, - checkDeprecatedTokenInConfig, checkSystemdConfigNotCreated, checkUserNotExists, checkHostmetricsConfigNotCreated, }, }, { - name: "installation token and hostmetrics", + name: "installation token and hostmetrics", + installType: BINARY_INSTALL | PACKAGE_INSTALL, options: installOptions{ - skipSystemd: true, + apiBaseURL: mockAPIBaseURL, installToken: installToken, installHostmetrics: true, }, - preChecks: []checkFunc{checkBinaryNotCreated, checkConfigNotCreated, checkUserConfigNotCreated, checkUserNotExists}, + preChecks: notInstalledChecks, postChecks: []checkFunc{ checkBinaryCreated, checkBinaryIsRunning, checkConfigCreated, - checkConfigFilesOwnershipAndPermissions(rootUser, rootGroup), + checkConfigFilesOwnershipAndPermissions, checkUserConfigCreated, - checkTokenInConfig, - checkSystemdConfigNotCreated, - checkUserNotExists, + checkTokenInEnvFile, + checkSystemdConfigCreated, + checkUserExists, checkHostmetricsConfigCreated, - checkHostmetricsOwnershipAndPermissions(rootUser, rootGroup), + checkHostmetricsOwnershipAndPermissions, }, }, { - name: "installation token only, binary not in PATH", + name: "installation token only, binary not in PATH", + installType: BINARY_INSTALL | PACKAGE_INSTALL, options: installOptions{ - skipSystemd: true, + apiBaseURL: mockAPIBaseURL, installToken: installToken, envs: map[string]string{ "PATH": "/sbin:/bin:/usr/sbin:/usr/bin", }, }, - preChecks: []checkFunc{checkBinaryNotCreated, checkConfigNotCreated, checkUserConfigNotCreated, checkUserNotExists}, + preChecks: notInstalledChecks, + postChecks: []checkFunc{ + checkBinaryCreated, + checkBinaryIsRunning, + checkConfigCreated, + checkConfigFilesOwnershipAndPermissions, + checkUserConfigCreated, + checkTokenInEnvFile, + checkSystemdConfigCreated, + checkUserExists, + }, + }, + { + name: "same installation token", + installType: BINARY_INSTALL, + options: installOptions{ + skipSystemd: true, + installToken: installToken, + }, + preActions: []checkFunc{ + preActionMockUserConfig, + preActionWriteTokenToUserConfig, + }, + preChecks: []checkFunc{ + checkBinaryNotCreated, + checkConfigNotCreated, + checkUserConfigCreated, + checkUserNotExists, + }, postChecks: []checkFunc{ checkBinaryCreated, checkBinaryIsRunning, checkConfigCreated, - checkConfigFilesOwnershipAndPermissions(rootUser, rootGroup), checkUserConfigCreated, checkTokenInConfig, checkSystemdConfigNotCreated, - checkUserNotExists, }, }, { - name: "same installation token", + name: "same installation token", + installType: PACKAGE_INSTALL, options: installOptions{ - skipSystemd: true, installToken: installToken, }, - preActions: []checkFunc{preActionMockUserConfig, preActionWriteTokenToUserConfig}, - preChecks: []checkFunc{checkBinaryNotCreated, checkConfigNotCreated, checkUserConfigCreated, checkUserNotExists}, - postChecks: []checkFunc{checkBinaryCreated, checkBinaryIsRunning, checkConfigCreated, checkUserConfigCreated, checkTokenInConfig, checkSystemdConfigNotCreated}, + preActions: []checkFunc{ + preActionInstallPreviousVersion, + }, + preChecks: []checkFunc{ + checkBinaryCreated, + checkConfigCreated, + checkUserConfigCreated, + checkTokenInEnvFile, + checkUserExists, + }, + postChecks: []checkFunc{ + checkBinaryCreated, + checkBinaryIsRunning, + checkConfigCreated, + checkUserConfigCreated, + checkTokenInEnvFile, + checkSystemdConfigCreated, + }, }, { - name: "different installation token", + name: "different installation token", + installType: BINARY_INSTALL, options: installOptions{ skipSystemd: true, installToken: installToken, }, - preActions: []checkFunc{preActionMockUserConfig, preActionWriteDifferentTokenToUserConfig}, - preChecks: []checkFunc{checkBinaryNotCreated, checkConfigNotCreated, checkUserConfigCreated, checkUserNotExists}, - postChecks: []checkFunc{checkBinaryNotCreated, checkConfigNotCreated, checkUserConfigCreated, checkSystemdConfigNotCreated, checkAbortedDueToDifferentToken}, + preActions: []checkFunc{ + preActionMockUserConfig, + preActionWriteDifferentTokenToUserConfig, + }, + preChecks: []checkFunc{ + checkBinaryNotCreated, + checkConfigNotCreated, + checkUserConfigCreated, + checkUserNotExists, + }, + postChecks: []checkFunc{ + checkBinaryNotCreated, + checkConfigNotCreated, + checkUserConfigCreated, + checkSystemdConfigNotCreated, + checkAbortedDueToDifferentToken, + }, installCode: 1, }, { - name: "adding installation token", + name: "different installation token", + installType: PACKAGE_INSTALL, options: installOptions{ - skipSystemd: true, installToken: installToken, }, - preActions: []checkFunc{preActionMockUserConfig}, - preChecks: []checkFunc{checkBinaryNotCreated, checkConfigNotCreated, checkUserConfigCreated, checkUserNotExists}, - postChecks: []checkFunc{checkBinaryCreated, checkConfigCreated, checkUserConfigCreated, checkTokenInConfig, checkSystemdConfigNotCreated}, + preActions: []checkFunc{ + preActionInstallPackage, + preActionWriteDifferentTokenToUserConfig, + }, + preChecks: installedWithSystemdChecks, + postChecks: []checkFunc{ + checkBinaryCreated, + checkConfigCreated, + checkUserConfigCreated, + checkSystemdConfigCreated, + checkAbortedDueToDifferentToken, + }, + installCode: 1, }, { - name: "editing installation token", + name: "adding installation token", + installType: BINARY_INSTALL, options: installOptions{ skipSystemd: true, - apiBaseURL: apiBaseURL, installToken: installToken, }, - preActions: []checkFunc{preActionMockUserConfig, preActionWriteEmptyUserConfig}, - preChecks: []checkFunc{checkBinaryNotCreated, checkConfigNotCreated, checkUserConfigCreated, checkUserNotExists}, - postChecks: []checkFunc{checkBinaryCreated, checkConfigCreated, checkUserConfigCreated, checkTokenInConfig, checkSystemdConfigNotCreated}, + preActions: []checkFunc{ + preActionMockUserConfig, + }, + preChecks: []checkFunc{ + checkBinaryNotCreated, + checkConfigNotCreated, + checkUserConfigCreated, + checkUserNotExists, + }, + postChecks: []checkFunc{ + checkBinaryCreated, + checkConfigCreated, + checkUserConfigCreated, + checkTokenInConfig, + checkSystemdConfigNotCreated, + }, }, { - name: "same api base url", + name: "adding installation token", + installType: PACKAGE_INSTALL, options: installOptions{ - skipSystemd: true, - apiBaseURL: apiBaseURL, - skipInstallToken: true, + installToken: installToken, + }, + preActions: []checkFunc{ + preActionInstallPreviousVersion, + }, + preChecks: installedWithSystemdChecks, + postChecks: []checkFunc{ + checkBinaryCreated, + checkConfigCreated, + checkUserConfigCreated, + checkTokenInEnvFile, + checkSystemdConfigCreated, }, - preActions: []checkFunc{preActionMockUserConfig, preActionWriteAPIBaseURLToUserConfig}, - preChecks: []checkFunc{checkBinaryNotCreated, checkConfigNotCreated, checkUserConfigCreated, checkUserNotExists}, - postChecks: []checkFunc{checkBinaryCreated, checkBinaryIsRunning, checkConfigCreated, checkUserConfigCreated, checkAPIBaseURLInConfig, - checkSystemdConfigNotCreated}, }, { - name: "different api base url", + name: "editing installation token", + installType: BINARY_INSTALL, options: installOptions{ - skipSystemd: true, - apiBaseURL: apiBaseURL, - skipInstallToken: true, + skipSystemd: true, + apiBaseURL: apiBaseURL, + installToken: installToken, + }, + preActions: []checkFunc{ + preActionMockUserConfig, + preActionWriteEmptyUserConfig, + }, + preChecks: []checkFunc{ + checkBinaryNotCreated, + checkConfigNotCreated, + checkUserConfigCreated, + checkUserNotExists, + }, + postChecks: []checkFunc{ + checkBinaryCreated, + checkConfigCreated, + checkUserConfigCreated, + checkTokenInConfig, + checkSystemdConfigNotCreated, }, - preActions: []checkFunc{preActionMockUserConfig, preActionWriteDifferentAPIBaseURLToUserConfig}, - preChecks: []checkFunc{checkBinaryNotCreated, checkConfigNotCreated, checkUserConfigCreated, checkUserNotExists}, - postChecks: []checkFunc{checkBinaryNotCreated, checkConfigNotCreated, checkUserConfigCreated, checkSystemdConfigNotCreated, - checkAbortedDueToDifferentAPIBaseURL}, - installCode: 1, }, { - name: "adding api base url", + name: "editing installation token", + installType: PACKAGE_INSTALL, options: installOptions{ - skipSystemd: true, - apiBaseURL: apiBaseURL, - skipInstallToken: true, + apiBaseURL: apiBaseURL, + installToken: installToken, + }, + preActions: []checkFunc{ + preActionInstallPreviousVersion, + preActionWriteEmptyUserConfig, + }, + preChecks: installedWithSystemdChecks, + postChecks: []checkFunc{ + checkBinaryCreated, + checkConfigCreated, + checkUserConfigCreated, + checkTokenInEnvFile, + checkSystemdConfigCreated, }, - preActions: []checkFunc{preActionMockUserConfig}, - preChecks: []checkFunc{checkBinaryNotCreated, checkConfigNotCreated, checkUserConfigCreated, checkUserNotExists}, - postChecks: []checkFunc{checkBinaryCreated, checkConfigCreated, checkUserConfigCreated, checkAPIBaseURLInConfig, checkSystemdConfigNotCreated}, }, { - name: "editing api base url", + name: "same api base url", + installType: BINARY_INSTALL, options: installOptions{ skipSystemd: true, apiBaseURL: apiBaseURL, skipInstallToken: true, }, - preActions: []checkFunc{preActionMockUserConfig, preActionWriteEmptyUserConfig}, - preChecks: []checkFunc{checkBinaryNotCreated, checkConfigNotCreated, checkUserConfigCreated, checkUserNotExists}, - postChecks: []checkFunc{checkBinaryCreated, checkConfigCreated, checkUserConfigCreated, checkAPIBaseURLInConfig, checkSystemdConfigNotCreated}, - }, - { - name: "empty installation token", - options: installOptions{ - skipSystemd: true, + preActions: []checkFunc{ + preActionMockUserConfig, + preActionWriteAPIBaseURLToUserConfig, }, - preActions: []checkFunc{preActionMockUserConfig, preActionWriteDifferentTokenToUserConfig}, - preChecks: []checkFunc{checkBinaryNotCreated, checkConfigNotCreated, checkUserConfigCreated, checkUserNotExists}, - postChecks: []checkFunc{checkBinaryCreated, checkConfigCreated, checkUserConfigCreated, checkSystemdConfigNotCreated, checkDifferentTokenInConfig}, - }, - { - name: "configuration with tags", - options: installOptions{ - skipSystemd: true, - skipInstallToken: true, - tags: map[string]string{ - "lorem": "ipsum", - "foo": "bar", - "escape_me": "'\\/", - "slash": "a/b", - "numeric": "1_024", - }, + preChecks: []checkFunc{ + checkBinaryNotCreated, + checkConfigNotCreated, + checkUserConfigCreated, + checkUserNotExists, }, - preChecks: []checkFunc{checkBinaryNotCreated, checkConfigNotCreated, checkUserConfigNotCreated, checkUserNotExists}, postChecks: []checkFunc{ checkBinaryCreated, checkBinaryIsRunning, checkConfigCreated, - checkConfigFilesOwnershipAndPermissions(rootUser, rootGroup), - checkTags, + checkUserConfigCreated, + checkAPIBaseURLInConfig, checkSystemdConfigNotCreated, }, }, { - name: "same tags", + name: "same api base url", + installType: PACKAGE_INSTALL, options: installOptions{ - skipSystemd: true, - skipInstallToken: true, - tags: map[string]string{ - "lorem": "ipsum", - "foo": "bar", - "escape_me": "'\\/", - "slash": "a/b", - "numeric": "1_024", - }, + apiBaseURL: apiBaseURL, + installToken: installToken, + }, + preActions: []checkFunc{ + preActionInstallPreviousVersion, + preActionWriteAPIBaseURLToUserConfig, + }, + preChecks: installedWithSystemdChecks, + postChecks: []checkFunc{ + checkBinaryCreated, + checkBinaryIsRunning, + checkConfigCreated, + checkUserConfigCreated, + checkAPIBaseURLInConfig, + checkSystemdConfigCreated, }, - preActions: []checkFunc{preActionMockUserConfig, preActionWriteTagsToUserConfig}, - preChecks: []checkFunc{checkBinaryNotCreated, checkConfigNotCreated, checkUserConfigCreated, checkUserNotExists}, - postChecks: []checkFunc{checkBinaryCreated, checkBinaryIsRunning, checkConfigCreated, checkUserConfigCreated, checkTags, - checkSystemdConfigNotCreated}, }, { - name: "different tags", + name: "different api base url", + installType: BINARY_INSTALL, options: installOptions{ skipSystemd: true, + apiBaseURL: apiBaseURL, skipInstallToken: true, - tags: map[string]string{ - "lorem": "ipsum", - "foo": "bar", + }, + preActions: []checkFunc{ + preActionMockUserConfig, + preActionWriteDifferentAPIBaseURLToUserConfig, + }, + preChecks: []checkFunc{ + checkBinaryNotCreated, + checkConfigNotCreated, + checkUserConfigCreated, + checkUserNotExists, + }, + postChecks: []checkFunc{ + checkBinaryNotCreated, + checkConfigNotCreated, + checkUserConfigCreated, + checkSystemdConfigNotCreated, + checkAbortedDueToDifferentAPIBaseURL, + }, + installCode: 1, + }, + { + name: "different api base url", + installType: PACKAGE_INSTALL, + options: installOptions{ + apiBaseURL: apiBaseURL, + installToken: installToken, + }, + preActions: []checkFunc{ + preActionInstallPackage, + preActionWriteDifferentAPIBaseURLToUserConfig, + }, + preChecks: installedWithSystemdChecks, + postChecks: []checkFunc{ + checkBinaryCreated, + checkConfigCreated, + checkUserConfigCreated, + checkSystemdConfigCreated, + checkAbortedDueToDifferentAPIBaseURL, + }, + installCode: 1, + }, + { + name: "adding api base url", + installType: BINARY_INSTALL, + options: installOptions{ + skipSystemd: true, + apiBaseURL: apiBaseURL, + skipInstallToken: true, + }, + preActions: []checkFunc{preActionMockUserConfig}, + preChecks: []checkFunc{ + checkBinaryNotCreated, + checkConfigNotCreated, + checkUserConfigCreated, + checkUserNotExists, + }, + postChecks: []checkFunc{ + checkBinaryCreated, + checkConfigCreated, + checkUserConfigCreated, + checkAPIBaseURLInConfig, + checkSystemdConfigNotCreated, + }, + }, + { + name: "adding api base url", + installType: PACKAGE_INSTALL, + options: installOptions{ + apiBaseURL: apiBaseURL, + installToken: installToken, + }, + preActions: []checkFunc{ + preActionInstallPackageWithOptions(installOptions{ + apiBaseURL: mockAPIBaseURL, + installToken: installToken, + version: previousPackageVersion, + }), + preActionWriteEmptyUserConfig, + }, + preChecks: installedWithSystemdChecks, + postChecks: []checkFunc{ + checkBinaryCreated, + checkConfigCreated, + checkUserConfigCreated, + checkAPIBaseURLInConfig, + checkSystemdConfigCreated, + }, + }, + { + name: "editing api base url", + installType: BINARY_INSTALL, + options: installOptions{ + skipSystemd: true, + apiBaseURL: apiBaseURL, + skipInstallToken: true, + }, + preActions: []checkFunc{ + preActionMockUserConfig, + preActionWriteEmptyUserConfig, + }, + preChecks: []checkFunc{ + checkBinaryNotCreated, + checkConfigNotCreated, + checkUserConfigCreated, + checkUserNotExists, + }, + postChecks: []checkFunc{ + checkBinaryCreated, + checkConfigCreated, + checkUserConfigCreated, + checkAPIBaseURLInConfig, + checkSystemdConfigNotCreated, + }, + }, + { + name: "editing api base url", + installType: PACKAGE_INSTALL, + options: installOptions{ + apiBaseURL: apiBaseURL, + installToken: installToken, + }, + preActions: []checkFunc{ + preActionInstallPackageWithOptions(installOptions{ + apiBaseURL: mockAPIBaseURL, + installToken: installToken, + }), + }, + preChecks: installedWithSystemdChecks, + postChecks: []checkFunc{ + checkBinaryCreated, + checkConfigCreated, + checkUserConfigCreated, + checkSystemdConfigCreated, + }, + installCode: 1, + }, + { + name: "empty installation token", + installType: BINARY_INSTALL, + options: installOptions{ + skipSystemd: true, + }, + preActions: []checkFunc{ + preActionMockUserConfig, + preActionWriteDifferentTokenToUserConfig, + }, + preChecks: []checkFunc{ + checkBinaryNotCreated, + checkConfigNotCreated, + checkUserConfigCreated, + checkUserNotExists, + }, + postChecks: []checkFunc{ + checkBinaryCreated, + checkConfigCreated, + checkUserConfigCreated, + checkSystemdConfigNotCreated, + checkDifferentTokenInConfig, + }, + }, + { + name: "upgrade with empty installation token", + installType: PACKAGE_INSTALL, + options: installOptions{ + installToken: "", + }, + preActions: []checkFunc{ + preActionInstallPreviousVersion, + preActionWriteDifferentTokenToUserConfig, + }, + preChecks: installedWithSystemdChecks, + postChecks: []checkFunc{ + checkBinaryCreated, + checkConfigCreated, + checkUserConfigCreated, + checkSystemdConfigCreated, + checkDifferentTokenInConfig, + }, + }, + { + name: "configuration with tags", + installType: BINARY_INSTALL, + options: installOptions{ + skipSystemd: true, + skipInstallToken: true, + tags: map[string]string{ + "lorem": "ipsum", + "foo": "bar", + "escape_me": "'\\/", + "slash": "a/b", + "numeric": "1_024", + }, + }, + preChecks: []checkFunc{ + checkBinaryNotCreated, + checkConfigNotCreated, + checkUserConfigNotCreated, + checkUserNotExists, + }, + postChecks: []checkFunc{ + checkBinaryCreated, + checkBinaryIsRunning, + checkConfigCreated, + checkConfigFilesOwnershipAndPermissions, + checkTags, + checkSystemdConfigNotCreated, + }, + }, + { + name: "configuration with tags", + installType: PACKAGE_INSTALL, + options: installOptions{ + installToken: installToken, + tags: map[string]string{ + "lorem": "ipsum", + "foo": "bar", + }, + }, + preChecks: []checkFunc{ + checkBinaryNotCreated, + checkConfigNotCreated, + checkUserConfigNotCreated, + checkUserNotExists, + }, + postChecks: []checkFunc{ + checkBinaryCreated, + checkBinaryIsRunning, + checkConfigCreated, + checkConfigFilesOwnershipAndPermissions, + checkTags, + checkSystemdConfigCreated, + }, + }, + { + name: "same tags", + installType: BINARY_INSTALL, + options: installOptions{ + skipSystemd: true, + skipInstallToken: true, + tags: map[string]string{ + "lorem": "ipsum", + "foo": "bar", + "escape_me": "'\\/", + "slash": "a/b", + "numeric": "1_024", + }, + }, + preActions: []checkFunc{ + preActionMockUserConfig, + preActionWriteTagsToUserConfig, + }, + preChecks: []checkFunc{ + checkBinaryNotCreated, + checkConfigNotCreated, + checkUserConfigCreated, + checkUserNotExists, + }, + postChecks: []checkFunc{ + checkBinaryCreated, + checkBinaryIsRunning, + checkConfigCreated, + checkUserConfigCreated, + checkTags, + checkSystemdConfigNotCreated, + }, + }, + { + name: "same tags", + installType: PACKAGE_INSTALL, + options: installOptions{ + installToken: installToken, + tags: map[string]string{ + "lorem": "ipsum", + "foo": "bar", + }, + }, + preActions: []checkFunc{ + preActionInstallPreviousVersion, + preActionWriteTagsToUserConfig, + }, + preChecks: installedWithSystemdChecks, + postChecks: []checkFunc{ + checkBinaryCreated, + checkBinaryIsRunning, + checkConfigCreated, + checkUserConfigCreated, + checkTags, + checkSystemdConfigCreated, + }, + }, + { + name: "different tags", + installType: BINARY_INSTALL, + options: installOptions{ + skipSystemd: true, + skipInstallToken: true, + tags: map[string]string{ + "lorem": "ipsum", + "foo": "bar", "escape_me": "'\\/", "slash": "a/b", "numeric": "1_024", }, }, - preActions: []checkFunc{preActionMockUserConfig, preActionWriteDifferentTagsToUserConfig}, - preChecks: []checkFunc{checkBinaryNotCreated, checkConfigNotCreated, checkUserConfigCreated, checkUserNotExists}, - postChecks: []checkFunc{checkBinaryNotCreated, checkConfigNotCreated, checkUserConfigCreated, checkDifferentTags, checkSystemdConfigNotCreated, - checkAbortedDueToDifferentTags}, - installCode: 1, + preActions: []checkFunc{ + preActionMockUserConfig, + preActionWriteDifferentTagsToUserConfig, + }, + preChecks: []checkFunc{ + checkBinaryNotCreated, + checkConfigNotCreated, + checkUserConfigCreated, + checkUserNotExists, + }, + postChecks: []checkFunc{ + checkBinaryNotCreated, + checkConfigNotCreated, + checkUserConfigCreated, + checkDifferentTags, + checkSystemdConfigNotCreated, + + checkAbortedDueToDifferentTags, + }, + installCode: 1, + }, + { + name: "different tags", + installType: PACKAGE_INSTALL, + options: installOptions{ + tags: map[string]string{ + "lorem": "ipsum", + "foo": "bar", + }, + }, + preActions: []checkFunc{ + preActionInstallPreviousVersion, + preActionWriteDifferentTagsToUserConfig, + }, + preChecks: installedWithSystemdChecks, + postChecks: []checkFunc{ + checkBinaryCreated, + checkConfigCreated, + checkUserConfigCreated, + checkDifferentTags, + checkSystemdConfigCreated, + + checkAbortedDueToDifferentTags, + }, + installCode: 1, + }, + { + name: "editing tags", + installType: BINARY_INSTALL, + options: installOptions{ + skipSystemd: true, + skipInstallToken: true, + tags: map[string]string{ + "lorem": "ipsum", + "foo": "bar", + "escape_me": "'\\/", + "slash": "a/b", + "numeric": "1_024", + }, + }, + preActions: []checkFunc{ + preActionMockUserConfig, + preActionWriteEmptyUserConfig, + }, + preChecks: []checkFunc{ + checkBinaryNotCreated, + checkConfigNotCreated, + checkUserConfigCreated, + checkUserNotExists, + }, + postChecks: []checkFunc{ + checkBinaryCreated, + checkBinaryIsRunning, + checkConfigCreated, + checkTags, + checkSystemdConfigNotCreated, + }, + }, + { + name: "editing tags", + installType: PACKAGE_INSTALL, + options: installOptions{ + installToken: installToken, + tags: map[string]string{ + "lorem": "ipsum", + "foo": "bar", + }, + }, + preActions: []checkFunc{ + preActionInstallPreviousVersion, + preActionWriteEmptyUserConfig, + }, + preChecks: installedWithSystemdChecks, + postChecks: []checkFunc{ + checkBinaryCreated, + checkBinaryIsRunning, + checkConfigCreated, + checkTags, + checkSystemdConfigCreated, + }, + }, + { + name: "systemd", + installType: BINARY_INSTALL, + options: installOptions{ + installToken: installToken, + }, + preChecks: []checkFunc{ + checkBinaryNotCreated, + checkConfigNotCreated, + checkUserConfigNotCreated, + checkUserNotExists, + checkTokenEnvFileNotCreated, + }, + postChecks: []checkFunc{ + checkBinaryCreated, + checkBinaryIsRunning, + checkConfigCreated, + checkConfigFilesOwnershipAndPermissions, + checkUserConfigNotCreated, + checkSystemdConfigCreated, + checkSystemdEnvDirExists, + checkSystemdEnvDirPermissions, + checkTokenEnvFileCreated, + checkTokenInEnvFile, + checkUserExists, + checkVarLogACL, + }, + conditionalChecks: []condCheckFunc{ + checkSystemdAvailability, + }, + }, + { + name: "systemd", + installType: PACKAGE_INSTALL, + options: installOptions{ + apiBaseURL: mockAPIBaseURL, + installToken: installToken, + }, + preChecks: notInstalledChecks, + postChecks: []checkFunc{ + checkBinaryCreated, + checkBinaryIsRunning, + checkConfigCreated, + checkConfigFilesOwnershipAndPermissions, + checkUserConfigCreated, + checkSystemdConfigCreated, + checkSystemdEnvDirExists, + checkSystemdEnvDirPermissions, + checkTokenEnvFileCreated, + checkTokenInEnvFile, + checkUserExists, + checkVarLogACL, + }, + conditionalChecks: []condCheckFunc{ + checkSystemdAvailability, + }, }, { - name: "editing tags", + name: "systemd installation token with existing user directory", + installType: BINARY_INSTALL, options: installOptions{ - skipSystemd: true, - skipInstallToken: true, - tags: map[string]string{ - "lorem": "ipsum", - "foo": "bar", - "escape_me": "'\\/", - "slash": "a/b", - "numeric": "1_024", - }, + installToken: installToken, + }, + preActions: []checkFunc{ + preActionCreateHomeDirectory, + }, + preChecks: []checkFunc{ + checkBinaryNotCreated, + checkConfigNotCreated, + checkUserConfigNotCreated, + checkUserNotExists, + checkHomeDirectoryCreated, + }, + postChecks: []checkFunc{ + checkBinaryCreated, + checkBinaryIsRunning, + checkConfigCreated, + checkConfigFilesOwnershipAndPermissions, + checkSystemdConfigCreated, + checkSystemdEnvDirExists, + checkSystemdEnvDirPermissions, + checkTokenEnvFileCreated, + checkTokenInEnvFile, + checkUserExists, + checkVarLogACL, + checkOutputUserAddWarnings, + }, + conditionalChecks: []condCheckFunc{ + checkSystemdAvailability, }, - preActions: []checkFunc{preActionMockUserConfig, preActionWriteEmptyUserConfig}, - preChecks: []checkFunc{checkBinaryNotCreated, checkConfigNotCreated, checkUserConfigCreated, checkUserNotExists}, - postChecks: []checkFunc{checkBinaryCreated, checkBinaryIsRunning, checkConfigCreated, checkTags, checkSystemdConfigNotCreated}, }, { - name: "systemd", + name: "systemd installation token with existing user directory", + installType: PACKAGE_INSTALL, options: installOptions{ installToken: installToken, }, - preChecks: []checkFunc{checkBinaryNotCreated, checkConfigNotCreated, checkUserConfigNotCreated, checkUserNotExists, checkTokenEnvFileNotCreated}, + preActions: []checkFunc{ + preActionCreateHomeDirectory, + }, + preChecks: []checkFunc{ + checkBinaryNotCreated, + checkConfigNotCreated, + checkUserConfigNotCreated, + checkUserNotExists, + checkHomeDirectoryCreated, + }, postChecks: []checkFunc{ checkBinaryCreated, checkBinaryIsRunning, checkConfigCreated, - checkConfigFilesOwnershipAndPermissions(systemUser, systemUser), - checkUserConfigNotCreated, + checkConfigFilesOwnershipAndPermissions, checkSystemdConfigCreated, checkSystemdEnvDirExists, checkSystemdEnvDirPermissions, @@ -347,16 +1045,22 @@ func TestInstallScript(t *testing.T) { checkTokenInEnvFile, checkUserExists, checkVarLogACL, + checkOutputUserAddWarnings, + }, + conditionalChecks: []condCheckFunc{ + checkSystemdAvailability, }, - conditionalChecks: []condCheckFunc{checkSystemdAvailability}, - installCode: 3, // because of invalid installation token + installCode: 3, // because of invalid install token }, { - name: "systemd installation token with existing user directory", + name: "systemd existing installation different token env", + installType: BINARY_INSTALL, options: installOptions{ installToken: installToken, }, - preActions: []checkFunc{preActionCreateHomeDirectory}, + preActions: []checkFunc{ + preActionCreateHomeDirectory, + }, preChecks: []checkFunc{ checkBinaryNotCreated, checkConfigNotCreated, @@ -368,7 +1072,7 @@ func TestInstallScript(t *testing.T) { checkBinaryCreated, checkBinaryIsRunning, checkConfigCreated, - checkConfigFilesOwnershipAndPermissions(systemUser, systemUser), + checkConfigFilesOwnershipAndPermissions, checkSystemdConfigCreated, checkSystemdEnvDirExists, checkSystemdEnvDirPermissions, @@ -378,15 +1082,20 @@ func TestInstallScript(t *testing.T) { checkVarLogACL, checkOutputUserAddWarnings, }, - conditionalChecks: []condCheckFunc{checkSystemdAvailability}, - installCode: 3, // because of invalid install token + conditionalChecks: []condCheckFunc{ + checkSystemdAvailability, + }, + installCode: 3, // because of invalid install token }, { - name: "systemd existing installation different token env", + name: "systemd existing installation different token env", + installType: PACKAGE_INSTALL, options: installOptions{ installToken: installToken, }, - preActions: []checkFunc{preActionCreateHomeDirectory}, + preActions: []checkFunc{ + preActionCreateHomeDirectory, + }, preChecks: []checkFunc{ checkBinaryNotCreated, checkConfigNotCreated, @@ -398,7 +1107,7 @@ func TestInstallScript(t *testing.T) { checkBinaryCreated, checkBinaryIsRunning, checkConfigCreated, - checkConfigFilesOwnershipAndPermissions(systemUser, systemUser), + checkConfigFilesOwnershipAndPermissions, checkSystemdConfigCreated, checkSystemdEnvDirExists, checkSystemdEnvDirPermissions, @@ -408,18 +1117,50 @@ func TestInstallScript(t *testing.T) { checkVarLogACL, checkOutputUserAddWarnings, }, - conditionalChecks: []condCheckFunc{checkSystemdAvailability}, - installCode: 3, // because of invalid install token + conditionalChecks: []condCheckFunc{ + checkSystemdAvailability, + }, + installCode: 3, // because of invalid install token + }, + { + name: "installation of hostmetrics in systemd during upgrade", + installType: BINARY_INSTALL, + options: installOptions{ + installToken: installToken, + installHostmetrics: true, + }, + preActions: []checkFunc{ + preActionInstallPreviousVersion, + }, + conditionalChecks: []condCheckFunc{ + checkSystemdAvailability, + }, + preChecks: installedWithSystemdChecks, + postChecks: []checkFunc{ + checkBinaryCreated, + checkBinaryIsRunning, + checkConfigCreated, + checkUserConfigCreated, + checkTokenInEnvFile, + checkUserExists, + checkHostmetricsConfigCreated, + checkHostmetricsOwnershipAndPermissions, + }, }, { - name: "installation of hostmetrics in systemd during upgrade", + name: "installation of hostmetrics in systemd during upgrade", + installType: PACKAGE_INSTALL, options: installOptions{ installToken: installToken, installHostmetrics: true, }, - preActions: []checkFunc{preActionMockSystemdStructure, preActionCreateUser}, - conditionalChecks: []condCheckFunc{checkSystemdAvailability}, - preChecks: []checkFunc{checkBinaryCreated, checkConfigCreated, checkUserConfigCreated, checkUserExists}, + preActions: []checkFunc{ + preActionInstallPreviousVersion, + }, + conditionalChecks: []condCheckFunc{ + checkSystemdAvailability, + }, + preChecks: installedWithSystemdChecks, postChecks: []checkFunc{ checkBinaryCreated, checkBinaryIsRunning, @@ -428,107 +1169,353 @@ func TestInstallScript(t *testing.T) { checkTokenInEnvFile, checkUserExists, checkHostmetricsConfigCreated, - checkHostmetricsOwnershipAndPermissions(systemUser, systemUser), + checkHostmetricsOwnershipAndPermissions, + }, + }, + { + name: "uninstallation without autoconfirm fails", + installType: BINARY_INSTALL, + options: installOptions{ + uninstall: true, + }, + preActions: []checkFunc{ + preActionMockStructure, + }, + preChecks: []checkFunc{ + checkBinaryCreated, + checkConfigCreated, + checkUserConfigCreated, + checkUserNotExists, + }, + postChecks: []checkFunc{ + checkBinaryCreated, + checkConfigCreated, + checkUserConfigCreated, }, + installCode: 1, }, { - name: "uninstallation without autoconfirm fails", + name: "uninstallation without autoconfirm fails", + installType: PACKAGE_INSTALL, options: installOptions{ uninstall: true, }, + preActions: []checkFunc{ + preActionInstallPackage, + }, + preChecks: installedWithSystemdChecks, + postChecks: []checkFunc{ + checkBinaryCreated, + checkConfigCreated, + checkUserConfigCreated, + }, installCode: 1, - preActions: []checkFunc{preActionMockStructure}, - preChecks: []checkFunc{checkBinaryCreated, checkConfigCreated, checkUserConfigCreated, checkUserNotExists}, - postChecks: []checkFunc{checkBinaryCreated, checkConfigCreated, checkUserConfigCreated}, }, { - name: "uninstallation with autoconfirm", + name: "uninstallation with autoconfirm", + installType: BINARY_INSTALL, + options: installOptions{ + autoconfirm: true, + uninstall: true, + }, + preActions: []checkFunc{ + preActionMockStructure, + }, + preChecks: []checkFunc{ + checkBinaryCreated, + checkConfigCreated, + checkUserConfigCreated, + checkUserNotExists, + }, + postChecks: []checkFunc{ + checkBinaryNotCreated, + checkConfigCreated, + checkUserConfigCreated, + checkUninstallationOutput, + }, + }, + { + name: "uninstallation with autoconfirm", + installType: PACKAGE_INSTALL, + options: installOptions{ + autoconfirm: true, + uninstall: true, + }, + preActions: []checkFunc{ + preActionInstallPackage, + }, + preChecks: installedWithSystemdChecks, + postChecks: []checkFunc{ + checkBinaryNotCreated, + checkUserConfigOrBackupCreated, + checkUninstallationOutput, + }, + }, + { + name: "systemd uninstallation", + installType: BINARY_INSTALL, + options: installOptions{ + autoconfirm: true, + uninstall: true, + }, + preActions: []checkFunc{ + preActionMockSystemdStructure, + }, + preChecks: []checkFunc{ + checkBinaryCreated, + checkConfigCreated, + checkUserConfigCreated, + checkSystemdConfigCreated, + checkUserNotExists, + }, + postChecks: []checkFunc{ + checkBinaryNotCreated, + checkConfigCreated, + checkUserConfigCreated, + checkSystemdConfigCreated, + checkUserNotExists, + }, + conditionalChecks: []condCheckFunc{ + checkSystemdAvailability, + }, + }, + { + name: "systemd uninstallation", + installType: PACKAGE_INSTALL, options: installOptions{ autoconfirm: true, uninstall: true, }, - preActions: []checkFunc{preActionMockStructure}, - preChecks: []checkFunc{checkBinaryCreated, checkConfigCreated, checkUserConfigCreated, checkUserNotExists}, - postChecks: []checkFunc{checkBinaryNotCreated, checkConfigCreated, checkUserConfigCreated, checkUninstallationOutput}, + preActions: []checkFunc{ + preActionInstallPreviousVersion, + }, + preChecks: installedWithSystemdChecks, + postChecks: []checkFunc{ + checkBinaryNotCreated, + checkUserConfigOrBackupCreated, + checkSystemdConfigOrBackupCreated, + checkUserExists, + }, + conditionalChecks: []condCheckFunc{ + checkSystemdAvailability, + }, }, { - name: "systemd uninstallation", + name: "purge", + installType: BINARY_INSTALL, options: installOptions{ + uninstall: true, + purge: true, autoconfirm: true, + }, + preActions: []checkFunc{ + preActionMockStructure, + }, + preChecks: []checkFunc{ + checkBinaryCreated, + checkConfigCreated, + checkUserConfigCreated, + checkUserNotExists, + }, + postChecks: []checkFunc{ + checkBinaryNotCreated, + checkConfigNotCreated, + checkUserConfigNotCreated, + }, + }, + { + name: "purge", + installType: PACKAGE_INSTALL, + options: installOptions{ uninstall: true, + purge: true, + autoconfirm: true, + }, + preActions: []checkFunc{ + preActionInstallPackage, + }, + preChecks: installedWithSystemdChecks, + postChecks: []checkFunc{ + checkBinaryNotCreated, + checkConfigNotCreated, + checkUserConfigNotCreated, }, - preActions: []checkFunc{preActionMockSystemdStructure}, - preChecks: []checkFunc{checkBinaryCreated, checkConfigCreated, checkUserConfigCreated, checkSystemdConfigCreated, checkUserNotExists}, - postChecks: []checkFunc{checkBinaryNotCreated, checkConfigCreated, checkUserConfigCreated, checkSystemdConfigCreated, checkUserNotExists}, - conditionalChecks: []condCheckFunc{checkSystemdAvailability}, }, { - name: "purge", + name: "systemd purge", + installType: BINARY_INSTALL, options: installOptions{ uninstall: true, purge: true, autoconfirm: true, }, - preActions: []checkFunc{preActionMockStructure}, - preChecks: []checkFunc{checkBinaryCreated, checkConfigCreated, checkUserConfigCreated, checkUserNotExists}, - postChecks: []checkFunc{checkBinaryNotCreated, checkConfigNotCreated, checkUserConfigNotCreated}, + preActions: []checkFunc{ + preActionMockSystemdStructure, + }, + preChecks: []checkFunc{ + checkBinaryCreated, + checkConfigCreated, + checkUserConfigCreated, + checkSystemdConfigCreated, + checkUserNotExists, + }, + postChecks: notInstalledChecks, + conditionalChecks: []condCheckFunc{ + checkSystemdAvailability, + }, }, { - name: "systemd purge", + name: "systemd purge", + installType: PACKAGE_INSTALL, options: installOptions{ uninstall: true, purge: true, autoconfirm: true, }, - preActions: []checkFunc{preActionMockSystemdStructure}, - preChecks: []checkFunc{checkBinaryCreated, checkConfigCreated, checkUserConfigCreated, checkSystemdConfigCreated, checkUserNotExists}, - postChecks: []checkFunc{checkBinaryNotCreated, checkConfigNotCreated, checkUserConfigNotCreated, checkSystemdConfigNotCreated, checkUserNotExists}, - conditionalChecks: []condCheckFunc{checkSystemdAvailability}, + preActions: []checkFunc{ + preActionInstallPreviousVersion, + }, + preChecks: installedWithSystemdChecks, + postChecks: notInstalledChecks, + conditionalChecks: []condCheckFunc{ + checkSystemdAvailability, + }, }, { - name: "systemd creation if token in file", - options: installOptions{}, - preActions: []checkFunc{preActionMockUserConfig, preActionWriteDifferentTokenToUserConfig, preActionWriteDefaultAPIBaseURLToUserConfig}, - preChecks: []checkFunc{checkBinaryNotCreated, checkConfigNotCreated, checkUserConfigCreated, checkUserNotExists}, - postChecks: []checkFunc{checkBinaryCreated, checkBinaryIsRunning, checkConfigCreated, checkDifferentTokenInConfig, checkSystemdConfigCreated, - checkUserExists, checkTokenEnvFileNotCreated}, - conditionalChecks: []condCheckFunc{checkSystemdAvailability}, - installCode: 3, // because of invalid installation token + // This only applies to binary installations as packages + // will always use the token.env file. + name: "systemd creation if token in file", + installType: BINARY_INSTALL, + options: installOptions{}, + preActions: []checkFunc{ + preActionMockUserConfig, + preActionWriteDifferentTokenToUserConfig, + preActionWriteDefaultAPIBaseURLToUserConfig, + }, + preChecks: []checkFunc{ + checkBinaryNotCreated, + checkConfigNotCreated, + checkUserConfigCreated, + checkUserNotExists, + }, + postChecks: []checkFunc{ + checkBinaryCreated, + checkBinaryIsRunning, + checkConfigCreated, + checkDifferentTokenInConfig, + checkSystemdConfigCreated, + checkUserExists, + checkTokenEnvFileNotCreated, + }, + conditionalChecks: []condCheckFunc{ + checkSystemdAvailability, + }, }, { - name: "systemd installation if token in file", + // This only applies to binary installations as packages + // will always use the token.env file. + name: "systemd installation if token in file", + installType: BINARY_INSTALL, options: installOptions{ installToken: installToken, }, - preActions: []checkFunc{preActionWriteDifferentTokenToEnvFile}, - preChecks: []checkFunc{checkBinaryNotCreated, checkUserConfigNotCreated, checkUserNotExists}, - postChecks: []checkFunc{checkDifferentTokenInEnvFile, checkAbortedDueToDifferentToken}, - conditionalChecks: []condCheckFunc{checkSystemdAvailability}, - installCode: 1, // because of invalid installation token + preActions: []checkFunc{ + preActionWriteDifferentTokenToEnvFile, + }, + preChecks: []checkFunc{ + checkBinaryNotCreated, + checkUserConfigNotCreated, + checkUserNotExists, + }, + postChecks: []checkFunc{ + checkDifferentTokenInEnvFile, + checkAbortedDueToDifferentToken, + }, + conditionalChecks: []condCheckFunc{ + checkSystemdAvailability, + }, + installCode: 1, // because of invalid installation token }, { - name: "systemd installation if deprecated token in file", + // This only applies to binary installations as packages + // will always use the token.env file. + name: "systemd installation if deprecated token in file", + installType: BINARY_INSTALL, options: installOptions{ installToken: installToken, }, - preActions: []checkFunc{preActionWriteDifferentDeprecatedTokenToEnvFile}, - preChecks: []checkFunc{checkBinaryNotCreated, checkUserConfigNotCreated, checkUserNotExists}, - postChecks: []checkFunc{checkDifferentTokenInEnvFile, checkAbortedDueToDifferentToken}, - conditionalChecks: []condCheckFunc{checkSystemdAvailability}, - installCode: 1, // because of invalid installation token + preActions: []checkFunc{ + preActionWriteDifferentDeprecatedTokenToEnvFile, + }, + preChecks: []checkFunc{ + checkBinaryNotCreated, + checkUserConfigNotCreated, + checkUserNotExists, + }, + postChecks: []checkFunc{ + checkDifferentTokenInEnvFile, + checkAbortedDueToDifferentToken, + }, + conditionalChecks: []condCheckFunc{ + checkSystemdAvailability, + }, + installCode: 1, // because of invalid installation token }, { - name: "don't keep downloads", + name: "don't keep downloads", + installType: BINARY_INSTALL, options: installOptions{ skipInstallToken: true, dontKeepDownloads: true, }, - preChecks: []checkFunc{checkBinaryNotCreated, checkConfigNotCreated, checkUserConfigNotCreated, checkUserNotExists}, - postChecks: []checkFunc{checkBinaryCreated, checkBinaryIsRunning, checkConfigCreated, checkUserConfigNotCreated, checkSystemdConfigNotCreated}, + preChecks: notInstalledChecks, + postChecks: []checkFunc{ + checkBinaryCreated, + checkBinaryIsRunning, + checkConfigCreated, + checkUserConfigNotCreated, + checkSystemdConfigNotCreated, + }, + }, + { + name: "don't keep downloads", + installType: PACKAGE_INSTALL, + options: installOptions{ + apiBaseURL: mockAPIBaseURL, + installToken: installToken, + dontKeepDownloads: true, + }, + preChecks: notInstalledChecks, + postChecks: []checkFunc{ + checkBinaryCreated, + checkBinaryIsRunning, + checkConfigCreated, + checkUserConfigCreated, + checkSystemdConfigCreated, + }, }, } { - t.Run(spec.name, func(t *testing.T) { - runTest(t, &spec) - }) + binaryTestSpec := NewTestSpecFromTestSpec(spec) + packageTestSpec := NewTestSpecFromTestSpec(spec) + + if spec.installType&BINARY_INSTALL != 0 { + // Run spec for binary installation + binaryTestSpec.name = fmt.Sprintf("binary install -- %s", spec.name) + binaryTestSpec.options.useNativePackaging = false + + t.Run(binaryTestSpec.name, func(t *testing.T) { + runTest(t, &binaryTestSpec) + }) + } + + if spec.installType&PACKAGE_INSTALL != 0 { + // Run spec for package installation + packageTestSpec.name = fmt.Sprintf("package install -- %s", spec.name) + packageTestSpec.options.useNativePackaging = true + + t.Run(packageTestSpec.name, func(t *testing.T) { + runTest(t, &packageTestSpec) + }) + } } } diff --git a/scripts/install.sh b/scripts/install.sh index 38793a3c66..d7ea7886f3 100755 --- a/scripts/install.sh +++ b/scripts/install.sh @@ -46,6 +46,11 @@ ARG_SHORT_INSTALL_HOSTMETRICS='H' ARG_LONG_INSTALL_HOSTMETRICS='install-hostmetrics' ARG_SHORT_TIMEOUT='m' ARG_LONG_TIMEOUT='download-timeout' +ARG_SHORT_USE_NATIVE_PACKAGING='x' +ARG_LONG_USE_NATIVE_PACKAGING='use-native-packaging' + +BINARY_GITHUB_ORG="SumoLogic" +BINARY_GITHUB_REPO="sumologic-otel-collector" PACKAGE_GITHUB_ORG="SumoLogic" PACKAGE_GITHUB_REPO="sumologic-otel-collector-packaging" @@ -59,6 +64,7 @@ readonly ARG_SHORT_BRANCH ARG_LONG_BRANCH ARG_SHORT_SKIP_CONFIG ARG_LONG_SKIP_CO readonly ARG_SHORT_SKIP_TOKEN ARG_LONG_SKIP_TOKEN ARG_SHORT_FIPS ARG_LONG_FIPS ENV_TOKEN readonly ARG_SHORT_INSTALL_HOSTMETRICS ARG_LONG_INSTALL_HOSTMETRICS readonly ARG_SHORT_TIMEOUT ARG_LONG_TIMEOUT +readonly ARG_SHORT_USE_NATIVE_PACKAGING ARG_LONG_USE_NATIVE_PACKAGING readonly DEPRECATED_ARG_LONG_TOKEN DEPRECATED_ENV_TOKEN DEPRECATED_ARG_LONG_SKIP_TOKEN readonly PACKAGE_GITHUB_ORG PACKAGE_GITHUB_REPO @@ -90,9 +96,13 @@ SKIP_TOKEN="" SKIP_CONFIG=false CONFIG_PATH="" COMMON_CONFIG_PATH="" +HOSTMETRICS_CONFIG_PATH="" PURGE="" DOWNLOAD_ONLY="" INSTALL_HOSTMETRICS=false +USE_NATIVE_PACKAGING=false + +SYSTEMD_SERVICE_NAME="otelcol-sumo" LAUNCHD_CONFIG="" LAUNCHD_ENV_KEY="" @@ -128,14 +138,15 @@ function usage() { cat << EOF Usage: bash install.sh [--${ARG_LONG_TOKEN} ] [--${ARG_LONG_TAG} = [ --${ARG_LONG_TAG} ...]] [--${ARG_LONG_API} ] [--${ARG_LONG_VERSION} ] \\ - [--${ARG_LONG_YES}] [--${ARG_LONG_VERSION} ] [--${ARG_LONG_HELP}] + [--${ARG_LONG_YES}] [--${ARG_LONG_VERSION} ] [--${ARG_LONG_USE_NATIVE_PACKAGING}] [--${ARG_LONG_HELP}] Supported arguments: -${ARG_SHORT_TOKEN}, --${ARG_LONG_TOKEN} Installation token. It has precedence over 'SUMOLOGIC_INSTALLATION_TOKEN' env variable. - -${ARG_SHORT_SKIP_TOKEN}, --${ARG_LONG_SKIP_TOKEN} Skips requirement for installation token. + -${ARG_SHORT_SKIP_TOKEN}, --${ARG_LONG_SKIP_TOKEN} Skips requirement for installation token. This option do not disable default configuration creation. + -${ARG_SHORT_USE_NATIVE_PACKAGING}, --${ARG_LONG_USE_NATIVE_PACKAGING} Use native package installation rather than binary installation. -${ARG_SHORT_TAG}, --${ARG_LONG_TAG} Sets tag for collector. This argument can be use multiple times. One per tag. - -${ARG_SHORT_DOWNLOAD}, --${ARG_LONG_DOWNLOAD} Download new binary only and skip configuration part. + -${ARG_SHORT_DOWNLOAD}, --${ARG_LONG_DOWNLOAD} Download new binary or package only and skip configuration part. -${ARG_SHORT_UNINSTALL}, --${ARG_LONG_UNINSTALL} Removes Sumo Logic Distribution for OpenTelemetry Collector from the system and disable Systemd service eventually. @@ -156,7 +167,7 @@ Supported arguments: -${ARG_SHORT_HELP}, --${ARG_LONG_HELP} Prints this help and usage. Supported env variables: - ${ENV_TOKEN}= Installation token.' + ${ENV_TOKEN}= Installation token. EOF } @@ -165,7 +176,7 @@ function set_defaults() { FILE_STORAGE="${HOME_DIRECTORY}/file_storage" DOWNLOAD_CACHE_DIR="/var/cache/otelcol-sumo" # this is in case we want to keep downloaded binaries CONFIG_DIRECTORY="/etc/otelcol-sumo" - SYSTEMD_CONFIG="/etc/systemd/system/otelcol-sumo.service" + SYSTEMD_CONFIG="/lib/systemd/system/otelcol-sumo.service" SUMO_BINARY_PATH="/usr/local/bin/otelcol-sumo" USER_CONFIG_DIRECTORY="${CONFIG_DIRECTORY}/conf.d" USER_ENV_DIRECTORY="${CONFIG_DIRECTORY}/env" @@ -173,6 +184,7 @@ function set_defaults() { CONFIG_PATH="${CONFIG_DIRECTORY}/sumologic.yaml" COMMON_CONFIG_PATH="${USER_CONFIG_DIRECTORY}/common.yaml" COMMON_CONFIG_BAK_PATH="${USER_CONFIG_DIRECTORY}/common.yaml.bak" + HOSTMETRICS_CONFIG_PATH="${CONFIG_DIRECTORY}/conf.d/hostmetrics.yaml" INDENTATION=" " EXT_INDENTATION="${INDENTATION}${INDENTATION}" @@ -258,6 +270,9 @@ function parse_options() { "--${ARG_LONG_INSTALL_HOSTMETRICS}") set -- "$@" "-${ARG_SHORT_INSTALL_HOSTMETRICS}" ;; + "-${ARG_SHORT_USE_NATIVE_PACKAGING}"|--"${ARG_LONG_USE_NATIVE_PACKAGING}") + set -- "$@" "-${ARG_SHORT_USE_NATIVE_PACKAGING}" + ;; -*) echo "Unknown option ${arg}"; usage; exit 1 ;; *) @@ -270,7 +285,7 @@ function parse_options() { while true; do set +e - getopts "${ARG_SHORT_HELP}${ARG_SHORT_TOKEN}:${ARG_SHORT_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_INSTALL_HOSTMETRICS}${ARG_SHORT_TIMEOUT}:" opt + getopts "${ARG_SHORT_HELP}${ARG_SHORT_TOKEN}:${ARG_SHORT_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_INSTALL_HOSTMETRICS}${ARG_SHORT_TIMEOUT}:${ARG_SHORT_USE_NATIVE_PACKAGING}" opt set -e # Invalid argument catched, print and exit @@ -306,6 +321,7 @@ function parse_options() { "${ARG_SHORT_INSTALL_HOSTMETRICS}") INSTALL_HOSTMETRICS=true ;; "${ARG_SHORT_KEEP_DOWNLOADS}") KEEP_DOWNLOADS=true ;; "${ARG_SHORT_TIMEOUT}") CURL_MAX_TIME="${OPTARG}" ;; + "${ARG_SHORT_USE_NATIVE_PACKAGING}") USE_NATIVE_PACKAGING=true ;; "${ARG_SHORT_TAG}") if [[ "${OPTARG}" != ?*"="* ]]; then echo "Invalid tag: '${OPTARG}'. Should be in 'key=value' format" @@ -486,7 +502,7 @@ function get_package_versions() { } # Get versions from provided one to the latest -get_versions_from() { +function get_versions_from() { local versions readonly versions="${1}" @@ -507,7 +523,7 @@ get_versions_from() { return 0 } -get_package_versions_from() { +function get_package_versions_from() { local versions readonly versions="${1}" @@ -648,6 +664,65 @@ function print_breaking_changes() { fi } +function write_env_token() { + if [[ -n "${SUMOLOGIC_INSTALLATION_TOKEN}" && -z "${USER_TOKEN}" ]]; then + echo 'Writing installation token to env file' + write_installation_token_env "${SUMOLOGIC_INSTALLATION_TOKEN}" "${TOKEN_ENV_FILE}" + fi +} + +function install_hostmetrics() { + if [[ "${INSTALL_HOSTMETRICS}" == "true" ]]; then + echo -e "Installing ${OS_TYPE} hostmetrics configuration" + + if [[ "${USE_NATIVE_PACKAGING}" == "true" ]]; then + HOSTMETRICS_CONFIG_URL="https://raw.githubusercontent.com/SumoLogic/sumologic-otel-collector-packaging/${CONFIG_BRANCH}/assets/conf.d/${OS_TYPE}.yaml" + else + HOSTMETRICS_CONFIG_URL="https://raw.githubusercontent.com/SumoLogic/sumologic-otel-collector/${CONFIG_BRANCH}/examples/conf.d/${OS_TYPE}.yaml" + fi + + if ! curl --retry 5 --connect-timeout 5 --max-time 30 --retry-delay 0 --retry-max-time 150 -f -s "${HOSTMETRICS_CONFIG_URL}" -o "${HOSTMETRICS_CONFIG_PATH}"; then + echo "Cannot obtain hostmetrics configuration for '${CONFIG_BRANCH}' branch. Either '${HOSTMETRICS_CONFIG_URL}' is invalid, or the network connection is unstable." + exit 1 + fi + + chmod 644 "${HOSTMETRICS_CONFIG_PATH}" + + if [[ "${OS_TYPE}" == "linux" ]]; then + echo -e "Setting the CAP_DAC_READ_SEARCH Linux capability on the collector binary to allow it to read host metrics from /proc directory: setcap 'cap_dac_read_search=ep' \"${SUMO_BINARY_PATH}\"" + echo -e "You can remove it with the following command: sudo setcap -r \"${SUMO_BINARY_PATH}\"" + echo -e "Without this capability, the collector will not be able to collect some of the host metrics." + setcap 'cap_dac_read_search=ep' "${SUMO_BINARY_PATH}" + fi + fi +} + +function set_hostmetrics_ownership() { + if [[ -f "${HOSTMETRICS_CONFIG_PATH}" ]]; then + chown "${SYSTEM_USER}":"${SYSTEM_USER}" "${HOSTMETRICS_CONFIG_PATH}" + fi +} + +function update_api_base_url() { + # get user api url again as it may have changed after package installation + USER_API_URL="$(get_user_api_url "${COMMON_CONFIG_PATH}")" + + # fill in api base url + if [[ -n "${API_BASE_URL}" && -z "${USER_API_URL}" ]]; then + write_api_url "${API_BASE_URL}" "${COMMON_CONFIG_PATH}" "${EXT_INDENTATION}" + fi +} + +function update_tags() { + # get user fields again as they may have changed after package installation + USER_FIELDS="$(get_user_tags "${COMMON_CONFIG_PATH}" "${INDENTATION}" "${EXT_INDENTATION}")" + + # fill in tags + if [[ -n "${FIELDS}" && -z "${USER_FIELDS}" ]]; then + write_tags "${FIELDS}" "${COMMON_CONFIG_PATH}" "${INDENTATION}" "${EXT_INDENTATION}" + fi +} + # set up configuration function setup_config() { echo 'We are going to get and set up a default configuration for you' @@ -665,10 +740,10 @@ function setup_config() { mkdir -p "${USER_ENV_DIRECTORY}" echo 'Changing permissions for config files and storage' - chmod 551 "${CONFIG_DIRECTORY}" # config directory world traversable, as is the /etc/ standard + chmod 751 "${CONFIG_DIRECTORY}" # config directory world traversable, as is the /etc/ standard echo 'Changing permissions for user env directory' - chmod 550 "${USER_ENV_DIRECTORY}" + chmod 770 "${USER_ENV_DIRECTORY}" chmod g+s "${USER_ENV_DIRECTORY}" echo "Generating configuration and saving as ${CONFIG_PATH}" @@ -679,20 +754,7 @@ function setup_config() { exit 1 fi - if [[ "${INSTALL_HOSTMETRICS}" == "true" ]]; then - echo -e "Installing ${OS_TYPE} hostmetrics configuration" - HOSTMETRICS_CONFIG_URL="https://raw.githubusercontent.com/SumoLogic/sumologic-otel-collector/${CONFIG_BRANCH}/examples/conf.d/${OS_TYPE}.yaml" - if ! curl --retry 5 --connect-timeout 5 --max-time 30 --retry-delay 0 --retry-max-time 150 -f -s "${HOSTMETRICS_CONFIG_URL}" -o "${CONFIG_DIRECTORY}/conf.d/hostmetrics.yaml"; then - echo "Cannot obtain hostmetrics configuration for '${CONFIG_BRANCH}' branch. Either '${HOSTMETRICS_CONFIG_URL}' is invalid, or the network connection is unstable." - exit 1 - fi - if [[ "${OS_TYPE}" == "linux" ]]; then - echo -e "Setting the CAP_DAC_READ_SEARCH Linux capability on the collector binary to allow it to read host metrics from /proc directory: setcap 'cap_dac_read_search=ep' \"${SUMO_BINARY_PATH}\"" - echo -e "You can remove it with the following command: sudo setcap -r \"${SUMO_BINARY_PATH}\"" - echo -e "Without this capability, the collector will not be able to collect some of the host metrics." - setcap 'cap_dac_read_search=ep' "${SUMO_BINARY_PATH}" - fi - fi + install_hostmetrics # Ensure that configuration is created if [[ -f "${COMMON_CONFIG_PATH}" ]]; then @@ -709,14 +771,8 @@ function setup_config() { write_installation_token "${SUMOLOGIC_INSTALLATION_TOKEN}" "${COMMON_CONFIG_PATH}" "${EXT_INDENTATION}" fi - # fill in api base url - if [[ -n "${API_BASE_URL}" && -z "${USER_API_URL}" ]]; then - write_api_url "${API_BASE_URL}" "${COMMON_CONFIG_PATH}" "${EXT_INDENTATION}" - fi - - if [[ -n "${FIELDS}" && -z "${USER_FIELDS}" ]]; then - write_tags "${FIELDS}" "${COMMON_CONFIG_PATH}" "${INDENTATION}" "${EXT_INDENTATION}" - fi + update_api_base_url + update_tags # clean up bak file rm -f "${COMMON_CONFIG_BAK_PATH}" @@ -724,22 +780,35 @@ function setup_config() { # Finish setting permissions after we're done creating config files chmod -R 440 "${CONFIG_DIRECTORY}"/* # all files only readable by the owner - find "${CONFIG_DIRECTORY}/" -mindepth 1 -type d -exec chmod 550 {} \; # directories also traversable + if [[ -f "${USER_CONFIG_DIRECTORY}" ]]; then + chmod -R 640 "${USER_CONFIG_DIRECTORY}" + fi + if [[ -f "${COMMON_CONFIG_PATH}" ]]; then + chmod 660 "${COMMON_CONFIG_PATH}" + fi + if [[ -f "${HOSTMETRICS_CONFIG_PATH}" ]]; then + chmod 644 "${HOSTMETRICS_CONFIG_PATH}" + fi + find "${CONFIG_DIRECTORY}/" -mindepth 1 -type d -exec chmod 770 {} \; # directories also traversable } function setup_config_darwin() { - create_user_config_file "${COMMON_CONFIG_PATH}" add_extension_to_config "${COMMON_CONFIG_PATH}" write_sumologic_extension "${COMMON_CONFIG_PATH}" "${INDENTATION}" + update_api_base_url + update_tags - # fill in api base url - if [[ -n "${API_BASE_URL}" ]]; then - write_api_url "${API_BASE_URL}" "${COMMON_CONFIG_PATH}" "${EXT_INDENTATION}" - fi + # clean up bak file + rm -f "${COMMON_CONFIG_BAK_PATH}" +} - if [[ -n "${FIELDS}" ]]; then - write_tags "${FIELDS}" "${COMMON_CONFIG_PATH}" "${INDENTATION}" "${EXT_INDENTATION}" - fi +# setup config for linux packages +function setup_config_linux() { + add_extension_to_config "${COMMON_CONFIG_PATH}" + write_sumologic_extension "${COMMON_CONFIG_PATH}" "${INDENTATION}" + update_api_base_url + update_tags + write_env_token # clean up bak file rm -f "${COMMON_CONFIG_BAK_PATH}" @@ -764,7 +833,7 @@ function uninstall_darwin() { local UNINSTALL_SCRIPT_PATH UNINSTALL_SCRIPT_PATH="/Library/Application Support/otelcol-sumo/uninstall.sh" - echo "Going to uninstall otelcol-sumo." + echo "Going to uninstall otelcol-sumo otelcol-sumo package" if [[ "${PURGE}" == "true" ]]; then echo "WARNING: purge is not yet supported on darwin" @@ -775,26 +844,70 @@ function uninstall_darwin() { "${UNINSTALL_SCRIPT_PATH}" } +function deb_is_installed() { + local name + readonly name="${1}" + + command -v dpkg &> /dev/null && dpkg -s "${name}" +} + +function rpm_is_installed() { + local name + readonly name="${1}" + + command -v rpm &> /dev/null && rpm -q "${name}" +} + # uninstall otelcol-sumo on linux function uninstall_linux() { - local MSG - MSG="Going to remove Otelcol binary" + local INSTALL_TYPE + INSTALL_TYPE="binary" - if [[ "${PURGE}" == "true" ]]; then - MSG="${MSG}, user, file storage and configurations" + if rpm_is_installed "otelcol-sumo"; then + INSTALL_TYPE="rpm" fi - echo "${MSG}." - ask_to_continue - - # disable systemd service - if [[ -f "${SYSTEMD_CONFIG}" ]]; then - systemctl stop otelcol-sumo || true - systemctl disable otelcol-sumo || true + if deb_is_installed "otelcol-sumo"; then + INSTALL_TYPE="deb" fi - # remove binary - rm -f "${SUMO_BINARY_PATH}" + case "$INSTALL_TYPE" in + deb) + echo "Going to remove otelcol-sumo deb package" + ask_to_continue + + if [[ "${PURGE}" == "true" ]]; then + dpkg -P otelcol-sumo + else + dpkg -r otelcol-sumo + fi + ;; + rpm) + echo "Going to remove otelcol-sumo rpm package" + ask_to_continue + rpm -e otelcol-sumo + ;; + binary) + local MSG + MSG="Going to remove Otelcol binary" + + if [[ "${PURGE}" == "true" ]]; then + MSG="${MSG}, user, file storage and configurations" + fi + + echo "${MSG}." + ask_to_continue + + # disable systemd service + if [[ -f "${SYSTEMD_CONFIG}" ]]; then + systemctl stop otelcol-sumo || true + systemctl disable otelcol-sumo || true + fi + + # remove binary + rm -f "${SUMO_BINARY_PATH}" + ;; + esac if [[ "${PURGE}" == "true" ]]; then # remove configuration and data @@ -809,8 +922,6 @@ function uninstall_linux() { fi fi fi - - echo "Uninstallation completed" } function escape_sed() { @@ -1074,7 +1185,7 @@ function create_user_config_file() { fi touch "${file}" - chmod 440 "${file}" + chmod 660 "${file}" } # write extensions section to user configuration file @@ -1241,55 +1352,19 @@ function write_tags() { fi } -function get_binary_from_branch() { - local branch - readonly branch="${1}" - - local name - readonly name="${2}" - - - local actions_url actions_output artifacts_link artifact_id - readonly actions_url="https://api.github.com/repos/SumoLogic/sumologic-otel-collector/actions/runs?status=success&branch=${branch}&event=push&per_page=1" - echo -e "Getting artifacts from latest CI run for branch \"${branch}\":\t\t${actions_url}" - actions_output="$(curl -f -sS \ - --connect-timeout 5 \ - --max-time 30 \ - --retry 5 \ - --retry-delay 0 \ - --retry-max-time 150 \ - -H "Accept: application/vnd.github+json" \ - -H "Authorization: token ${GITHUB_TOKEN}" \ - "${actions_url}")" - readonly actions_output - - # get latest action run - artifacts_link="$(echo "${actions_output}" | grep '"url"' | grep -oE '"https.*collector/actions.*"' -m 1)" - # strip first and last double-quote from $artifacts_link - artifacts_link=${artifacts_link%\"} - artifacts_link="${artifacts_link#\"}" - artifacts_link="${artifacts_link}/artifacts" - readonly artifacts_link +function get_file_from_url() { + local url download_path download_filename extra_curl_args + readonly url="${1}" + readonly download_path="${2}" + shift 2 + readonly extra_curl_args=("$@") - echo -e "Getting artifact id for CI run:\t\t${artifacts_link}" - artifact_id="$(curl -f -sS \ - --connect-timeout 5 \ - --max-time 30 \ - --retry 5 \ - --retry-delay 0 \ - --retry-max-time 150 \ - -H "Accept: application/vnd.github+json" \ - -H "Authorization: token ${GITHUB_TOKEN}" \ - "${artifacts_link}" \ - | grep -E '"(id|name)"' \ - | grep -B 1 "\"${name}\"" -m 1 \ - | grep -oE "[0-9]+" -m 1)" - readonly artifact_id + local download_filename download_cache_path + download_filename="$(basename "${download_path}")" + download_cache_path="${DOWNLOAD_CACHE_DIR}/${download_filename}" + readonly download_filename download_cache_path - local artifact_url download_path curl_args - readonly artifact_url="https://api.github.com/repos/SumoLogic/sumologic-otel-collector/actions/artifacts/${artifact_id}/zip" - readonly download_path="${DOWNLOAD_CACHE_DIR}/${name}.zip" - echo -e "Downloading binary from: ${artifact_url}" + echo -e "Downloading:\t\t${url}" curl_args=( "-fL" "--connect-timeout" "5" @@ -1297,156 +1372,109 @@ function get_binary_from_branch() { "--retry" "5" "--retry-delay" "0" "--retry-max-time" "150" - "--output" "${download_path}" + "--output" "${download_cache_path}" "--progress-bar" ) + set +u + curl_args+=( "${extra_curl_args[@]}" ) + set -u + if [ "${KEEP_DOWNLOADS}" == "true" ]; then - curl_args+=("-z" "${download_path}") + curl_args+=("-z" "${download_cache_path}") fi - curl "${curl_args[@]}" \ - -H "Accept: application/vnd.github+json" \ - -H "Authorization: token ${GITHUB_TOKEN}" \ - "${artifact_url}" - unzip -p "$download_path" "${name}" >"${TMPDIR}"/otelcol-sumo + curl "${curl_args[@]}" "${url}" + + cp -f "${download_cache_path}" "${download_path}" + if [ "${KEEP_DOWNLOADS}" == "false" ]; then - rm -f "${download_path}" + rm -f "${download_cache_path}" fi } -function get_binary_from_url() { - local url download_filename download_path curl_args +function get_output_from_github_api() { + local url readonly url="${1}" - echo -e "Downloading:\t\t${url}" - download_filename=$(basename "${url}") - readonly download_filename - readonly download_path="${DOWNLOAD_CACHE_DIR}/${download_filename}" curl_args=( - "-fL" + "-f" + "-sS" "--connect-timeout" "5" - "--max-time" "${CURL_MAX_TIME}" + "--max-time" "30" "--retry" "5" "--retry-delay" "0" "--retry-max-time" "150" - "--output" "${download_path}" - "--progress-bar" + "-H" "Accept: application/vnd.github+json" + "-H" "Authorization: token ${GITHUB_TOKEN}" ) - if [ "${KEEP_DOWNLOADS}" == "true" ]; then - curl_args+=("-z" "${download_path}") - fi - curl "${curl_args[@]}" "${url}" - - cp -f "${download_path}" "${TMPDIR}"/otelcol-sumo - if [ "${KEEP_DOWNLOADS}" == "false" ]; then - rm -f "${download_path}" - fi + curl "${curl_args[@]}" "${url}" } -function get_package_from_branch() { - local branch - readonly branch="${1}" +function get_github_actions_artifact() { + local org repo branch artifact_regex destination_path + readonly org="${1}" + readonly repo="${2}" + readonly branch="${3}" + readonly artifact_regex="${4}" + readonly destination_path="${5}" - local name - readonly name="${2}" + local base_url actions_url + readonly base_url="https://api.github.com/repos/${org}/${repo}/actions" + readonly actions_url="${base_url}/runs?status=success&branch=${branch}&event=push&per_page=1" - local actions_url actions_output artifacts_link artifact_id - readonly actions_url="https://api.github.com/repos/${PACKAGE_GITHUB_ORG}/${PACKAGE_GITHUB_REPO}/actions/runs?status=success&branch=${branch}&event=push&per_page=1" echo -e "Getting artifacts from latest CI run for branch \"${branch}\":\t\t${actions_url}" - actions_output="$(curl -f -sS \ - --connect-timeout 5 \ - --max-time 30 \ - --retry 5 \ - --retry-delay 0 \ - --retry-max-time 150 \ - -H "Accept: application/vnd.github+json" \ - -H "Authorization: token ${GITHUB_TOKEN}" \ - "${actions_url}")" + actions_output="$(get_output_from_github_api "${actions_url}")" readonly actions_output # get latest action run - artifacts_link="$(echo "${actions_output}" | grep '"url"' | grep -oE '"https.*packaging/actions.*"' -m 1)" - + url_regex="\"https.*${org}/${repo}/actions.*\"" + artifacts_link="$(echo "${actions_output}" | grep '"url"' | grep -oE "${url_regex}" -m 1)" # strip first and last double-quote from $artifacts_link artifacts_link=${artifacts_link%\"} artifacts_link="${artifacts_link#\"}" artifacts_link="${artifacts_link}/artifacts" readonly artifacts_link - echo -e "Getting artifact id for CI run:\t\t${artifacts_link}" - artifact_id="$(curl -f -sS \ - --connect-timeout 5 \ - --max-time 30 \ - --retry 5 \ - --retry-delay 0 \ - --retry-max-time 150 \ - -H "Accept: application/vnd.github+json" \ - -H "Authorization: token ${GITHUB_TOKEN}" \ - "${artifacts_link}" \ - | grep -E '"(id|name)"' \ - | grep -B 1 "\"${name}\"" -m 1 \ - | grep -oE "[0-9]+" -m 1)" + echo -e "Getting artifact id and name from CI run:\t\t${artifacts_link}" + artifacts_output="$(get_output_from_github_api "${artifacts_link}")" + artifact_name_ids="$(echo "${artifacts_output}" | grep -E '"(id|name)"')" + artifact_name_id="$(echo "${artifact_name_ids}" | grep -B 1 "\"${artifact_regex}\"" -m 1)" + artifact_id="$(echo "${artifact_name_id}" | grep -oE "[0-9]+" -m 1)" readonly artifact_id - echo "Artifact ID: ${artifact_id}" - - local artifact_url download_path curl_args - readonly artifact_url="https://api.github.com/repos/${PACKAGE_GITHUB_ORG}/${PACKAGE_GITHUB_REPO}/actions/artifacts/${artifact_id}/zip" - readonly download_path="${DOWNLOAD_CACHE_DIR}/${artifact_id}.zip" - echo -e "Downloading package from: ${artifact_url}" - curl_args=( - "-fL" - "--connect-timeout" "5" - "--max-time" "${CURL_MAX_TIME}" - "--retry" "5" - "--retry-delay" "0" - "--retry-max-time" "150" - "--output" "${download_path}" - "--progress-bar" + artifact_name="$(echo "${artifact_name_ids}" | grep -oE "\"${artifact_regex}\"" -m 1)" + # strip first and last double-quote from $artifact_name + artifact_name=${artifact_name%\"} + artifact_name="${artifact_name#\"}" + readonly artifact_name + + local artifact_url artifact_zip extra_curl_args + readonly artifact_url="${base_url}/artifacts/${artifact_id}/zip" + readonly artifact_zip="${TMPDIR}/${artifact_name}.zip" + readonly extra_curl_args=( + "-H" "Accept: application/vnd.github+json" + "-H" "Authorization: token ${GITHUB_TOKEN}" ) - if [ "${KEEP_DOWNLOADS}" == "true" ]; then - curl_args+=("-z" "${download_path}") - fi - curl "${curl_args[@]}" \ - -H "Accept: application/vnd.github+json" \ - -H "Authorization: token ${GITHUB_TOKEN}" \ - "${artifact_url}" - unzip -p "$download_path" > "${TMPDIR}/otelcol-sumo.pkg" - if [ "${KEEP_DOWNLOADS}" == "false" ]; then - rm -f "${download_path}" - fi -} + get_file_from_url "${artifact_url}" "${artifact_zip}" "${extra_curl_args[@]}" -function get_package_from_url() { - local url download_filename download_path curl_args - readonly url="${1}" - echo -e "Downloading:\t\t${url}" + unzip -p "${artifact_zip}" "${artifact_name}" > "${destination_path}" +} - download_filename=$(basename "${url}") - readonly download_filename - readonly download_path="${DOWNLOAD_CACHE_DIR}/${download_filename}" - curl_args=( - "-fL" - "--connect-timeout" "5" - "--max-time" "${CURL_MAX_TIME}" - "--retry" "5" - "--retry-delay" "0" - "--retry-max-time" "150" - "--output" "${download_path}" - "--progress-bar" - ) - if [ "${KEEP_DOWNLOADS}" == "true" ]; then - curl_args+=("-z" "${download_path}") - fi - curl "${curl_args[@]}" "${url}" +function get_github_release_artifact() { + local org repo artifact_name version destination_path + readonly org="${1}" + readonly repo="${2}" + readonly artifact_name="${3}" + readonly version="${4}" + readonly destination_path="${5}" - cp -f "${download_path}" "${TMPDIR}/otelcol-sumo.pkg" + local url + url="https://github.com/${org}/${repo}/releases/download/v${version}/${artifact_name}" + readonly url - if [ "${KEEP_DOWNLOADS}" == "false" ]; then - rm -f "${download_path}" - fi + get_file_from_url "${url}" "${destination_path}" } function set_acl_on_log_paths() { @@ -1536,119 +1564,46 @@ function plutil_replace_key() { fi } -############################ Main code - -OS_TYPE="$(get_os_type)" -ARCH_TYPE="$(get_arch_type)" -readonly OS_TYPE ARCH_TYPE - -echo -e "Detected OS type:\t${OS_TYPE}" -echo -e "Detected architecture:\t${ARCH_TYPE}" - -set_defaults -parse_options "$@" -set_tmpdir -install_missing_dependencies -check_dependencies - -readonly SUMOLOGIC_INSTALLATION_TOKEN API_BASE_URL FIELDS CONTINUE FILE_STORAGE CONFIG_DIRECTORY SYSTEMD_CONFIG UNINSTALL -readonly USER_CONFIG_DIRECTORY USER_ENV_DIRECTORY CONFIG_DIRECTORY CONFIG_PATH COMMON_CONFIG_PATH -readonly ACL_LOG_FILE_PATHS -readonly INSTALL_HOSTMETRICS -readonly CURL_MAX_TIME -readonly LAUNCHD_CONFIG LAUNCHD_ENV_KEY LAUNCHD_TOKEN_KEY - -if [[ "${UNINSTALL}" == "true" ]]; then - uninstall - exit 0 -fi - -# Attempt to find a token from an existing installation -case "${OS_TYPE}" in -darwin) - USER_TOKEN="$(plutil_extract_key "${LAUNCHD_CONFIG}" "${LAUNCHD_TOKEN_KEY}")" - ;; -*) - USER_TOKEN="$(get_user_config "${COMMON_CONFIG_PATH}")" - - # If Systemd is not disabled, try to extract token from systemd env file - if [[ -z "${USER_TOKEN}" && "${SYSTEMD_DISABLED}" == "false" ]]; then - USER_TOKEN="$(get_user_env_config "${TOKEN_ENV_FILE}")" - fi - ;; -esac -readonly USER_TOKEN - -# Exit if installation token is not set and there is no user configuration -if [[ -z "${SUMOLOGIC_INSTALLATION_TOKEN}" && "${SKIP_TOKEN}" != "true" && -z "${USER_TOKEN}" && -z "${DOWNLOAD_ONLY}" ]]; then - echo "Installation token has not been provided. Please set the '${ENV_TOKEN}' environment variable." - echo "You can ignore this requirement by adding '--${ARG_LONG_SKIP_TOKEN} argument." - exit 1 -fi +function get_existing_user_token() { + local user_token -# verify if passed arguments are the same like in user's configuration -if [[ -z "${DOWNLOAD_ONLY}" ]]; then - if [[ -n "${USER_TOKEN}" && -n "${SUMOLOGIC_INSTALLATION_TOKEN}" && "${USER_TOKEN}" != "${SUMOLOGIC_INSTALLATION_TOKEN}" ]]; then - echo "You are trying to install with different token than in your configuration file!" - exit 1 - fi - - if [[ -f "${COMMON_CONFIG_PATH}" ]]; then - INDENTATION="$(get_indentation "${COMMON_CONFIG_PATH}" "${INDENTATION}")" - EXT_INDENTATION="$(get_extension_indentation "${COMMON_CONFIG_PATH}" "${INDENTATION}")" - readonly INDENTATION EXT_INDENTATION + # Attempt to find a token from an existing installation + case "${OS_TYPE}" in + darwin) + user_token="$(plutil_extract_key "${LAUNCHD_CONFIG}" "${LAUNCHD_TOKEN_KEY}")" + ;; + linux) + user_token="$(get_user_config "${COMMON_CONFIG_PATH}")" - USER_API_URL="$(get_user_api_url "${COMMON_CONFIG_PATH}")" - if [[ -n "${USER_API_URL}" && -n "${API_BASE_URL}" && "${USER_API_URL}" != "${API_BASE_URL}" ]]; then - echo "You are trying to install with different api base url than in your configuration file!" - exit 1 - fi + # If Systemd is not disabled, try to extract token from systemd env file + if [[ -z "${user_token}" && "${SYSTEMD_DISABLED}" == "false" ]]; then + user_token="$(get_user_env_config "${TOKEN_ENV_FILE}")" + fi + ;; + *) + user_token="$(get_user_config "${COMMON_CONFIG_PATH}")" + ;; + esac - USER_FIELDS="$(get_user_tags "${COMMON_CONFIG_PATH}" "${INDENTATION}" "${EXT_INDENTATION}")" - FIELDS_TO_COMPARE="$(get_fields_to_compare "${FIELDS}")" + echo "${user_token}" +} - if [[ -n "${USER_FIELDS}" && -n "${FIELDS_TO_COMPARE}" && "${USER_FIELDS}" != "${FIELDS_TO_COMPARE}" ]]; then - echo "You are trying to install with different tags than in your configuration file!" - exit 1 - fi +function detect_distro_type() { + if test -f /etc/debian_version; then + echo "debian" + elif test -f /etc/redhat-release; then + echo "redhat" fi -fi - -set +u -if [[ -n "${BINARY_BRANCH}" && -z "${GITHUB_TOKEN}" ]]; then - echo "GITHUB_TOKEN env is required for '${ARG_LONG_BINARY_BRANCH}' option" - exit 1 -fi -set -u - -# Disable systemd if token is not specified at all -if [[ -z "${SUMOLOGIC_INSTALLATION_TOKEN}" && -z "${USER_TOKEN}" ]]; then - SYSTEMD_DISABLED=true -fi - -readonly SYSTEMD_DISABLED +} -if [ "${FIPS}" == "true" ]; then - if [ "${OS_TYPE}" != "linux" ] || [ "${ARCH_TYPE}" != "amd64" ]; then - echo "Error: The FIPS-approved binary is only available for linux/amd64" +function install_package() { + if [[ "${SKIP_CONFIG}" == "true" ]]; then + echo "SKIP_CONFIG is not supported" exit 1 fi -fi -if [[ "${OS_TYPE}" == "darwin" ]]; then - package_arch="" - case "${ARCH_TYPE}" in - "amd64") package_arch="intel" ;; - "arm64") package_arch="apple" ;; - *) - echo "Unsupported architecture for darwin: ${ARCH_TYPE}" - exit 1 - ;; - esac - readonly package_arch - - if [[ "${SKIP_CONFIG}" == "true" ]]; then - echo "SKIP_CONFIG is not supported on darwin" + if [[ "${SKIP_TOKEN}" == "true" ]]; then + echo "SKIP_TOKEN is not supported" exit 1 fi @@ -1669,33 +1624,79 @@ if [[ "${OS_TYPE}" == "darwin" ]]; then echo -e "Version to install:\t${VERSION}" + if [[ -z "${CONFIG_BRANCH}" ]]; then + CONFIG_BRANCH="v${VERSION}" + fi + readonly CONFIG_BRANCH + + case "${OS_TYPE}" in + "darwin") + install_darwin_package "${ARCH_TYPE}" + ;; + "linux") + install_linux_package "${ARCH_TYPE}" + ;; + *) + echo "Error: Unsupported OS for package installation" + exit 1 + ;; + esac +} + +function install_darwin_package() { + local arch_type + readonly arch_type="${1}" + + package_arch="" + case "${arch_type}" in + "amd64") package_arch="intel" ;; + "arm64") package_arch="apple" ;; + *) + echo "Unsupported architecture for darwin: ${ARCH_TYPE}" + exit 1 + ;; + esac + readonly package_arch + package_suffix="${package_arch}.pkg" + pkg="${TMPDIR}/otelcol-sumo-${package_suffix}" + readonly package_suffix pkg if [[ -n "${BINARY_BRANCH}" ]]; then - artifact_name="otelcol-sumo_.*-${package_suffix}" - get_package_from_branch "${BINARY_BRANCH}" "${artifact_name}" + get_github_actions_artifact \ + "${PACKAGE_GITHUB_ORG}" \ + "${PACKAGE_GITHUB_REPO}" \ + "${BINARY_BRANCH}" \ + "otelcol-sumo_.*-${package_suffix}" \ + "${pkg}" else - artifact_name="otelcol-sumo_${VERSION}-${package_suffix}" - readonly artifact_name - - LINK="https://github.com/${PACKAGE_GITHUB_ORG}/${PACKAGE_GITHUB_REPO}/releases/download/v${VERSION}/${artifact_name}" - readonly LINK - - get_package_from_url "${LINK}" + get_github_release_artifact \ + "${PACKAGE_GITHUB_ORG}" \ + "${PACKAGE_GITHUB_REPO}" \ + "otelcol-sumo_${VERSION}-${package_suffix}" \ + "${VERSION}" \ + "${pkg}" fi - pkg="${TMPDIR}/otelcol-sumo.pkg" - choices="${TMPDIR}/otelcol-sumo-choices.xml" - readonly pkg choices - if [[ "${DOWNLOAD_ONLY}" == "true" ]]; then echo "Package downloaded to: ${pkg}" exit 0 fi + choices="${TMPDIR}/otelcol-sumo-choices.xml" + readonly choices + # Extract choices xml from meta package, override the choices to enable # optional choices, and then install using the new choice selections + set +e installer -showChoiceChangesXML -pkg "${pkg}" -target / > "${choices}" + RC=$? + set -e + if [[ "${RC}" != "0" ]]; then + echo "Error extracting choices xml from pkg" + cat "${choices}" + exit 1 + fi # Determine how many installation choices exist choices_count=$(plutil -convert raw -o - "${choices}") @@ -1729,7 +1730,7 @@ if [[ "${OS_TYPE}" == "darwin" ]]; then installer -applyChoiceChangesXML "$choices" -pkg "$pkg" -target / - if [[ -n "${SUMOLOGIC_INSTALLATION_TOKEN}" && -z "${USER_TOKEN}" && "${SKIP_TOKEN}" != "true" ]]; then + if [[ -n "${SUMOLOGIC_INSTALLATION_TOKEN}" && -z "${USER_TOKEN}" ]]; then echo "Writing installation token to launchd config" write_installation_token_launchd "${SUMOLOGIC_INSTALLATION_TOKEN}" "${LAUNCHD_CONFIG}" fi @@ -1739,10 +1740,265 @@ if [[ "${OS_TYPE}" == "darwin" ]]; then # Run an unload/load launchd config to pull in new changes & restart the service launchctl unload "${LAUNCHD_CONFIG}" launchctl load -w "${LAUNCHD_CONFIG}" +} + +function install_linux_package() { + local arch_type + readonly arch_type="${1}" + + local distro_type + distro_type="$(detect_distro_type)" + readonly distro_type + + case "${distro_type}" in + "debian") install_linux_deb_package "${arch_type}" ;; + "redhat") install_linux_rpm_package "${arch_type}" ;; + *) + echo "Error: Could not detect if OS is debian or redhat based" + exit 1 + esac +} + +function install_linux_deb_package() { + local arch_type + readonly arch_type="${1}" + + package_arch="" + case "${arch_type}" in + "amd64") package_arch="amd64" ;; + "arm64") package_arch="arm64" ;; + *) + echo "Error: Unsupported architecture for linux deb packages: ${arch_type}" + exit 1 + ;; + esac + readonly package_arch + + package_suffix="${package_arch}.deb" + pkg="${TMPDIR}/otelcol-sumo_${package_suffix}" + readonly package_suffix pkg + + if [[ -n "${BINARY_BRANCH}" ]]; then + get_package_from_branch \ + "${PACKAGE_GITHUB_ORG}" \ + "${PACKAGE_GITHUB_REPO}" \ + "${BINARY_BRANCH}" \ + "${pkg}" + else + get_github_release_artifact \ + "${PACKAGE_GITHUB_ORG}" \ + "${PACKAGE_GITHUB_REPO}" \ + "otelcol-sumo_${VERSION}_${package_suffix}" \ + "${VERSION}" \ + "${pkg}" + fi + + if [[ "${DOWNLOAD_ONLY}" == "true" ]]; then + echo "Package downloaded to: ${pkg}" + exit 0 + fi + + echo "Installing otelcol-sumo package" + dpkg -i "${pkg}" + + setup_config_linux + install_hostmetrics + set_hostmetrics_ownership + + # Enable and start the systemd service for otelcol-sumo + systemd_enable_service "${SYSTEMD_SERVICE_NAME}" + systemd_start_service "${SYSTEMD_SERVICE_NAME}" + systemd_check_service_status "${SYSTEMD_SERVICE_NAME}" +} + +function install_linux_rpm_package() { + local arch_type + readonly arch_type="${1}" + + package_arch="" + case "${arch_type}" in + "amd64") package_arch="x86_64" ;; + "arm64") package_arch="aarch64" ;; + *) + echo "Error: Unsupported architecture for linux rpm packages: ${arch_type}" + exit 1 + ;; + esac + readonly package_arch + + package_suffix="${package_arch}.rpm" + pkg="${TMPDIR}/otelcol-sumo.${package_suffix}" + readonly package_suffix pkg + + if [[ -n "${BINARY_BRANCH}" ]]; then + get_package_from_branch \ + "${PACKAGE_GITHUB_ORG}" \ + "${PACKAGE_GITHUB_REPO}" \ + "${BINARY_BRANCH}" \ + "otelcol-sumo-.*.${package_suffix}" \ + "${pkg}" + else + get_github_release_artifact \ + "${PACKAGE_GITHUB_ORG}" \ + "${PACKAGE_GITHUB_REPO}" \ + "otelcol-sumo-${VERSION}.${package_suffix}" \ + "${VERSION}" \ + "${pkg}" + fi + + if [[ "${DOWNLOAD_ONLY}" == "true" ]]; then + echo "Package downloaded to: ${pkg}" + exit 0 + fi + + if rpm_is_installed "otelcol-sumo"; then + echo "Upgrading otelcol-sumo package" + rpm -Uvh "${pkg}" + else + echo "Installing otelcol-sumo package" + rpm -ivh "${pkg}" + fi + + setup_config_linux + install_hostmetrics + set_hostmetrics_ownership + + # Enable and start the systemd service for otelcol-sumo + systemd_enable_service "${SYSTEMD_SERVICE_NAME}" + systemd_start_service "${SYSTEMD_SERVICE_NAME}" + systemd_check_service_status "${SYSTEMD_SERVICE_NAME}" +} + +function systemd_enable_service() { + local service + service="${1}" + + echo "Enabling ${service} service" + systemctl enable "${service}" +} + +function systemd_start_service() { + local service + service="${1}" + + echo "Starting ${service} service" + systemctl start "${service}" +} + +function systemd_check_service_status() { + local service + service="${1}" + + echo "Waiting 10s before checking status" + sleep 10 + systemctl status "${service}" --no-pager +} + +############################ Main code + +OS_TYPE="$(get_os_type)" +ARCH_TYPE="$(get_arch_type)" +readonly OS_TYPE ARCH_TYPE + +echo -e "Detected OS type:\t${OS_TYPE}" +echo -e "Detected architecture:\t${ARCH_TYPE}" + +set_defaults +parse_options "$@" +set_tmpdir +install_missing_dependencies +check_dependencies + +# Force native packaging on darwin +if [[ "${OS_TYPE}" == "darwin" ]]; then + USE_NATIVE_PACKAGING="true" +fi + +if [ "${FIPS}" == "true" ]; then + if [ "${OS_TYPE}" != "linux" ] || [ "${ARCH_TYPE}" != "amd64" ] || [ "${USE_NATIVE_PACKAGING}" == "true" ]; then + echo "Error: The FIPS-approved binary is only available for linux/amd64" + exit 1 + fi +fi + +readonly SUMOLOGIC_INSTALLATION_TOKEN API_BASE_URL FIELDS CONTINUE FILE_STORAGE CONFIG_DIRECTORY SYSTEMD_CONFIG UNINSTALL +readonly USER_CONFIG_DIRECTORY USER_ENV_DIRECTORY CONFIG_DIRECTORY CONFIG_PATH COMMON_CONFIG_PATH +readonly ACL_LOG_FILE_PATHS +readonly INSTALL_HOSTMETRICS +readonly CURL_MAX_TIME +readonly LAUNCHD_CONFIG LAUNCHD_ENV_KEY LAUNCHD_TOKEN_KEY +readonly USE_NATIVE_PACKAGING + +if [[ "${UNINSTALL}" == "true" ]]; then + uninstall + exit 0 +fi + +USER_TOKEN="$(get_existing_user_token)" +readonly USER_TOKEN +# Exit if installation token is not set and there is no user configuration +if [[ -z "${SUMOLOGIC_INSTALLATION_TOKEN}" && "${SKIP_TOKEN}" != "true" && -z "${USER_TOKEN}" && -z "${DOWNLOAD_ONLY}" ]]; then + echo "Installation token has not been provided. Please set the '${ENV_TOKEN}' environment variable." + echo "You can ignore this requirement by adding '--${ARG_LONG_SKIP_TOKEN} argument." + exit 1 +fi + +# verify if passed arguments are the same like in user's configuration +if [[ -z "${DOWNLOAD_ONLY}" ]]; then + if [[ -n "${USER_TOKEN}" && -n "${SUMOLOGIC_INSTALLATION_TOKEN}" && "${USER_TOKEN}" != "${SUMOLOGIC_INSTALLATION_TOKEN}" ]]; then + echo "You are trying to install with different token than in your configuration file!" + exit 1 + fi + + if [[ -f "${COMMON_CONFIG_PATH}" ]]; then + INDENTATION="$(get_indentation "${COMMON_CONFIG_PATH}" "${INDENTATION}")" + EXT_INDENTATION="$(get_extension_indentation "${COMMON_CONFIG_PATH}" "${INDENTATION}")" + readonly INDENTATION EXT_INDENTATION + + USER_API_URL="$(get_user_api_url "${COMMON_CONFIG_PATH}")" + if [[ -n "${USER_API_URL}" && -n "${API_BASE_URL}" && "${USER_API_URL}" != "${API_BASE_URL}" ]]; then + echo "You are trying to install with different api base url than in your configuration file!" + exit 1 + fi + + USER_FIELDS="$(get_user_tags "${COMMON_CONFIG_PATH}" "${INDENTATION}" "${EXT_INDENTATION}")" + FIELDS_TO_COMPARE="$(get_fields_to_compare "${FIELDS}")" + + if [[ -n "${USER_FIELDS}" && -n "${FIELDS_TO_COMPARE}" && "${USER_FIELDS}" != "${FIELDS_TO_COMPARE}" ]]; then + echo "You are trying to install with different tags than in your configuration file!" + exit 1 + fi + fi +fi + +set +u +if [[ -n "${BINARY_BRANCH}" && -z "${GITHUB_TOKEN}" ]]; then + echo "GITHUB_TOKEN env is required for '${ARG_LONG_BINARY_BRANCH}' option" + exit 1 +fi +set -u + +# Disable systemd if token is not specified at all +if [[ -z "${SUMOLOGIC_INSTALLATION_TOKEN}" && -z "${USER_TOKEN}" ]]; then + SYSTEMD_DISABLED=true +fi + +readonly SYSTEMD_DISABLED + +################################################################################ +# Native package installation +################################################################################ + +if [[ "${USE_NATIVE_PACKAGING}" == "true" || "${OS_TYPE}" == "darwin" ]]; then + install_package exit 0 fi +################################################################################ +# Binary installation +################################################################################ + echo -e "Getting installed version..." INSTALLED_VERSION="$(get_installed_version)" echo -e "Installed version:\t${INSTALLED_VERSION:-none}" @@ -1760,7 +2016,6 @@ VERSION_PREFIX="${VERSION%.*}" # cut off the suffix starting with the last MAJOR_VERSION="${VERSION_PREFIX%.*}" # take the prefix from before the first stop MINOR_VERSION="${VERSION_PREFIX#*.}" # take the suffix after the first stop - readonly VERSIONS VERSION INSTALLED_VERSION VERSION_PREFIX MAJOR_VERSION MINOR_VERSION echo -e "Version to install:\t${VERSION}" @@ -1799,18 +2054,26 @@ else echo "Getting FIPS-compliant binary" binary_suffix="fips-${binary_suffix}" fi + binary_path="${TMPDIR}/otelcol-sumo" if [[ -n "${BINARY_BRANCH}" ]]; then - get_binary_from_branch "${BINARY_BRANCH}" "otelcol-sumo-${binary_suffix}" + get_github_actions_artifact \ + "${BINARY_GITHUB_ORG}" \ + "${BINARY_GITHUB_REPO}" \ + "${BINARY_BRANCH}" \ + "otelcol-sumo-${binary_suffix}" \ + "${binary_path}" else - LINK="https://github.com/SumoLogic/sumologic-otel-collector/releases/download/v${VERSION}/otelcol-sumo-${VERSION}-${binary_suffix}" - readonly LINK - - get_binary_from_url "${LINK}" + get_github_release_artifact \ + "${BINARY_GITHUB_ORG}" \ + "${BINARY_GITHUB_REPO}" \ + "otelcol-sumo-${VERSION}-${binary_suffix}" \ + "${VERSION}" \ + "${binary_path}" fi echo -e "Moving otelcol-sumo to /usr/local/bin" - mv "${TMPDIR}"/otelcol-sumo "${SUMO_BINARY_PATH}" + mv "${binary_path}" "${SUMO_BINARY_PATH}" echo -e "Setting ${SUMO_BINARY_PATH} to be executable" chmod +x "${SUMO_BINARY_PATH}" @@ -1841,10 +2104,9 @@ fi echo 'We are going to set up a systemd service' -if [[ -n "${SUMOLOGIC_INSTALLATION_TOKEN}" && -z "${USER_TOKEN}" ]]; then - echo 'Writing installation token to env file' - write_installation_token_env "${SUMOLOGIC_INSTALLATION_TOKEN}" "${TOKEN_ENV_FILE}" - chmod -R 440 "${TOKEN_ENV_FILE}" +write_env_token +if [[ -f "${TOKEN_ENV_FILE}" ]]; then + chmod -R 660 "${TOKEN_ENV_FILE}" fi if [[ -f "${SYSTEMD_CONFIG}" ]]; then @@ -1852,8 +2114,11 @@ if [[ -f "${SYSTEMD_CONFIG}" ]]; then # for example first installation without hostmetrics and second with hostmetrics if getent passwd "${SYSTEM_USER}" > /dev/null && [[ "${SKIP_CONFIG}" == "false" ]]; then echo 'Ensuring that ownership for config and storage is correct' - chown -R "${SYSTEM_USER}":"${SYSTEM_USER}" "${HOME_DIRECTORY}" "${CONFIG_DIRECTORY}"/* - chown -R "${SYSTEM_USER}":"${SYSTEM_USER}" "${USER_ENV_DIRECTORY}" + chown -R "${SYSTEM_USER}":"${SYSTEM_USER}" \ + "${HOME_DIRECTORY}" \ + "${CONFIG_DIRECTORY}" \ + "${USER_ENV_DIRECTORY}" + set_hostmetrics_ownership fi echo "Configuration for systemd service (${SYSTEMD_CONFIG}) already exist. Restarting service" systemctl restart otelcol-sumo @@ -1863,7 +2128,7 @@ fi echo 'Creating user and group' if getent passwd "${SYSTEM_USER}" > /dev/null; then echo 'User and group already created' -else + else ADDITIONAL_OPTIONS="" if [[ -d "${HOME_DIRECTORY}" ]]; then # do not create home directory as it already exists @@ -1881,8 +2146,11 @@ set_acl_on_log_paths if [[ "${SKIP_CONFIG}" == "false" ]]; then echo 'Changing ownership for config and storage' - chown -R "${SYSTEM_USER}":"${SYSTEM_USER}" "${HOME_DIRECTORY}" "${CONFIG_DIRECTORY}"/* - chown -R "${SYSTEM_USER}":"${SYSTEM_USER}" "${USER_ENV_DIRECTORY}" + chown -R "${SYSTEM_USER}":"${SYSTEM_USER}" \ + "${HOME_DIRECTORY}" \ + "${CONFIG_DIRECTORY}" \ + "${USER_ENV_DIRECTORY}" + set_hostmetrics_ownership fi SYSTEMD_CONFIG_URL="https://raw.githubusercontent.com/SumoLogic/sumologic-otel-collector/${CONFIG_BRANCH}/examples/systemd/otelcol-sumo.service" @@ -1933,12 +2201,6 @@ if command -v sestatus && sestatus; then fi fi -echo 'Enable otelcol-sumo service' -systemctl enable otelcol-sumo - -echo 'Starting otelcol-sumo service' -systemctl start otelcol-sumo - -echo 'Waiting 10s before checking status' -sleep 10 -systemctl status otelcol-sumo --no-pager +systemd_enable_service "${SYSTEMD_SERVICE_NAME}" +systemd_start_service "${SYSTEMD_SERVICE_NAME}" +systemd_check_service_status "${SYSTEMD_SERVICE_NAME}"