interface WorkbenchConfig {
API_HOST: string;
- VOCABULARY_URL: string;
- FILE_VIEWERS_CONFIG_URL: string;
+ VOCABULARY_URL?: string;
+ FILE_VIEWERS_CONFIG_URL?: string;
}
export interface ClusterConfigJSON {
ClusterID: string;
- RemoteClusters: {
+ RemoteClusters: {
[key: string]: {
ActivateUsers: boolean
Host: string
Scheme: string
}
};
+ Mail?: {
+ SupportEmailAddress: string;
+ };
Services: {
Controller: {
ExternalURL: string
}
WebDAV: {
ExternalURL: string
+ },
+ WebDAVDownload: {
+ ExternalURL: string
+ },
+ WebShell: {
+ ExternalURL: string
}
};
Workbench: {
ArvadosDocsite: string;
VocabularyURL: string;
FileViewersConfigURL: string;
+ WelcomePageHTML: string;
+ InactivePageHTML: string;
+ SSHHelpPageHTML: string;
+ SSHHelpHostSuffix: string;
+ SiteName: string;
+ };
+ Login: {
+ LoginCluster: string;
+ Google: {
+ Enable: boolean;
+ }
+ LDAP: {
+ Enable: boolean;
+ }
+ OpenIDConnect: {
+ Enable: boolean;
+ }
+ PAM: {
+ Enable: boolean;
+ }
+ SSO: {
+ Enable: boolean;
+ }
+ };
+ Collections: {
+ ForwardSlashNameSubstitution: string;
};
}
workbench2Url: string;
vocabularyUrl: string;
fileViewersConfigUrl: string;
+ loginCluster: string;
+ clusterConfig: ClusterConfigJSON;
+ apiRevision: number;
}
+export const buildConfig = (clusterConfigJSON: ClusterConfigJSON): Config => {
+ const config = new Config();
+ config.rootUrl = clusterConfigJSON.Services.Controller.ExternalURL;
+ config.baseUrl = `${config.rootUrl}/${ARVADOS_API_PATH}`;
+ config.uuidPrefix = clusterConfigJSON.ClusterID;
+ config.websocketUrl = clusterConfigJSON.Services.Websocket.ExternalURL;
+ config.workbench2Url = clusterConfigJSON.Services.Workbench2.ExternalURL;
+ config.workbenchUrl = clusterConfigJSON.Services.Workbench1.ExternalURL;
+ config.keepWebServiceUrl = clusterConfigJSON.Services.WebDAVDownload.ExternalURL;
+ config.loginCluster = clusterConfigJSON.Login.LoginCluster;
+ config.clusterConfig = clusterConfigJSON;
+ config.apiRevision = 0;
+ mapRemoteHosts(clusterConfigJSON, config);
+ return config;
+};
+
+const getApiRevision = async (apiUrl: string) => {
+ try {
+ const dd = (await Axios.get<any>(`${apiUrl}/${DISCOVERY_DOC_PATH}`)).data;
+ return parseInt(dd.revision, 10) || 0;
+ } catch {
+ console.warn("Unable to get API Revision number, defaulting to zero. Some features may not work properly.");
+ return 0;
+ }
+};
+
+const removeTrailingSlashes = (config: ClusterConfigJSON): ClusterConfigJSON => {
+ const svcs: any = {};
+ Object.keys(config.Services).map((s) => {
+ svcs[s] = config.Services[s];
+ if (svcs[s].hasOwnProperty('ExternalURL')) {
+ svcs[s].ExternalURL = svcs[s].ExternalURL.replace(/\/+$/, '');
+ }
+ });
+ return {...config, Services: svcs};
+};
+
export const fetchConfig = () => {
return Axios
.get<WorkbenchConfig>(WORKBENCH_CONFIG_URL + "?nocache=" + (new Date()).getTime())
.then(response => response.data)
- .catch(() => Promise.resolve(getDefaultConfig()))
- .then(workbenchConfig => Axios
- .get<ClusterConfigJSON>(getClusterConfigURL(workbenchConfig.API_HOST))
- .then(response => {
-
- const config = new Config();
- const clusterConfigJSON = response.data;
- const docsite = clusterConfigJSON.Workbench.ArvadosDocsite;
- const warnDeprecation = (varName: string) => console.warn(
-`A value for ${varName} was found in ${WORKBENCH_CONFIG_URL}. This configuration is deprecated. \
-Please use the centralized configuration instead. See more at ${docsite}admin/config-migration.html`);
+ .catch(() => {
+ console.warn(`There was an exception getting the Workbench config file at ${WORKBENCH_CONFIG_URL}. Using defaults instead.`);
+ return Promise.resolve(getDefaultConfig());
+ })
+ .then(workbenchConfig => {
+ if (workbenchConfig.API_HOST === undefined) {
+ throw new Error(`Unable to start Workbench. API_HOST is undefined in ${WORKBENCH_CONFIG_URL} or the environment.`);
+ }
+ return Axios.get<ClusterConfigJSON>(getClusterConfigURL(workbenchConfig.API_HOST)).then(async response => {
+ const clusterConfigJSON = removeTrailingSlashes(response.data);
+ const apiRevision = await getApiRevision(clusterConfigJSON.Services.Controller.ExternalURL);
+ const config = { ...buildConfig(clusterConfigJSON), apiRevision };
+ const warnLocalConfig = (varName: string) => console.warn(
+ `A value for ${varName} was found in ${WORKBENCH_CONFIG_URL}. To use the Arvados centralized configuration instead, \
+remove the entire ${varName} entry from ${WORKBENCH_CONFIG_URL}`);
// Check if the workbench config has an entry for vocabulary and file viewer URLs
// If so, use these values (even if it is an empty string), but print a console warning.
- // Otherwise, use the cluster config or default values.
+ // Otherwise, use the cluster config.
let fileViewerConfigUrl;
if (workbenchConfig.FILE_VIEWERS_CONFIG_URL !== undefined) {
- warnDeprecation("FILE_VIEWERS_CONFIG_URL");
+ warnLocalConfig("FILE_VIEWERS_CONFIG_URL");
fileViewerConfigUrl = workbenchConfig.FILE_VIEWERS_CONFIG_URL;
}
else {
let vocabularyUrl;
if (workbenchConfig.VOCABULARY_URL !== undefined) {
- warnDeprecation("VOCABULARY_URL");
+ warnLocalConfig("VOCABULARY_URL");
vocabularyUrl = workbenchConfig.VOCABULARY_URL;
}
else {
}
config.vocabularyUrl = vocabularyUrl;
- config.rootUrl = clusterConfigJSON.Services.Controller.ExternalURL;
- config.baseUrl = `${config.rootUrl}/${ARVADOS_API_PATH}`;
- config.uuidPrefix = clusterConfigJSON.ClusterID;
- config.websocketUrl = clusterConfigJSON.Services.Websocket.ExternalURL;
- config.workbench2Url = clusterConfigJSON.Services.Workbench2.ExternalURL;
- config.workbenchUrl = clusterConfigJSON.Services.Workbench1.ExternalURL;
- config.keepWebServiceUrl = clusterConfigJSON.Services.WebDAV.ExternalURL;
- mapRemoteHosts(clusterConfigJSON, config);
-
return { config, apiHost: workbenchConfig.API_HOST };
- })
- );
+ });
+ });
};
// Maps remote cluster hosts and removes the default RemoteCluster entry
export const mapRemoteHosts = (clusterConfigJSON: ClusterConfigJSON, config: Config) => {
config.remoteHosts = {};
- Object.keys(clusterConfigJSON.RemoteClusters).forEach (k => { config.remoteHosts[k] = clusterConfigJSON.RemoteClusters[k].Host; });
+ Object.keys(clusterConfigJSON.RemoteClusters).forEach(k => { config.remoteHosts[k] = clusterConfigJSON.RemoteClusters[k].Host; });
delete config.remoteHosts["*"];
};
+export const mockClusterConfigJSON = (config: Partial<ClusterConfigJSON>): ClusterConfigJSON => ({
+ ClusterID: "",
+ RemoteClusters: {},
+ Services: {
+ Controller: { ExternalURL: "" },
+ Workbench1: { ExternalURL: "" },
+ Workbench2: { ExternalURL: "" },
+ Websocket: { ExternalURL: "" },
+ WebDAV: { ExternalURL: "" },
+ WebDAVDownload: { ExternalURL: "" },
+ WebShell: { ExternalURL: "" },
+ },
+ Workbench: {
+ ArvadosDocsite: "",
+ VocabularyURL: "",
+ FileViewersConfigURL: "",
+ WelcomePageHTML: "",
+ InactivePageHTML: "",
+ SSHHelpPageHTML: "",
+ SSHHelpHostSuffix: "",
+ SiteName: "",
+ },
+ Login: {
+ LoginCluster: "",
+ Google: {
+ Enable: false,
+ },
+ LDAP: {
+ Enable: false,
+ },
+ OpenIDConnect: {
+ Enable: false,
+ },
+ PAM: {
+ Enable: false,
+ },
+ SSO: {
+ Enable: false,
+ },
+ },
+ Collections: {
+ ForwardSlashNameSubstitution: "",
+ },
+ ...config
+});
+
export const mockConfig = (config: Partial<Config>): Config => ({
baseUrl: "",
keepWebServiceUrl: "",
workbenchUrl: "",
workbench2Url: "",
vocabularyUrl: "",
- fileViewersConfigUrl: ""
+ fileViewersConfigUrl: "",
+ loginCluster: "",
+ clusterConfig: mockClusterConfigJSON({}),
+ apiRevision: 0,
+ ...config
});
-const getDefaultConfig = (): WorkbenchConfig => ({
- API_HOST: process.env.REACT_APP_ARVADOS_API_HOST || "",
- VOCABULARY_URL: "",
- FILE_VIEWERS_CONFIG_URL: "",
-});
+const getDefaultConfig = (): WorkbenchConfig => {
+ let apiHost = "";
+ const envHost = process.env.REACT_APP_ARVADOS_API_HOST;
+ if (envHost !== undefined) {
+ console.warn(`Using default API host ${envHost}.`);
+ apiHost = envHost;
+ }
+ else {
+ console.warn(`No API host was found in the environment. Workbench may not be able to communicate with Arvados components.`);
+ }
+ return {
+ API_HOST: apiHost,
+ VOCABULARY_URL: undefined,
+ FILE_VIEWERS_CONFIG_URL: undefined,
+ };
+};
export const ARVADOS_API_PATH = "arvados/v1";
-export const CLUSTER_CONFIG_URL = "arvados/v1/config";
-export const getClusterConfigURL = (apiHost: string) => `${window.location.protocol}//${apiHost}/${CLUSTER_CONFIG_URL}?nocache=${(new Date()).getTime()}`;
\ No newline at end of file
+export const CLUSTER_CONFIG_PATH = "arvados/v1/config";
+export const DISCOVERY_DOC_PATH = "discovery/v1/apis/arvados/v1/rest";
+export const getClusterConfigURL = (apiHost: string) => `${window.location.protocol}//${apiHost}/${CLUSTER_CONFIG_PATH}?nocache=${(new Date()).getTime()}`;