Skip to content

Commit 4979016

Browse files
committed
better detection of NODEJSAPPs
1 parent b0213e9 commit 4979016

File tree

4 files changed

+135
-46
lines changed

4 files changed

+135
-46
lines changed

__tests__/api/BundlePush/BundlePusher.test.ts

Lines changed: 56 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1043,6 +1043,13 @@ describe("BundlePusher01", () => {
10431043
zosmfProfile = { host: "wibble", user: "user" };
10441044
sshProfile = { host: "wibble", user: "user" };
10451045
cicsProfile = { host: "wibble", user: "user", password: "thisIsntReal", cicsPlex: "12345678" };
1046+
readSpy = jest.spyOn(fs, "readFileSync").mockImplementation((data: string) => {
1047+
if (data.indexOf("cics.xml") > -1) {
1048+
return "<manifest xmlns=\"http://www.ibm.com/xmlns/prod/cics/bundle\">" +
1049+
"<define name=\"test\" type=\"http://www.ibm.com/xmlns/prod/cics/bundle/WIBBLE\" path=\"nodejsapps/test.nodejsapp\"></define>" +
1050+
"</manifest>";
1051+
}
1052+
});
10461053
cmciSpy.mockImplementation((cicsSession: any, regionData: cmci.IResourceParms) => {
10471054
if (regionData.name === "CICSRegion") {
10481055
return { response: {
@@ -1112,7 +1119,14 @@ describe("BundlePusher01", () => {
11121119
sshProfile = { host: "wibble", user: "user" };
11131120
cicsProfile = { host: "wibble", user: "user", password: "thisIsntReal" };
11141121
submitSpy = jest.spyOn(SubmitJobs, "submitJclString").mockImplementation(() =>
1115-
[{ddName: "SYSTSPRT", stepName: "DFHDPLOY", data: "DFHRL2055I http://www.ibm.com/xmlns/prod/cics/bundle/NODEJSAPP"}] );
1122+
[{ddName: "SYSTSPRT", stepName: "DFHDPLOY", data: "DFHRL2055I"}] );
1123+
readSpy = jest.spyOn(fs, "readFileSync").mockImplementation((data: string) => {
1124+
if (data.indexOf("cics.xml") > -1) {
1125+
return "<manifest xmlns=\"http://www.ibm.com/xmlns/prod/cics/bundle\">" +
1126+
"<define name=\"test\" type=\"http://www.ibm.com/xmlns/prod/cics/bundle/NODEJSAPP\" path=\"nodejsapps/test.nodejsapp\"></define>" +
1127+
"</manifest>";
1128+
}
1129+
});
11161130
cmciSpy.mockImplementation((cicsSession: any, regionData: cmci.IResourceParms) => {
11171131
if (regionData.name === "CICSRegion") {
11181132
return { response: {
@@ -1186,7 +1200,14 @@ describe("BundlePusher01", () => {
11861200
sshProfile = { host: "wibble", user: "user" };
11871201
cicsProfile = { host: "wibble", user: "user", password: "thisIsntReal", cicsPlex: "12345678", regionName: "12345678" };
11881202
submitSpy = jest.spyOn(SubmitJobs, "submitJclString").mockImplementation(() =>
1189-
[{ddName: "SYSTSPRT", stepName: "DFHDPLOY", data: "DFHRL2012I http://www.ibm.com/xmlns/prod/cics/bundle/NODEJSAPP"}] );
1203+
[{ddName: "SYSTSPRT", stepName: "DFHDPLOY", data: "DFHRL2012I"}] );
1204+
readSpy = jest.spyOn(fs, "readFileSync").mockImplementation((data: string) => {
1205+
if (data.indexOf("cics.xml") > -1) {
1206+
return "<manifest xmlns=\"http://www.ibm.com/xmlns/prod/cics/bundle\">" +
1207+
"<define name=\"test\" type=\"http://www.ibm.com/xmlns/prod/cics/bundle/NODEJSAPP\" path=\"nodejsapps/test.nodejsapp\"></define>" +
1208+
"</manifest>";
1209+
}
1210+
});
11901211
cmciSpy.mockImplementation((cicsSession: any, nodejsData: cmci.IResourceParms) => {
11911212
if (nodejsData.name === "CICSNodejsapp") {
11921213
throw new Error("Injected CMCI GET error");
@@ -1226,7 +1247,14 @@ describe("BundlePusher01", () => {
12261247
sshProfile = { host: "wibble", user: "user" };
12271248
cicsProfile = { host: "wibble", user: "user", password: "thisIsntReal", cicsPlex: "12345678", regionName: "12345678" };
12281249
submitSpy = jest.spyOn(SubmitJobs, "submitJclString").mockImplementation(() =>
1229-
[{ddName: "SYSTSPRT", stepName: "DFHDPLOY", data: "DFHRL2012I http://www.ibm.com/xmlns/prod/cics/bundle/NODEJSAPP"}] );
1250+
[{ddName: "SYSTSPRT", stepName: "DFHDPLOY", data: "DFHRL2012I"}] );
1251+
readSpy = jest.spyOn(fs, "readFileSync").mockImplementation((data: string) => {
1252+
if (data.indexOf("cics.xml") > -1) {
1253+
return "<manifest xmlns=\"http://www.ibm.com/xmlns/prod/cics/bundle\">" +
1254+
"<define name=\"test\" type=\"http://www.ibm.com/xmlns/prod/cics/bundle/NODEJSAPP\" path=\"nodejsapps/test.nodejsapp\"></define>" +
1255+
"</manifest>";
1256+
}
1257+
});
12301258
cmciSpy.mockImplementation((cicsSession: any, nodejsData: cmci.IResourceParms) => {
12311259
if (nodejsData.name === "CICSNodejsapp") {
12321260
return {};
@@ -1266,7 +1294,14 @@ describe("BundlePusher01", () => {
12661294
sshProfile = { host: "wibble", user: "user" };
12671295
cicsProfile = { host: "wibble", user: "user", password: "thisIsntReal", cicsPlex: "12345678", regionName: "12345678" };
12681296
submitSpy = jest.spyOn(SubmitJobs, "submitJclString").mockImplementation(() =>
1269-
[{ddName: "SYSTSPRT", stepName: "DFHDPLOY", data: "DFHRL2012I http://www.ibm.com/xmlns/prod/cics/bundle/NODEJSAPP"}] );
1297+
[{ddName: "SYSTSPRT", stepName: "DFHDPLOY", data: "DFHRL2012I"}] );
1298+
readSpy = jest.spyOn(fs, "readFileSync").mockImplementation((data: string) => {
1299+
if (data.indexOf("cics.xml") > -1) {
1300+
return "<manifest xmlns=\"http://www.ibm.com/xmlns/prod/cics/bundle\">" +
1301+
"<define name=\"name\" type=\"http://www.ibm.com/xmlns/prod/cics/bundle/NODEJSAPP\" path=\"nodejsapps/test.nodejsapp\"></define>" +
1302+
"</manifest>";
1303+
}
1304+
});
12701305
cmciSpy.mockImplementation((cicsSession: any, nodejsData: cmci.IResourceParms) => {
12711306
if (nodejsData.name === "CICSNodejsapp") {
12721307
return { response: {
@@ -1318,7 +1353,14 @@ describe("BundlePusher01", () => {
13181353
sshProfile = { host: "wibble", user: "user" };
13191354
cicsProfile = { host: "wibble", user: "user", password: "thisIsntReal", cicsPlex: "12345678", regionName: "12345678" };
13201355
submitSpy = jest.spyOn(SubmitJobs, "submitJclString").mockImplementation(() =>
1321-
[{ddName: "SYSTSPRT", stepName: "DFHDPLOY", data: "DFHRL2012I http://www.ibm.com/xmlns/prod/cics/bundle/NODEJSAPP"}] );
1356+
[{ddName: "SYSTSPRT", stepName: "DFHDPLOY", data: "DFHRL2012I"}] );
1357+
readSpy = jest.spyOn(fs, "readFileSync").mockImplementation((data: string) => {
1358+
if (data.indexOf("cics.xml") > -1) {
1359+
return "<manifest xmlns=\"http://www.ibm.com/xmlns/prod/cics/bundle\">" +
1360+
"<define name=\"name\" type=\"http://www.ibm.com/xmlns/prod/cics/bundle/NODEJSAPP\" path=\"nodejsapps/test.nodejsapp\"></define>" +
1361+
"</manifest>";
1362+
}
1363+
});
13221364
cmciSpy.mockImplementation((cicsSession: any, nodejsData: cmci.IResourceParms) => {
13231365
if (nodejsData.name === "CICSNodejsapp") {
13241366
return { response: {
@@ -1370,7 +1412,15 @@ describe("BundlePusher01", () => {
13701412
sshProfile = { host: "wibble", user: "user" };
13711413
cicsProfile = { host: "wibble", user: "user", password: "thisIsntReal", cicsPlex: "12345678", regionName: "12345678" };
13721414
submitSpy = jest.spyOn(SubmitJobs, "submitJclString").mockImplementation(() =>
1373-
[{ddName: "SYSTSPRT", stepName: "DFHDPLOY", data: "DFHRL2012I http://www.ibm.com/xmlns/prod/cics/bundle/NODEJSAPP"}] );
1415+
[{ddName: "SYSTSPRT", stepName: "DFHDPLOY", data: "DFHRL2012I"}] );
1416+
readSpy = jest.spyOn(fs, "readFileSync").mockImplementation((data: string) => {
1417+
if (data.indexOf("cics.xml") > -1) {
1418+
return "<manifest xmlns=\"http://www.ibm.com/xmlns/prod/cics/bundle\">" +
1419+
"<define name=\"name\" type=\"http://www.ibm.com/xmlns/prod/cics/bundle/NODEJSAPP\" path=\"nodejsapps/test.nodejsapp\"></define>" +
1420+
"<define name=\"name2\" type=\"http://www.ibm.com/xmlns/prod/cics/bundle/NODEJSAPP\" path=\"nodejsapps/test.nodejsapp\"></define>" +
1421+
"</manifest>";
1422+
}
1423+
});
13741424
cmciSpy.mockImplementation((cicsSession: any, nodejsData: cmci.IResourceParms) => {
13751425
if (nodejsData.name === "CICSNodejsapp") {
13761426
return { response: {

src/api/BundleContent/Bundle.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,17 @@ node_modules -
126126
return true;
127127
}
128128

129+
/**
130+
* Determines whether the Bundle contains any resources of the specified type
131+
* @param {string} resource - The resource to query
132+
* @returns {boolean}
133+
* @throws ImperativeError
134+
* @memberof Bundle
135+
*/
136+
public containsDefinitionsOfType(resourceType: string): boolean {
137+
return this.manifest.containsDefinitionsOfType(resourceType);
138+
}
139+
129140
/**
130141
* Returns the Bundle's identity (id) value.
131142
* @returns {string}

src/api/BundleContent/Manifest.ts

Lines changed: 43 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -316,18 +316,8 @@ export class Manifest {
316316

317317
const definition = bundlePart.getPartData();
318318

319-
// Create the array of definitions if it doesn't already exist
320-
if (this.manifestAsJson.manifest.define === undefined) {
321-
this.manifestAsJson.manifest.define = [];
322-
}
323-
324-
// If what already exists is an object (as may happen when appending
325-
// to an existing XML manifest with only one entry) convert it to an array;
326-
if (Array.isArray(this.manifestAsJson.manifest.define) === false) {
327-
const obj = this.manifestAsJson.manifest.define as any;
328-
this.manifestAsJson.manifest.define = [];
329-
this.manifestAsJson.manifest.define.push(obj as IBundlePartDataType);
330-
}
319+
// Ensure that the definitions array is usable
320+
this.prepareDefinitionsArray();
331321

332322
// Search the array for a definition with the same name and
333323
// type as the one we're trying to add, if found then update
@@ -347,6 +337,47 @@ export class Manifest {
347337
this.manifestAsJson.manifest.define.push(definition);
348338
}
349339

340+
/**
341+
* Does the bundle contain any resource definitions of the
342+
* specified type?
343+
*
344+
* @param {String} resourceType - the resource type
345+
* @throws ImperativeError
346+
* @memberof Manifest
347+
*/
348+
public containsDefinitionsOfType(resourceType: string): boolean {
349+
350+
// Ensure that the definitions array is usable
351+
this.prepareDefinitionsArray();
352+
353+
// Search the array for a definition with the nominated type
354+
let i: number;
355+
for (i = 0; i < this.manifestAsJson.manifest.define.length; i++) {
356+
const candidate = this.manifestAsJson.manifest.define[i];
357+
if (candidate.type === resourceType) {
358+
return true;
359+
}
360+
}
361+
362+
return false;
363+
}
364+
365+
366+
private prepareDefinitionsArray() {
367+
// Create the array of definitions if it doesn't already exist
368+
if (this.manifestAsJson.manifest.define === undefined) {
369+
this.manifestAsJson.manifest.define = [];
370+
}
371+
372+
// If what already exists is an object (as may happen when appending
373+
// to an existing XML manifest with only one entry) convert it to an array;
374+
if (Array.isArray(this.manifestAsJson.manifest.define) === false) {
375+
const obj = this.manifestAsJson.manifest.define as any;
376+
this.manifestAsJson.manifest.define = [];
377+
this.manifestAsJson.manifest.define.push(obj as IBundlePartDataType);
378+
}
379+
}
380+
350381
// Read an existing manifest file into an object
351382
private readManifest() {
352383
// read the manifest from the file system

src/api/BundlePush/BundlePusher.ts

Lines changed: 25 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,7 @@ export class BundlePusher {
129129
await this.runAllNpmInstalls(sshSession, packageJsonFiles);
130130

131131
// Run DFHDPLOY to install the bundle
132-
await this.deployBundle(zosMFSession, bd, cicsSession);
132+
await this.deployBundle(zosMFSession, bd, cicsSession, bundle);
133133

134134
// Complete the progress bar
135135
this.progressBar.percentComplete = TaskProgress.ONE_HUNDRED_PERCENT;
@@ -340,7 +340,7 @@ export class BundlePusher {
340340
this.startProgressBar();
341341
}
342342

343-
private async deployBundle(zosMFSession: AbstractSession, bd: BundleDeployer, cicsSession: AbstractSession) {
343+
private async deployBundle(zosMFSession: AbstractSession, bd: BundleDeployer, cicsSession: AbstractSession, bundle: Bundle) {
344344
// End the current progress bar so that DEPLOY can create its own
345345
this.updateStatus("Deploying bundle '" + this.params.arguments.name + "' to CICS");
346346
this.endProgressBar();
@@ -369,9 +369,9 @@ export class BundlePusher {
369369

370370
// Collect general information about the regions in the CICSplex scope
371371
const diagnosticsWorking = await this.outputGeneralDiagnostics(cicsSession);
372-
if (diagnosticsWorking) {
372+
if (diagnosticsWorking && bundle.containsDefinitionsOfType("http://www.ibm.com/xmlns/prod/cics/bundle/NODEJSAPP")) {
373373
// Generate additional diagnostic output for Node.js
374-
await this.outputNodejsSpecificDiagnostics(cicsSession, dfhdployOutput);
374+
await this.outputNodejsSpecificDiagnostics(cicsSession);
375375
}
376376

377377
// Now rethrow the original error, if there was one.
@@ -635,32 +635,29 @@ export class BundlePusher {
635635
return scopeFound;
636636
}
637637

638-
private async outputNodejsSpecificDiagnostics(cicsSession: AbstractSession, dfhdployOutput: string) {
639-
// Did the Bundle contents include a NODEJSAPP?
640-
if (dfhdployOutput.indexOf("http://www.ibm.com/xmlns/prod/cics/bundle/NODEJSAPP") > -1) {
641-
let diagnosticsIssued = false;
642-
try {
643-
// Attempt to gather additional Node.js specific information from CICS
644-
this.updateStatus("Gathering Node.js diagnostics");
645-
diagnosticsIssued = await this.gatherNodejsDiagnosticsFromCics(cicsSession);
646-
}
647-
catch (diagnosticsError) {
648-
// Something went wrong generating diagnostic info. Don't trouble the user
649-
// with what might be an exotic error message (e.g. hex dump of an entire HTML page),
650-
// just log the failure.
651-
if (this.params.arguments.silent === undefined) {
652-
const logger = Logger.getAppLogger();
653-
logger.debug(diagnosticsError.message);
654-
}
638+
private async outputNodejsSpecificDiagnostics(cicsSession: AbstractSession) {
639+
let diagnosticsIssued = false;
640+
try {
641+
// Attempt to gather additional Node.js specific information from CICS
642+
this.updateStatus("Gathering Node.js diagnostics");
643+
diagnosticsIssued = await this.gatherNodejsDiagnosticsFromCics(cicsSession);
644+
}
645+
catch (diagnosticsError) {
646+
// Something went wrong generating diagnostic info. Don't trouble the user
647+
// with what might be an exotic error message (e.g. hex dump of an entire HTML page),
648+
// just log the failure.
649+
if (this.params.arguments.silent === undefined) {
650+
const logger = Logger.getAppLogger();
651+
logger.debug(diagnosticsError.message);
655652
}
653+
}
656654

657-
// We must have a cics profile in order to have got this far, so suggest a command that can be run to figure out more.
658-
if (diagnosticsIssued === false) {
659-
const msg = "For further information on the state of your NODEJSAPP resources, consider running the following command:\n\n" +
660-
"zowe cics get resource CICSNodejsapp --region-name " + this.params.arguments.scope +
661-
" --criteria \"BUNDLE=" + this.params.arguments.name + "\" --cics-plex " + this.params.arguments.cicsplex + "\n";
662-
this.issueMessage(msg);
663-
}
655+
// We must have a cics profile in order to have got this far, so suggest a command that can be run to figure out more.
656+
if (diagnosticsIssued === false) {
657+
const msg = "For further information on the state of your NODEJSAPP resources, consider running the following command:\n\n" +
658+
"zowe cics get resource CICSNodejsapp --region-name " + this.params.arguments.scope +
659+
" --criteria \"BUNDLE=" + this.params.arguments.name + "\" --cics-plex " + this.params.arguments.cicsplex + "\n";
660+
this.issueMessage(msg);
664661
}
665662
}
666663

0 commit comments

Comments
 (0)