Skip to content
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
87768c8
Add zwe validate config and zwe validate bind commands, and use zwe v…
1000TurquoisePogs Aug 8, 2025
d2d7eaa
Cleanup startup and add opt-out
1000TurquoisePogs Aug 8, 2025
fd915e1
Compile fixes and example fixes
1000TurquoisePogs Aug 11, 2025
988ce12
fix compilation errors, fix schema errors, tiny test for alias
MarkAckert Aug 11, 2025
962241b
restore lost `additionalProperties`
MarkAckert Aug 11, 2025
fbd95c3
Fix CLI path and add print of component quantity
1000TurquoisePogs Aug 15, 2025
4427e27
Merge branch 'v3.x/staging' into feature/v3/validate-bind
1000TurquoisePogs Sep 4, 2025
26e3fda
use bind-test pr
1000TurquoisePogs Oct 13, 2025
9b0f87d
Merge branch 'v3.x/staging' into feature/v3/validate-bind
1000TurquoisePogs Oct 13, 2025
d1bfa9d
return manifest.json.template to normal branches
1000TurquoisePogs Oct 14, 2025
d2e3b3a
Merge branch 'v3.x/staging' into feature/v3/validate-bind
1000TurquoisePogs Oct 14, 2025
0380b15
Merge branch 'v3.x/staging' into feature/v3/validate-bind
MarkAckert Oct 14, 2025
d5ccb72
Merge branch 'v3.x/staging' into feature/v3/validate-bind
MarkAckert Oct 15, 2025
0e859af
Change bind-test output to debug, unless error seen. Add debug messag…
1000TurquoisePogs Oct 16, 2025
9111188
Added more debug info. Changed validator schema to have 3 options: do…
1000TurquoisePogs Oct 22, 2025
e274fd7
Add check on how to disable if needed
1000TurquoisePogs Oct 22, 2025
406489b
COrrected property name
1000TurquoisePogs Oct 22, 2025
0b014aa
Merge branch 'v3.x/staging' into feature/v3/validate-bind
MarkAckert Oct 30, 2025
729232a
update startupChecks field names, update logic for reading startupChe…
MarkAckert Oct 31, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

All notable changes to the Zowe Installer will be documented in this file.

## `3.4.0`

- Enhancement: Command `zwe validate` contains subcommands which can be used to validate a Zowe instance in advance of running it.

## `3.3.0`

- Bugfix: YAML lookup for HA instances within "haInstances" was not working when HA instance names were uppercase. Now, the lookup is case insensitive to allow for any casing of HA instance names. [#4370](https://github.com/zowe/zowe-install-packaging/pull/4370)
Expand Down
1 change: 0 additions & 1 deletion bin/commands/config/validate/.help
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
Runs schema validation upon given zowe yaml configuration files.
This command can be used to prove that the zowe configuration is good before starting zowe.
It requires that zowe.useConfigmgr=true or --configmgr are set.
This command can optionally validate enabled components or all components, but otherwise would only validate the zowe core configuration.
3 changes: 2 additions & 1 deletion bin/commands/internal/start/prepare/.errors
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
ZWEL0141E|141|User %s does not have write permission on %s.
ZWEL0302W||You are running the Zowe process under user id IZUSVR. This is not recommended and may impact your z/OS MF server negatively.
ZWEL0317E||Component %s commands.configure ended with rc=%s.
ZWEL0317E||Component %s commands.configure ended with rc=%s.
ZWEL0323E||Certificate validation failed. Fix errors listed before starting Zowe.
9 changes: 6 additions & 3 deletions bin/commands/internal/start/prepare/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import * as javaCI from '../../../../libs/java_ci';
import * as node from '../../../../libs/node';
import * as zosmf from '../../../../libs/zosmf';
import * as zoslib from '../../../../libs/zos';
import * as validateBind from '../../../validate/port/bind/index';

//# This command prepares everything needed to start Zowe.
const cliParameterConfig = std.getenv('ZWE_CLI_PARAMETER_CONFIG');
Expand Down Expand Up @@ -189,20 +190,22 @@ function globalValidate(enabledComponents:string[]): void {
common.printFormattedInfo("ZWELS", "zwe-internal-start-prepare,global_validate", "global validations are successful");
}




// Validate component properties if script exists
function validateComponents(enabledComponents:string[]): any {
common.printFormattedInfo("ZWELS", "zwe-internal-start-prepare,validate_components", "process component validations ...");

if ( !(ZOWE_CONFIG.zowe.launchScript?.startupChecks?.ports === false || ZOWE_CONFIG.zowe.launchScript?.startupChecks?.bypassAll === true)) {
validateBind.execute(true);
}

const componentEnvironments = {};

// reset error counter
let privateErrors = 0;
std.setenv('ZWE_PRIVATE_ERRORS_FOUND','0');

let apimlModulithEnabled = enabledComponents.includes('apiml');

for (let i = 0; i < enabledComponents.length; i++) {
let componentId = enabledComponents[i];
common.printFormattedTrace("ZWELS", "zwe-internal-start-prepare,validate_components", `- checking ${componentId}`);
Expand Down
3 changes: 3 additions & 0 deletions bin/commands/validate/config/.examples
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
zwe validate config -c /path/to/zowe.yaml
zwe validate config -c FILE(/customizations/zowe.yaml):FILE(/defaults/zowe.yaml) --all
zwe validate config -c 'FILE(/path/to/zowe.yaml):PARMLIB(ZOWE.PARMLIB(YAML))'
3 changes: 3 additions & 0 deletions bin/commands/validate/config/.help
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Runs schema validation upon given zowe yaml configuration files.
This command can be used to prove that the zowe configuration is good before starting zowe.
This command can optionally validate enabled components or all components, but otherwise would only validate the zowe core configuration.
2 changes: 2 additions & 0 deletions bin/commands/validate/config/.parameters
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
components||boolean|||||Turns on validation for enabled components.
all||boolean|||||Turns on validation for all components, even disabled ones.
17 changes: 17 additions & 0 deletions bin/commands/validate/config/cli.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
/*
This program and the accompanying materials are made available
under the terms of the Eclipse Public License v2.0 which
accompanies this distribution, and is available at
https://www.eclipse.org/legal/epl-v20.html

SPDX-License-Identifier: EPL-2.0

Copyright Contributors to the Zowe Project.
*/
import * as std from 'cm_std';
import * as index from '../../config/validate/index';
import * as configmgr from '../../../libs/configmgr';

index.execute(std.getenv('ZWE_CLI_PARAMETER_CONFIG'), std.getenv('ZWE_CLI_PARAMETER_COMPONENTS')=='true', std.getenv('ZWE_CLI_PARAMETER_ALL')!='true');

configmgr.cleanupTempDir();
19 changes: 19 additions & 0 deletions bin/commands/validate/config/index.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
#!/bin/sh

#######################################################################
# This program and the accompanying materials are made available
# under the terms of the Eclipse Public License v2.0 which
# accompanies this distribution, and is available at
# https://www.eclipse.org/legal/epl-v20.html
#
# SPDX-License-Identifier: EPL-2.0
#
# Copyright Contributors to the Zowe Project.
#######################################################################

if [ -z "${ZWE_PRIVATE_TMP_MERGED_YAML_DIR}" ]; then
# user-facing command, use tmpdir to not mess up workspace permissions
export ZWE_PRIVATE_TMP_MERGED_YAML_DIR=1
fi
_CEE_RUNOPTS="XPLINK(ON),HEAPPOOLS(OFF),HEAPPOOLS64(OFF)" ${ZWE_zowe_runtimeDirectory}/bin/utils/configmgr -script "${ZWE_zowe_runtimeDirectory}/bin/commands/validate/config/cli.js"

3 changes: 3 additions & 0 deletions bin/commands/validate/port/bind/.examples
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
zwe validate port bind -c /path/to/zowe.yaml
zwe validate port bind -c FILE(/customizations/zowe.yaml):FILE(/defaults/zowe.yaml) -o componentName
zwe validate port bind -c 'FILE(/path/to/zowe.yaml):PARMLIB(ZOWE.PARMLIB(YAML))'
1 change: 1 addition & 0 deletions bin/commands/validate/port/bind/.help
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Checks to see if the network ports requested for use by enabled Zowe components are already occupied.
1 change: 1 addition & 0 deletions bin/commands/validate/port/bind/.parameters
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
component-name,component|o|string|||||Component name to be checked. If not provided, all enabled components are checked.
17 changes: 17 additions & 0 deletions bin/commands/validate/port/bind/cli.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
/*
This program and the accompanying materials are made available
under the terms of the Eclipse Public License v2.0 which
accompanies this distribution, and is available at
https://www.eclipse.org/legal/epl-v20.html

SPDX-License-Identifier: EPL-2.0

Copyright Contributors to the Zowe Project.
*/
import * as std from 'cm_std';
import * as index from './index';
import * as configmgr from '../../../../libs/configmgr';

index.execute(std.getenv("ZWE_CLI_PARAMETER_COMPONENT_NAME"));

configmgr.cleanupTempDir();
19 changes: 19 additions & 0 deletions bin/commands/validate/port/bind/index.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
#!/bin/sh

#######################################################################
# This program and the accompanying materials are made available
# under the terms of the Eclipse Public License v2.0 which
# accompanies this distribution, and is available at
# https://www.eclipse.org/legal/epl-v20.html
#
# SPDX-License-Identifier: EPL-2.0
#
# Copyright Contributors to the Zowe Project.
#######################################################################

if [ -z "${ZWE_PRIVATE_TMP_MERGED_YAML_DIR}" ]; then
# user-facing command, use tmpdir to not mess up workspace permissions
export ZWE_PRIVATE_TMP_MERGED_YAML_DIR=1
fi
_CEE_RUNOPTS="XPLINK(ON),HEAPPOOLS(OFF),HEAPPOOLS64(OFF)" ${ZWE_zowe_runtimeDirectory}/bin/utils/configmgr -script "${ZWE_zowe_runtimeDirectory}/bin/commands/validate/port/available/cli.js"

82 changes: 82 additions & 0 deletions bin/commands/validate/port/bind/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
/*
This program and the accompanying materials are made available
under the terms of the Eclipse Public License v2.0 which
accompanies this distribution, and is available at
https://www.eclipse.org/legal/epl-v20.html

SPDX-License-Identifier: EPL-2.0

Copyright Contributors to the Zowe Project.
*/

import * as std from 'cm_std';
import * as common from '../../../../libs/common';
import * as config from '../../../../libs/config';
import * as component from '../../../../libs/component';
import * as shell from '../../../../libs/shell';

export function execute(quitOnError?: boolean, componentName?: string) {
let enabledComponents = componentName ? [componentName] : component.getEnabledComponents();
let hasErrors = false;
const ZOWE_CONFIG=config.getZoweConfig();
let bindUtilPath = ZOWE_CONFIG.zowe.runtimeDirectory;
if (!bindUtilPath.endsWith('/')) {
bindUtilPath+='/';
}
bindUtilPath+='bin/utils/bind-test';

let myJobname = std.getenv('_BPX_JOBNAME');


for (let i = 0; i < enabledComponents.length; i++) {
let componentName = enabledComponents[i];
let port = ZOWE_CONFIG.components[componentName].port;
if (isComponentInAPIMLModulith(componentName)) {
if (componentName == 'gateway' && !port) {
port = ZOWE_CONFIG.components.apiml.port;
} else if (compopnentName != 'discovery') {
continue;
}
}

if (port) {
let componentManifest: any;
const componentDir = component.findComponentDirectory(componentName);
if (componentDir) {
componentManifest = component.getManifest(componentDir);
}
let jobname = component.getJobnameForComponent(componentName, componentManifest);



let listenAddress = '0.0.0.0';
if (ZOWE_CONFIG.components[componentName].zowe?.network?.server?.listenAddresses) {
listenAddress = ZOWE_CONFIG.components[componentName].zowe.network.server.listenAddresses[0];
} else if (ZOWE_CONFIG.zowe?.network?.server?.listenAddresses) {
listenAddress = ZOWE_CONFIG.zowe.network.server.listenAddresses[0];
}

//TODO this only works on z/OS, but configmgr also only works on z/OS, so at this time the limitation has not been exposed.
if (jobname) {
std.setenv('_BPX_JOBNAME', jobname);
}
let result = shell.execSync(bindUtilPath, '--host', listenAddress, '--port', port);
if (jobname) {
//restore
std.setenv('_BPX_JOBNAME', myJobname);
}
if (result.rc) {
common.printFormattedError(`ZWELS`, `zwe-validate-port-available`, `${componentName} port ${port} not available or command failed.`);
hasErrors = true;
}

}
}
if (!hasErrors) {
common.printFormattedInfo(`ZWELS`, `zwe-validate-port-available`, `Zowe port bind validation passed.`);
} else if (!quitOnError) {
common.printFormattedError(`ZWELS`, `zwe-validate-port-available`, `Zowe port bind validation failed, review output for action items before running Zowe.`);
} else {
common.printErrorAndExit(`Zowe port bind validation failed, review output for action items before running Zowe.`, null, 8);
}
}
64 changes: 61 additions & 3 deletions bin/libs/component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,64 @@ const MANIFEST_SCHEMAS = `${runtimeDirectory}/schemas/manifest-schema.json:${COM
const PLUGIN_DEF_SCHEMA_ID = "https://zowe.org/schemas/v2/appfw-plugin-definition";
const PLUGIN_DEF_SCHEMAS = `${runtimeDirectory}/components/app-server/schemas/plugindefinition-schema.json`;

const INDIVIDUAL_APIML_COMPONENTS = ['gateway', 'discovery', 'api-catalog', 'caching-service', 'zaas'];

export function isComponentInAPIMLModulith(componentName: string): boolean {
let apimlModulith = ZOWE_CONFIG.components.apiml?.enabled;
return apimlModulith && INDIVIDUAL_APIML_COMPONENTS.includes(componentName);
}

export function getJobnameForComponent(componentName: string, componentManifest?: any): string {
let apimlModulith = ZOWE_CONFIG.components.apiml?.enabled;
let jobnamePrefix = ZOWE_CONFIG.zowe.job?.prefix || '';
if (componentManifest && componentManifest.jobnameSuffix) {
return jobnamePrefix + componentManifest.jobnameSuffix;
} else if (componentManifest && componentManifest.jobname) {
return componentManifest.jobname;
} else {
switch (componentName) {
case 'gateway':
return jobnamePrefix+'AG';
case 'discovery':
if (apimlModulith) {
return jobnamePrefix+'AG';
} else {
return jobnamePrefix+'AD';
}
case 'api-catalog':
if (apimlModulith) {
return jobnamePrefix+'AG';
} else {
return jobnamePrefix+'AC';
}
case 'caching-service':
if (apimlModulith) {
return jobnamePrefix+'AG';
} else {
return jobnamePrefix+'CS';
}
case 'zaas':
if (apimlModulith) {
return jobnamePrefix+'AG';
} else {
return jobnamePrefix+'AZ';
}
case 'zss':
return jobnamePrefix+'SZ';
case 'app-server':
if ((std.getenv('ZLUX_NO_CLUSTER') == '1') || (ZOWE_CONFIG.zowe.environments?.ZLUX_NO_CLUSTER == 1)) {
return jobnamePrefix+'DS';
} else {
//its probably the current jobname, but we have no field to gather that.
return '';
}
default:
//we dont know
return '';
}
}
}

// This intentionally lies about individual apiml components for backward compatibility.
// If the apiml modulith is enabled, all are considered enabled.
export function getEnabledComponents() {
Expand All @@ -52,13 +110,13 @@ export function getEnabledComponents() {
let components = Object.keys(haConfig.components);
let enabled: string[] = [];
let apimlModulithEnabled = haConfig.components.apiml.enabled == true;
let individualApimlComponents = ['gateway', 'discovery', 'api-catalog', 'caching-service', 'zaas'];


if (apimlModulithEnabled) {
enabled = enabled.concat(individualApimlComponents);
enabled = enabled.concat(INDIVIDUAL_APIML_COMPONENTS);

//do not process individual apiml components further
components = components.filter(name => !individualApimlComponents.includes(name));
components = components.filter(name => !INDIVIDUAL_APIML_COMPONENTS.includes(name));
}

components.forEach((key) => {
Expand Down
3 changes: 3 additions & 0 deletions files/defaults.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,9 @@ zowe:
logLevel: "info"
# Set to "exit" if you'd like startup to exit if any component has an error in the configure stage, otherwise zwe will warn but continue.
onComponentConfigureFail: "warn"
startupChecks:
bypassAll: false
ports: true

# >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
# How we want to verify SSL certificates of services. Valid values are:
Expand Down
10 changes: 10 additions & 0 deletions schemas/manifest-schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,16 @@
"$ref": "/schemas/v2/server-common#zoweReverseDomainNotation",
"description": "Defines a long, computer-readable identifier of the component. If the component is hosted as one of the projects in Open Mainframe Project, the identifier also matches the component path in the Zowe Artifactory. For example, 'org.zowe.explorer-jes' is a valid identifier. You can locate the component's official releases by looking into the 'libs-release-local/org/zowe/explorer-jes/' directory in the Zowe Artifactory (https://zowe.jfrog.io/ui/repos/tree/General/libs-release-local%2Forg%2Fzowe%2Fexplorer-jes)"
},
"jobname": {
"type": "string",
"description": "States which jobname the component may use",
"maxLength": 8
},
"jobnameSuffix": {
"type": "string",
"description": "States which jobname suffix the component may use combined with the Zowe job prefix as a full job name",
"maxLength": 8
},
"version": {
"$ref": "/schemas/v2/server-common#zoweSemverVersion",
"description": "This is the current version of the component without the prefix of v. For example, 2.0.0 is a valid version value."
Expand Down
19 changes: 16 additions & 3 deletions schemas/zowe-yaml-schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -587,15 +587,15 @@
},
"logDirectory": {
"$ref": "/schemas/v2/server-common#zowePath",
"description": "Path to where you want to store Zowe log files."
"description": "Path to where you want to store Zowe log files. This cannot reside within the runtime directory."
},
"workspaceDirectory": {
"$ref": "/schemas/v2/server-common#zowePath",
"description": "Path to where you want to store Zowe workspace files. Zowe workspace are used by Zowe component runtime to store temporary files."
"description": "Path to where you want to store Zowe workspace files. Zowe workspace are used by Zowe component runtime to store temporary files. This cannot reside within the runtime directory."
},
"extensionDirectory": {
"$ref": "/schemas/v2/server-common#zowePath",
"description": "Path to where you want to store Zowe extensions. \"zwe components install\" will install new extensions into this directory."
"description": "Path to where you want to store Zowe extensions. \"zwe components install\" will install new extensions into this directory. This cannot reside within the runtime directory."
},
"job": {
"type": "object",
Expand Down Expand Up @@ -692,6 +692,7 @@
"launchScript": {
"type": "object",
"description": "Customize Zowe launch scripts (zwe commands) behavior.",
"additionalProperties": false,
"properties": {
"logLevel": {
"type": "string",
Expand All @@ -703,6 +704,18 @@
"description": "Chooses how 'zwe start' behaves if a component configure script fails",
"enum": ["warn", "exit"],
"default": "warn"
},
"startupChecks": {
"bypassAll": {
"type": "boolean",
"default": false,
"description": "Skips all startup checks listed within the zowe.launchScript.startupChecks section"
},
"ports": {
"type": "boolean",
"default": true,
"description": "Checks the port for each enabled component to ensure Zowe can bind to it and that it is not already occupied by some other program"
}
}
}
},
Expand Down
Loading