diff --git a/src/server/config.ts b/src/server/config.ts index 66da66c6d..5f134d166 100644 --- a/src/server/config.ts +++ b/src/server/config.ts @@ -23,7 +23,7 @@ import { Cluster } from "../common/models/cluster/cluster"; import { DataCube } from "../common/models/data-cube/data-cube"; import { arraySum } from "../common/utils/general/general"; import { appSettingsToYAML } from "../common/utils/yaml-helper/yaml-helper"; -import { ServerSettings } from "./models/server-settings/server-settings"; +import { ServerSettings, ServerSettingsJS } from "./models/server-settings/server-settings"; import { loadFileSync } from "./utils/file/file"; import { SettingsManager } from "./utils/settings-manager/settings-manager"; import { SettingsStore } from "./utils/settings-store/settings-store"; @@ -166,24 +166,26 @@ export const START_SERVER = !PRINT_CONFIG; const logger = START_SERVER ? LOGGER : NULL_LOGGER; // Load server settings -var serverSettingsFilePath = parsedArgs["config"]; +let configPath = parsedArgs["config"]; if (parsedArgs["examples"]) { - serverSettingsFilePath = path.join(__dirname, "../../config-examples.yaml"); + configPath = path.join(__dirname, "../../config-examples.yaml"); } -var anchorPath: string; -var serverSettingsJS: any; -if (serverSettingsFilePath) { - anchorPath = path.dirname(serverSettingsFilePath); +let serverSettingsJS: ServerSettingsJS; +let configDirPath; +let configContent; +if (configPath) { + configDirPath = path.dirname(configPath); try { - serverSettingsJS = loadFileSync(serverSettingsFilePath, "yaml"); - logger.log(`Using config ${serverSettingsFilePath}`); + configContent = loadFileSync(configPath, "yaml"); + serverSettingsJS = configContent; + logger.log(`Using config ${configPath}`); } catch (e) { - exitWithError(`Could not load config from '${serverSettingsFilePath}': ${e.message}`); + exitWithError(`Could not load config from '${configPath}': ${e.message}`); } } else { - anchorPath = process.cwd(); + configDirPath = process.cwd(); serverSettingsJS = {}; } @@ -196,11 +198,12 @@ if (parsedArgs["server-host"]) { if (parsedArgs["server-root"]) { serverSettingsJS.serverRoot = parsedArgs["server-root"]; } -if (parsedArgs["auth"]) { - serverSettingsJS.auth = parsedArgs["auth"]; +if (parsedArgs["verbose"]) { + serverSettingsJS.verbose = parsedArgs["verbose"]; } -export const VERBOSE = Boolean(parsedArgs["verbose"] || serverSettingsJS.verbose); +// TODO: Remove this export +export const VERBOSE = Boolean(serverSettingsJS.verbose); export const SERVER_SETTINGS = ServerSettings.fromJS(serverSettingsJS); // --- Sign of Life ------------------------------- @@ -210,28 +213,18 @@ if (START_SERVER) { // --- Location ------------------------------- -var settingsStore: SettingsStore = null; - -if (serverSettingsFilePath) { - var settingsLocation = SERVER_SETTINGS.getSettingsLocation(); - if (settingsLocation) { - switch (settingsLocation.getLocation()) { - case "file": - var settingsFilePath = path.resolve(anchorPath, settingsLocation.uri); - settingsStore = SettingsStore.fromReadOnlyFile(settingsFilePath, settingsLocation.getFormat()); - break; - default: - exitWithError(`unknown location '${settingsLocation.location}'`); - } - - } else { - settingsStore = SettingsStore.fromReadOnlyFile(serverSettingsFilePath, "yaml"); - } +let settingsStore: SettingsStore; + +if (configContent) { + const appSettings = AppSettings.fromJS(configContent, {}); + // TODO: this validation should be done via #365 + appSettings.validate(); + settingsStore = SettingsStore.create(appSettings); } else { - var initAppSettings = AppSettings.BLANK; + let initAppSettings = AppSettings.BLANK; // If a file is specified add it as a dataCube - var fileToLoad = parsedArgs["file"]; + const fileToLoad = parsedArgs["file"]; if (fileToLoad) { initAppSettings = initAppSettings.addDataCube(new DataCube({ name: path.basename(fileToLoad, path.extname(fileToLoad)), @@ -253,13 +246,13 @@ if (serverSettingsFilePath) { })); } - settingsStore = SettingsStore.fromTransient(initAppSettings); + settingsStore = SettingsStore.create(initAppSettings); } export const SETTINGS_MANAGER = new SettingsManager(settingsStore, { logger, verbose: VERBOSE, - anchorPath, + anchorPath: configDirPath, initialLoadTimeout: SERVER_SETTINGS.getPageMustLoadTimeout() }); diff --git a/src/server/models/server-settings/server-settings.mocha.ts b/src/server/models/server-settings/server-settings.mocha.ts index bbae32480..096f85371 100644 --- a/src/server/models/server-settings/server-settings.mocha.ts +++ b/src/server/models/server-settings/server-settings.mocha.ts @@ -23,9 +23,6 @@ describe("ServerSettings", () => { it("is an immutable class", () => { testImmutableClass(ServerSettings, [ {}, - { - port: 9090 - }, { port: 9091 }, @@ -50,17 +47,6 @@ describe("ServerSettings", () => { serverRoot: "/swivs", readinessEndpoint: "/status/readiness", pageMustLoadTimeout: 901 - }, - { - port: 9091, - auth: "my_auth.js" - }, - { - port: 9091, - settingsLocation: { - location: "file", - uri: "path/to/my/file.yaml" - } } ]); }); diff --git a/src/server/models/server-settings/server-settings.ts b/src/server/models/server-settings/server-settings.ts index c8ecf790e..be5bbb104 100644 --- a/src/server/models/server-settings/server-settings.ts +++ b/src/server/models/server-settings/server-settings.ts @@ -16,7 +16,6 @@ */ import { BackCompat, BaseImmutable } from "immutable-class"; -import { SettingsLocation } from "../settings-location/settings-location"; export type Iframe = "allow" | "deny"; export type TrustProxy = "none" | "always"; @@ -30,10 +29,10 @@ export interface ServerSettingsValue { livenessEndpoint?: string; requestLogFormat?: string; pageMustLoadTimeout?: number; + verbose?: boolean; iframe?: Iframe; trustProxy?: TrustProxy; strictTransportSecurity?: StrictTransportSecurity; - settingsLocation?: SettingsLocation; } export interface ServerSettingsJS extends ServerSettingsValue { @@ -69,13 +68,13 @@ export class ServerSettings extends BaseImmutable Iframe; public getTrustProxy: () => TrustProxy; public getStrictTransportSecurity: () => StrictTransportSecurity; - public getSettingsLocation: () => SettingsLocation; } BaseImmutable.finalize(ServerSettings); diff --git a/src/server/models/settings-location/settings-location.mocha.ts b/src/server/models/settings-location/settings-location.mocha.ts deleted file mode 100644 index 2fd5f363c..000000000 --- a/src/server/models/settings-location/settings-location.mocha.ts +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright 2015-2016 Imply Data, Inc. - * Copyright 2017-2019 Allegro.pl - * - * 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 { expect } from "chai"; -import { testImmutableClass } from "immutable-class-tester"; -import { SettingsLocation } from "./settings-location"; - -describe("SettingsLocation", () => { - it("is an immutable class", () => { - testImmutableClass(SettingsLocation, [ - { - location: "file", - uri: "../private/lol.yaml" - }, - { - location: "mysql", - uri: "mysql://root:@192.168.99.100:3306/datazoo" - }, - { - location: "mysql", - uri: "mysql://root:@192.168.99.100:3306/datazoo", - table: "swiv_state" - } - ]); - }); - - describe("gets the right format", () => { - it("gets yaml", () => { - var settingsLocation = SettingsLocation.fromJS({ - location: "file", - uri: "../private/lol.yaml" - }); - - expect(settingsLocation.getFormat()).to.equal("yaml"); - }); - - }); - -}); diff --git a/src/server/models/settings-location/settings-location.ts b/src/server/models/settings-location/settings-location.ts deleted file mode 100644 index 7efe17945..000000000 --- a/src/server/models/settings-location/settings-location.ts +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Copyright 2015-2016 Imply Data, Inc. - * Copyright 2017-2019 Allegro.pl - * - * 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 { BaseImmutable, Property } from "immutable-class"; - -export type Location = "file" | "mysql" | "postgres"; -export type Format = "json" | "yaml"; - -export interface SettingsLocationValue { - location: Location; - uri: string; - table?: string; - format?: Format; - readOnly?: boolean; -} - -export interface SettingsLocationJS { - location: Location; - uri: string; - table?: string; - format?: Format; - readOnly?: boolean; -} - -export class SettingsLocation extends BaseImmutable { - static LOCATION_VALUES: Location[] = ["file", "mysql", "postgres"]; - static DEFAULT_FORMAT: Format = "json"; - static FORMAT_VALUES: Format[] = ["json", "yaml"]; - - static isSettingsLocation(candidate: any): candidate is SettingsLocation { - return candidate instanceof SettingsLocation; - } - - static fromJS(parameters: SettingsLocationJS): SettingsLocation { - return new SettingsLocation(BaseImmutable.jsToValue(SettingsLocation.PROPERTIES, parameters)); - } - - static PROPERTIES: Property[] = [ - { name: "location", possibleValues: SettingsLocation.LOCATION_VALUES }, - { name: "uri" }, - { name: "table", defaultValue: null }, - { name: "format", defaultValue: SettingsLocation.DEFAULT_FORMAT, possibleValues: SettingsLocation.FORMAT_VALUES }, - { name: "readOnly", defaultValue: false } - ]; - - public location: Location; - public uri: string; - public table: string; - public format: Format; - public readOnly: boolean; - - constructor(parameters: SettingsLocationValue) { - super(parameters); - - // remove table if file - if (this.location === "file" && this.table) this.table = null; - } - - public getLocation: () => Location; - public getUri: () => string; - public getTable: () => string; - - public getFormat(): Format { - if (this.format) return this.format; - - // derive format from extension if not set, and possible - if (this.location === "file") { - if (/\.json$/.test(this.uri)) { - return "json"; - } else if (/\.yaml$/.test(this.uri)) { - return "yaml"; - } - } - - return SettingsLocation.DEFAULT_FORMAT; - } - - public getReadOnly: () => boolean; - -} - -BaseImmutable.finalize(SettingsLocation); diff --git a/src/server/utils/settings-store/settings-store.ts b/src/server/utils/settings-store/settings-store.ts index 31c5e84ce..b9c5143ad 100644 --- a/src/server/utils/settings-store/settings-store.ts +++ b/src/server/utils/settings-store/settings-store.ts @@ -15,47 +15,16 @@ * limitations under the License. */ -import * as fs from "fs-promise"; -import * as yaml from "js-yaml"; import { AppSettings } from "../../../common/models/app-settings/app-settings"; -import { inlineVars } from "../../../common/utils/general/general"; -import { Format } from "../../models/settings-location/settings-location"; +import { Nullary } from "../../../common/utils/functional/functional"; -function readSettingsFactory(filepath: string, format: Format, inline = false): () => Promise { - return () => fs.readFile(filepath, "utf-8") - .then(fileData => { - switch (format) { - case "json": - return JSON.parse(fileData); - case "yaml": - return yaml.safeLoad(fileData); - default: - throw new Error(`unsupported format '${format}'`); - } - }) - .then(appSettingsJS => { - if (inline) appSettingsJS = inlineVars(appSettingsJS, process.env); - const appSettings = AppSettings.fromJS(appSettingsJS, { }); - appSettings.validate(); - return appSettings; - }); -} +type SettingsPromise = Nullary>; export class SettingsStore { - static fromTransient(initAppSettings: AppSettings): SettingsStore { - let settingsStore = new SettingsStore(); - settingsStore.readSettings = () => Promise.resolve(initAppSettings); - return settingsStore; - } - - static fromReadOnlyFile(filepath: string, format: Format): SettingsStore { - let settingsStore = new SettingsStore(); - settingsStore.readSettings = readSettingsFactory(filepath, format, true); - return settingsStore; + static create(appSettings: AppSettings): SettingsStore { + return new SettingsStore(() => Promise.resolve(appSettings)); } - public readSettings: () => Promise; - - constructor() { + constructor(public readSettings: SettingsPromise) { } }