/
validate-configs.ts
114 lines (98 loc) · 3.55 KB
/
validate-configs.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
import os from 'os';
import convict from 'convict';
import {
TSError, isFunction, isPlainObject, isEmpty, concat, PartialDeep
} from '@terascope/utils';
import { getConnectorSchema } from './connector-utils';
import foundationSchema from './schema';
import * as i from './interfaces';
function validateConfig(
cluster: { isMaster: boolean },
schema: convict.Schema<any>,
namespaceConfig: any
) {
try {
const config = convict(schema || {});
config.load(namespaceConfig);
if (cluster.isMaster) {
config.validate({
// IMPORTANT: changing this will break things
// FIXME
// false is deprecated and will be removed in ^5.0.0
// must be warn or strict
allowed: true,
} as any);
}
return config.getProperties();
} catch (err) {
throw new TSError(err, { reason: 'Error validating configuration' });
}
}
function extractSchema<S>(
fn: any,
sysconfig: PartialDeep<i.FoundationSysConfig<S>>
): Record<string, any> {
if (isFunction(fn)) {
return fn(sysconfig);
}
if (isPlainObject(fn)) {
return fn;
}
return {};
}
/**
* @param cluster the nodejs cluster metadata
* @param config the config object passed to the library terafoundation
* @param sysconfig unvalidated sysconfig
*/
export default function validateConfigs<S = {}, A = {}, D extends string = string>(
cluster: i.Cluster,
config: i.FoundationConfig<S, A, D>,
sysconfig: PartialDeep<i.FoundationSysConfig<S>>
): i.FoundationSysConfig<S> {
if (!isPlainObject(config) || isEmpty(config)) {
throw new Error('Terafoundation requires a valid application configuration');
}
if (!isPlainObject(sysconfig) || isEmpty(sysconfig)) {
throw new Error('Terafoundation requires a valid system configuration');
}
const schema = extractSchema(config.config_schema, sysconfig);
schema.terafoundation = foundationSchema;
const result: any = {};
if (config.schema_formats) {
config.schema_formats.forEach((format) => {
convict.addFormat(format);
});
}
const schemaKeys = concat(Object.keys(schema), Object.keys(sysconfig));
for (const schemaKey of schemaKeys) {
const subSchema = schema[schemaKey] || {};
const subConfig = sysconfig[schemaKey] || {};
result[schemaKey] = validateConfig(cluster, subSchema, subConfig);
if (schemaKey === 'terafoundation') {
result[schemaKey].connectors = {};
const connectors: Record<string, any> = subConfig.connectors || {};
for (const [connector, connectorConfig] of Object.entries(connectors)) {
const connectorSchema = getConnectorSchema(connector);
result[schemaKey].connectors[connector] = {};
for (const [connection, connectionConfig] of Object.entries(connectorConfig)) {
result[schemaKey].connectors[connector][connection] = validateConfig(
cluster,
connectorSchema,
connectionConfig as any
);
}
}
}
}
// Annotate the config with some information about this instance.
const hostname = os.hostname();
if (process.env.POD_IP) {
result._nodeName = process.env.POD_IP;
} else if (cluster.worker) {
result._nodeName = `${hostname}.${cluster.worker.id}`;
} else {
result._nodeName = hostname;
}
return result;
}