Skip to content

Commit

Permalink
Merge pull request #8147 from cowboyd/elastic-search-new-client
Browse files Browse the repository at this point in the history
Add ability to re-use search cluster configuration from ElasticSearchSearchEngine
  • Loading branch information
camilaibs committed Dec 15, 2021
2 parents 22354ee + c479598 commit 1115165
Show file tree
Hide file tree
Showing 8 changed files with 356 additions and 98 deletions.
6 changes: 6 additions & 0 deletions .changeset/add-new-client-method-to-elastic-search-egine.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
'@backstage/plugin-search-backend-module-elasticsearch': patch
---

Add `newClient()` method to re-use the configuration of the elastic search
engine with custom clients
12 changes: 12 additions & 0 deletions docs/features/search/search-engines.md
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,18 @@ within your instance. The configuration options are documented in the
The underlying functionality is using official ElasticSearch client version 7.x,
meaning that ElasticSearch version 7 is the only one confirmed to be supported.

Should you need to create your own bespoke search experiences that require more
than just a query translator (such as faceted search or Relay pagination), you
can access the configuration of the search engine in order to create new elastic
search clients. The version of the client need not be the same as one used
internally by the elastic search engine plugin. For example:

```typescript
import { Client } from '@elastic/elastic-search';

const client = searchEngine.newClient(options => new Client(options));
```

## Example configurations

### AWS
Expand Down
99 changes: 94 additions & 5 deletions plugins/search-backend-module-elasticsearch/api-report.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,30 +3,119 @@
> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/).
```ts
import { Client } from '@elastic/elasticsearch';
/// <reference types="node" />

import { Config } from '@backstage/config';
import type { ConnectionOptions } from 'tls';
import { IndexableDocument } from '@backstage/search-common';
import { Logger as Logger_2 } from 'winston';
import { SearchEngine } from '@backstage/search-common';
import { SearchQuery } from '@backstage/search-common';
import { SearchResultSet } from '@backstage/search-common';

// Warning: (ae-missing-release-tag) "ElasticSearchClientOptions" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
// Warning: (ae-unresolved-link) The @link reference could not be resolved: The package "@backstage/plugin-search-backend-module-elasticsearch" does not have an export "ElasticSearchEngine"
//
// @public
export interface ElasticSearchClientOptions {
// Warning: (ae-forgotten-export) The symbol "ElasticSearchAgentOptions" needs to be exported by the entry point index.d.ts
//
// (undocumented)
agent?: ElasticSearchAgentOptions | ((opts?: any) => unknown) | false;
// Warning: (ae-forgotten-export) The symbol "ElasticSearchAuth" needs to be exported by the entry point index.d.ts
//
// (undocumented)
auth?: ElasticSearchAuth;
// (undocumented)
cloud?: {
id: string;
username?: string;
password?: string;
};
// (undocumented)
compression?: 'gzip';
// Warning: (ae-forgotten-export) The symbol "ElasticSearchConnectionConstructor" needs to be exported by the entry point index.d.ts
//
// (undocumented)
Connection?: ElasticSearchConnectionConstructor;
// (undocumented)
disablePrototypePoisoningProtection?: boolean | 'proto' | 'constructor';
// (undocumented)
enableMetaHeader?: boolean;
// (undocumented)
headers?: Record<string, any>;
// (undocumented)
maxRetries?: number;
// (undocumented)
name?: string | symbol;
// Warning: (ae-forgotten-export) The symbol "ElasticSearchNodeOptions" needs to be exported by the entry point index.d.ts
//
// (undocumented)
node?:
| string
| string[]
| ElasticSearchNodeOptions
| ElasticSearchNodeOptions[];
// (undocumented)
nodeFilter?: (connection: any) => boolean;
// (undocumented)
nodes?:
| string
| string[]
| ElasticSearchNodeOptions
| ElasticSearchNodeOptions[];
// (undocumented)
nodeSelector?: ((connections: any[]) => any) | string;
// (undocumented)
opaqueIdPrefix?: string;
// (undocumented)
pingTimeout?: number;
// (undocumented)
provider?: 'aws' | 'elastic';
// (undocumented)
proxy?: string | URL;
// (undocumented)
requestTimeout?: number;
// (undocumented)
resurrectStrategy?: 'ping' | 'optimistic' | 'none';
// (undocumented)
sniffEndpoint?: string;
// (undocumented)
sniffInterval?: number | boolean;
// (undocumented)
sniffOnConnectionFault?: boolean;
// (undocumented)
sniffOnStart?: boolean;
// (undocumented)
ssl?: ConnectionOptions;
// (undocumented)
suggestCompression?: boolean;
// Warning: (ae-forgotten-export) The symbol "ElasticSearchTransportConstructor" needs to be exported by the entry point index.d.ts
//
// (undocumented)
Transport?: ElasticSearchTransportConstructor;
}

// @public (undocumented)
export class ElasticSearchSearchEngine implements SearchEngine {
constructor(
elasticSearchClient: Client,
elasticSearchClientOptions: ElasticSearchClientOptions,
aliasPostfix: string,
indexPrefix: string,
logger: Logger_2,
);
// Warning: (ae-forgotten-export) The symbol "ElasticSearchOptions" needs to be exported by the entry point index.d.ts
//
// (undocumented)
static fromConfig(
options: ElasticSearchOptions,
): Promise<ElasticSearchSearchEngine>;
static fromConfig({
logger,
config,
aliasPostfix,
indexPrefix,
}: ElasticSearchOptions): Promise<ElasticSearchSearchEngine>;
// (undocumented)
index(type: string, documents: IndexableDocument[]): Promise<void>;
newClient<T>(create: (options: ElasticSearchClientOptions) => T): T;
// (undocumented)
query(query: SearchQuery): Promise<SearchResultSet>;
// Warning: (ae-forgotten-export) The symbol "ElasticSearchQueryTranslator" needs to be exported by the entry point index.d.ts
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
/*
* Copyright 2021 The Backstage Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import type { ConnectionOptions as TLSConnectionOptions } from 'tls';

/**
* Options used to configure the `@elastic/elasticsearch` client and
* are what will be passed as an argument to the
* {@link ElasticSearchEngine.newClient} method
*
* They are drawn from the `ClientOptions` class of `@elastic/elasticsearch`,
* but are maintained separately so that this interface is not coupled to
*/
export interface ElasticSearchClientOptions {
provider?: 'aws' | 'elastic';
node?:
| string
| string[]
| ElasticSearchNodeOptions
| ElasticSearchNodeOptions[];
nodes?:
| string
| string[]
| ElasticSearchNodeOptions
| ElasticSearchNodeOptions[];
Transport?: ElasticSearchTransportConstructor;
Connection?: ElasticSearchConnectionConstructor;
maxRetries?: number;
requestTimeout?: number;
pingTimeout?: number;
sniffInterval?: number | boolean;
sniffOnStart?: boolean;
sniffEndpoint?: string;
sniffOnConnectionFault?: boolean;
resurrectStrategy?: 'ping' | 'optimistic' | 'none';
suggestCompression?: boolean;
compression?: 'gzip';
ssl?: TLSConnectionOptions;
agent?: ElasticSearchAgentOptions | ((opts?: any) => unknown) | false;
nodeFilter?: (connection: any) => boolean;
nodeSelector?: ((connections: any[]) => any) | string;
headers?: Record<string, any>;
opaqueIdPrefix?: string;
name?: string | symbol;
auth?: ElasticSearchAuth;
proxy?: string | URL;
enableMetaHeader?: boolean;
cloud?: {
id: string;
username?: string;
password?: string;
};
disablePrototypePoisoningProtection?: boolean | 'proto' | 'constructor';
}

export type ElasticSearchAuth =
| {
username: string;
password: string;
}
| {
apiKey:
| string
| {
id: string;
api_key: string;
};
};

export interface ElasticSearchNodeOptions {
url: URL;
id?: string;
agent?: ElasticSearchAgentOptions;
ssl?: TLSConnectionOptions;
headers?: Record<string, any>;
roles?: {
master: boolean;
data: boolean;
ingest: boolean;
ml: boolean;
};
}

export interface ElasticSearchAgentOptions {
keepAlive?: boolean;
keepAliveMsecs?: number;
maxSockets?: number;
maxFreeSockets?: number;
}

export interface ElasticSearchConnectionConstructor {
new (opts?: any): any;
statuses: {
ALIVE: string;
DEAD: string;
};
roles: {
MASTER: string;
DATA: string;
INGEST: string;
ML: string;
};
}

export interface ElasticSearchTransportConstructor {
new (opts?: any): any;
sniffReasons: {
SNIFF_ON_START: string;
SNIFF_INTERVAL: string;
SNIFF_ON_CONNECTION_FAULT: string;
DEFAULT: string;
};
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
*/

import { getVoidLogger } from '@backstage/backend-common';
import { SearchEngine } from '@backstage/search-common';
import { Client } from '@elastic/elasticsearch';
import Mock from '@elastic/elasticsearch-mock';
import {
Expand All @@ -33,28 +32,31 @@ class ElasticSearchSearchEngineForTranslatorTests extends ElasticSearchSearchEng
}

const mock = new Mock();
const client = new Client({
const options = {
node: 'http://localhost:9200',
Connection: mock.getConnection(),
});
};

describe('ElasticSearchSearchEngine', () => {
let testSearchEngine: SearchEngine;
let testSearchEngine: ElasticSearchSearchEngine;
let inspectableSearchEngine: ElasticSearchSearchEngineForTranslatorTests;
let client: Client;

beforeEach(() => {
testSearchEngine = new ElasticSearchSearchEngine(
client,
options,
'search',
'',
getVoidLogger(),
);
inspectableSearchEngine = new ElasticSearchSearchEngineForTranslatorTests(
client,
options,
'search',
'',
getVoidLogger(),
);
// eslint-disable-next-line dot-notation
client = testSearchEngine['elasticSearchClient'];
});

describe('queryTranslator', () => {
Expand Down

0 comments on commit 1115165

Please sign in to comment.