Skip to content

Commit

Permalink
add reporting osd server configurations (#222)
Browse files Browse the repository at this point in the history
Signed-off-by: Zhongnan Su <szhongna@amazon.com>
  • Loading branch information
zhongnansu committed Nov 9, 2021
1 parent b941c82 commit 5f01a02
Show file tree
Hide file tree
Showing 12 changed files with 254 additions and 71 deletions.
3 changes: 2 additions & 1 deletion dashboards-reports/opensearch_dashboards.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,6 @@
"requiredPlugins": ["navigation", "data", "opensearchDashboardsUtils"],
"optionalPlugins": ["share"],
"server": true,
"ui": true
"ui": true,
"configPath": ["opensearch_reporting"]
}
69 changes: 69 additions & 0 deletions dashboards-reports/server/config/config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
/*
* SPDX-License-Identifier: Apache-2.0
*
* The OpenSearch Contributors require contributions made to
* this file be licensed under the Apache-2.0 license or a
* compatible open source license.
*
* Modifications Copyright OpenSearch Contributors. See
* GitHub history for details.
*/

import {
CoreSetup,
Logger,
PluginInitializerContext,
} from '../../../../src/core/server';
import { ReportingConfigType } from './schema';
import { get } from 'lodash';
import { first, map } from 'rxjs/operators';
import { createConfig$ } from './createConfig';

interface Config<BaseType> {
get<Key1 extends keyof BaseType>(key1: Key1): BaseType[Key1];
get<Key1 extends keyof BaseType, Key2 extends keyof BaseType[Key1]>(
key1: Key1,
key2: Key2
): BaseType[Key1][Key2];
}

interface OsdServerConfigType {
server: {
basePath: string;
host: string;
name: string;
port: number;
protocol: string;
};
}

export interface ReportingConfig extends Config<ReportingConfigType> {
osdConfig: Config<OsdServerConfigType>;
}

export const buildConfig = async (
initContext: PluginInitializerContext<ReportingConfigType>,
core: CoreSetup,
logger: Logger
): Promise<ReportingConfig> => {
const config$ = initContext.config.create<ReportingConfigType>();
const serverInfo = core.http.getServerInfo();
const osdConfig = {
server: {
basePath: core.http.basePath.serverBasePath,
host: serverInfo.hostname,
name: serverInfo.name,
port: serverInfo.port,
protocol: serverInfo.protocol,
},
};

const reportingConfig$ = createConfig$(core, config$, logger);
const reportingConfig = await reportingConfig$.pipe(first()).toPromise();
return {
get: (...keys: string[]) => get(reportingConfig, keys.join('.'), null),
osdConfig: {
get: (...keys: string[]) => get(osdConfig, keys.join('.'), null),
},
};
};
53 changes: 53 additions & 0 deletions dashboards-reports/server/config/createConfig.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
/*
* SPDX-License-Identifier: Apache-2.0
*
* The OpenSearch Contributors require contributions made to
* this file be licensed under the Apache-2.0 license or a
* compatible open source license.
*
* Modifications Copyright OpenSearch Contributors. See
* GitHub history for details.
*/

import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';
import { CoreSetup, Logger } from '../../../../src/core/server';

import { ReportingConfigType } from './schema';

/*
* Set up dynamic config defaults
*/
export function createConfig$(
core: CoreSetup,
config$: Observable<ReportingConfigType>,
logger: Logger
) {
return config$.pipe(
map((config) => {
const { osd_server: reportingServer } = config;
const serverInfo = core.http.getServerInfo();
// osd_server.hostname, default to server.host
const osdServerHostname = reportingServer.hostname
? reportingServer.hostname
: serverInfo.hostname;

// osd_server.port, default to server.port
const osdServerPort = reportingServer.port
? reportingServer.port
: serverInfo.port;
// osd_server.protocol, default to server.protocol
const osdServerProtocol = reportingServer.protocol
? reportingServer.protocol
: serverInfo.protocol;
return {
...config,
osd_server: {
hostname: osdServerHostname,
port: osdServerPort,
protocol: osdServerProtocol,
},
};
})
);
}
19 changes: 19 additions & 0 deletions dashboards-reports/server/config/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
/*
* SPDX-License-Identifier: Apache-2.0
*
* The OpenSearch Contributors require contributions made to
* this file be licensed under the Apache-2.0 license or a
* compatible open source license.
*
* Modifications Copyright OpenSearch Contributors. See
* GitHub history for details.
*/

import { PluginConfigDescriptor } from '../../../../src/core/server';
import { ConfigSchema, ReportingConfigType } from './schema';
export { buildConfig } from './config';
export { ConfigSchema, ReportingConfigType };

export const config: PluginConfigDescriptor<ReportingConfigType> = {
schema: ConfigSchema,
};
41 changes: 41 additions & 0 deletions dashboards-reports/server/config/schema.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/*
* SPDX-License-Identifier: Apache-2.0
*
* The OpenSearch Contributors require contributions made to
* this file be licensed under the Apache-2.0 license or a
* compatible open source license.
*
* Modifications Copyright OpenSearch Contributors. See
* GitHub history for details.
*/

import { schema, TypeOf } from '@osd/config-schema';

const OsdServerSchema = schema.object({
hostname: schema.maybe(
schema.string({
validate(value) {
if (value === '0') {
return 'must not be "0" for the headless browser to correctly resolve the host';
}
},
hostname: true,
})
),
port: schema.maybe(schema.number()),
protocol: schema.maybe(
schema.string({
validate(value) {
if (!/^https?$/.test(value)) {
return 'must be "http" or "https"';
}
},
})
),
}); // default values are all dynamic in createConfig$

export const ConfigSchema = schema.object({
osd_server: OsdServerSchema,
});

export type ReportingConfigType = TypeOf<typeof ConfigSchema>;
18 changes: 8 additions & 10 deletions dashboards-reports/server/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,21 +24,19 @@
* permissions and limitations under the License.
*/

import {
HttpServerInfo,
PluginInitializerContext,
} from '../../../src/core/server';
import { PluginInitializerContext } from '../../../src/core/server';
import { ReportingConfigType } from './config';
import { ReportsDashboardsPlugin } from './plugin';

export type AccessInfoType = {
basePath: string;
serverInfo: HttpServerInfo;
};
export { config } from './config';
export { ReportingConfig } from './config/config';
export { ReportsDashboardsPlugin as Plugin };

// This exports static code and TypeScript types,
// as well as, OpenSearch Dashboards Platform `plugin()` initializer.

export function plugin(initializerContext: PluginInitializerContext) {
export function plugin(
initializerContext: PluginInitializerContext<ReportingConfigType>
) {
return new ReportsDashboardsPlugin(initializerContext);
}

Expand Down
45 changes: 31 additions & 14 deletions dashboards-reports/server/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,9 @@ import {
import registerRoutes from './routes';
import { pollAndExecuteJob } from './executor/executor';
import { POLL_INTERVAL } from './utils/constants';
import { AccessInfoType } from 'server';
import { NotificationsPlugin } from './clusters/notificationsPlugin';
import { buildConfig, ReportingConfigType } from './config';
import { ReportingConfig } from './config/config';

export interface ReportsPluginRequestContext {
logger: Logger;
Expand All @@ -61,24 +62,40 @@ export class ReportsDashboardsPlugin
Plugin<ReportsDashboardsPluginSetup, ReportsDashboardsPluginStart> {
private readonly logger: Logger;
private readonly semaphore: SemaphoreInterface;

constructor(initializerContext: PluginInitializerContext) {
this.logger = initializerContext.logger.get();

private readonly initializerContext: PluginInitializerContext<
ReportingConfigType
>;
private reportingConfig?: ReportingConfig;

constructor(context: PluginInitializerContext<ReportingConfigType>) {
this.logger = context.logger.get();
this.initializerContext = context;
const timeoutError = new Error('Server busy');
timeoutError.statusCode = 503;
this.semaphore = withTimeout(new Semaphore(1), 180000, timeoutError);
}

public setup(core: CoreSetup) {
public async setup(core: CoreSetup) {
this.logger.debug('reports-dashboards: Setup');

const config = core.http.getServerInfo();
const serverBasePath = core.http.basePath.serverBasePath;
const accessInfo: AccessInfoType = {
basePath: serverBasePath,
serverInfo: config,
};
try {
const config = await buildConfig(
this.initializerContext,
core,
this.logger
);
this.reportingConfig = config;
this.logger.debug('Setup complete');
} catch (error) {
this.logger.error(
`Error in Reporting setup, reporting may not function properly`
);
this.logger.error(error);
}

if (!this.reportingConfig) {
throw new Error('Reporting Config is not initialized');
}

const router = core.http.createRouter();
// Deprecated API. Switch to the new opensearch client as soon as https://github.com/elastic/kibana/issues/35508 done.
Expand All @@ -97,7 +114,7 @@ export class ReportsDashboardsPlugin
);

// Register server side APIs
registerRoutes(router, accessInfo);
registerRoutes(router, this.reportingConfig);

// put logger into route handler context, so that we don't need to pass through parameters
core.http.registerRouteHandlerContext(
Expand All @@ -108,7 +125,7 @@ export class ReportsDashboardsPlugin
logger: this.logger,
semaphore: this.semaphore,
opensearchReportsClient,
notificationsClient
notificationsClient,
};
}
);
Expand Down
8 changes: 4 additions & 4 deletions dashboards-reports/server/routes/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,11 @@ import registerReportSourceRoute from './reportSource';
import registerMetricRoute from './metric';
import registerNotificationRoute from './notifications';
import { IRouter } from '../../../../src/core/server';
import { AccessInfoType } from 'server';
import { ReportingConfig } from 'server/config/config';

export default function (router: IRouter, accessInfo: AccessInfoType) {
registerReportRoute(router, accessInfo);
registerReportDefinitionRoute(router, accessInfo);
export default function (router: IRouter, config: ReportingConfig) {
registerReportRoute(router, config);
registerReportDefinitionRoute(router, config);
registerReportSourceRoute(router);
registerMetricRoute(router);
registerNotificationRoute(router);
Expand Down
12 changes: 6 additions & 6 deletions dashboards-reports/server/routes/lib/createReport.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,14 +46,14 @@ import { SetCookie, Headers } from 'puppeteer-core';
import { updateReportState } from './updateReportState';
import { saveReport } from './saveReport';
import { SemaphoreInterface } from 'async-mutex';
import { AccessInfoType } from 'server';
import { ReportingConfig } from 'server';
import _ from 'lodash';

export const createReport = async (
request: OpenSearchDashboardsRequest,
context: RequestHandlerContext,
report: ReportSchemaType,
accessInfo: AccessInfoType,
config: ReportingConfig,
savedReportId?: string
): Promise<CreateReportResultType> => {
const isScheduledTask = false;
Expand All @@ -73,10 +73,10 @@ export const createReport = async (
request.query.dateFormat || DATA_REPORT_CONFIG.excelDateFormat;
// @ts-ignore
const csvSeparator = request.query.csvSeparator || ',';
const {
basePath,
serverInfo: { protocol, port, hostname },
} = accessInfo;
const protocol = config.get('osd_server', 'protocol');
const hostname = config.get('osd_server', 'hostname');
const port = config.get('osd_server', 'port');
const basePath = config.osdConfig.get('server', 'basePath');

let createReportResult: CreateReportResultType;
let reportId;
Expand Down
Loading

0 comments on commit 5f01a02

Please sign in to comment.