Skip to content

Read cluster and secrets from the WDT results JSON file #178

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Oct 31, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
214 changes: 31 additions & 183 deletions electron/app/js/wdtPrepareModel.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@

const path = require('path');
const { readFile } = require('fs/promises');
const jsYaml = require('js-yaml');

const i18n = require('./i18next.config');
const childProcessExecutor = require('./childProcessExecutor');
Expand All @@ -19,15 +18,10 @@ const errorUtils = require('./errorUtils');

const MINIMUM_WDT_PREPARE_VERSION = '2.0.0';

const _secretsFileName = 'k8s_secrets.json';
const _wkoDomainSpecFileName = 'wko-domain.yaml';
const _vzApplicationSpecFileName = 'vz-application.yaml';
const _resultsFileName = 'results.json';

const _deleteTempDirectory = true;

const _wkoTargetTypeName = i18n.t('prepare-model-wko-target-type-name');
const _vzTargetTypeName = i18n.t('prepare-model-wko-target-type-name');

async function prepareModel(currentWindow, stdoutChannel, stderrChannel, prepareConfig) {
const logger = getLogger();
const { javaHome, oracleHome, projectDirectory, modelsSubdirectory, modelFiles,
Expand Down Expand Up @@ -119,7 +113,9 @@ async function prepareModel(currentWindow, stdoutChannel, stderrChannel, prepare
}

try {
results['secrets'] = await getJsonSecretsContent(outputDirectory);
const jsonResults = await getJsonResultsContent(outputDirectory);
results['secrets'] = jsonResults['secrets'];
results['domain'] = jsonResults['domain'];
} catch (err) {
results.isSuccess = false;
results.reason = errorUtils.getErrorMessage(err);
Expand All @@ -129,14 +125,6 @@ async function prepareModel(currentWindow, stdoutChannel, stderrChannel, prepare
return Promise.resolve(results);
}

try {
results['domain'] = await getTargetSpecContent(wdtTargetType, outputDirectory);
} catch (err) {
results.isSuccess = false;
results.reason = errorUtils.getErrorMessage(err);
results.error = err;
logger.error(results.reason);
}
removeTempDirectory(outputDirectory).then().catch();
return Promise.resolve(results);
}
Expand Down Expand Up @@ -228,49 +216,48 @@ function getUpdatedModelFileNames(updatedFileMap, files) {
return updatedFiles;
}

async function getJsonSecretsContent(outputDirectory) {
const secretsFileName = path.join(outputDirectory, _secretsFileName);
async function getJsonResultsContent(outputDirectory) {
const resultsFileName = path.join(outputDirectory, _resultsFileName);

return new Promise((resolve, reject) => {
fsUtils.exists(secretsFileName).then(doesExist => {
fsUtils.exists(resultsFileName).then(doesExist => {
if (!doesExist) {
return reject(new Error(i18n.t('prepare-model-secrets-file-missing-error-message',
{ fileName: secretsFileName })));
return reject(new Error(i18n.t('prepare-model-results-file-missing-error-message',
{ fileName: resultsFileName })));
}

readFile(secretsFileName, { encoding: 'utf8' }).then(data => {
readFile(resultsFileName, { encoding: 'utf8' }).then(data => {
let jsonContent;
try {
jsonContent = JSON.parse(data);
resolve(formatSecretsData(jsonContent));
resolve(formatResultsData(jsonContent));
} catch (err) {
const error = new Error(i18n.t('prepare-model-secrets-file-parse-error-message',
{ fileName: secretsFileName, error: errorUtils.getErrorMessage(err) }));
const error = new Error(i18n.t('prepare-model-results-file-parse-error-message',
{ fileName: resultsFileName, error: errorUtils.getErrorMessage(err) }));
error.cause = err;
reject(err);
}
}).catch(err => {
const error = new Error(i18n.t('prepare-model-secrets-file-read-error-message',
{ fileName: secretsFileName, error: errorUtils.getErrorMessage(err) }));
const error = new Error(i18n.t('prepare-model-results-file-read-error-message',
{ fileName: resultsFileName, error: errorUtils.getErrorMessage(err) }));
error.cause = err;
reject(err);
});
}).catch(err => reject(err));
});
}

function formatSecretsData(jsonContent) {
function formatResultsData(jsonContent) {
const results = { };
if (!jsonContent) {
return results;
}

results['domainUID'] = jsonContent.domainUID;
const secrets = jsonContent['secrets'] || [];
results.secrets = [];
for (const secret of secrets) {
for (const [secretName, secret] of Object.entries(secrets)) {
const secretResult = {
name: secret['secretName']
name: secretName
};
const secretKeys = secret['keys'];
if (secretKeys) {
Expand All @@ -289,169 +276,30 @@ function formatSecretsData(jsonContent) {
results.secrets.push(secretResult);
}
}
return results;
}

async function getTargetSpecContent(wdtTargetType, outputDirectory) {
let result = { };
switch (wdtTargetType) {
case 'wko':
result = await getWkoSpecContent(outputDirectory);
break;

case 'vz':
result = await getVzSpecContent(outputDirectory);
break;

default:
// k8s target produces no spec...
break;
}
return Promise.resolve(result);
}

async function getWkoSpecContent(outputDirectory) {
const specFile = path.join(outputDirectory, _wkoDomainSpecFileName);

return new Promise((resolve, reject) => {
fsUtils.exists(specFile).then(doesExist => {
if (!doesExist) {
const error = new Error(i18n.t('prepare-model-spec-file-missing-error-message',
{ targetType: _wkoTargetTypeName, fileName: specFile }));
reject(error);
}

readFile(specFile, { encoding: 'utf8' }).then(data => {
try {
const yamlDoc = jsYaml.load(data, { filename: specFile, json: true });
resolve(formatWkoDomainSpecData(yamlDoc));
} catch (err) {
const error = new Error(i18n.t('prepare-model-spec-file-parse-error-message',
{ targetType: _wkoTargetTypeName, fileName: specFile, error: errorUtils.getErrorMessage(err) }));
error.cause = err;
reject(error);
}
}).catch(err => {
const error = new Error(i18n.t('prepare-model-spec-file-read-error-message',
{ targetType: _wkoTargetTypeName, fileName: specFile, error: errorUtils.getErrorMessage(err) }));
error.cause = err;
reject(error);
});
}).catch(err => reject(getFileExistsErrorMessage(_wkoTargetTypeName, specFile, err)));
});
}
const domain = {};
domain['domainUID'] = jsonContent.domainUID;

function formatWkoDomainSpecData(yamlDoc) {
const result = { };
if (yamlDoc) {
if ('metadata' in yamlDoc && 'name' in yamlDoc['metadata']) {
result['domainUID'] = yamlDoc['metadata']['name'];
}
if ('spec' in yamlDoc && 'clusters' in yamlDoc['spec']) {
const clusters = yamlDoc['spec']['clusters'];
const clustersResult = [];
for (const cluster of clusters) {
const clusterResult = {
clusterName: cluster['clusterName'],
replicas: cluster['replicas'] || 0
};
clustersResult.push(clusterResult);
}
result['clusters'] = clustersResult;
}
const clusters = jsonContent['clusters'] || [];
const clustersResult = [];
for (const [clusterName, cluster] of Object.entries(clusters)) {
const clusterResult = {
clusterName: clusterName,
replicas: cluster['serverCount'] || 0
};
clustersResult.push(clusterResult);
}
return result;
}

async function getVzSpecContent(outputDirectory) {
const specFile = path.join(outputDirectory, _vzApplicationSpecFileName);
domain['clusters'] = clustersResult;

return new Promise((resolve, reject) => {
fsUtils.exists(specFile).then(doesExist => {
if (!doesExist) {
const error = new Error(i18n.t('prepare-model-spec-file-missing-error-message',
{ targetType: _vzTargetTypeName, fileName: specFile }));
reject(error);
}

readFile(specFile, { encoding: 'utf8' }).then(data => {
let yamlDocs;
try {
yamlDocs = jsYaml.loadAll(data, { filename: specFile, json: true });
} catch (err) {
const error = new Error(i18n.t('prepare-model-spec-file-parse-error-message',
{ targetType: _vzTargetTypeName, fileName: specFile, error: errorUtils.getErrorMessage(err) }));
error.cause = err;
reject(error);
}

try {
resolve(formatVzApplicationSpecData(specFile, yamlDocs));
} catch (err) {
reject(err);
}
}).catch(err => {
const error = new Error(i18n.t('prepare-model-spec-file-read-error-message',
{ targetType: _vzTargetTypeName, fileName: specFile, error: errorUtils.getErrorMessage(err) }));
error.cause = err;
reject(error);
});
}).catch(err => reject(getFileExistsErrorMessage(_wkoTargetTypeName, specFile, err)));
});
results['domain'] = domain;
return results;
}

function getToolTargetType(wdtTargetType, targetDomainLocation) {
const suffix = targetDomainLocation === 'mii' ? '' : `-${targetDomainLocation}`;
return `${wdtTargetType}${suffix}`;
}

function getFileExistsErrorMessage(targetType, fileName, err) {
const error = new Error(i18n.t('prepare-model-spec-file-exists-error-message',
{ targetType: targetType, fileName: fileName, error: errorUtils.getErrorMessage(err) }));
error.cause = err;
return error;
}

function formatVzApplicationSpecData(specFile, yamlDocs) {
const domainSpec = findVzDomainSpec(specFile, yamlDocs);
const domainUID = domainSpec.domainUID;

const clustersResult = [];
if (domainSpec.clusters) {
for (const cluster of domainSpec.clusters) {
clustersResult.push({ clusterName: cluster.clusterName, replicas: cluster.replicas });
}
}
return {
domainUID: domainUID,
clusters: clustersResult
};
}

function findVzDomainSpec(specFile, yamlDocs) {
let result;
if (yamlDocs && yamlDocs.length > 0) {
for (const yamlDoc of yamlDocs) {
if (yamlDoc['kind'] !== 'Component') {
continue;
}
if (yamlDoc.spec?.workload?.kind === 'VerrazzanoWebLogicWorkload') {
result = yamlDoc;
break;
}
}
}

if (!result) {
throw new Error(i18n.t('prepare-model-vz-spec-file-missing-domain-error-message', { fileName: specFile }));
} else if (!result.spec?.workload?.spec?.template?.spec) {
throw new Error(i18n.t('prepare-model-vz-spec-file-missing-spec-error-message', { fileName: specFile }));
} else {
result = result.spec.workload.spec.template.spec;
}
return result;
}

module.exports = {
prepareModel
};
14 changes: 3 additions & 11 deletions electron/app/locales/en/electron.json
Original file line number Diff line number Diff line change
Expand Up @@ -250,17 +250,9 @@
"prepare-model-model-file-not-exists-error-message": "Unable to prepare model with non-existent model file: {{modelFile}}.",
"prepare-model-error-exit-code-error-message": "Prepare Model script exited with {{exitCode}}, which indicates an error.",
"prepare-model-execution-failed-error-message": "Prepare Model script failed: {{error}}",
"prepare-model-secrets-file-missing-error-message": "Prepare Model failed to generate the expected secrets file {{fileName}}",
"prepare-model-secrets-file-read-error-message": "Prepare Model failed to read secrets file {{fileName}}: {{error}}",
"prepare-model-secrets-file-parse-error-message": "Prepare Model failed to parse secrets file {{fileName}}: {{error}}",
"prepare-model-spec-file-missing-error-message": "Prepare Model failed to generate the expected {{targetType}} specification file {{fileName}}",
"prepare-model-spec-file-exists-error-message": "Prepare Model failed to determine whether the {{targetType}} specification file {{fileName}} exists: {{error}}",
"prepare-model-spec-file-read-error-message": "Prepare Model failed to read the {{targetType}} specification file {{fileName}}: {{error}}",
"prepare-model-spec-file-parse-error-message": "Prepare Model failed to parse the {{targetType}} specification file {{fileName}}: {{error}}",
"prepare-model-vz-spec-file-missing-domain-error-message": "Prepare model failed to find the Verrazzano component that defined the WebLogic Kubernetes Operator domain in {{fileName}}",
"prepare-model-vz-spec-file-missing-spec-error-message": "Prepare model failed to find the WebLogic Kubernetes Operator domain's spec field in the Verrazzano component defined in {{fileName}}",
"prepare-model-wko-target-type-name": "WebLogic Kubernetes Operator domain",
"prepare-model-vz-target-type-name": "Verrazzano application",
"prepare-model-results-file-missing-error-message": "Prepare Model failed to generate the expected results file {{fileName}}",
"prepare-model-results-file-read-error-message": "Prepare Model failed to read results file {{fileName}}: {{error}}",
"prepare-model-results-file-parse-error-message": "Prepare Model failed to parse results file {{fileName}}: {{error}}",

"wit-inspect-inspect-error-message": "Inspecting image {{imageTag}} failed: {{error}}.",
"wit-inspect-inspect-parse-error-message": "Inspecting image {{imageTag}} failed due to a JSON parse error parsing the response: {{error}}.",
Expand Down
2 changes: 1 addition & 1 deletion tools/wdt-config/targets/vz-dii/target.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
},
"variable_injectors" : {"PORT": {},"HOST": {},"URL": {}},
"validation_method" : "lax",
"credentials_output_method" : "script",
"results_output_method" : "json",
"exclude_domain_bin_contents": true,
"wls_credentials_name" : "__weblogic-credentials__",
"additional_output" : "vz-application.yaml",
Expand Down
2 changes: 1 addition & 1 deletion tools/wdt-config/targets/vz-pv/target.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
},
"variable_injectors" : {"PORT": {},"HOST": {},"URL": {}},
"validation_method" : "lax",
"credentials_output_method" : "script",
"results_output_method" : "json",
"exclude_domain_bin_contents": true,
"wls_credentials_name" : "__weblogic-credentials__",
"additional_output" : "vz-application.yaml",
Expand Down
2 changes: 1 addition & 1 deletion tools/wdt-config/targets/vz/target.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
"variable_injectors" : {"PORT": {},"HOST": {},"URL": {}},
"validation_method" : "wktui",
"credentials_method" : "secrets",
"credentials_output_method" : "json",
"results_output_method" : "json",
"exclude_domain_bin_contents": true,
"wls_credentials_name" : "__weblogic-credentials__",
"additional_secrets": "runtime-encryption-secret",
Expand Down
2 changes: 1 addition & 1 deletion tools/wdt-config/targets/wko-dii/target.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
},
"variable_injectors" : {"PORT": {},"HOST": {},"URL": {}},
"validation_method" : "wktui",
"credentials_output_method" : "json",
"results_output_method" : "json",
"exclude_domain_bin_contents": true,
"wls_credentials_name" : "__weblogic-credentials__",
"additional_output" : "wko-domain.yaml",
Expand Down
2 changes: 1 addition & 1 deletion tools/wdt-config/targets/wko-pv/target.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
},
"variable_injectors" : {"PORT": {},"HOST": {},"URL": {}},
"validation_method" : "wktui",
"credentials_output_method" : "json",
"results_output_method" : "json",
"exclude_domain_bin_contents": true,
"wls_credentials_name" : "__weblogic-credentials__",
"additional_output" : "wko-domain.yaml",
Expand Down
2 changes: 1 addition & 1 deletion tools/wdt-config/targets/wko/target.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
"variable_injectors" : {"PORT": {},"HOST": {},"URL": {}},
"validation_method" : "wktui",
"credentials_method" : "secrets",
"credentials_output_method" : "json",
"results_output_method" : "json",
"exclude_domain_bin_contents": true,
"wls_credentials_name" : "__weblogic-credentials__",
"additional_secrets": "runtime-encryption-secret",
Expand Down