import { Subject } from 'rxjs' ; import { takeUntil } from 'rxjs/operators' ; import { CoreService } from 'src/core/types' ; import { SavedObjectsServiceStart } from 'src/core/server' ; import { CoreContext } from '../core_context' ; import { OpenSearchConfigType } from '../opensearch/opensearch_config' ; import { HttpConfigType } from '../http' ; import { LoggingConfigType } from '../logging' ; import { SavedObjectsConfigType } from '../saved_objects/saved_objects_config' ; import { CoreServicesUsageData , CoreUsageData , CoreUsageDataStart } from './types' ; import { isConfigured } from './is_configured' ; import { OpenSearchServiceStart } from '../opensearch' ; import { OpenSearchDashboardsConfigType } from '../opensearch_dashboards_config' ; import { MetricsServiceSetup , OpsMetrics } from '..' ; export interface SetupDeps { metrics : MetricsServiceSetup ; } export interface StartDeps { savedObjects : SavedObjectsServiceStart ; opensearch : OpenSearchServiceStart ; } param index param opensearchDashboardsConfigIndex const opensearchDashboardsOrTaskManagerIndex = ( index , opensearchDashboardsConfigIndex ) => { return index === opensearchDashboardsConfigIndex ? '.kibana' : '.kibana_task_manager' ; } ; export class CoreUsageDataService implements CoreService < void , CoreUsageDataStart > { private opensearchConfig ? : OpenSearchConfigType ; private configService : CoreContext [ 'configService' ] ; private httpConfig ? : HttpConfigType ; private loggingConfig ? : LoggingConfigType ; private soConfig ? : SavedObjectsConfigType ; private stop$ : Subject < void > ; private opsMetrics ? : OpsMetrics ; private opensearchDashboardsConfig ? : OpenSearchDashboardsConfigType ; constructor ( core ) { this . configService = core . configService ; this . stop$ = new Subject ( ) ; } private async getSavedObjectIndicesUsageData ( savedObjects , opensearch ) { const indices = await Promise . all ( Array . from ( savedObjects . getTypeRegistry ( ) . getAllTypes ( ) . reduce ( ( acc , type ) => { const index = type . indexPattern ?? this . opensearchDashboardsConfig ! . index ; return index != null ? acc . add ( index ) : acc ; } , new Set < string > ( ) ) . values ( ) ) . map ( ( index ) => { return opensearch . client . asInternalUser . cat . indices < any [ ] > ( { index , format : 'JSON' , bytes : 'b' , } ) . then ( ( { body } ) => { const stats = body [ 0 ] ; return { alias : opensearchDashboardsOrTaskManagerIndex ( index , this . opensearchDashboardsConfig ! . index ) , docsCount : stats [ 'docs.count' ] , docsDeleted : stats [ 'docs.deleted' ] , storeSizeBytes : stats [ 'store.size' ] , primaryStoreSizeBytes : stats [ 'pri.store.size' ] , } ; } ) ; } ) ) ; return { indices , } ; } private async getCoreUsageData ( savedObjects , opensearch ) { if ( this . opensearchConfig == null || this . httpConfig == null || this . soConfig == null || this . opsMetrics == null ) { throw new Error ( 'Unable to read config valuopensearch. Ensure that setup() has completed.' ) ; } const opensearchConfig = this . opensearchConfig ; const soUsageData = await this . getSavedObjectIndicesUsageData ( savedObjects , opensearch ) ; const http = this . httpConfig ; return { config : { opensearch : { apiVersion : opensearchConfig . apiVersion , sniffOnStart : opensearchConfig . sniffOnStart , sniffIntervalMs : opensearchConfig . sniffInterval !== false ? opensearchConfig . sniffInterval . asMilliseconds ( ) : - 1 , sniffOnConnectionFault : opensearchConfig . sniffOnConnectionFault , numberOfHostsConfigured : Array . isArray ( opensearchConfig . hosts ) ? opensearchConfig . hosts . length : isConfigured . string ( opensearchConfig . hosts ) ? 1 : 0 , customHeadersConfigured : isConfigured . record ( opensearchConfig . customHeaders ) , healthCheckDelayMs : opensearchConfig . healthCheck . delay . asMilliseconds ( ) , logQueries : opensearchConfig . logQueries , pingTimeoutMs : opensearchConfig . pingTimeout . asMilliseconds ( ) , requestHeadersWhitelistConfigured : isConfigured . stringOrArray ( opensearchConfig . requestHeadersWhitelist , [ 'authorization' ] ) , requestTimeoutMs : opensearchConfig . requestTimeout . asMilliseconds ( ) , shardTimeoutMs : opensearchConfig . shardTimeout . asMilliseconds ( ) , ssl : { alwaysPresentCertificate : opensearchConfig . ssl . alwaysPresentCertificate , certificateAuthoritiesConfigured : isConfigured . stringOrArray ( opensearchConfig . ssl . certificateAuthorities ) , certificateConfigured : isConfigured . string ( opensearchConfig . ssl . certificate ) , keyConfigured : isConfigured . string ( opensearchConfig . ssl . key ) , verificationMode : opensearchConfig . ssl . verificationMode , truststoreConfigured : isConfigured . record ( opensearchConfig . ssl . truststore ) , keystoreConfigured : isConfigured . record ( opensearchConfig . ssl . keystore ) , } , } , http : { basePathConfigured : isConfigured . string ( http . basePath ) , maxPayloadInBytes : http . maxPayload . getValueInBytes ( ) , rewriteBasePath : http . rewriteBasePath , keepaliveTimeout : http . keepaliveTimeout , socketTimeout : http . socketTimeout , compression : { enabled : http . compression . enabled , referrerWhitelistConfigured : isConfigured . array ( http . compression . referrerWhitelist ) , } , xsrf : { disableProtection : http . xsrf . disableProtection , whitelistConfigured : isConfigured . array ( http . xsrf . whitelist ) , } , requestId : { allowFromAnyIp : http . requestId . allowFromAnyIp , ipAllowlistConfigured : isConfigured . array ( http . requestId . ipAllowlist ) , } , ssl : { certificateAuthoritiesConfigured : isConfigured . stringOrArray ( http . ssl . certificateAuthorities ) , certificateConfigured : isConfigured . string ( http . ssl . certificate ) , cipherSuites : http . ssl . cipherSuites , keyConfigured : isConfigured . string ( http . ssl . key ) , redirectHttpFromPortConfigured : isConfigured . number ( http . ssl . redirectHttpFromPort ) , supportedProtocols : http . ssl . supportedProtocols , clientAuthentication : http . ssl . clientAuthentication , keystoreConfigured : isConfigured . record ( http . ssl . keystore ) , truststoreConfigured : isConfigured . record ( http . ssl . truststore ) , } , } , logging : { appendersTypesUsed : Array . from ( Array . from ( this . loggingConfig ?. appenders . values ( ) ?? [ ] ) . reduce ( ( acc , a ) => acc . add ( a . kind ) , new Set < string > ( ) ) . values ( ) ) , loggersConfiguredCount : this . loggingConfig ?. loggers . length ?? 0 , } , savedObjects : { maxImportPayloadBytes : this . soConfig . maxImportPayloadBytes . getValueInBytes ( ) , maxImportExportSizeBytes : this . soConfig . maxImportExportSize . getValueInBytes ( ) , } , } , environment : { memory : { heapSizeLimit : this . opsMetrics . process . memory . heap . size_limit , heapTotalBytes : this . opsMetrics . process . memory . heap . total_in_bytes , heapUsedBytes : this . opsMetrics . process . memory . heap . used_in_bytes , } , } , services : { savedObjects : soUsageData , } , } ; } setup ( { metrics } ) { metrics . getOpsMetrics$ ( ) . pipe ( takeUntil ( this . stop$ ) ) . subscribe ( ( opsMetrics ) => ( this . opsMetrics = opsMetrics ) ) ; this . configService . atPath < OpenSearchConfigType > ( 'opensearch' ) . pipe ( takeUntil ( this . stop$ ) ) . subscribe ( ( config ) => { this . opensearchConfig = config ; } ) ; this . configService . atPath < HttpConfigType > ( 'server' ) . pipe ( takeUntil ( this . stop$ ) ) . subscribe ( ( config ) => { this . httpConfig = config ; } ) ; this . configService . atPath < LoggingConfigType > ( 'logging' ) . pipe ( takeUntil ( this . stop$ ) ) . subscribe ( ( config ) => { this . loggingConfig = config ; } ) ; this . configService . atPath < SavedObjectsConfigType > ( 'savedObjects' ) . pipe ( takeUntil ( this . stop$ ) ) . subscribe ( ( config ) => { this . soConfig = config ; } ) ; this . configService . atPath < OpenSearchDashboardsConfigType > ( 'opensearchDashboards' ) . pipe ( takeUntil ( this . stop$ ) ) . subscribe ( ( config ) => { this . opensearchDashboardsConfig = config ; } ) ; } start ( { savedObjects , opensearch } ) { return { getCoreUsageData : ( ) => { return this . getCoreUsageData ( savedObjects , opensearch ) ; } , } ; } stop ( ) { this . stop$ . next ( ) ; this . stop$ . complete ( ) ; } }