Skip to content

Commit

Permalink
Zowe Suite v1.22.0
Browse files Browse the repository at this point in the history
  • Loading branch information
zowe-robot authored Apr 14, 2021
2 parents 7a99f12 + 6d5a4e7 commit 4bde020
Show file tree
Hide file tree
Showing 10 changed files with 394 additions and 149 deletions.
35 changes: 35 additions & 0 deletions .github/pull_request_template.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<!-- Thank you for submitting a PR to Zowe! To help us understand, test, and give feedback on your code, please fill in the details below. -->

## Proposed changes
<!-- Describe the big picture of your changes here to communicate to the maintainers why we should accept this pull request. If it fixes a bug or resolves a feature request, be sure to link to that issue. -->

This PR addresses Issue: [*Link to Github issue within https://github.com/zowe/zlux/issues* if any]

This PR depends upon the following PRs:

## Type of change
Please delete options that are not relevant.
- [ ] Bug fix (non-breaking change which fixes an issue)
- [ ] New feature (non-breaking change which adds functionality)
- [ ] Change in a documentation
- [ ] Refactor the code
- [ ] Chore, repository cleanup, updates the dependencies.
- [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected)

## PR Checklist
Please delete options that are not relevant.
- [ ] If the changes in this PR are meant for the next release / mainline, this PR targets the "staging" branch.
- [ ] My code follows the style guidelines of this project (see: [Contributing guideline](https://github.com/zowe/zlux/blob/master/CONTRIBUTING.md))
- [ ] I have commented my code, particularly in hard-to-understand areas
- [ ] I have made corresponding changes to the documentation
- [ ] New and existing unit tests pass locally with my changes
- [ ] video or image is included if visual changes are made
- [ ] Relevant update to CHANGELOG.md
- [ ] My changes generate no new warnings
- [ ] I have added tests that prove my fix is effective or that my feature works, or describe a test method below

## Testing
<!-- Describe how this code should be tested. I've you've added an automated or unit test, then describe how to run it. Otherwise, describe how you have tested it and how others should test it. -->

## Further comments
<!-- If this is a relatively large or complex change, kick off the discussion by explaining why you chose the solution you did and what alternatives you considered, or if there are follow-up tasks and TODOs etc... -->
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,12 @@
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.21.0

- Bugfix: Use hostname given by zowe config in order to avoid errors from the hostname certificate matching when accessing the app server through APIML
- Enhancement: app-server will contact zss through apiml if apiml is enabled and app-server finds that zss is accessible from apiml
- sso-auth plugin no longer keeps zss cookie within app-server; the cookie will now be sent to and used from the browser, to facilitate high availability

## 1.19.0

- Increased default retry attempts to connect to api discovery server from 3 to 100, for a total retry duration of a little over 15 minutes.
Expand Down
65 changes: 65 additions & 0 deletions lib/apiml.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,14 @@
const Promise = require("bluebird");
const eureka = require('eureka-js-client').Eureka;
const zluxUtil = require('./util');
const https = require('https');

const log = zluxUtil.loggers.apiml;

const DEFAULT_AGENT_CHECK_TIMEOUT = 30000;
const AGENT_CHECK_RECONNECT_DELAY = 5000;


const MEDIATION_LAYER_EUREKA_DEFAULTS = {
"preferSameZone": false,
"maxRetries": 100,
Expand Down Expand Up @@ -100,6 +105,66 @@ ApimlConnector.prototype = {
return this.ipAddr;
}
}),


checkAgent(timeout, serviceName) {
let timer = timeout ? timeout : DEFAULT_AGENT_CHECK_TIMEOUT;
const end = Date.now() + timer;

return new Promise((resolve, reject) => {
const options = Object.assign({
host: this.apimlHost,
port: this.apimlPort,
method: 'GET',
path: `/eureka/apps/${serviceName}`,
headers: {'accept':'application/json'}
}, this.tlsOptions);
//dont need client auth, apiml will reject if these are unknown to apiml anyway.
delete options.cert;
delete options.key;


const issueRequest = () => {
if (Date.now() > end) {
log.warn(`ZWED0045`, this.apimlHost, this.apimlPort);
return reject(new Error(`Call timeout when fetching agent status from APIML`));
}

let data = [];

const req = https.request(options, (res) => {
res.on('data', (chunk) => data.push(chunk));
res.on('end', () => {
log.debug(`Query rc=`,res.statusCode);
if (res.statusCode == 200) {
resolve();
} else {
let dataJson;
try {
if (data.length > 0) {
dataJson = JSON.parse(Buffer.concat(data).toString());
}
} catch (e) {
//leave undefined
}
log.debug(`Could not find agent on APIML. Trying again in ${AGENT_CHECK_RECONNECT_DELAY}ms. Code=${res.statusCode}. Body=${dataJson}`);
setTimeout(issueRequest, AGENT_CHECK_RECONNECT_DELAY);
}
});
});
req.setTimeout(timer,()=> {
reject(new Error(`Call timeout when fetching agent status from APIML`));
});
req.on('error', (error) => {
log.warn("APIML query error:", error.message);
setTimeout(issueRequest, AGENT_CHECK_RECONNECT_DELAY);
});
req.end();
};

issueRequest();
});
},

_makeMainInstanceProperties(overrides) {
const instance = Object.assign({}, MEDIATION_LAYER_INSTANCE_DEFAULTS);
Expand Down
112 changes: 75 additions & 37 deletions lib/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,12 @@ Server.prototype = {
},

start: Promise.coroutine(function*() {
//this parameter has been duplicated all over the code, trying to consolidate.
const allowInvalidTLSProxy = this.startUpConfig.allowInvalidTLSProxy || this.userConfig.node.allowInvalidTLSProxy;
this.userConfig.node.allowInvalidTLSProxy = allowInvalidTLSProxy;

const firstWorker = !(process.clusterManager && process.clusterManager.getIndexInCluster() != 0);

if (this.userConfig.node.childProcesses) {
for (const proc of this.userConfig.node.childProcesses) {
if (!process.clusterManager || process.clusterManager.getIndexInCluster() == 0 || !proc.once) {
Expand Down Expand Up @@ -181,19 +187,19 @@ Server.prototype = {
//+ ' JSON format');
throw new Error("ZWED0028E - Config invalid")
}
util.deepFreeze(this.userConfig);
this.webServer.setConfig(wsConfig);
const httpPort = wsConfig.http ? wsConfig.http.port : undefined;
const httpsPort = wsConfig.https ? wsConfig.https.port : undefined;
const cookiePort = httpsPort ? httpsPort : httpPort;
const webAppOptions = {
hostname: this.userConfig.node.hostname ? this.userConfig.node.hostname : os.hostname(),
httpPort: httpPort,
httpsPort: httpsPort,
productCode: this.appConfig.productCode,
productDir: this.userConfig.productDir,
proxiedHost: this.startUpConfig.proxiedHost,
proxiedPort: this.startUpConfig.proxiedPort,
allowInvalidTLSProxy: this.startUpConfig.allowInvalidTLSProxy,
allowInvalidTLSProxy: allowInvalidTLSProxy,
rootRedirectURL: this.appConfig.rootRedirectURL,
rootServices: this.appConfig.rootServices,
serverConfig: this.userConfig,
Expand All @@ -205,18 +211,74 @@ Server.prototype = {
newPluginHandler: (pluginDef) => this.newPluginSubmitted(pluginDef),
auth: WebAuth(this.authManager, cookiePort, cookiePort === httpsPort),
pluginLoader: this.pluginLoader,
langManagers: this.langManagers
langManagers: this.langManagers,
tlsOptions: this.webServer.getTlsOptions()
};
/*
if either proxiedHost or proxiedPort were specified, then there is intent to connect to an agent.
However, zlux may be run without one, so if both are undefined then don't check for connection.
*/
if (process.platform !== 'os390' &&
((this.startUpConfig.proxiedHost !== undefined) || (this.startUpConfig.proxiedPort !== undefined))) {
const host = this.startUpConfig.proxiedHost;
const port = this.startUpConfig.proxiedPort;
yield checkProxiedHost(host, port, this.userConfig.agent.handshakeTimeout);
if (this.userConfig.node.mediationLayer &&
this.userConfig.node.mediationLayer.server &&
!this.userConfig.node.mediationLayer.server.gatewayHostname) {
this.userConfig.node.mediationLayer.server.gatewayHostname = this.userConfig.node.mediationLayer.server.hostname;
}
let usingApiml = this.userConfig.node.mediationLayer && this.userConfig.node.mediationLayer.enabled;
if (usingApiml) {
const apimlConfig = this.userConfig.node.mediationLayer;
if (firstWorker) {
let apimlTlsOptions;
if (apimlConfig.tlsOptions != null) {
apimlTlsOptions = {};
WebServer.readTlsOptionsFromConfig(apimlConfig.tlsOptions, apimlTlsOptions);
} else {
apimlTlsOptions = this.webServer.getTlsOptions();
}
installLogger.debug('ZWED0033I', JSON.stringify(webAppOptions.httpPort), JSON.stringify(webAppOptions.httpsPort), JSON.stringify(apimlConfig)); //installLogger.info('The http port given to the APIML is: ', webAppOptions.httpPort);
//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: webAppOptions.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();
}

if (this.userConfig.agent
&& this.userConfig.agent.mediationLayer
&& this.userConfig.agent.mediationLayer.enabled
&& this.userConfig.agent.mediationLayer.serviceName
&& this.userConfig.node.mediationLayer.server.gatewayPort) {
//at this point, we expect zss to also be attached to the mediation layer, so lets adjust.
webAppOptions.proxiedHost = apimlConfig.server.hostname;
webAppOptions.proxiedPort = this.userConfig.node.mediationLayer.server.gatewayPort;
if (firstWorker) {
yield this.apiml.checkAgent(this.userConfig.agent.handshakeTimeout,
this.userConfig.agent.mediationLayer.serviceName);
}
} else if (this.userConfig.agent && this.userConfig.agent.mediationLayer) {
this.userConfig.agent.mediationLayer.enabled = false;
}
}
if (this.userConfig.agent && !usingApiml) {
if (this.userConfig.agent.mediationLayer && this.userConfig.agent.mediationLayer.enabled) {
this.userConfig.agent.mediationLayer.enabled = false;
}
if (firstWorker &&
(process.platform !== 'os390') &&
((this.startUpConfig.proxiedHost !== undefined) || (this.startUpConfig.proxiedPort !== undefined))){
/*
if either proxiedHost or proxiedPort were specified, then there is intent to connect to an agent.
However, zlux may be run without one, so if both are undefined then don't check for connection.
*/
yield checkProxiedHost(webAppOptions.proxiedHost,
webAppOptions.proxiedPort,
this.userConfig.agent.handshakeTimeout);
}
}
util.deepFreeze(this.userConfig);
this.webApp = makeWebApp(webAppOptions);
yield this.webServer.startListening(this.webApp);
this.webApp.init();
Expand All @@ -234,6 +296,7 @@ Server.prototype = {
}
}
let messageIssued = false;
this.pluginLoader.setTlsOptions(this.startUpConfig.allowInvalidTLSProxy, this.webServer.getTlsOptions());
this.pluginLoader.on('pluginFound', util.asyncEventListener(event => {
pluginCount++;
if (event.data.error) {
Expand Down Expand Up @@ -308,31 +371,6 @@ Server.prototype = {
for (let i = 0; i < this.langManagers.length; i++) {
yield this.langManagers[i].startAll();
}
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) {
apimlTlsOptions = {};
WebServer.readTlsOptionsFromConfig(apimlConfig.tlsOptions, apimlTlsOptions);
} else {
apimlTlsOptions = this.webServer.getTlsOptions();
}
installLogger.debug('ZWED0033I', JSON.stringify(webAppOptions.httpPort), JSON.stringify(webAppOptions.httpsPort), JSON.stringify(apimlConfig)); //installLogger.info('The http port given to the APIML is: ', webAppOptions.httpPort);
//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: 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();
}
}),

pluginLoadingFinished(adr, percent, loaded, total) {
Expand Down
34 changes: 15 additions & 19 deletions lib/plugin-loader.js
Original file line number Diff line number Diff line change
Expand Up @@ -573,6 +573,7 @@ function PluginLoader(options) {
this.options = zluxUtil.makeOptionsObject(defaultOptions, options);
this.plugins = [];
this.pluginMap = {};
this.tlsOptions = null;
};
PluginLoader.prototype = {
constructor: PluginLoader,
Expand Down Expand Up @@ -865,27 +866,18 @@ PluginLoader.prototype = {
return new Promise((complete, fail)=> {
let appServerComp = {};
let agentComp = {};
let host;
let port;
const requestOptions = zluxUtil.getAgentRequestOptions(config, this.tlsOptions, false);

appServerComp.os = process.platform; // Operating system
appServerComp.cpu = process.arch; // CPU architecture

if (config && config.agent && config.agent.host) {
host = config.agent.host;
if (config.agent.http) {
port = config.agent.http.port;
} else if (config.agent.https) {
port = config.agent.https.port;
}
}
if (!host || !port) {
if (!requestOptions) {
complete();
} else {
let url = 'http://' + host + ':' + port + '/server/agent/environment';

const httpApi = requestOptions.protocol == 'https:' ? https : http;
requestOptions.path = '/server/agent/environment';
return new Promise((resolve, reject) => { /* Obtains and stores environment information from agent */
http.get(url, (res) => {
httpApi.get(requestOptions, (res) => {
const { statusCode } = res; // TODO: Check status code for bad status
const contentType = res.headers['content-type'];

Expand Down Expand Up @@ -918,12 +910,11 @@ PluginLoader.prototype = {
bootstrapLogger.severe(e.message);
resolve();
});

}).then(() => { /* Obtains and stores the endpoints exposed by the agent */

url = 'http://' + host + ':' + port + '/server/agent/services';

requestOptions.path = '/server/agent/services';
return new Promise((resolve, reject) => {
http.get(url, (res) => {
httpApi.get(requestOptions, (res) => {
const { statusCode } = res; // TODO: Check status code for bad status
const contentType = res.headers['content-type'];

Expand Down Expand Up @@ -1021,7 +1012,12 @@ PluginLoader.prototype = {
}
}
},


setTlsOptions: function (allowInvalidTLSProxy, tlsOptions) {
this.tlsOptions = {rejectUnauthorized: !allowInvalidTLSProxy};
Object.assign(this.tlsOptions, tlsOptions);
},

issueRefreshFinish() {
this.emit('refreshFinish', {});
},
Expand Down
Loading

0 comments on commit 4bde020

Please sign in to comment.