Skip to content

Commit

Permalink
Zowe Suite v1.12.0
Browse files Browse the repository at this point in the history
  • Loading branch information
zowe-robot authored Jun 11, 2020
2 parents 8c2ab76 + a12c018 commit d6f6ae1
Show file tree
Hide file tree
Showing 22 changed files with 429 additions and 149 deletions.
17 changes: 17 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Zlux Server Framework Changelog

All notable changes to the Zlux Server Framework package will be documented in this file.
This repo is part of the app-server Zowe Component, and the change logs here may appear on Zowe.org in that section.

## 1.12.0

- Bugfix: Server handles if implementationDefaults or mediationLayer objects are missing
- Bugfix: SSH connecting from terminal-proxy was very slow on node v12+
- Bugfix: Lease info for mediation layer was a value that caused periodic heartbeat failure
- Add ability to state where a plugin path is relative to, instead of just where the server is running.
- Bugfix: Logout now allows security plugins to clear cookies
- Removed tokenInjector from sso-auth, since when SSO is being used token injection logic is not needed anymore.
- Bugfix: When trying to dynamically load a plugin with unmet dependencies, the response from the server would hang
- Support for reading keys, certificates, and certificate authority content from SAF keyrings via safkeyring:// specification in the node.https configuration object
- App server will now reattempt to connect to zss if it doesn't initially

30 changes: 25 additions & 5 deletions lib/apiml.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,8 @@ const MEDIATION_LAYER_INSTANCE_DEFAULTS = {
name: 'MyOwn'
},
leaseInfo: {
durationInSecs: 10,
renewalIntervalInSecs: 10
durationInSecs: 90, // 3 * heartbeatInterval
renewalIntervalInSecs: 30 // heartbeatInterval
},
metadata: {
"routed-services.1.gateway-url": "/api/v1",
Expand Down Expand Up @@ -72,15 +72,33 @@ const MEDIATION_LAYER_INSTANCE_DEFAULTS = {
}
};

function ApimlConnector({ hostName, ipAddr, httpPort, httpsPort, apimlHost,
function ApimlConnector({ hostName, httpPort, httpsPort, apimlHost,
apimlPort, tlsOptions, eurekaOverrides }) {
Object.assign(this, { hostName, ipAddr, httpPort, httpsPort, apimlHost,
Object.assign(this, { hostName, httpPort, httpsPort, apimlHost,
apimlPort, tlsOptions, eurekaOverrides });
this.vipAddress = hostName;
}

ApimlConnector.prototype = {
constructor: ApimlConnector,

setBestIpFromConfig: Promise.coroutine(function *getBaseIpFromConfig(nodeConfig) {
const nodeIps = yield zluxUtil.uniqueIps(nodeConfig.https && nodeConfig.https.ipAddresses ? nodeConfig.https.ipAddresses : nodeConfig.http.ipAddresses);
const eurekaIp = yield zluxUtil.uniqueIps([nodeConfig.mediationLayer.server.hostname]);
if (nodeIps.includes(eurekaIp)) {
this.ipAddr = zluxUtil.getLoopbackAddress(nodeIps);
return this.ipAddr;
} else {
for (let i = 0; i < nodeIps.length; i++) {
if (nodeIps[i] != '0.0.0.0') {
this.ipAddr = nodeIps[i];
return this.ipAddr;
}
}
this.ipAddr = zluxUtil.getLoopbackAddress(nodeIps);
return this.ipAddr;
}
}),

_makeMainInstanceProperties(overrides) {
const instance = Object.assign({}, MEDIATION_LAYER_INSTANCE_DEFAULTS);
Expand Down Expand Up @@ -189,13 +207,15 @@ ApimlConnector.prototype = {
const zluxServerEurekaClient = new eureka(zluxProxyServerInstanceConfig);
//zluxServerEurekaClient.logger.level('debug');
this.zluxServerEurekaClient = zluxServerEurekaClient;
const ipAddr = this.ipAddr;
const appServerUrl = `https://${this.apimlHost}:${this.apimlPort}/ui/v1/${zluxProxyServerInstanceConfig.instance.app}/`;
return new Promise(function (resolve, reject) {
zluxServerEurekaClient.start(function (error) {
if (error) {
log.warn('ZWED0005W', error); //log.warn(error);
reject(error);
} else {
log.info('ZWED0021I'); //log.info('Eureka Client Registered');
log.info('ZWED0021I', ipAddr, appServerUrl); //log.info('Eureka Client Registered from %s. Available at %s');
resolve();
}
});
Expand Down
11 changes: 9 additions & 2 deletions lib/assets/i18n/log/messages_en.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"0":"Main Server Resource File",
"ZWED0020I":"Registering at %s",
"ZWED0021I":"Eureka Client Registered",
"ZWED0021I":"Eureka Client Registered from %s. Available at %s",
"ZWED0022I":"RESERVED: Fork worker %s",
"ZWED0023I":"RESERVED: Restart worker %s",
"ZWED0024I":"RESERVED: Keys=%s",
Expand Down Expand Up @@ -346,5 +346,12 @@
"ZWED0112E":"The server found no plugin implementing the specified default authentication type of %s.",
"ZWED0113E":"The server found no authentication types. Verify that the server configuration file defines server authentication.",
"ZWED0114E":"The server found no plugin implementing the specified default authentication type of %s.",
"ZWED0115E":"RESERVED: Unable to retrieve storage object from cluster. This is probably due to a timeout.\nYou may change the default of '%s' ms by setting 'node.cluster.storageTimeout' within the config. %s"
"ZWED0115E":"RESERVED: Unable to retrieve storage object from cluster. This is probably due to a timeout.\nYou may change the default of '%s' ms by setting 'node.cluster.storageTimeout' within the config. %s",
"ZWED0145E":"Cannot load SAF keyring content outside of z/OS",
"ZWED0146E":"SAF keyring data had no attribute \"%s\". Attributes=",
"ZWED0147E":"SAF keyring data was not found for \"%s\"",
"ZWED0148E":"Exception thrown when reading SAF keyring, e=",
"ZWED0149E":"SAF keyring reference missing userId \"%s\", keyringName \"%s\", or label \"%s\"",
"ZWED0150E":"Cannot load SAF keyring due to missing keyring_js library",
"ZWED0151E":"RESERVED: Env var %s not found"
}
2 changes: 1 addition & 1 deletion lib/auth-manager.js
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ AuthManager.prototype = {
pluginsByCategory = [];
this.authTypes[category] = pluginsByCategory;
}
if (this.config.implementationDefaults[category]) {
if (this.config.implementationDefaults && this.config.implementationDefaults[category]) {
const index = this.config.implementationDefaults[category].plugins.indexOf(plugin.identifier);
if (index != -1) {
pluginsByCategory.splice(index, 0, plugin.identifier);
Expand Down
4 changes: 1 addition & 3 deletions lib/clusterManager.js
Original file line number Diff line number Diff line change
Expand Up @@ -221,9 +221,7 @@ if (cluster.isMaster) {
}

ClusterManager.prototype.setStorageAll = function(pluginId, dict, resultHandler) {
const allStorage = this.storage.getAll(pluginId);
allStorage[pluginId] = dict;
this.storage.setAll(allStorage, pluginId);
this.storage.setAll(dict, pluginId);
return resultHandler(true);
}

Expand Down
2 changes: 1 addition & 1 deletion lib/depgraph.js
Original file line number Diff line number Diff line change
Expand Up @@ -206,7 +206,7 @@ DependencyGraph.prototype = {
const pluginsSorted = [];
let time = 0;
for (let importedPlugin of Object.values(graph)) {
visit(importedPlugin, true);
visit(importedPlugin);
}
return pluginsSorted;

Expand Down
10 changes: 6 additions & 4 deletions lib/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
'use strict';
const Promise = require('bluebird');
const util = require('./util');
const os = require('os');
const WebServer = require('./webserver');
const PluginLoader = require('./plugin-loader');
const makeWebApp = require('./webapp').makeWebApp;
Expand Down Expand Up @@ -214,7 +215,7 @@ Server.prototype = {
((this.startUpConfig.proxiedHost !== undefined) || (this.startUpConfig.proxiedPort !== undefined))) {
const host = this.startUpConfig.proxiedHost;
const port = this.startUpConfig.proxiedPort;
yield checkProxiedHost(host, port);
yield checkProxiedHost(host, port, this.userConfig.agent.handshakeTimeout);
}
this.webApp = makeWebApp(webAppOptions);
yield this.webServer.startListening(this.webApp);
Expand Down Expand Up @@ -307,7 +308,8 @@ Server.prototype = {
for (let i = 0; i < this.langManagers.length; i++) {
yield this.langManagers[i].startAll();
}
if (this.userConfig.node.mediationLayer.enabled) {
if ((this.userConfig.node.mediationLayer && this.userConfig.node.mediationLayer.enabled)
&& (!process.clusterManager || process.clusterManager.getIndexInCluster() == 0)) {
const apimlConfig = this.userConfig.node.mediationLayer;
let apimlTlsOptions;
if (apimlConfig.tlsOptions != null) {
Expand All @@ -320,15 +322,15 @@ Server.prototype = {
//installLogger.info('The https port given to the APIML is: ', webAppOptions.httpsPort);
//installLogger.info('The zlux-apiml config are: ', apimlConfig);
this.apiml = new ApimlConnector({
hostName: 'localhost',
ipAddr: '127.0.0.1',
hostName: os.hostname(),
httpPort: webAppOptions.httpPort,
httpsPort: webAppOptions.httpsPort,
apimlHost: apimlConfig.server.hostname,
apimlPort: apimlConfig.server.port,
tlsOptions: apimlTlsOptions,
eurekaOverrides: apimlConfig.eureka
});
yield this.apiml.setBestIpFromConfig(webAppOptions.serverConfig.node);
yield this.apiml.registerMainServerInstance();
}
}),
Expand Down
40 changes: 36 additions & 4 deletions lib/plugin-loader.js
Original file line number Diff line number Diff line change
Expand Up @@ -562,7 +562,22 @@ PluginLoader.prototype = {
bootstrapLogger.debug("ZWED0121I", util.inspect(pluginPtrDef)); //bootstrapLogger.log(bootstrapLogger.FINER, util.inspect(pluginPtrDef));
let pluginBasePath = pluginPtrDef.pluginLocation;
if (!path.isAbsolute(pluginBasePath)) {
pluginBasePath = this.options.relativePathResolver(pluginBasePath, process.cwd());
let relativeTo = process.cwd();
if (typeof pluginPtrDef.relativeTo == 'string') {
if (pluginPtrDef.relativeTo.startsWith('$')) {
const envVar = process.env[pluginPtrDef.relativeTo.substr(1)];
if (envVar) {
relativeTo = envVar;
} else {
return {location: pluginBasePath,
identifier: pluginPtrDef.identifier,
error: new Error(`ZWED0151E - Env var ${pluginPtrDef.relativeTo} not found`)};
}
} else {
relativeTo = pluginPtrDef.relativeTo;
}
}
pluginBasePath = this.options.relativePathResolver(pluginBasePath, relativeTo);
}
if (!fs.existsSync(pluginBasePath)) {
return {location: pluginBasePath,
Expand Down Expand Up @@ -602,7 +617,22 @@ PluginLoader.prototype = {
bootstrapLogger.log(bootstrapLogger.FINER, util.inspect(pluginPtrDef));
let pluginBasePath = pluginPtrDef.pluginLocation;
if (!path.isAbsolute(pluginBasePath)) {
pluginBasePath = this.options.relativePathResolver(pluginBasePath, process.cwd());
let relativeTo = process.cwd();
if (typeof pluginPtrDef.relativeTo == 'string') {
if (pluginPtrDef.relativeTo.startsWith('$')) {
const envVar = process.env[pluginPtrDef.relativeTo.substr(1)];
if (envVar) {
relativeTo = envVar;
} else {
return {location: pluginBasePath,
identifier: pluginPtrDef.identifier,
error: new Error(`ZWED0151E - Env var ${pluginPtrDef.relativeTo} not found`)};
}
} else {
relativeTo = pluginPtrDef.relativeTo;
}
}
pluginBasePath = this.options.relativePathResolver(pluginBasePath, relativeTo);
}
let pluginDefPath = path.join(pluginBasePath, 'pluginDefinition.json');
jsonUtils.readJSONFileWithCommentsAsync(pluginDefPath).then(function(pluginDef){
Expand Down Expand Up @@ -688,7 +718,7 @@ PluginLoader.prototype = {
});
}
} else {
bootstrapLogger.warn('Could not read plugins dir, e=',e);
bootstrapLogger.warn('Could not read plugins dir, e=',err);
}
});
});
Expand Down Expand Up @@ -735,10 +765,12 @@ PluginLoader.prototype = {
return !this.pluginMap[plugin.identifier];
});
for (const rejectedPlugin of sortedAndRejectedPlugins.rejects) {
bootstrapLogger.warn(`ZWED0033W`, rejectedPlugin.pluginId, zluxUtil.formatErrorStatus(rejectedPlugin.validationError, DependencyGraph.statuses)); //bootstrapLogger.warn(`Could not initialize plugin`
const rejectionError = zluxUtil.formatErrorStatus(rejectedPlugin.validationError, DependencyGraph.statuses);
bootstrapLogger.warn(`ZWED0033W`, rejectedPlugin.pluginId, rejectionError); //bootstrapLogger.warn(`Could not initialize plugin`
//+ ` ${rejectedPlugin.pluginId}: `
//+ zluxUtil.formatErrorStatus(rejectedPlugin.validationError,
//DependencyGraph.statuses));
newPlugins.push(Object.assign(rejectedPlugin, {error: rejectionError}));
}

let isFirstRun = Object.keys(this.pluginMap).length === 0;
Expand Down
28 changes: 22 additions & 6 deletions lib/proxy.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ const WebSocket = require('ws');
const net = require('net');

const proxyLog = util.loggers.proxyLogger;
const RECONNECT_DELAY = 5000;
const DEFAULT_HANDSHAKE_TIMEOUT = 30000;

function convertOptions(request, realHost, realPort, urlPrefix) {
var options = {};
Expand Down Expand Up @@ -301,24 +303,38 @@ function makeWsProxy(host, port, urlPrefix, isHttps) {
};
};

function checkProxiedHost(host, port) {
function checkProxiedHost(host, port, handshakeTimeout) {
const client = new net.Socket();
let timeLeft = handshakeTimeout ? handshakeTimeout : DEFAULT_HANDSHAKE_TIMEOUT;
return new Promise((resolve, reject) => {
client.connect(port, host, () => {
const connect = () => {
client.connect(port, host)
timeLeft = timeLeft - RECONNECT_DELAY;
}

client.once("connect", () => {
client.destroy();
resolve();
});

client.on('error', (e) => {
proxyLog.warn(`ZWED0045W`, host, port); //proxyLog.warn(`Failed to reach the auth services host for address ${host}:${port}`);
if (host === '127.0.0.1') {
proxyLog.warn("ZWED0046W"); //proxyLog.warn("The auth services host system was not " +
if (timeLeft <= 0) {
proxyLog.warn(`ZWED0045W`, host, port); //proxyLog.warn(`Failed to reach the auth services host for address ${host}:${port}`);
if (host === '127.0.0.1') {
proxyLog.warn("ZWED0046W"); //proxyLog.warn("The auth services host system was not " +
//"specified at startup, and defaulted to 127.0.0.1.\n" +
//"Verify that the auth services server is running, " +
//"or specify at startup the remote host and port to connect to. " +
//"See documentation for details.");
}
reject(`Communication with ${host}:${port} failed: ${e.toString()}`);
} else if (e.code == 'ECONNREFUSED') {
proxyLog.warn("Failed to connect to the server, will attempt again...")
setTimeout(connect, RECONNECT_DELAY)
}
reject(`Communication with ${host}:${port} failed: ${e.toString()}`);
});

connect();
});
}

Expand Down
2 changes: 1 addition & 1 deletion lib/unp-constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ exports.EXIT_AUTH = 3;
exports.EXIT_PFX_READ = 4;
exports.EXIT_HTTPS_LOAD = 5;
exports.EXIT_NO_PLUGINS = 6;

exports.EXIT_NO_SAFKEYRING = 7;



Expand Down
8 changes: 4 additions & 4 deletions lib/webapp.js
Original file line number Diff line number Diff line change
Expand Up @@ -178,8 +178,8 @@ function createDataserviceStorage(pluginId) {
return process.clusterManager.deleteStorageByKey(pluginId, key);
}

storageObj.deleteAll = function (key) {
return process.clusterManager.deleteStorageByKey(pluginId, {});
storageObj.deleteAll = function () {
return process.clusterManager.setStorageAll(pluginId, {});
}

contentLogger.debug("'" + pluginId + "' context is loaded with storage object: ", storageObj);
Expand Down Expand Up @@ -1171,7 +1171,7 @@ function WebApp(options){
secure: 'auto'
}
}));
this.loopbackSecret = process.env.loopbackSecret ? process.env.loopbackSecret : 'different',
this.loopbackSecret = process.env.loopbackSecret ? process.env.loopbackSecret : 'different';
process.env.expressSessionSecret = undefined;
process.env.loopbackSecret = undefined;

Expand Down Expand Up @@ -1257,7 +1257,7 @@ WebApp.prototype = {
installStaticHanders() {
const webdir = path.join(path.join(this.options.productDir,
this.options.productCode), 'web');
const rootPage = this.options.rootRedirectURL? this.options.rootRedirectURL
const rootPage = this.options.rootRedirectURL? '.'+this.options.rootRedirectURL
: '/';
if (rootPage != '/') {
this.expressApp.get('/', function(req,res) {
Expand Down
2 changes: 1 addition & 1 deletion lib/webauth.js
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,7 @@ module.exports = function(authManager, cookiePort, isSecurePort) {
} else {
handlerResult = {success: true};
}
result.addHandlerResult(handlerResult, handler, res);
result.addHandlerResult(handlerResult, handler, res, handlerResult.cookies);
if (req.session.authPlugins) {
delete req.session.authPlugins[pluginID];
}
Expand Down
Loading

0 comments on commit d6f6ae1

Please sign in to comment.