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

OpenSearch: Add config button to detect opensearch version #153

Merged
merged 14 commits into from
May 8, 2023
Merged

Conversation

iwysiu
Copy link
Contributor

@iwysiu iwysiu commented Apr 24, 2023

What this PR does / why we need it:
Currently, opensearch uses a drop down menu in the config form to get the version. This is inconvenient for users and requires us to maintain the list of OpenSearch versions (which we aren't really doing). This commit exchanges the menu for a button that saves the config (to make sure it connects properly) and detects the version. It's behind the opensearchDetectVersion feature flag.

Before:
Screenshot 2023-03-29 at 10 12 59 AM

The new ui:
Screenshot 2023-04-24 at 5 41 54 PM

When the call to get the version fails:
Screenshot 2023-04-24 at 5 41 36 PM

It was also changed to default to a null version (so the user has to set it to successfully configure the datasource) and for test to error when the elasticsearch version is >= 7.11.0. I can remove those changes if we think they're unnecessary.

Error for a too high elasticsearch version:
Screenshot 2023-04-25 at 1 47 47 PM

Which issue(s) this PR fixes:

Fixes #132 #131

Special notes for your reviewer:
If you want to test this with elasticsearch, you can run make devenv sources=elastic in the main grafana repo to connect to http://localhost:9200/ or make devenv sources=elastic elastic_version=7.10.0 to pick a specific version. (Run make devenv-down to take them down after)

@github-actions
Copy link

Backend code coverage report for PR #153
No changes

@github-actions
Copy link

github-actions bot commented Apr 24, 2023

Frontend code coverage report for PR #153

Plugin Main PR Difference
src 77.77% 77.82% .05%

@github-actions
Copy link

github-actions bot commented Apr 24, 2023

Levitate is-compatible report:

🔍 Resolving @grafana/data@latest...
🔍 Resolving @grafana/ui@latest...
🔍 Resolving @grafana/runtime@latest...
🔍 Resolving @grafana/e2e-selectors@latest...

🔬 Checking compatibility between ./src/module.ts and @grafana/data@9.5.1...
✔ Found @grafana/data version 9.0.2 locally

🔬 Checking compatibility between ./src/module.ts and @grafana/ui@9.5.1...
✔ Found @grafana/ui version 9.0.2 locally

🔬 Checking compatibility between ./src/module.ts and @grafana/runtime@9.5.1...
✔ Found @grafana/runtime version 9.0.2 locally

🔬 Checking compatibility between ./src/module.ts and @grafana/e2e-selectors@9.5.1...
✔ Found @grafana/e2e-selectors version 9.0.2 locally

✔️ ./src/module.ts appears to be compatible with @grafana/data,@grafana/ui,@grafana/runtime,@grafana/e2e-selectors

@@ -0,0 +1,50 @@
import { DataSourceInstanceSettings, DataSourcePluginMeta, PluginMetaInfo, PluginType } from '@grafana/data';
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Maybe excessive? But I figured we might get use out of it in the future.

@@ -2,7 +2,9 @@ import { DataSourceSettings } from '@grafana/data';
import { Flavor, OpenSearchOptions } from '../types';
import { createDatasourceSettings } from '../dependencies/mocks';

export function createDefaultConfigOptions(): DataSourceSettings<OpenSearchOptions> {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Moved this file for neatness

message: 'OpenSearch error: ' + message,
error: err.data.error,
};
let newErr = new Error('OpenSearch error: ' + message);
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I needed to change this to an Error type to catch it properly in OpenSearchDetails.tsx

value.jsonData.flavor} ${value.jsonData.version}`;
}

const getServerlessSettings = (event: React.SyntheticEvent<HTMLInputElement, Event>) => {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

All of the query code assumes that a version and flavor are set, so rather than refactor that in this commit, I set the flavor and version when serverless is toggled. (I checked and you cannot get a version from serverless). I figured just setting it to the latest one was ok, as we'll need to go make other code changes anyway if a new latest version introduces breaking changes.

Copy link
Member

Choose a reason for hiding this comment

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

Do we need a version/flavor if it's serverless? Aren't all serverless the same flavor/version?

Copy link
Contributor Author

@iwysiu iwysiu Apr 26, 2023

Choose a reason for hiding this comment

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

Yup, serverless are all the same! but (at least at present) our query code expects a version to be set, so we need one to be set.

Copy link
Member

Choose a reason for hiding this comment

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

I tested this with a serverless datasource and the flow as a bit weird:

Screen.Recording.2023-05-03.at.1.30.10.PM.mov

what if when we get/set version we check if it's serverless based on the url and then set the toggle?

I think we should be able to dynamically determine it based on the url, I think for example most of the endpoints are formatted like https://{someidorsomething}.{region}.aoss.amazonaws.com

I wonder if we could do a regex for aoss.amazonaws.com and if it's there we set the version to serverless or something?

useEffect(() => {
setSaved(false);
}, [
options.url,
Copy link
Contributor Author

@iwysiu iwysiu Apr 25, 2023

Choose a reason for hiding this comment

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

This is probably excessive, but since the user has to click a button to save it anyway, I figured it was better to err on the side of re-saving too often.

@iwysiu iwysiu marked this pull request as ready for review April 25, 2023 20:47
@iwysiu iwysiu requested a review from a team as a code owner April 25, 2023 20:47
@iwysiu iwysiu requested review from fridgepoet and kevinwcyu and removed request for a team April 25, 2023 20:47
Copy link
Member

@sarahzinger sarahzinger left a comment

Choose a reason for hiding this comment

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

Looking cool!

I don't love the concept of having save and get version in the same button, but I also get that in this case it might make sense because you can't detect the version without saving your auth settings.

Another question that I'm only just thinking through now, is there a reason we have to surface this to users at all? What if testDatasource was responsible for getting/setting the opensearch version and we didn't show a field for this at all?

}
await getBackendSrv()
.put(`/api/datasources/${options.id}`, options)
.then((result: { datasource: any }) => {
Copy link
Member

Choose a reason for hiding this comment

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

nitpicky but just sharing for knowledge in case its fun to rewrite async js :D that when you have await you don't need to use .thens so this could be rewritten as:

const { datasource} = await getBackendSrv().put(`/api/datasources/${options.id}`, options);
options.version = darasource.version;
....

Copy link
Contributor Author

Choose a reason for hiding this comment

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

done

expect(last(onChangeMock.mock.calls)[0].jsonData.flavor).toBe(Flavor.OpenSearch);
expect(last(onChangeMock.mock.calls)[0].jsonData.version).toBe('2.6.0');

// rerender with the changed value
Copy link
Member

Choose a reason for hiding this comment

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

neat I don't think I've used this before :)

@@ -143,10 +171,15 @@ describe('OpenSearchDetails', () => {
const onChangeMock = jest.fn();

const defaultConfig = createDefaultConfigOptions();
const opensearchDetectVersionValue = config.featureToggles.opensearchDetectVersion;
Copy link
Member

Choose a reason for hiding this comment

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

might make sense to take this out of the describe, it's very unlikely but I guess I could see a world where we edit config.featureToggles.opesearchDetectVersion directly in a previous test up above and accidentally never reset it or something?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

like this?

value.jsonData.flavor} ${value.jsonData.version}`;
}

const getServerlessSettings = (event: React.SyntheticEvent<HTMLInputElement, Event>) => {
Copy link
Member

Choose a reason for hiding this comment

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

Do we need a version/flavor if it's serverless? Aren't all serverless the same flavor/version?

` is not supported by the OpenSearch plugin. Use the ElasticSearch plugin.`,
});
}
//https://grafana.com/docs/grafana/latest/datasources/elasticsearch/
Copy link
Member

Choose a reason for hiding this comment

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

nice addition! Maybe we can share a link somehow?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The commented out link was from when I was trying to add the link. I couldn't get it to render properly 😞, whatever calls testDatasource displayed the whole href block.

Copy link
Contributor Author

@iwysiu iwysiu left a comment

Choose a reason for hiding this comment

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

Another question that I'm only just thinking through now, is there a reason we have to surface this to users at all? What if testDatasource was responsible for getting/setting the opensearch version and we didn't show a field for this at all?

That was more or less proposal 1! I think we decided not to do that so that the users would be aware that the version has to be reset if they update their OpenSearch instance.

}
await getBackendSrv()
.put(`/api/datasources/${options.id}`, options)
.then((result: { datasource: any }) => {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

done

@@ -143,10 +171,15 @@ describe('OpenSearchDetails', () => {
const onChangeMock = jest.fn();

const defaultConfig = createDefaultConfigOptions();
const opensearchDetectVersionValue = config.featureToggles.opensearchDetectVersion;
Copy link
Contributor Author

Choose a reason for hiding this comment

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

like this?

value.jsonData.flavor} ${value.jsonData.version}`;
}

const getServerlessSettings = (event: React.SyntheticEvent<HTMLInputElement, Event>) => {
Copy link
Contributor Author

@iwysiu iwysiu Apr 26, 2023

Choose a reason for hiding this comment

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

Yup, serverless are all the same! but (at least at present) our query code expects a version to be set, so we need one to be set.

` is not supported by the OpenSearch plugin. Use the ElasticSearch plugin.`,
});
}
//https://grafana.com/docs/grafana/latest/datasources/elasticsearch/
Copy link
Contributor Author

Choose a reason for hiding this comment

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

The commented out link was from when I was trying to add the link. I couldn't get it to render properly 😞, whatever calls testDatasource displayed the whole href block.

Copy link
Contributor

@kevinwcyu kevinwcyu left a comment

Choose a reason for hiding this comment

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

nice, tested out with es and os and works for me. just a comment about providing an error message earlier about the unsupported version when the save and get version button is pressed.

@@ -630,6 +644,15 @@ export class OpenSearchDatasource extends DataSourceApi<OpenSearchQuery, OpenSea
return JSON.stringify(queryObj);
}

async getOpenSearchVersion(): Promise<{ flavor: Flavor; version: string }> {
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: can we export the Version interface from here and use that here?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

done!

setVersionErr('');
await saveOptions();
try {
const version = await datasource.getOpenSearchVersion();
Copy link
Contributor

Choose a reason for hiding this comment

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

can getOpenSearchVersion check for supported versions and throw an error if it's >=7.11.0? right now it can successfully set a version and it appears to be ok, but i don't see an error until i save and test the datasource.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

done!

Copy link
Contributor Author

@iwysiu iwysiu left a comment

Choose a reason for hiding this comment

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

Made Kevin's changes. Still could not figure out how to get the Alert to render with a link 😞

@@ -630,6 +644,15 @@ export class OpenSearchDatasource extends DataSourceApi<OpenSearchQuery, OpenSea
return JSON.stringify(queryObj);
}

async getOpenSearchVersion(): Promise<{ flavor: Flavor; version: string }> {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

done!

setVersionErr('');
await saveOptions();
try {
const version = await datasource.getOpenSearchVersion();
Copy link
Contributor Author

Choose a reason for hiding this comment

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

done!

Copy link
Member

@sarahzinger sarahzinger left a comment

Choose a reason for hiding this comment

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

Cool stuff!

I was playing around with this and one thing I could see happening is users click Save and Get Version misread this as Get and Save and think that their version is saved as well? I do sort of wonder if we should just call it Get Version after all? Or alternatively we could save again after the version is set? Idk what do you think? Am I overthinking this? It's a tricky ui question here

Screen.Recording.2023-05-03.at.1.44.10.PM.mov

Also had an idea for optimizing the serverless flow. But also these suggestions feel like things we could explore in future issues/prs if we want to merge as is I'm down!

const { Select, Switch } = LegacyForms;

const opensearchDetectVersionValue = config.featureToggles.opensearchDetectVersion;
Copy link
Member

Choose a reason for hiding this comment

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

yeah this is what I meant!

const { Select, Switch } = LegacyForms;

const opensearchDetectVersionValue = config.featureToggles.opensearchDetectVersion;

afterAll(() => {
Copy link
Member

Choose a reason for hiding this comment

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

does this work when it's outside of the describe? it might have to be inside? Please go ahead and tell me if I'm wrong tho haha

value.jsonData.flavor} ${value.jsonData.version}`;
}

const getServerlessSettings = (event: React.SyntheticEvent<HTMLInputElement, Event>) => {
Copy link
Member

Choose a reason for hiding this comment

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

I tested this with a serverless datasource and the flow as a bit weird:

Screen.Recording.2023-05-03.at.1.30.10.PM.mov

what if when we get/set version we check if it's serverless based on the url and then set the toggle?

I think we should be able to dynamically determine it based on the url, I think for example most of the endpoints are formatted like https://{someidorsomething}.{region}.aoss.amazonaws.com

I wonder if we could do a regex for aoss.amazonaws.com and if it's there we set the version to serverless or something?

@iwysiu
Copy link
Contributor Author

iwysiu commented May 4, 2023

Edited after further discussion to:

  • save after getting the version
  • have an info box explicitly call out what happens when upgrading
  • moves serverless toggle above the version field, so hopefully users who need that toggle it first

Screenshot 2023-05-04 at 3 02 46 PM

datasourceRequestMock.mockImplementation(() => {
return Promise.resolve({ data: { version: { number: '7.11.1' } } });
});
//'ElasticSearch version 7.11.1 is not supported by the OpenSearch plugin. Use the ElasticSearch plugin.'
Copy link
Contributor

Choose a reason for hiding this comment

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

is this comment left over from development?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

yup, oops

@iwysiu iwysiu merged commit 8d50fcd into main May 8, 2023
5 checks passed
@iwysiu iwysiu deleted the iwysiu/131 branch May 8, 2023 18:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Add button to auto-detect version to config editor
4 participants