Skip to content

Commit

Permalink
Merge pull request #146 from zowe/yamlFromPax
Browse files Browse the repository at this point in the history
Retrieve example-zowe.yaml, zowe-yaml-schema.json and server-common.json Schemas from Zowe Runtime Dir (for upload/download install types)
  • Loading branch information
DivergentEuropeans authored May 29, 2024
2 parents 4c6230b + 1a09524 commit e8ae277
Show file tree
Hide file tree
Showing 16 changed files with 1,735 additions and 154 deletions.
3 changes: 2 additions & 1 deletion src/actions/InstallActions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
* Copyright Contributors to the Zowe Project.
*/

import { InstallationArgs } from '../renderer/components/stages/installation/installationSlice';
import { IIpcConnectionArgs, IResponse } from '../types/interfaces';
import { FTPInstallation, CLIInstallation } from './InstallationHandler';

Expand Down Expand Up @@ -42,7 +43,7 @@ export class InstallActions {

runInstallation (
connectionArgs: IIpcConnectionArgs,
installationArgs: {installationDir: string, installationType: string, userUploadedPaxPath: string},
installationArgs: InstallationArgs,
version: string, zoweConfig: any, skipDownload: boolean): Promise<IResponse> {
return this.strategy.runInstallation(connectionArgs, installationArgs, version, zoweConfig, skipDownload);
}
Expand Down
162 changes: 134 additions & 28 deletions src/actions/InstallationHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,23 +12,27 @@ import { app } from 'electron';
import { DataType, FileTransfer } from "../services/FileTransfer";
import path from "path/posix";
import { Script } from "../services/RunScript";
import { stringify } from 'yaml';
import { parse, stringify } from 'yaml';
import { IIpcConnectionArgs, IResponse } from '../types/interfaces';
import { ProgressStore } from "../storage/ProgressStore";
import * as fs from 'fs';
import { ConfigurationStore } from '../storage/ConfigurationStore';
import { InstallationArgs } from '../renderer/components/stages/installation/installationSlice';

class Installation {

public async runInstallation (
connectionArgs: IIpcConnectionArgs,
installationArgs: {installationDir: string, installationType: string, userUploadedPaxPath: string},
installationArgs: InstallationArgs,
version: string,
zoweConfig: any,
skipDownload: boolean
): Promise<IResponse> {
const currentConfig: any = ConfigurationStore.getConfig();
const SMPE_INSTALL: boolean = installationArgs.installationType === "smpe";
const savingResult = await this.generateYamlFile(zoweConfig);
if (!savingResult.status) {
console.log("failed to save yaml");
return savingResult;
}

Expand Down Expand Up @@ -81,30 +85,14 @@ class Installation {
}
} else {
//if the user has selected an SMPE or opted to upload their own pax, we simply set this status to true as no download is required
download = {status: true, details: ''}
unpax = upload = download = {status: true, details: ''}
ProgressStore.set('installation.download', true);
}

if(!download.status){
return {status: false, details: `Error downloading pax: ${download.details}`};
}

console.log("uploading...");
if(installationArgs.installationType === "upload"){
//upload the PAX the user selected in the "Install Type" stage to the installation dir (from the planning stage)
console.log('Uploading user selected pax')
upload = await new FileTransfer().upload(connectionArgs, installationArgs.userUploadedPaxPath, path.join(installationArgs.installationDir, "zowe.pax"), DataType.BINARY)
} else if (installationArgs.installationType === "download"){
console.log('Uploading pax downloaded from jfrog')
upload = await this.uploadPax(connectionArgs, installationArgs.installationDir);
}
ProgressStore.set('installation.upload', upload.status);

if(!upload.status){
return {status: false, details: `Error uploading pax: ${upload.details}`};
}

unpax = {status: false, details: ""};
if (!SMPE_INSTALL) {
console.log("unpaxing...");
unpax = await this.unpax(connectionArgs, installationArgs.installationDir);
Expand All @@ -114,6 +102,114 @@ class Installation {
return {status: false, details: `Error unpaxing Zowe archive: ${unpax.details}`};
}
}
let yamlObj
let zoweRuntimePath = installationArgs.installationType === "smpe" ? installationArgs.installationDir : installationArgs.installationDir + "/runtime";
let readPaxYamlAndSchema = await this.readExampleYamlAndSchema(connectionArgs, zoweRuntimePath);
if(readPaxYamlAndSchema.details.yaml){
const parseExampleYamlFromPax = function(catPath: string){
const jobOutputSplit = JSON.stringify(readPaxYamlAndSchema.details.yaml).split(`cat ${catPath}\\r\\n`)
if(jobOutputSplit[1]){
const trimmedYamlSchema = jobOutputSplit[1].split(`+ echo 'Script finished.'`)[0].split(`Script finished.`);
// console.log("\n\n *** trimmedYamlSchema[0]: ", trimmedYamlSchema[0].replaceAll(`\\r\\n`, `\r\n`).replaceAll(`\\"`, `"`));
return trimmedYamlSchema[0].replaceAll(`\\r\\n`, `\r\n`).replaceAll(`\\"`, `"`);
}
return "";
}
const yamlFromPax = parseExampleYamlFromPax(`${zoweRuntimePath}/example-zowe.yaml`);
if(yamlFromPax){
try {
yamlObj = parse(yamlFromPax);
if (currentConfig) {
console.log("current config:", JSON.stringify(currentConfig));
// console.log("yamlObj: ", JSON.stringify(yamlObj));
yamlObj = {...currentConfig, ...yamlObj}
console.log("merged yamlObj: ", JSON.stringify(yamlObj));
}
if (yamlObj.zowe.runtimeDirectory === undefined && installationArgs.installationDir) {
yamlObj.zowe.runtimeDirectory = installationArgs.installationDir;
}
if (yamlObj.zowe.workspaceDirectory === undefined && installationArgs.workspaceDir) {
yamlObj.zowe.workspaceDirectory = installationArgs.workspaceDir;
}
if (yamlObj.zowe.logDirectory === undefined && installationArgs.logDir) {
yamlObj.zowe.logDirectory = installationArgs.logDir;
}
if (yamlObj.zowe.extensionDirectory === undefined && installationArgs.extensionDir) {
yamlObj.zowe.extensionDirectory = installationArgs.extensionDir;
}
if (yamlObj.zowe.rbacProfileIdentifier === undefined && installationArgs.rbacProfile) {
yamlObj.zowe.rbacProfileIdentifier = installationArgs.rbacProfile;
}
if (yamlObj.zowe.job.name === undefined && installationArgs.jobName) {
yamlObj.zowe.job.name = installationArgs.jobName;
}
if (yamlObj.zowe.job.prefix === undefined && installationArgs.jobPrefix) {
yamlObj.zowe.job.prefix = installationArgs.jobPrefix;
}
if (yamlObj.zowe.cookieIdentifier === undefined && installationArgs.cookieId) {
yamlObj.zowe.cookieIdentifier = installationArgs.cookieId;
}
if (yamlObj.java.home === undefined && installationArgs.javaHome) {
yamlObj.java.home = installationArgs.javaHome;
}
if (yamlObj.node.home === undefined && installationArgs.nodeHome) {
yamlObj.node.home = installationArgs.nodeHome;
}
if (yamlObj.zOSMF.host === undefined && installationArgs.zosmfHost) {
yamlObj.zOSMF.host = installationArgs.zosmfHost;
}
if (yamlObj.zOSMF.port === undefined && installationArgs.zosmfPort) {
yamlObj.zOSMF.port = installationArgs.zosmfPort;
}
if (yamlObj.zOSMF.applId === undefined && installationArgs.zosmfApplId) {
yamlObj.zOSMF.applId = installationArgs.zosmfApplId;
}
if (zoweConfig) {
yamlObj = {...yamlObj, ...zoweConfig};
}
console.log('Setting merged yaml:', JSON.stringify(yamlObj));
ConfigurationStore.setConfig(yamlObj);
} catch(e) {
console.log('error parsing example-zowe.yaml:', e);
}
} else {
console.log("no yaml found from pax");
}

//No reason not to always set schema to latest if user is re-running installation
if(readPaxYamlAndSchema.details.yamlSchema && readPaxYamlAndSchema.details.serverCommon){
const parseSchemaFromPax = function(inputString: string, catPath: string){
const jobOutputSplit = inputString.split(`cat ${catPath}\\r\\n`)
if(jobOutputSplit[1]){
const trimmedYamlSchema = jobOutputSplit[1].split(`Script finished.`)[0].split(`Script finished.`);
return trimmedYamlSchema[0].replaceAll(`\\r\\n`, `\r\n`).replaceAll(`\\"`, `"`).replaceAll(`\\\\"`, `\\"`);
}
return "";
}
try {
let yamlSchema = JSON.parse(parseSchemaFromPax(JSON.stringify(readPaxYamlAndSchema.details.yamlSchema), `${zoweRuntimePath}/schemas/zowe-yaml-schema.json`));
const serverCommon = JSON.parse(parseSchemaFromPax(JSON.stringify(readPaxYamlAndSchema.details.serverCommon), `${zoweRuntimePath}/schemas/server-common.json`));
// console.log('yaml schema:', parseSchemas(JSON.stringify(readPaxYamlAndSchema.details.yamlSchema), `${zoweRuntimePath}/schemas/zowe-yaml-schema.json`));
// console.log('server common', parseSchemas(JSON.stringify(readPaxYamlAndSchema.details.serverCommon), `${zoweRuntimePath}/schemas/server-common.json`));
if(yamlSchema && serverCommon){
// FIXME: Link schema by $ref properly - https://jsonforms.io/docs/ref-resolving
// Without these, AJV does not properly find $refs in the schema and therefore validation cannot occur
yamlSchema.properties.zowe.properties.setup.properties.dataset.properties.parmlibMembers.properties.zis = serverCommon.$defs.datasetMember;
yamlSchema.properties.zowe.properties.setup.properties.certificate.properties.pkcs12.properties.directory = serverCommon.$defs.path;
yamlSchema.$id = serverCommon.$id;
if(yamlSchema.$defs?.networkSettings?.properties?.server?.properties?.listenAddresses?.items){
delete yamlSchema.$defs?.networkSettings?.properties?.server?.properties?.listenAddresses?.items?.ref;
yamlSchema.$defs.networkSettings.properties.server.properties.listenAddresses.items = serverCommon.$defs.ipv4
}
console.log('Setting schema from runtime dir:', JSON.stringify(yamlSchema));
ConfigurationStore.setSchema(yamlSchema);
}
} catch (e) {
console.log('error setting schema from pax:', e);
}
}

}

let installation;
if (installationArgs.installationType !== "smpe") {
Expand All @@ -133,7 +229,7 @@ class Installation {
let initMvs;
if(installation.status){
console.log("running zwe init mvs...");
initMvs = await this.initMVS(connectionArgs, SMPE_INSTALL ? installationArgs.installationDir : installationArgs.installationDir + '/runtime');
initMvs = await this.initMVS(connectionArgs, installationArgs.installationDir);
ProgressStore.set('installation.initMVS', initMvs.status);
} else {
initMvs = {status: false, details: `zwe install step failed, unable to run zwe init mvs.`}
Expand All @@ -144,7 +240,7 @@ class Installation {
return {status: false, details: `Error running zwe init mvs: ${initMvs.details}`};
}

return {status: download.status && uploadYaml.status && upload.status && unpax.status && installation.status && initMvs.status, details: 'Zowe install successful.'};
return {status: download.status && uploadYaml.status && upload.status && unpax.status && installation.status && initMvs.status, details: {message: 'Zowe install successful.', mergedYaml: yamlObj}};
} catch (error) {
return {status: false, details: error.message};
}
Expand Down Expand Up @@ -275,13 +371,8 @@ class Installation {
return {status: true, details: ''};
}

async uploadYaml(connectionArgs: IIpcConnectionArgs, installDir: string) {
const tempPath = path.join(app.getPath("temp"), "zowe.yaml");
const filePath = path.join(installDir, "zowe.yaml");
await new FileTransfer().upload(connectionArgs, tempPath, filePath, DataType.BINARY)
const script = `chtag -t -c ISO8859-1 ${installDir}/zowe.yaml`;
const result = await new Script().run(connectionArgs, script);
return {status: result.rc === 0, details: result.jobOutput}
async uploadYaml(connectionArgs: IIpcConnectionArgs, installDir: string): Promise<IResponse> {
return {status: false, details: 'Method not implemented.'}
}

async downloadPax(version: string): Promise<IResponse> {
Expand All @@ -303,6 +394,10 @@ class Installation {
async initMVS(connectionArgs: IIpcConnectionArgs, installDir: string): Promise<IResponse> {
return {status: false, details: 'Method not implemented.'}
}

async readExampleYamlAndSchema(connectionArgs: IIpcConnectionArgs, installDir: string): Promise<IResponse>{
return {status: false, details: 'Method not implemented.'}
}

}

Expand All @@ -311,6 +406,7 @@ export class FTPInstallation extends Installation {
async uploadYaml(connectionArgs: IIpcConnectionArgs, installDir: string) {
const tempPath = path.join(app.getPath("temp"), "zowe.yaml");
const filePath = path.join(installDir, "zowe.yaml");
console.log(`Uploading ${tempPath} to ${filePath}`)
await new FileTransfer().upload(connectionArgs, tempPath, filePath, DataType.BINARY)
const script = `chtag -t -c ISO8859-1 ${installDir}/zowe.yaml`;
const result = await new Script().run(connectionArgs, script);
Expand Down Expand Up @@ -360,6 +456,16 @@ export class FTPInstallation extends Installation {
return {status: result.rc === 0, details: result.jobOutput}
}

async readExampleYamlAndSchema(connectionArgs: IIpcConnectionArgs, installDir: string){
const catYaml = `cat ${installDir}/example-zowe.yaml`;
const yamlResult = await new Script().run(connectionArgs, catYaml);
const catYamlSchema = `cat ${installDir}/schemas/zowe-yaml-schema.json`;
const yamlSchemaResult = await new Script().run(connectionArgs, catYamlSchema);
const catCommonSchema = `cat ${installDir}/schemas/server-common.json`;
const commonSchemaResult = await new Script().run(connectionArgs, catCommonSchema);
return {status: yamlResult.rc === 0 && yamlSchemaResult.rc == 0 && commonSchemaResult.rc == 0, details: {yaml: yamlResult.jobOutput, yamlSchema: yamlSchemaResult.jobOutput, serverCommon: commonSchemaResult.jobOutput}}
}

async checkInstallData() {
// FIXME: Refine installation data validation
}
Expand Down
15 changes: 13 additions & 2 deletions src/main/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,8 +92,8 @@ const createWindow = (): void => {
});

ipcMain.handle('get-config', async (event) => {
const res: any = await PlanningActions.getConfig();
return res;
const res: any = await ConfigurationStore.getConfig();
return {status: true, details: res};
});

ipcMain.handle('set-schema', async (event, schema: any) => {
Expand All @@ -102,6 +102,12 @@ const createWindow = (): void => {
});


ipcMain.handle('get-schema', async (event, schema: any) => {
const res: any = await ConfigurationStore.getSchema();
return {status: true, details: res};
});


ipcMain.handle('get-config-by-key', async (_event, key: string) => {
const res = await ConfigurationStore.getConfigByKey(key);
return res;
Expand All @@ -112,6 +118,11 @@ const createWindow = (): void => {
return res;
});

ipcMain.handle('set-config-by-key-no-validate', async (_event, key: string, value) => {
const res = await ConfigurationStore.setConfigByKeyNoValidate(key, value);
return res;
});

ipcMain.handle('get-zowe-version', async () => {
const res = await PlanningActions.getZoweVersion();
return res;
Expand Down
19 changes: 15 additions & 4 deletions src/renderer/components/common/Stepper.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -55,14 +55,14 @@ export default function HorizontalLinearStepper({stages, initialization}:{stages
completeProgress.reviewStatus
];

const subStageProgressStatus = [
const [subStageProgressStatus, setProgressStatus] = useState([
completeProgress.datasetInstallationStatus,
completeProgress.networkingStatus,
completeProgress.apfAuthStatus,
completeProgress.securityStatus,
completeProgress.certificateStatus,
completeProgress.launchConfigStatus
]
])

const TYPE_YAML = "yaml";
const TYPE_JCL = "jcl";
Expand All @@ -76,9 +76,18 @@ export default function HorizontalLinearStepper({stages, initialization}:{stages
const [editorContent, setEditorContent] = useState('');

useEffect(() => {
const mvsCompleteListener = (completed: boolean) => {
setProgressStatus([true, completeProgress.networkingStatus,
completeProgress.apfAuthStatus,
completeProgress.securityStatus,
completeProgress.certificateStatus,
completeProgress.launchConfigStatus])
};
eventDispatcher.on('updateActiveStep', updateActiveStepListener);
eventDispatcher.on('initMvsComplete', mvsCompleteListener);
return () => {
eventDispatcher.off('updateActiveStep', updateActiveStepListener);
eventDispatcher.off('initMvsComplete', mvsCompleteListener);
};
}, []);

Expand Down Expand Up @@ -169,7 +178,9 @@ export default function HorizontalLinearStepper({stages, initialization}:{stages

setActiveStep(newActiveStep);
const newSubStep = isSubStep ? subStepIndex : 0;
setActiveSubStep(newSubStep);
if((subStepIndex > 0 && subStageProgressStatus[0] === true) || subStepIndex === 0){ //only allow substages after installation to be navigated to if init mvs has been completed
setActiveSubStep(newSubStep);
}
}

const getStepIcon = (error: any, stageId: number, isSubStep?: boolean, subStepId?: number) => {
Expand Down Expand Up @@ -309,7 +320,7 @@ export default function HorizontalLinearStepper({stages, initialization}:{stages
}
{stages[activeStep] && stages[activeStep].isSkippable &&
<Button
disabled={isNextStepEnabled}
disabled={stages[activeStep] && stages[activeStep].subStages ? !stages[activeStep].subStages[activeSubStep].isSkippable : !stages[activeStep].isSkippable}
variant="contained"
sx={{ textTransform: 'none', mr: 1 }}
onClick={() => handleSkip()}
Expand Down
Loading

0 comments on commit e8ae277

Please sign in to comment.