From ab5b5881ff42b5aabf901042dbed8d3510479657 Mon Sep 17 00:00:00 2001
From: Bandini Bhopi <bandinib@amazon.com>
Date: Wed, 9 Aug 2023 01:03:54 +0000
Subject: [PATCH] Remove minimum constraint on opensearch hosts

Signed-off-by: Bandini Bhopi <bandinib@amazon.com>
---
 .../opensearch/client/cluster_client.ts       |  2 +-
 .../server/opensearch/opensearch_config.ts    |  2 +-
 .../saved_objects/saved_objects_service.ts    |  9 ------
 src/core/server/status/status_service.test.ts | 21 +++++++++++--
 src/core/server/status/status_service.ts      | 31 +++++++++++++------
 src/core/server/status/types.ts               |  2 +-
 6 files changed, 43 insertions(+), 24 deletions(-)

diff --git a/src/core/server/opensearch/client/cluster_client.ts b/src/core/server/opensearch/client/cluster_client.ts
index b29eea89d4db..ac2348921658 100644
--- a/src/core/server/opensearch/client/cluster_client.ts
+++ b/src/core/server/opensearch/client/cluster_client.ts
@@ -101,7 +101,7 @@ export class ClusterClient implements ICustomClusterClient {
       return;
     }
     this.isClosed = true;
-    await Promise.all([this.asInternalUser.close(), this.rootScopedClient.close()]);
+    await Promise.all([this.asInternalUser.close(noop), this.rootScopedClient.close(noop)]);
   }
 
   private getScopedHeaders(request: ScopeableRequest): Headers {
diff --git a/src/core/server/opensearch/opensearch_config.ts b/src/core/server/opensearch/opensearch_config.ts
index fee26c354fbe..7ef3a7665a97 100644
--- a/src/core/server/opensearch/opensearch_config.ts
+++ b/src/core/server/opensearch/opensearch_config.ts
@@ -53,7 +53,7 @@ export const configSchema = schema.object({
     defaultValue: false,
   }),
   sniffOnConnectionFault: schema.boolean({ defaultValue: false }),
-  hosts: schema.oneOf([hostURISchema, schema.arrayOf(hostURISchema, { minSize: 1 })], {
+  hosts: schema.oneOf([hostURISchema, schema.arrayOf(hostURISchema)], {
     defaultValue: 'http://localhost:9200',
   }),
   username: schema.maybe(
diff --git a/src/core/server/saved_objects/saved_objects_service.ts b/src/core/server/saved_objects/saved_objects_service.ts
index 43296f340d85..dfce9c4110b3 100644
--- a/src/core/server/saved_objects/saved_objects_service.ts
+++ b/src/core/server/saved_objects/saved_objects_service.ts
@@ -464,15 +464,6 @@ export class SavedObjectsService
         'Waiting until all OpenSearch nodes are compatible with OpenSearch Dashboards before starting saved objects migrations...'
       );
 
-      // TODO: Move to Status Service https://github.com/elastic/kibana/issues/41983
-      this.setupDeps!.opensearch.opensearchNodesCompatibility$.subscribe(
-        ({ isCompatible, message }) => {
-          if (!isCompatible && message) {
-            this.logger.error(message);
-          }
-        }
-      );
-
       await this.setupDeps!.opensearch.opensearchNodesCompatibility$.pipe(
         filter((nodes) => nodes.isCompatible),
         take(1)
diff --git a/src/core/server/status/status_service.test.ts b/src/core/server/status/status_service.test.ts
index 354a78210cea..bb7d241305bb 100644
--- a/src/core/server/status/status_service.test.ts
+++ b/src/core/server/status/status_service.test.ts
@@ -33,19 +33,34 @@ import { of, BehaviorSubject } from 'rxjs';
 import { ServiceStatus, ServiceStatusLevels, CoreStatus } from './types';
 import { StatusService } from './status_service';
 import { first } from 'rxjs/operators';
-import { mockCoreContext } from '../core_context.mock';
 import { ServiceStatusLevelSnapshotSerializer } from './test_utils';
 import { environmentServiceMock } from '../environment/environment_service.mock';
 import { httpServiceMock } from '../http/http_service.mock';
 import { metricsServiceMock } from '../metrics/metrics_service.mock';
+import { CoreContext } from '../core_context';
+import { configServiceMock, loggingSystemMock } from '../mocks';
+import { Env } from '../config';
+import { REPO_ROOT } from '@osd/dev-utils';
+import { getEnvOptions } from '../config/mocks';
 
 expect.addSnapshotSerializer(ServiceStatusLevelSnapshotSerializer);
-
+const configService = configServiceMock.create();
+configService.atPath.mockReturnValue(
+  new BehaviorSubject({
+    hosts: ['http://1.2.3.4'],
+  } as any)
+);
+let env: Env;
+let coreContext: CoreContext;
+const logger = loggingSystemMock.create();
 describe('StatusService', () => {
   let service: StatusService;
+  env = Env.createDefault(REPO_ROOT, getEnvOptions());
+
+  coreContext = { coreId: Symbol(), env, logger, configService: configService as any };
 
   beforeEach(() => {
-    service = new StatusService(mockCoreContext.create());
+    service = new StatusService(coreContext);
   });
 
   const delay = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms));
diff --git a/src/core/server/status/status_service.ts b/src/core/server/status/status_service.ts
index 10547e510fa6..1ef440ff5b29 100644
--- a/src/core/server/status/status_service.ts
+++ b/src/core/server/status/status_service.ts
@@ -47,6 +47,7 @@ import { config, StatusConfigType } from './status_config';
 import { ServiceStatus, CoreStatus, InternalStatusServiceSetup } from './types';
 import { getSummaryStatus } from './get_summary_status';
 import { PluginsStatusService } from './plugins_status';
+import { OpenSearchConfigType } from '../opensearch/opensearch_config';
 
 interface SetupDeps {
   opensearch: Pick<InternalOpenSearchServiceSetup, 'status$'>;
@@ -60,6 +61,7 @@ interface SetupDeps {
 export class StatusService implements CoreService<InternalStatusServiceSetup> {
   private readonly logger: Logger;
   private readonly config$: Observable<StatusConfigType>;
+  private readonly openSearchConfig$: Observable<OpenSearchConfigType>;
 
   private pluginsStatus?: PluginsStatusService;
   private overallSubscription?: Subscription;
@@ -67,6 +69,7 @@ export class StatusService implements CoreService<InternalStatusServiceSetup> {
   constructor(private readonly coreContext: CoreContext) {
     this.logger = coreContext.logger.get('status');
     this.config$ = coreContext.configService.atPath<StatusConfigType>(config.path);
+    this.openSearchConfig$ = coreContext.configService.atPath<OpenSearchConfigType>('opensearch');
   }
 
   public async setup({
@@ -78,7 +81,9 @@ export class StatusService implements CoreService<InternalStatusServiceSetup> {
     environment,
   }: SetupDeps) {
     const statusConfig = await this.config$.pipe(take(1)).toPromise();
-    const core$ = this.setupCoreStatus({ opensearch, savedObjects });
+    const openSearchConfig = await this.openSearchConfig$.pipe(take(1)).toPromise();
+    const isOpenSearchEnabled = openSearchConfig.hosts.length > 0;
+    const core$ = this.setupCoreStatus({ opensearch, savedObjects }, isOpenSearchEnabled);
     this.pluginsStatus = new PluginsStatusService({ core$, pluginDependencies });
 
     const overall$: Observable<ServiceStatus> = combineLatest([
@@ -140,15 +145,23 @@ export class StatusService implements CoreService<InternalStatusServiceSetup> {
     }
   }
 
-  private setupCoreStatus({
-    opensearch,
-    savedObjects,
-  }: Pick<SetupDeps, 'opensearch' | 'savedObjects'>): Observable<CoreStatus> {
+  private setupCoreStatus(
+    { opensearch, savedObjects }: Pick<SetupDeps, 'opensearch' | 'savedObjects'>,
+    isOpenSearchEnabled: boolean = true
+  ): Observable<CoreStatus> {
     return combineLatest([opensearch.status$, savedObjects.status$]).pipe(
-      map(([opensearchStatus, savedObjectsStatus]) => ({
-        opensearch: opensearchStatus,
-        savedObjects: savedObjectsStatus,
-      })),
+      map(([opensearchStatus, savedObjectsStatus]) => {
+        if (isOpenSearchEnabled) {
+          return {
+            opensearch: opensearchStatus,
+            savedObjects: savedObjectsStatus,
+          };
+        } else {
+          return {
+            savedObjects: savedObjectsStatus,
+          };
+        }
+      }),
       distinctUntilChanged<CoreStatus>(isDeepStrictEqual),
       shareReplay(1)
     );
diff --git a/src/core/server/status/types.ts b/src/core/server/status/types.ts
index efb1c822e9c2..7dda05dacd4d 100644
--- a/src/core/server/status/types.ts
+++ b/src/core/server/status/types.ts
@@ -134,7 +134,7 @@ export type ServiceStatusLevel = typeof ServiceStatusLevels[keyof typeof Service
  * @public
  */
 export interface CoreStatus {
-  opensearch: ServiceStatus;
+  opensearch?: ServiceStatus;
   savedObjects: ServiceStatus;
 }