Skip to content

Commit

Permalink
Allow controlling telemetry via the ODO_TRACKING_CONSENT environmen…
Browse files Browse the repository at this point in the history
…t variable (#6258)

* Add support for ODO_TRACKING_CONSENT env variable

Co-authored-by: Armel Soro <asoro@redhat.com>

* Replace deprecated 'ODO_DISABLE_TELEMETRY' env var with 'ODO_TRACKING_CONSENT' in integration tests

* Log environment of process launched with 'helper_run' in integration tests

`odo` behavior might be altered based on certain environment variables.
So this is to help debug future issues that might happen.

Because the process environment also contains the
current OS environment, we purposely limit the content
to variables prefixed with 'ODO_' or particular ones
(like 'TELEMETRY_CALLER').

* Test conflicting situations when using both 'ODO_DISABLE_TELEMETRY' and 'ODO_TRACKING_CONSENT'

* Disable golangci-lint 'staticcheck' check about using the deprecated 'segment.DisableTelemetryEnv'

However, due to [1], line-based directives do not seem to be working.

* Make ODO_TRACKING_CONSENT env var take precedence over the ConsentTelemetry preference

See [1] for more context.

[1] https://github.com/redhat-developer/odo/pull/6258\#issuecomment-1293736398

* Add new 'segment#isTrackingConsentEnabled' function, as suggested in review

This would make it easier to rename the values if needed or add aliases later.

* Add more unit test cases, especially when any of the telemetry var is not there in the env

* Document ODO_TRACKING_CONSENT

* fixup! Add new 'segment#isTrackingConsentEnabled' function, as suggested in review

* fixup! fixup! Add new 'segment#isTrackingConsentEnabled' function, as suggested in review

Co-authored-by: Tomas Kral <tkral@redhat.com>
  • Loading branch information
rm3l and kadel authored Oct 31, 2022
1 parent fd04ea6 commit 719fe99
Show file tree
Hide file tree
Showing 11 changed files with 403 additions and 155 deletions.
6 changes: 6 additions & 0 deletions .golangci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -77,3 +77,9 @@ issues:
# Set to 0 to disable.
# Default: 3
max-same-issues: 0
exclude-rules:
- linters:
- staticcheck
# Workaround to exclude some 'staticcheck' messages, because line-based directive does not seem to work with golangci-lint
# See https://github.com/golangci/golangci-lint/issues/741#issuecomment-1017014331
text: "SA1019: segment.DisableTelemetryEnv is deprecated"
5 changes: 4 additions & 1 deletion USAGE_DATA.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
Usage Data
---

You can help improve `odo` by allowing it to collect usage data.
Read more about our privacy statement in this article on [developers.redhat.com](https://developers.redhat.com/article/tool-data-collection).

If the user has consented to `odo` collecting usage data, the following data will be collected when a command is executed -

* Command Name
Expand Down Expand Up @@ -47,5 +50,5 @@ Note: Telemetry data is not collected when you run `--help` for commands.
#### Disable
`odo preference set ConsentTelemetry false`

Alternatively you can _disable_ telemetry by setting `ODO_DISABLE_TELEMETRY` environment variable to `true`.
Alternatively you can _disable_ telemetry by setting the `ODO_TRACKING_CONSENT` environment variable to `no`.
This environment variable will override the `ConsentTelemetry` value set by `odo preference`.
21 changes: 11 additions & 10 deletions docs/website/docs/overview/configure.md
Original file line number Diff line number Diff line change
Expand Up @@ -179,13 +179,14 @@ Options here are mostly used for debugging and testing `odo` behavior.

### Environment variables controlling `odo` behavior

| Variable | Usage | Since | Example |
|-----------------------------|---------------------------------------------------------------------------------------------------------------------|---------------|---------------------------------|
| `PODMAN_CMD` | The command executed to run the local podman binary. `podman` by default | v2.4.2 | `podman` |
| `DOCKER_CMD` | The command executed to run the local docker binary. `docker` by default | v2.4.2 | `docker` |
| `ODO_LOG_LEVEL` | Useful for setting a log level to be used by `odo` commands. Takes precedence over the `-v` flag. | v1.0.2 | 3 |
| `ODO_DISABLE_TELEMETRY` | Useful for disabling telemetry collection. | v2.1.0 | `true` |
| `GLOBALODOCONFIG` | Useful for setting a different location of global preference file `preference.yaml`. | v0.0.19 | `~/.config/odo/preference.yaml` |
| `ODO_DEBUG_TELEMETRY_FILE` | Useful for debugging telemetry. When set it will save telemetry data to a file instead of sending it to the server. | v3.0.0-alpha1 | `/tmp/telemetry_data.json` |
| `DEVFILE_PROXY` | Integration tests will use this address as Devfile registry instead of `registry.stage.devfile.io` | v3.0.0-beta3 | `my-registry.example.com` |
| `TELEMETRY_CALLER` | Caller identifier passed to telemetry. Case-insensitive. Acceptable values: `vscode`, `intellij`, `jboss`. | v3.1.0 | `intellij` |
| Variable | Usage | Since | Example |
|-----------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------------|---------------------------------|
| `PODMAN_CMD` | The command executed to run the local podman binary. `podman` by default | v2.4.2 | `podman` |
| `DOCKER_CMD` | The command executed to run the local docker binary. `docker` by default | v2.4.2 | `docker` |
| `ODO_LOG_LEVEL` | Useful for setting a log level to be used by `odo` commands. Takes precedence over the `-v` flag. | v1.0.2 | 3 |
| `ODO_DISABLE_TELEMETRY` | Useful for disabling [telemetry collection](https://github.com/redhat-developer/odo/blob/main/USAGE_DATA.md). **Deprecated in v3.2.0**. Use `ODO_TRACKING_CONSENT` instead. | v2.1.0 | `true` |
| `GLOBALODOCONFIG` | Useful for setting a different location of global preference file `preference.yaml`. | v0.0.19 | `~/.config/odo/preference.yaml` |
| `ODO_DEBUG_TELEMETRY_FILE` | Useful for debugging [telemetry](https://github.com/redhat-developer/odo/blob/main/USAGE_DATA.md). When set it will save telemetry data to a file instead of sending it to the server. | v3.0.0-alpha1 | `/tmp/telemetry_data.json` |
| `DEVFILE_PROXY` | Integration tests will use this address as Devfile registry instead of `registry.stage.devfile.io` | v3.0.0-beta3 | `my-registry.example.com` |
| `TELEMETRY_CALLER` | Caller identifier passed to [telemetry](https://github.com/redhat-developer/odo/blob/main/USAGE_DATA.md). Case-insensitive. Acceptable values: `vscode`, `intellij`, `jboss`. | v3.1.0 | `intellij` |
| `ODO_TRACKING_CONSENT` | Useful for controlling [telemetry](https://github.com/redhat-developer/odo/blob/main/USAGE_DATA.md). Acceptable values: `yes` ([enables telemetry](https://github.com/redhat-developer/odo/blob/main/USAGE_DATA.md) and skips consent prompt), `no` (disables telemetry and consent prompt). Takes precedence over the [`ConsentTelemetry`](#preference-key-table) preference. | v3.2.0 | `yes` |
53 changes: 43 additions & 10 deletions pkg/odo/genericclioptions/runnable.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import (
"gopkg.in/AlecAivazis/survey.v1/terminal"

"github.com/devfile/library/pkg/devfile/parser"

"github.com/redhat-developer/odo/pkg/machineoutput"

"github.com/redhat-developer/odo/pkg/odo/cmdline"
Expand Down Expand Up @@ -80,25 +81,57 @@ func GenericRun(o Runnable, cmd *cobra.Command, args []string) {
var err error
startTime := time.Now()
cfg, _ := preference.NewClient()
disableTelemetry, _ := strconv.ParseBool(os.Getenv(segment.DisableTelemetryEnv))
//lint:ignore SA1019 We deprecated this env var, but until it is removed, we still need to support it
disableTelemetryValue, disableTelemetryEnvSet := os.LookupEnv(segment.DisableTelemetryEnv)
disableTelemetry, _ := strconv.ParseBool(disableTelemetryValue)
debugTelemetry := segment.GetDebugTelemetryFile()
isTrackingConsentEnabled, trackingConsentEnvSet, trackingConsentErr := segment.IsTrackingConsentEnabled()

// check for conflicting settings
if trackingConsentErr == nil && disableTelemetryEnvSet && trackingConsentEnvSet && disableTelemetry == isTrackingConsentEnabled {
//lint:ignore SA1019 We deprecated this env var, but we really want users to know there is a conflict here
util.LogErrorAndExit(
fmt.Errorf("%[1]s and %[2]s values are in conflict. %[1]s is deprecated, please use only %[2]s",
segment.DisableTelemetryEnv, segment.TrackingConsentEnv), "")
}

// Prompt the user to consent for telemetry if a value is not set already
// Skip prompting if the preference command is called
// This prompt has been placed here so that it does not prompt the user when they call --help
if !cfg.IsSet(preference.ConsentTelemetrySetting) && cmd.Parent().Name() != "preference" {
if !segment.RunningInTerminal() {
klog.V(4).Infof("Skipping telemetry question because there is no terminal (tty)\n")
} else if disableTelemetry {
klog.V(4).Infof("Skipping telemetry question due to %s=%t\n", segment.DisableTelemetryEnv, disableTelemetry)
} else {
var consentTelemetry bool
prompt := &survey.Confirm{Message: "Help odo improve by allowing it to collect usage data. Read about our privacy statement: https://developers.redhat.com/article/tool-data-collection. You can change your preference later by changing the ConsentTelemetry preference.", Default: true}
err = survey.AskOne(prompt, &consentTelemetry, nil)
ui.HandleError(err)
if err == nil {
if err1 := cfg.SetConfiguration(preference.ConsentTelemetrySetting, strconv.FormatBool(consentTelemetry)); err1 != nil {
klog.V(4).Info(err1.Error())
var askConsent bool
if trackingConsentErr != nil {
klog.V(4).Infof("error in determining value of tracking consent env var: %v", trackingConsentErr)
askConsent = true
} else if trackingConsentEnvSet {
trackingConsent := os.Getenv(segment.TrackingConsentEnv)
if isTrackingConsentEnabled {
klog.V(4).Infof("Skipping telemetry question due to %s=%s\n", segment.TrackingConsentEnv, trackingConsent)
klog.V(4).Info("Telemetry is enabled!\n")
if err1 := cfg.SetConfiguration(preference.ConsentTelemetrySetting, "true"); err1 != nil {
klog.V(4).Info(err1.Error())
}
} else {
klog.V(4).Infof("Skipping telemetry question due to %s=%s\n", segment.TrackingConsentEnv, trackingConsent)
}
} else if disableTelemetry {
//lint:ignore SA1019 We deprecated this env var, but until it is removed, we still need to support it
klog.V(4).Infof("Skipping telemetry question due to %s=%t\n", segment.DisableTelemetryEnv, disableTelemetry)
} else {
askConsent = true
}
if askConsent {
var consentTelemetry bool
prompt := &survey.Confirm{Message: "Help odo improve by allowing it to collect usage data. Read about our privacy statement: https://developers.redhat.com/article/tool-data-collection. You can change your preference later by changing the ConsentTelemetry preference.", Default: true}
err = survey.AskOne(prompt, &consentTelemetry, nil)
ui.HandleError(err)
if err == nil {
if err1 := cfg.SetConfiguration(preference.ConsentTelemetrySetting, strconv.FormatBool(consentTelemetry)); err1 != nil {
klog.V(4).Info(err1.Error())
}
}
}
}
Expand Down
56 changes: 52 additions & 4 deletions pkg/segment/segment.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,17 @@ const TelemetryClient = "odo"
// DisableTelemetryEnv is name of environment variable, if set to true it disables odo telemetry completely
// hiding even the question
const (
DisableTelemetryEnv = "ODO_DISABLE_TELEMETRY"
// DisableTelemetryEnv is name of environment variable, if set to true it disables odo telemetry completely.
// Setting it to false has the same effect as not setting it at all == does NOT enable telemetry!
// This has priority over TelemetryTrackingEnv
//
// Deprecated: Use TrackingConsentEnv instead.
DisableTelemetryEnv = "ODO_DISABLE_TELEMETRY"
// TrackingConsentEnv controls whether odo tracks telemetry or not.
// Setting it to 'no' has the same effect as DisableTelemetryEnv=true (telemetry is disabled and no question asked)
// Settings this to 'yes' skips the question about telemetry and enables user tracking.
// Possible values are yes/no.
TrackingConsentEnv = "ODO_TRACKING_CONSENT"
DebugTelemetryFileEnv = "ODO_DEBUG_TELEMETRY_FILE"
TelemetryCaller = "TELEMETRY_CALLER"
)
Expand Down Expand Up @@ -258,14 +268,52 @@ func IsTelemetryEnabled(cfg preference.Client) bool {
klog.V(4).Info("Checking telemetry enable status")
// The env variable gets precedence in this decision.
// In case a non-bool value was passed to the env var, we ignore it

//lint:ignore SA1019 We deprecated this env var, but until it is removed, we still need to support it
disableTelemetry, _ := strconv.ParseBool(os.Getenv(DisableTelemetryEnv))
if disableTelemetry {
klog.V(4).Infof("Sending telemetry disabled by %s=%t\n", DisableTelemetryEnv, disableTelemetry)
//lint:ignore SA1019 We deprecated this env var, but until it is removed, we still need to support it
klog.V(4).Infof("Sending telemetry disabled by %q env variable\n", DisableTelemetryEnv)
return false
} else if cfg.GetConsentTelemetry() {
}

trackingConsentEnabled, present, err := IsTrackingConsentEnabled()
if err != nil {
klog.V(4).Infof("error in determining value of tracking consent env var: %v", err)
} else if present {
//Takes precedence over the ConsentTelemetry preference
if !trackingConsentEnabled {
klog.V(4).Info("Sending telemetry disabled by env variable\n")
return false
}
klog.V(4).Info("Sending telemetry enabled by env variable\n")
return true
}
return false

isEnabled := cfg.GetConsentTelemetry()
s := "Sending telemetry disabled by preference"
if isEnabled {
s = "Sending telemetry enabled by preference"
}
klog.V(4).Infof("%s\n", s)
return isEnabled
}

// IsTrackingConsentEnabled returns whether tracking consent is enabled, based on the value of the TrackingConsentEnv environment variable.
// The second value returned indicates whether the variable is present in the environment.
func IsTrackingConsentEnabled() (enabled bool, present bool, err error) {
trackingConsent, ok := os.LookupEnv(TrackingConsentEnv)
if !ok {
return false, false, nil
}
switch trackingConsent {
case "yes":
return true, true, nil
case "no":
return false, true, nil
default:
return false, true, fmt.Errorf("invalid value for %s: %q", TrackingConsentEnv, trackingConsent)
}
}

// sanitizeUserInfo sanitizes username from the error string
Expand Down
Loading

0 comments on commit 719fe99

Please sign in to comment.