Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Telemetry] Remind users about telemetry on each minor version #49644

Merged
merged 10 commits into from
Nov 5, 2019

Conversation

pmuellr
Copy link
Member

@pmuellr pmuellr commented Oct 29, 2019

Summary

If a user has previously opted out of telemetry, we are making a
change to re-prompt them when the version of Kibana they are
running changes. Previously, once opted out, they would never
get prompted again.

resolves #49519

Checklist

Use strikethroughs to remove checklist items you don't feel are applicable to this PR.

For maintainers

resolves elastic#49519

If a user has previously opted out of telemetry, we are making a
change to re-prompt them when the version of Kibana they are
running changes.  Previously, once opted out, they would never
get prompted again.
@pmuellr
Copy link
Member Author

pmuellr commented Oct 29, 2019

First pass at fixing #49519 - "Re-prompt for telemetry opt-in at each minor version upgrade, if not opted in"

This seems like it works, but not sure if there's a better approach.

We will start storing the kibana version used, when persisting the opt-in setting. When determining the opt-in value, we make a change if the value is false, in that we check if the version of Kiban used when it was set to false is the same as the current version of Kibana. If they're different, return a null value which indicates they should be prompted.

Not sure if we need a migration, since we're updating the SO mapping, but having the new field lastVersionChecked return null is perfectly fine.

Also not sure the best way to check the current Kibana version - server.config.get('pkg.version') seems to work, but perhaps there's something better (or we could cache it somewhere in the plugin at startup). Certainly this code won't work under NP.

@elasticmachine
Copy link
Contributor

Pinging @elastic/kibana-stack-services (Team:Stack Services)

@pmuellr pmuellr added the release_note:skip Skip the PR/issue when compiling release notes label Oct 29, 2019
@pmuellr
Copy link
Member Author

pmuellr commented Oct 29, 2019

I've added label release_note:skip, but guessing we will probably want SOME KIND OF NOTE SOMEWHERE, since this is new behavior, and is likely unexpected by both customers and elasticians.

@pmuellr pmuellr changed the title forces a re-prompt of telemetry opt-in when Kibana version changes forces a re-prompt of telemetry opt-in when Kibana major/minor version changes Oct 29, 2019
@elasticmachine
Copy link
Contributor

💚 Build Succeeded

@gmmorris
Copy link
Contributor

Code LGTM and seems to be behaving as expected.

The only issue is that Patch version, once that's sorted 👍

@pmuellr
Copy link
Member Author

pmuellr commented Oct 29, 2019

@restrry pointed me at some existing code to get the Kibana version in NP, as well as some code that is checking Kibana versions

@pmuellr
Copy link
Member Author

pmuellr commented Oct 29, 2019

The branch today seems pretty good. Now testing major/minor, not just does the previous version != the current version.

Going to see about adding tests tomorrow. Should certainly be able to add some unit tests for the optIn calculator, not sure how functional tests might work, will need to investigate ...

@elasticmachine
Copy link
Contributor

💚 Build Succeeded

@gmmorris gmmorris self-requested a review October 30, 2019 08:36
Copy link
Contributor

@gmmorris gmmorris left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Made some small notes about typing and what I think might be some unnecessary repetition, but none of it is blocking, so happy to approve and leave it to you what to do.

It would be nice to add an FTS test that runs across the process, but I'm not familiar enough to know how feasible that is, so up to you.

Copy link
Contributor

@mikecote mikecote left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code LGTM

@pmuellr
Copy link
Member Author

pmuellr commented Oct 30, 2019

Some notes on manual testing.

The changes involve a new lastVersionChecked field in the telemetry:telemetry SavedObject. When the currently existing field enabled is changed (boolean value, true: opt'd in, false: opt'd out, null: hasn't opt'd either way yet), we now write out the Kibana version being used. The check to display the opt-in banner used to be (is the enabled field == null), but now the banner will be displayed if you previously opt'd out AND the Kibana version you're running is a minor release or more later than when you opt'd out.

So, to test, we'll be dealing with the saved object, updating it with bogus values, deleting it, etc, and then reloading a Kibana page in the browser. And then checking it after clicking the banner, to ensure the values are as expected.

getting it:

curl -k https://elastic:changeme@localhost:5601/api/saved_objects/telemetry/telemetry

returns

{
  ...
  "attributes": {
    "enabled": false,
    "lastVersionChecked": "8.0.0"
  },
  ...
}

updating it:

curl -k -X PUT -H "kbn-xsrf: foo" -H "content-type: application/json" \
  https://elastic:changeme@localhost:5601/api/saved_objects/telemetry/telemetry \
  -d '{"attributes": {"enabled": false, "lastVersionChecked": "7.9.0"}}'

deleting it:

curl -k -X DELETE -H "kbn-xsrf: foo" https://elastic:changeme@localhost:5601/api/saved_objects/telemetry/telemetry

Copy link
Member

@Bamieh Bamieh left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, a few nits

@pmuellr pmuellr changed the title forces a re-prompt of telemetry opt-in when Kibana major/minor version changes remind users about telemetry on each minor version Oct 30, 2019
@pmuellr pmuellr changed the title remind users about telemetry on each minor version [Telemetry] remind users about telemetry on each minor version Oct 30, 2019
@pmuellr pmuellr added release_note:enhancement and removed release_note:skip Skip the PR/issue when compiling release notes labels Oct 30, 2019
@pmuellr pmuellr changed the title [Telemetry] remind users about telemetry on each minor version [Telemetry] Remind users about telemetry on each minor version Oct 30, 2019
@pmuellr pmuellr added the v8.0.0 label Oct 30, 2019
@elasticmachine
Copy link
Contributor

💔 Build Failed

@elasticmachine
Copy link
Contributor

💔 Build Failed

@pmuellr
Copy link
Member Author

pmuellr commented Oct 31, 2019

@elasticmachine merge upstream

@pmuellr
Copy link
Member Author

pmuellr commented Oct 31, 2019

Can't quite tell, but might have passed the last ci except for the failed prbot:outdated, so it's definitely time to Always Be Merging. Let's see ...

@elasticmachine
Copy link
Contributor

💔 Build Failed

Copy link
Contributor

@Bargs Bargs left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Left a couple of minor suggestions but nothing that's an absolute must in my mind.

I agree with the other reviewers who said an end to end functional test would be nice to confirm the opt in shows up in the browser as expected, especially since we're relying on null as a convention to mean "show the opt in".

const { attributes }: { attributes: SavedObjectAttributes } = savedObject;

// if enabled is already null, return null
if (attributes.enabled == null) return null;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if (attributes.enabled == null) return null;
if (attributes.enabled === null) return null;

Can we change this to triple equals?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's against my nature, since == catches undefined as well as null. I could be convinced otherwise, but don't remember doing a === null in a long time, unless I was specifically wanting to check null vs undefined for some reason.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In what valid situation would attributes.enabled be undefined, and why should we return null in that situation?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If someone (maybe us, accidently??) reset the saved object attributes to {}, the enabled field would be undefined, not null. In questionable cases like this (as well as if the semver wasn't parseable), I've made some arbitrary decisions, and in most cases, you'd want this to be considered "re-prompt the user".

It's easy for me to imagine folks wanting to defeat banner-ism by hacking saved objects, so ... I've tried to be pretty conservative here in our checks of things users might be "providing" to use :-)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If someone (maybe us, accidently??) reset the saved object attributes to {}, the enabled field would be undefined, not null.

In this scenario the fact that enabled is undefined is a bug and IMO we shouldn't act like it means something it doesn't. Looseness like this leads to subtle bugs that are hard to fix.

That said, the stakes are low in this context, so if you don't want to make the change we can simply agree to disagree.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we'll have to agree to disagree at this point, but would welcome some kind of project-wide guidance on this. As noted elsewhere, I think I lived for a while with a linter than MADE you use == null, so I'll admit my brain may be warped.

Still, seems like unless you are specifically expecting a null OR undefined, as semantically different things, from an API, you should always just use == null for such checks. Also note, there are plenty of folks who shorten this check to !x (from x == null), since it's often the case that this works as well, but those ones do kinda bug me :-)

const currentSemver = parseSemver(currentKibanaVersion);

// if either version is invalid, return null
if (lastSemver == null || currentSemver == null) return null;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if (lastSemver == null || currentSemver == null) return null;
if (lastSemver === null || currentSemver === null) return null;

Triple equals would be nice here as well if semver specifically returns null when there is a parse error.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

for cases like this, where there's a local function I can validate won't return undefined, I'm happier to to use a === check, but still kind of consider it to be bad form, for future-proofing in case some day the called function DOES end up returning undefined.

I'm curious why you're looking for this.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The docs for semver's parse specifically state that null is returned if the value can't be parsed. You're guessing that in the future, if parse starts to return undefined, that undefined will mean the same as null. But that is not necessarily the case. Some future version of parse might return undefined for some other reason, and then we might have a bug on our hands because this condition is overly loose. I don't consider null and undefined interchangeable, they can mean two very different things depending on context.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some future version of parse() might return undefined for some other reason, and then we might have a bug on our hands because this condition is overly loose.

I guess I'd say, based on my years-long, unhappy history with semver (as much as I don't like it, it gets a lot of use, so it's the best out there, as long as you protect yourself), that we'd more likely see some future of version of parse() return undefined where it returns null today, and then we might have a bug on our hands because === null is overly strict. :-)

I don't trust 3rd party libraries much ...

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's also the case that I've used linters (standard?) that used to complain if you ever DID do an === null or === undefined. Happened to fit with my world view, so was happy with it. Or was I brainwashed?!?! heh

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

that we'd more likely see some future of version of parse() return undefined where it returns null today, and then we might have a bug on our hands because === null is overly strict. :-)

Nope, because our unit tests would catch this. The === null condition would fail and we would get an unexpected result. This is the benefit of being strict. On the other hand, our unit tests would likely not catch the bug in my example because the looseness of the check may cover up an issue. Semver might respond to some issue by returning undefined but this == check will make it look like everything is fine.

my years-long, unhappy history with semver

My decades long, unhappy history with Javascript has taught me to never use double equals :) It's not just me:

https://2ality.com/2011/12/strict-equality-exemptions.html (look especially at Case 2)

https://stackoverflow.com/a/359509 (note in particular the quote from Javascript: The Good Parts)

Preferring triples equals is a best practice most of the community agrees upon.

But like I said above, the stakes in this particular situation are probably low, so if you are not convinced, we can agree to disagree.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

pro-tip: you will never convince me of anything based on references to "JavaScript: The Good Parts". hehe

I'm slightly curious, because I thought triple quotes were best practice for number/boolean/string, but double quotes was actually best practice for null/undefined.

It would certainly be interesting to add a lint rule disallowing == null and see what the vsCode Problems page looks like.

quick search:

search results files
== null 600 236
=== null 339 177
=== undefined 573 284
== undefined 8 1 hahahaha

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was attempting an appeal to authority out of frustration since the concrete explanations I gave you are for some reason unconvincing. You didn't actually respond to the concrete explanation I gave about this specific piece of code we're looking at. You also ignored the information from the first link I provided, which has a section (which I called out) that specifically deals with this particular use of ==. Instead you made a flippant comment about Javascript: The Good Parts and listed a statistic from the existing code base which is irrelevant to the discussion of whether using == is actually a good idea, or if it is appropriate to use in this specific context. You also keep noting that the default ruleset of some linter you used encouraged use of ==. This is also an appeal to authority, except the authority is anonymous and their reasoning is unknown, so I would say this is also irrelevant to this specific conversation.

I won't reply anymore, because I'm obviously extremely frustrated and this is not a productive conversation.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note: sent a note to Bargs offline, as I didn't realize his frustration level on this - I thought the issue was resolved but we were just having some banter on the topic of == null.

Comment on lines +58 to +66
let threw = false;
try {
await callGetTelemetryOptIn(params);
} catch (err) {
threw = true;
expect(err.message).toBe(SavedObjectOtherErrorMessage);
}

expect(threw).toBe(true);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just an FYI, Jest has helpers to make asserting on exceptions easier https://jestjs.io/docs/en/expect#tothrowerror

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It does, I've used them before, but I couldn't get it to work this time. For some reason, it wouldn't catch the exception in the jest test, but then also claimed the exception that got thrown wasn't handled, and I was .... waaa??? ... spent 20 minutes trying to figure it out in the debugger, gave up, did it by hand :-)

@@ -8,5 +8,6 @@ export default function ({ loadTestFile }) {
describe('Telemetry', () => {
loadTestFile(require.resolve('./telemetry'));
loadTestFile(require.resolve('./telemetry_local'));
loadTestFile(require.resolve('./opt_in'));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This may be a historical question for someone else, but do you know why these API integration tests are under xpack when the code is in OSS?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hahaha, great question, don't know exactly. I believe telemetry moved from x-pack to OSS (or at least not x-pack), the code was migrated, and of course it turns out the functional tests didn't actually HAVE to move, and so ... didn't.

Seemed out-of-scope for this PR, but I'll open a new issue to track it.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

opened issue #49933 to track this

@elasticmachine
Copy link
Contributor

💚 Build Succeeded

Copy link
Member

@Bamieh Bamieh left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. Thanks!

@Bamieh
Copy link
Member

Bamieh commented Nov 4, 2019

@elasticmachine merge upstream

@elasticmachine
Copy link
Contributor

💚 Build Succeeded

@pmuellr pmuellr merged commit 5ba237a into elastic:master Nov 5, 2019
pmuellr added a commit to pmuellr/kibana that referenced this pull request Nov 5, 2019
…ic#49644)

resolves elastic#49519

If a user has previously opted out of telemetry, this PR will
cause them to be prompted again, when the major or minor version
of Kibana changes. Previously, once opted out, they would never
get prompted again.
pmuellr added a commit to pmuellr/kibana that referenced this pull request Nov 5, 2019
…ic#49644)

resolves elastic#49519

If a user has previously opted out of telemetry, this PR will
cause them to be prompted again, when the major or minor version
of Kibana changes. Previously, once opted out, they would never
get prompted again.
pmuellr added a commit that referenced this pull request Nov 5, 2019
… (#50026)

resolves #49519

If a user has previously opted out of telemetry, this PR will
cause them to be prompted again, when the major or minor version
of Kibana changes. Previously, once opted out, they would never
get prompted again.
pmuellr added a commit that referenced this pull request Nov 5, 2019
… (#50025)

resolves #49519

If a user has previously opted out of telemetry, this PR will
cause them to be prompted again, when the major or minor version
of Kibana changes. Previously, once opted out, they would never
get prompted again.
@alexfrancoeur alexfrancoeur mentioned this pull request Nov 15, 2019
1 task
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Re-prompt for telemetry opt-in at each minor version upgrade, if not opted in
6 participants