Consume elasticsearch.publicBaseUrl where possible (#192741)

## Summary

This actually consumes the public base url in the cloud plugin and the
places depending on the `elasticsearchUrl` value populated there.

---------

Co-authored-by: Rodney Norris <rodney@tattdcodemonkey.com>
This commit is contained in:
Sander Philipse 2024-09-19 16:57:47 +02:00 committed by GitHub
parent 88163b063a
commit b4a7b2e216
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
31 changed files with 234 additions and 73 deletions

View file

@ -21,6 +21,7 @@ const createOpts = async (props: KibanaConnectionDetailsProviderProps) => {
const { http, docLinks, analytics } = start.core;
const locator = start.plugins?.share?.url?.locators.get('MANAGEMENT_APP_LOCATOR');
const manageKeysLink = await locator?.getUrl({ sectionId: 'security', appId: 'api_keys' });
const elasticsearchConfig = await start.plugins?.cloud?.fetchElasticsearchConfig();
const result: ConnectionDetailsOpts = {
...options,
navigateToUrl: start.core.application
@ -35,7 +36,7 @@ const createOpts = async (props: KibanaConnectionDetailsProviderProps) => {
},
endpoints: {
id: start.plugins?.cloud?.cloudId,
url: start.plugins?.cloud?.elasticsearchUrl,
url: elasticsearchConfig?.elasticsearchUrl,
cloudIdLearMoreLink: docLinks?.links?.cloud?.beatsAndLogstashConfiguration,
...options?.endpoints,
},

View file

@ -6,8 +6,7 @@
* your election, the "Elastic License 2.0", the "GNU Affero General Public
* License v3.0 only", or the "Server Side Public License, v 1".
*/
import React, { FC, PropsWithChildren, useContext } from 'react';
import React, { FC, PropsWithChildren, useContext, useEffect } from 'react';
export interface DeploymentDetailsContextValue {
cloudId?: string;
@ -58,7 +57,7 @@ export interface DeploymentDetailsKibanaDependencies {
cloud: {
isCloudEnabled: boolean;
cloudId?: string;
elasticsearchUrl?: string;
fetchElasticsearchConfig: () => Promise<{ elasticsearchUrl?: string }>;
};
/** DocLinksStart contract */
docLinks: {
@ -79,11 +78,19 @@ export interface DeploymentDetailsKibanaDependencies {
export const DeploymentDetailsKibanaProvider: FC<
PropsWithChildren<DeploymentDetailsKibanaDependencies>
> = ({ children, ...services }) => {
const [elasticsearchUrl, setElasticsearchUrl] = React.useState<string>('');
useEffect(() => {
services.cloud.fetchElasticsearchConfig().then((config) => {
setElasticsearchUrl(config.elasticsearchUrl || '');
});
}, [services.cloud]);
const {
core: {
application: { navigateToUrl },
},
cloud: { isCloudEnabled, cloudId, elasticsearchUrl },
cloud: { isCloudEnabled, cloudId },
share: {
url: { locators },
},

View file

@ -47,6 +47,7 @@ test('set correct defaults', () => {
"maxSockets": 800,
"password": undefined,
"pingTimeout": "PT30S",
"publicBaseUrl": undefined,
"requestHeadersWhitelist": Array [
"authorization",
"es-client-authentication",

View file

@ -359,6 +359,13 @@ export class ElasticsearchConfig implements IElasticsearchConfig {
*/
public readonly hosts: string[];
/**
* Optional host that users can use to connect to your Elasticsearch cluster,
* this URL will be shown in Kibana as the Elasticsearch URL
*/
public readonly publicBaseUrl?: string;
/**
* List of Kibana client-side headers to send to Elasticsearch when request
* scoped cluster client is used. If this is an empty array then *no* client-side
@ -473,6 +480,7 @@ export class ElasticsearchConfig implements IElasticsearchConfig {
this.skipStartupConnectionCheck = rawConfig.skipStartupConnectionCheck;
this.apisToRedactInLogs = rawConfig.apisToRedactInLogs;
this.dnsCacheTtl = rawConfig.dnsCacheTtl;
this.publicBaseUrl = rawConfig.publicBaseUrl;
const { alwaysPresentCertificate, verificationMode } = rawConfig.ssl;
const { key, keyPassphrase, certificate, certificateAuthorities } = readKeyAndCerts(rawConfig);

View file

@ -135,6 +135,7 @@ export class ElasticsearchService
agentStatsProvider: {
getAgentsStats: agentManager.getAgentsStats.bind(agentManager),
},
publicBaseUrl: config.publicBaseUrl,
};
}
@ -194,6 +195,7 @@ export class ElasticsearchService
metrics: {
elasticsearchWaitTime,
},
publicBaseUrl: config.publicBaseUrl,
};
}

View file

@ -138,6 +138,12 @@ export interface ElasticsearchServiceStart {
* Returns the capabilities for the default cluster.
*/
getCapabilities: () => ElasticsearchCapabilities;
/**
* The public base URL (if any) that should be used by end users to access the Elasticsearch cluster.
*/
readonly publicBaseUrl?: string;
}
/**

View file

@ -212,6 +212,7 @@ export function createPluginSetupContext<TPlugin, TPluginDependencies>({
docLinks: deps.docLinks,
elasticsearch: {
legacy: deps.elasticsearch.legacy,
publicBaseUrl: deps.elasticsearch.publicBaseUrl,
setUnauthorizedErrorHandler: deps.elasticsearch.setUnauthorizedErrorHandler,
},
executionContext: {

View file

@ -11,3 +11,5 @@ export const ELASTIC_SUPPORT_LINK = 'https://support.elastic.co/';
* This is the page for managing your snapshots on Cloud.
*/
export const CLOUD_SNAPSHOTS_PATH = 'elasticsearch/snapshots/';
export const ELASTICSEARCH_CONFIG_ROUTE = '/api/internal/cloud/elasticsearch_config';

View file

@ -6,3 +6,7 @@
*/
export type OnBoardingDefaultSolution = 'es' | 'oblt' | 'security';
export interface ElasticsearchConfigType {
elasticsearch_url?: string;
}

View file

@ -19,7 +19,9 @@ function createSetupMock(): jest.Mocked<CloudSetup> {
deploymentUrl: 'deployment-url',
profileUrl: 'profile-url',
organizationUrl: 'organization-url',
elasticsearchUrl: 'elasticsearch-url',
fetchElasticsearchConfig: jest
.fn()
.mockResolvedValue({ elasticsearchUrl: 'elasticsearch-url' }),
kibanaUrl: 'kibana-url',
cloudHost: 'cloud-host',
cloudDefaultPort: '443',
@ -53,6 +55,7 @@ const createStartMock = (): jest.Mocked<CloudStart> => ({
serverless: {
projectId: undefined,
},
fetchElasticsearchConfig: jest.fn().mockResolvedValue({ elasticsearchUrl: 'elasticsearch-url' }),
});
export const cloudMock = {

View file

@ -37,6 +37,7 @@ describe('Cloud Plugin', () => {
const plugin = new CloudPlugin(initContext);
const coreSetup = coreMock.createSetup();
coreSetup.http.get.mockResolvedValue({ elasticsearch_url: 'elasticsearch-url' });
const setup = plugin.setup(coreSetup);
return { setup };
@ -110,8 +111,8 @@ describe('Cloud Plugin', () => {
it('exposes components decoded from the cloudId', () => {
const decodedId: DecodedCloudId = {
defaultPort: '9000',
host: 'host',
elasticsearchUrl: 'elasticsearch-url',
host: 'host',
kibanaUrl: 'kibana-url',
};
decodeCloudIdMock.mockReturnValue(decodedId);
@ -120,7 +121,6 @@ describe('Cloud Plugin', () => {
expect.objectContaining({
cloudDefaultPort: '9000',
cloudHost: 'host',
elasticsearchUrl: 'elasticsearch-url',
kibanaUrl: 'kibana-url',
})
);
@ -184,6 +184,11 @@ describe('Cloud Plugin', () => {
});
expect(setup.serverless.projectType).toBe('security');
});
it('exposes fetchElasticsearchConfig', async () => {
const { setup } = setupPlugin();
const result = await setup.fetchElasticsearchConfig();
expect(result).toEqual({ elasticsearchUrl: 'elasticsearch-url' });
});
});
});
@ -307,5 +312,13 @@ describe('Cloud Plugin', () => {
const start = plugin.start(coreStart);
expect(start.serverless.projectName).toBe('My Awesome Project');
});
it('exposes fetchElasticsearchConfig', async () => {
const { plugin } = startPlugin();
const coreStart = coreMock.createStart();
coreStart.http.get.mockResolvedValue({ elasticsearch_url: 'elasticsearch-url' });
const start = plugin.start(coreStart);
const result = await start.fetchElasticsearchConfig();
expect(result).toEqual({ elasticsearchUrl: 'elasticsearch-url' });
});
});
});

View file

@ -12,12 +12,13 @@ import type { CoreSetup, CoreStart, Plugin, PluginInitializerContext } from '@kb
import { registerCloudDeploymentMetadataAnalyticsContext } from '../common/register_cloud_deployment_id_analytics_context';
import { getIsCloudEnabled } from '../common/is_cloud_enabled';
import { parseDeploymentIdFromDeploymentUrl } from '../common/parse_deployment_id_from_deployment_url';
import { CLOUD_SNAPSHOTS_PATH } from '../common/constants';
import { CLOUD_SNAPSHOTS_PATH, ELASTICSEARCH_CONFIG_ROUTE } from '../common/constants';
import { decodeCloudId, type DecodedCloudId } from '../common/decode_cloud_id';
import { getFullCloudUrl } from '../common/utils';
import { parseOnboardingSolution } from '../common/parse_onboarding_default_solution';
import type { CloudSetup, CloudStart } from './types';
import type { CloudSetup, CloudStart, PublicElasticsearchConfigType } from './types';
import { getSupportUrl } from './utils';
import { ElasticsearchConfigType } from '../common/types';
export interface CloudConfigType {
id?: string;
@ -66,12 +67,14 @@ export class CloudPlugin implements Plugin<CloudSetup> {
private readonly isServerlessEnabled: boolean;
private readonly contextProviders: Array<FC<PropsWithChildren<unknown>>> = [];
private readonly logger: Logger;
private elasticsearchConfig?: PublicElasticsearchConfigType;
constructor(private readonly initializerContext: PluginInitializerContext) {
this.config = this.initializerContext.config.get<CloudConfigType>();
this.isCloudEnabled = getIsCloudEnabled(this.config.id);
this.isServerlessEnabled = !!this.config.serverless?.project_id;
this.logger = initializerContext.logger.get();
this.elasticsearchConfig = undefined;
}
public setup(core: CoreSetup): CloudSetup {
@ -99,7 +102,6 @@ export class CloudPlugin implements Plugin<CloudSetup> {
csp,
baseUrl,
...this.getCloudUrls(),
elasticsearchUrl: decodedId?.elasticsearchUrl,
kibanaUrl: decodedId?.kibanaUrl,
cloudHost: decodedId?.host,
cloudDefaultPort: decodedId?.defaultPort,
@ -119,6 +121,7 @@ export class CloudPlugin implements Plugin<CloudSetup> {
registerCloudService: (contextProvider) => {
this.contextProviders.push(contextProvider);
},
fetchElasticsearchConfig: this.fetchElasticsearchConfig.bind(this, core.http),
};
}
@ -166,7 +169,6 @@ export class CloudPlugin implements Plugin<CloudSetup> {
profileUrl,
organizationUrl,
projectsUrl,
elasticsearchUrl: decodedId?.elasticsearchUrl,
kibanaUrl: decodedId?.kibanaUrl,
isServerlessEnabled: this.isServerlessEnabled,
serverless: {
@ -176,6 +178,7 @@ export class CloudPlugin implements Plugin<CloudSetup> {
},
performanceUrl,
usersAndRolesUrl,
fetchElasticsearchConfig: this.fetchElasticsearchConfig.bind(this, coreStart.http),
};
}
@ -216,4 +219,26 @@ export class CloudPlugin implements Plugin<CloudSetup> {
projectsUrl: fullCloudProjectsUrl,
};
}
private async fetchElasticsearchConfig(
http: CoreStart['http']
): Promise<PublicElasticsearchConfigType> {
if (this.elasticsearchConfig !== undefined) {
// This config should be fully populated on first fetch, so we should avoid refetching from server
return this.elasticsearchConfig;
}
try {
const result = await http.get<ElasticsearchConfigType>(ELASTICSEARCH_CONFIG_ROUTE, {
version: '1',
});
this.elasticsearchConfig = { elasticsearchUrl: result.elasticsearch_url || undefined };
return this.elasticsearchConfig;
} catch {
this.logger.error('Failed to fetch Elasticsearch config');
return {
elasticsearchUrl: undefined,
};
}
}
}

View file

@ -58,9 +58,9 @@ export interface CloudStart {
*/
projectsUrl?: string;
/**
* The full URL to the elasticsearch cluster.
* Fetches the full URL to the elasticsearch cluster.
*/
elasticsearchUrl?: string;
fetchElasticsearchConfig: () => Promise<PublicElasticsearchConfigType>;
/**
* The full URL to the Kibana deployment.
*/
@ -150,9 +150,9 @@ export interface CloudSetup {
*/
snapshotsUrl?: string;
/**
* The full URL to the elasticsearch cluster.
* Fetches the full URL to the elasticsearch cluster.
*/
elasticsearchUrl?: string;
fetchElasticsearchConfig: () => Promise<PublicElasticsearchConfigType>;
/**
* The full URL to the Kibana deployment.
*/
@ -225,3 +225,12 @@ export interface CloudSetup {
orchestratorTarget?: string;
};
}
export interface PublicElasticsearchConfigType {
/**
* The URL to the Elasticsearch cluster, derived from xpack.elasticsearch.publicBaseUrl if populated
* Otherwise this is based on the cloudId
* If neither is populated, this will be undefined
*/
elasticsearchUrl?: string;
}

View file

@ -18,6 +18,7 @@ import { decodeCloudId, DecodedCloudId } from '../common/decode_cloud_id';
import { parseOnboardingSolution } from '../common/parse_onboarding_default_solution';
import { getFullCloudUrl } from '../common/utils';
import { readInstanceSizeMb } from './env';
import { defineRoutes } from './routes/elasticsearch_routes';
interface PluginsSetup {
usageCollection?: UsageCollectionSetup;
@ -201,6 +202,9 @@ export class CloudPlugin implements Plugin<CloudSetup, CloudStart> {
if (this.config.id) {
decodedId = decodeCloudId(this.config.id, this.logger);
}
const router = core.http.createRouter();
const elasticsearchUrl = core.elasticsearch.publicBaseUrl || decodedId?.elasticsearchUrl;
defineRoutes({ logger: this.logger, router, elasticsearchUrl });
return {
...this.getCloudUrls(),
@ -209,7 +213,7 @@ export class CloudPlugin implements Plugin<CloudSetup, CloudStart> {
organizationId,
instanceSizeMb: readInstanceSizeMb(),
deploymentId,
elasticsearchUrl: core.elasticsearch.publicBaseUrl || decodedId?.elasticsearchUrl,
elasticsearchUrl,
kibanaUrl: decodedId?.kibanaUrl,
cloudHost: decodedId?.host,
cloudDefaultPort: decodedId?.defaultPort,

View file

@ -0,0 +1,35 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import { IRouter } from '@kbn/core/server';
import { Logger } from '@kbn/logging';
import { ElasticsearchConfigType } from '../../common/types';
import { ELASTICSEARCH_CONFIG_ROUTE } from '../../common/constants';
export function defineRoutes({
elasticsearchUrl,
logger,
router,
}: {
elasticsearchUrl?: string;
logger: Logger;
router: IRouter;
}) {
router.versioned
.get({
path: ELASTICSEARCH_CONFIG_ROUTE,
access: 'internal',
})
.addVersion({ version: '1', validate: {} }, async (context, request, response) => {
const body: ElasticsearchConfigType = {
elasticsearch_url: elasticsearchUrl,
};
return response.ok({
body,
});
});
}

View file

@ -22,6 +22,12 @@ jest.mock('../../../../shared/enterprise_search_url', () => ({
getEnterpriseSearchUrl: () => 'http://localhost:3002',
}));
jest.mock('../../../../shared/cloud_details/cloud_details', () => ({
useCloudDetails: () => ({
elasticsearchUrl: 'your_deployment_url',
}),
}));
describe('AnalyticsCollectionIntegrate', () => {
const analyticsCollections: AnalyticsCollection = {
events_datastream: 'analytics-events-example',
@ -55,7 +61,7 @@ describe('AnalyticsCollectionIntegrate', () => {
.toMatchInlineSnapshot(`
"<script type=\\"text/javascript\\">
window.elasticAnalytics.createTracker({
endpoint: \\"elasticsearch-url\\",
endpoint: \\"your_deployment_url\\",
collectionName: \\"example\\",
apiKey: \\"########\\",
// Optional: sampling rate percentage: 0-1, 0 = no events, 1 = all events

View file

@ -90,6 +90,7 @@ http.cors.allow-headers: X-Requested-With, X-Auth-Token, Content-Type, Content-L
)}
</p>
<EuiLink
data-test-subj="enterpriseSearchCORSStepLearnMoreAboutCorsForBehavioralAnalyticsLink"
href={docLinks.behavioralAnalyticsCORS}
data-telemetry-id="entSearchContent-analytics-cors-learnMoreLink"
external
@ -130,6 +131,7 @@ const apiKeyStep = (
}
)}{' '}
<EuiLink
data-test-subj="enterpriseSearchApiKeyStepLearnMoreAboutApiKeysLink"
href={docLinks.apiKeys}
data-telemetry-id="entSearchContent-analytics-apiKey-learnMoreLink"
external
@ -148,6 +150,7 @@ const apiKeyStep = (
<EuiFlexGroup gutterSize="s">
<EuiFlexItem grow={false}>
<EuiButton
data-test-subj="enterpriseSearchApiKeyStepCreateApiKeyButton"
iconSide="left"
iconType="plusInCircleFilled"
onClick={openApiKeyModal}
@ -163,6 +166,7 @@ const apiKeyStep = (
</EuiFlexItem>
<EuiFlexItem grow={false}>
<EuiButton
data-test-subj="enterpriseSearchApiKeyStepViewKeysButton"
iconSide="left"
iconType="popout"
data-telemetry-id="entSearchContent-analytics-apiKey-viewKeysButton"

View file

@ -5,6 +5,8 @@
* 2.0.
*/
import { useEffect, useState } from 'react';
import { useValues } from 'kea';
import { KibanaLogic } from '../kibana';
@ -18,10 +20,18 @@ export interface CloudDetails {
export const useCloudDetails = (): CloudDetails => {
const { cloud } = useValues(KibanaLogic);
const [elasticsearchUrl, setElasticsearchUrl] = useState<string | undefined>('');
useEffect(() => {
cloud?.fetchElasticsearchConfig().then((config) => {
setElasticsearchUrl(config.elasticsearchUrl);
});
}, [cloud]);
return {
cloudId: cloud?.cloudId,
deploymentUrl: cloud?.deploymentUrl,
elasticsearchUrl: cloud?.elasticsearchUrl,
elasticsearchUrl,
kibanaUrl: cloud?.kibanaUrl,
};
};

View file

@ -5,6 +5,8 @@
* 2.0.
*/
import { CloudSetup } from '@kbn/cloud-plugin/public';
import { getCloudEnterpriseSearchHost } from './get_cloud_enterprise_search_host';
const defaultPortCloud = {
@ -20,7 +22,8 @@ const defaultPortCloud = {
serverless: {
projectId: undefined,
},
};
fetchElasticsearchConfig: jest.fn(),
} as CloudSetup;
// 9243
const customPortCloud = {
cloudId:
@ -35,7 +38,8 @@ const customPortCloud = {
serverless: {
projectId: undefined,
},
};
fetchElasticsearchConfig: jest.fn(),
} as CloudSetup;
const missingDeploymentIdCloud = {
cloudId:
'dXMtY2VudHJhbDEuZ2NwLmNsb3VkLmVzLmlvOjkyNDMkYWMzMWViYjkwMjQxNzczMTU3MDQzYzM0ZmQyNmZkNDYkYTRjMDYyMzBlNDhjOGZjZTdiZTg4YTA3NGEzYmIzZTA=',
@ -46,7 +50,8 @@ const missingDeploymentIdCloud = {
serverless: {
projectId: undefined,
},
};
fetchElasticsearchConfig: jest.fn(),
} as CloudSetup;
const noCloud = {
cloudId: undefined,
isCloudEnabled: false,
@ -56,7 +61,8 @@ const noCloud = {
serverless: {
projectId: undefined,
},
};
fetchElasticsearchConfig: jest.fn(),
} as CloudSetup;
describe('getCloudEnterpriseSearchHost', () => {
it('uses the default port', () => {

View file

@ -10,7 +10,7 @@ import { FC } from 'react';
import { kea, MakeLogicType } from 'kea';
import { ChartsPluginStart } from '@kbn/charts-plugin/public';
import { CloudSetup } from '@kbn/cloud-plugin/public';
import { CloudSetup, CloudStart } from '@kbn/cloud-plugin/public';
import { ConsolePluginStart } from '@kbn/console-plugin/public';
import {
ApplicationStart,
@ -48,7 +48,7 @@ export interface KibanaLogicProps {
application: ApplicationStart;
capabilities: Capabilities;
charts?: ChartsPluginStart;
cloud?: CloudSetup;
cloud?: CloudSetup & CloudStart;
config: ClientConfigType;
connectorTypes?: ConnectorDefinition[];
console?: ConsolePluginStart;
@ -83,7 +83,7 @@ export interface KibanaValues {
application: ApplicationStart;
capabilities: Capabilities;
charts: ChartsPluginStart | null;
cloud: CloudSetup | null;
cloud: (CloudSetup & CloudStart) | null;
config: ClientConfigType;
connectorTypes: ConnectorDefinition[];
consolePlugin: ConsolePluginStart | null;
@ -168,7 +168,10 @@ export const KibanaLogic = kea<MakeLogicType<KibanaValues>>({
],
}),
selectors: ({ selectors }) => ({
isCloud: [() => [selectors.cloud], (cloud?: CloudSetup) => Boolean(cloud?.isCloudEnabled)],
isCloud: [
() => [selectors.cloud],
(cloud?: CloudSetup & CloudStart) => Boolean(cloud?.isCloudEnabled),
],
}),
});

View file

@ -41,6 +41,7 @@ export const mockKibanaProps: KibanaLogicProps = {
charts: chartPluginMock.createStartContract(),
cloud: {
...cloudMock.createSetup(),
...cloudMock.createStart(),
isCloudEnabled: false,
},
config: {

View file

@ -24,6 +24,8 @@ export const getCloud = ({ isCloudEnabled }: { isCloudEnabled: boolean }) => {
projectId: undefined,
projectName: undefined,
},
fetchElasticsearchConfig: () =>
Promise.resolve({ elasticsearchUrl: 'https://elastisearch-url' }),
};
return cloud;

View file

@ -5,7 +5,7 @@
* 2.0.
*/
import React, { useState, useMemo } from 'react';
import React, { useState, useEffect } from 'react';
import { i18n } from '@kbn/i18n';
import { FormattedMessage } from '@kbn/i18n-react';
import {
@ -62,12 +62,16 @@ export const DetailsPageOverview: React.FunctionComponent<Props> = ({ indexDetai
const [selectedLanguage, setSelectedLanguage] = useState<LanguageDefinition>(curlDefinition);
const elasticsearchURL = useMemo(() => {
return plugins.cloud?.elasticsearchUrl ?? 'https://your_deployment_url';
const [elasticsearchUrl, setElasticsearchUrl] = useState<string>('');
useEffect(() => {
plugins.cloud?.fetchElasticsearchConfig().then((config) => {
setElasticsearchUrl(config.elasticsearchUrl || 'https://your_deployment_url');
});
}, [plugins.cloud]);
const codeSnippetArguments: LanguageDefinitionSnippetArguments = {
url: elasticsearchURL,
url: elasticsearchUrl,
apiKey: 'your_api_key',
indexName: name,
};

View file

@ -5,6 +5,7 @@
* 2.0.
*/
import { useEffect, useState } from 'react';
import { useKibana } from './use_kibana';
import { ELASTICSEARCH_URL_PLACEHOLDER } from '../constants';
@ -14,5 +15,13 @@ export const useElasticsearchUrl = (): string => {
services: { cloud },
} = useKibana();
return cloud?.elasticsearchUrl ?? ELASTICSEARCH_URL_PLACEHOLDER;
const [elasticsearchUrl, setElasticsearchUrl] = useState<string>(ELASTICSEARCH_URL_PLACEHOLDER);
useEffect(() => {
cloud?.fetchElasticsearchConfig().then((config) => {
setElasticsearchUrl(config?.elasticsearchUrl || ELASTICSEARCH_URL_PLACEHOLDER);
});
}, [cloud]);
return elasticsearchUrl;
};

View file

@ -8,7 +8,6 @@
import { render } from '@testing-library/react';
import { PY_LANG_CLIENT } from './py_lang_client'; // Adjust the import path according to your project structure
import { ES_CLIENT_DETAILS } from '../view_code_flyout';
import { CloudSetup } from '@kbn/cloud-plugin/public';
import { ChatForm } from '../../../types';
describe('PY_LANG_CLIENT function', () => {
@ -24,9 +23,7 @@ describe('PY_LANG_CLIENT function', () => {
summarization_model: 'Your-new-model',
} as unknown as ChatForm;
const clientDetails = ES_CLIENT_DETAILS({
elasticsearchUrl: 'http://my-local-cloud-instance',
} as unknown as CloudSetup);
const clientDetails = ES_CLIENT_DETAILS('http://my-local-cloud-instance');
const { container } = render(PY_LANG_CLIENT(formValues, clientDetails));

View file

@ -7,7 +7,6 @@
import { render } from '@testing-library/react';
import { ES_CLIENT_DETAILS } from '../view_code_flyout';
import { CloudSetup } from '@kbn/cloud-plugin/public';
import { ChatForm } from '../../../types';
import { LANGCHAIN_PYTHON } from './py_langchain_python';
@ -24,9 +23,7 @@ describe('PY_LANGCHAIN function', () => {
summarization_model: 'Your-new-model',
} as unknown as ChatForm;
const clientDetails = ES_CLIENT_DETAILS({
elasticsearchUrl: 'http://my-local-cloud-instance',
} as unknown as CloudSetup);
const clientDetails = ES_CLIENT_DETAILS('http://my-local-cloud-instance');
const { container } = render(LANGCHAIN_PYTHON(formValues, clientDetails));

View file

@ -20,7 +20,6 @@ import {
import { FormattedMessage } from '@kbn/i18n-react';
import React, { useEffect, useState } from 'react';
import { useFormContext } from 'react-hook-form';
import { CloudSetup } from '@kbn/cloud-plugin/public';
import { AnalyticsEvents } from '../../analytics/constants';
import { useUsageTracker } from '../../hooks/use_usage_tracker';
import { ChatForm, PlaygroundPageMode } from '../../types';
@ -35,21 +34,13 @@ interface ViewCodeFlyoutProps {
selectedPageMode: PlaygroundPageMode;
}
export const ES_CLIENT_DETAILS = (cloud: CloudSetup | undefined) => {
if (cloud) {
return `
export const ES_CLIENT_DETAILS = (elasticsearchUrl: string) => {
return `
es_client = Elasticsearch(
"${cloud.elasticsearchUrl}",
"${elasticsearchUrl || '<your-elasticsearch-url>'}",
api_key=os.environ["ES_API_KEY"]
)
`;
}
return `
es_client = Elasticsearch(
"<your-elasticsearch-url>"
)
`;
};
export const ViewCodeFlyout: React.FC<ViewCodeFlyoutProps> = ({ onClose, selectedPageMode }) => {
@ -60,8 +51,13 @@ export const ViewCodeFlyout: React.FC<ViewCodeFlyoutProps> = ({ onClose, selecte
const {
services: { cloud, http },
} = useKibana();
const CLIENT_STEP = ES_CLIENT_DETAILS(cloud);
const [elasticsearchUrl, setElasticsearchUrl] = useState<string>('');
useEffect(() => {
cloud?.fetchElasticsearchConfig().then((config) => {
setElasticsearchUrl(config.elasticsearchUrl || '');
});
}, [cloud]);
const CLIENT_STEP = ES_CLIENT_DETAILS(elasticsearchUrl);
const steps: Record<string, React.ReactElement> = {
'lc-py': LANGCHAIN_PYTHON(formValues, CLIENT_STEP),

View file

@ -42,13 +42,10 @@ import { LanguageGrid } from '../languages/language_grid';
import { useIngestPipelines } from '../../hooks/api/use_ingest_pipelines';
import { DEFAULT_INGESTION_PIPELINE } from '../../../../common';
import {
API_KEY_PLACEHOLDER,
CLOUD_ID_PLACEHOLDER,
ELASTICSEARCH_URL_PLACEHOLDER,
} from '../../constants';
import { API_KEY_PLACEHOLDER, CLOUD_ID_PLACEHOLDER } from '../../constants';
import { ApiKeyPanel } from '../api_key/api_key';
import { useElasticsearchUrl } from '../../hooks/use_elastisearch_url';
export interface APIIndexEmptyPromptProps {
indexName: string;
@ -63,14 +60,14 @@ export const APIIndexEmptyPrompt = ({ indexName, onBackClick }: APIIndexEmptyPro
const [selectedPipeline, setSelectedPipeline] = React.useState<string>('');
const [clientApiKey, setClientApiKey] = useState<string>(API_KEY_PLACEHOLDER);
const { elasticsearchURL, cloudId } = useMemo(() => {
const { elasticsearchUrl } = useElasticsearchUrl();
const { cloudId } = useMemo(() => {
return {
elasticsearchURL: cloud?.elasticsearchUrl ?? ELASTICSEARCH_URL_PLACEHOLDER,
cloudId: cloud?.cloudId ?? CLOUD_ID_PLACEHOLDER,
};
}, [cloud]);
const codeSnippetArguments: LanguageDefinitionSnippetArguments = {
url: elasticsearchURL,
url: elasticsearchUrl,
apiKey: clientApiKey,
cloudId,
indexName,

View file

@ -39,7 +39,7 @@ describe('<Overview />', () => {
});
});
const pathname = '/app/elasticsearch';
(useLocation as jest.Mock).mockImplementationOnce(() => ({
(useLocation as jest.Mock).mockImplementation(() => ({
pathname,
}));
});

View file

@ -41,11 +41,7 @@ import { DEFAULT_INGESTION_PIPELINE } from '../../../common';
import { docLinks } from '../../../common/doc_links';
import { useKibanaServices } from '../hooks/use_kibana';
import { useAssetBasePath } from '../hooks/use_asset_base_path';
import {
API_KEY_PLACEHOLDER,
CLOUD_ID_PLACEHOLDER,
ELASTICSEARCH_URL_PLACEHOLDER,
} from '../constants';
import { API_KEY_PLACEHOLDER, CLOUD_ID_PLACEHOLDER } from '../constants';
import { javaDefinition } from './languages/java';
import { languageDefinitions } from './languages/languages';
import { LanguageGrid } from './languages/language_grid';
@ -57,14 +53,16 @@ import { SelectClientCallouts } from './select_client_callouts';
import { PipelineManageButton } from './pipeline_manage_button';
import { OPTIONAL_LABEL } from '../../../common/i18n_string';
import { useIngestPipelines } from '../hooks/api/use_ingest_pipelines';
import { useElasticsearchUrl } from '../hooks/use_elastisearch_url';
export const ElasticsearchOverview = () => {
const [selectedLanguage, setSelectedLanguage] = useState<LanguageDefinition>(javaDefinition);
const [clientApiKey, setClientApiKey] = useState<string>(API_KEY_PLACEHOLDER);
const { application, cloud, user, share, console: consolePlugin } = useKibanaServices();
const { elasticsearchURL, cloudId } = useMemo(() => {
const { elasticsearchUrl } = useElasticsearchUrl();
const { cloudId } = useMemo(() => {
return {
elasticsearchURL: cloud?.elasticsearchUrl ?? ELASTICSEARCH_URL_PLACEHOLDER,
cloudId: cloud?.cloudId ?? CLOUD_ID_PLACEHOLDER,
};
}, [cloud]);
@ -87,7 +85,7 @@ export const ElasticsearchOverview = () => {
const [selectedPipeline, setSelectedPipeline] = React.useState<string>('');
const codeSnippetArguments: LanguageDefinitionSnippetArguments = {
url: elasticsearchURL,
url: elasticsearchUrl,
apiKey: clientApiKey,
cloudId,
ingestPipeline: selectedPipeline,
@ -167,7 +165,10 @@ export const ElasticsearchOverview = () => {
bottomBorder="extended"
data-test-subj="cloud-details-section"
>
<CloudDetailsPanel cloudId={cloud.cloudId} elasticsearchUrl={cloud.elasticsearchUrl} />
<CloudDetailsPanel
cloudId={cloud.cloudId}
elasticsearchUrl={elasticsearchUrl || undefined}
/>
</EuiPageTemplate.Section>
<EuiPageTemplate.Section
color="subdued"

View file

@ -5,11 +5,18 @@
* 2.0.
*/
import { useState, useEffect } from 'react';
import { ELASTICSEARCH_URL_PLACEHOLDER } from '../constants';
import { useKibanaServices } from './use_kibana';
export const useElasticsearchUrl = () => {
const { cloud } = useKibanaServices();
const [elasticsearchUrl, setElasticsearchUrl] = useState<string>(ELASTICSEARCH_URL_PLACEHOLDER);
useEffect(() => {
cloud?.fetchElasticsearchConfig().then((config) => {
setElasticsearchUrl(config.elasticsearchUrl || ELASTICSEARCH_URL_PLACEHOLDER);
});
});
return { elasticsearchUrl: cloud?.elasticsearchUrl ?? ELASTICSEARCH_URL_PLACEHOLDER };
return { elasticsearchUrl };
};