Skip to content

adding support for working with older operator versions with the latest Helm chart #192

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
Nov 4, 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
10 changes: 8 additions & 2 deletions electron/app/js/helmUtils.js
Original file line number Diff line number Diff line change
Expand Up @@ -121,17 +121,23 @@ async function uninstallIngressController(helmExe, ingressName, ingressNamespace
});
}

async function installWko(helmExe, name, namespace, helmChartValues, helmOptions) {
async function installWko(helmExe, name, version, namespace, helmChartValues, helmOptions) {
const args = [ 'install', name, _wkoHelmChartName, '--namespace', namespace ];
if (version) {
args.push('--version', version);
}
processHelmChartValues(args, helmChartValues);
processHelmOptions(args, helmOptions);
args.push('--wait');

return _runHelmWko(helmExe, name, namespace, args, helmOptions, 'helm-install-wko-failed-error-message');
}

async function updateWko(helmExe, name, namespace, helmChartValues, helmOptions) {
async function updateWko(helmExe, name, version, namespace, helmChartValues, helmOptions) {
const args = [ 'upgrade', name, _wkoHelmChartName, '--namespace', namespace, '--reuse-values' ];
if (version) {
args.push('--version', version);
}
processHelmChartValues(args, helmChartValues);
processHelmOptions(args, helmOptions);
args.push('--wait');
Expand Down
2 changes: 2 additions & 0 deletions electron/app/js/ipcRendererPreload.js
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,8 @@ contextBridge.exposeInMainWorld(
'get-image-builder-exe',
'get-kube-config-files',
'get-latest-wko-image-name',
'get-latest-wko-version-number',
'get-wko-release-versions',
'get-archive-entry-types',
'get-archive-entry',
'get-network-settings',
Expand Down
25 changes: 25 additions & 0 deletions electron/app/js/wktTools.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ const {
getWdtLatestReleaseName,
getWitLatestReleaseName,
getWkoLatestReleaseImageName,
getWkoLatestReleaseVersion,
updateTools
} = require('./wktToolsInstaller');
const { getProxyOptionsFromPreferences } = require('./githubUtils');
Expand All @@ -29,6 +30,7 @@ const VERSION_FILE_NAME = 'VERSION.txt';
let _toolsDirectory;
let _wdtDirectory;
let _witDirectory;
let _wkoVersion;
let _wkoImageName;
let _wktMode;

Expand Down Expand Up @@ -120,14 +122,36 @@ async function getWdtSupportedDomainTypes() {
});
}

async function getLatestWkoVersion() {
if (_wkoVersion) {
return Promise.resolve(_wkoVersion);
}
return new Promise((resolve, reject) => {
getProxyOptionsFromPreferences().then(options => {
getWkoLatestReleaseVersion(options).then(version => {
_wkoVersion = version;
_wkoImageName = `ghcr.io/oracle/weblogic-kubernetes-operator:${_wkoVersion}`;
resolve(version);
}).catch(err => reject(new Error(`Failed to get the latest WebLogic Kubernetes Operator Version: ${err}`)));
}).catch(err => reject(err));
});
}

async function getLatestWkoImageName() {
if (_wkoImageName) {
return Promise.resolve(_wkoImageName);
} else if (_wkoVersion) {
return Promise.resolve(`ghcr.io/oracle/weblogic-kubernetes-operator:${_wkoVersion}`);
}
return new Promise((resolve, reject) => {
getProxyOptionsFromPreferences().then(options => {
getWkoLatestReleaseImageName(options).then(imageName => {
_wkoImageName = imageName;
const index = imageName.lastIndexOf(':');
if (index > -1) {
_wkoVersion = _wkoImageName.slice(index + 1);
}
_wkoVersion = imageName.split(':')[1];
resolve(imageName);
}).catch(err => reject(new Error(`Failed to get the latest WebLogic Kubernetes Operator Image Name: ${err}`)));
}).catch(err => reject(err));
Expand Down Expand Up @@ -285,6 +309,7 @@ module.exports = {
getInstalledWdtReleaseName,
getInstalledWitReleaseName,
getLatestWkoImageName,
getLatestWkoVersion,
getValidateModelShellScript,
getWdtCustomConfigDirectory,
getWdtSupportedDomainTypes,
Expand Down
13 changes: 11 additions & 2 deletions electron/app/js/wktToolsInstaller.js
Original file line number Diff line number Diff line change
Expand Up @@ -102,10 +102,18 @@ async function getWitLatestReleaseName(options) {
});
}

async function getWkoLatestReleaseImageName(options) {
async function getWkoLatestReleaseVersion(options) {
return new Promise((resolve, reject) => {
getLatestReleaseObject(wkoToolName, ghApiWkoBaseUrl, options).then(latestReleaseObj => {
const version = latestReleaseObj['name'].split(' ')[1];
resolve(version);
}).catch(err => reject(new Error(`Failed to determine latest release version for ${wkoToolName}: ${err}`)));
});
}

async function getWkoLatestReleaseImageName(options) {
return new Promise((resolve, reject) => {
getWkoLatestReleaseVersion(options).then(version => {
resolve(`${wkoImageName}:${version}`);
}).catch(err => reject(new Error(`Failed to determine latest release name for ${wkoToolName}: ${err}`)));
});
Expand Down Expand Up @@ -279,5 +287,6 @@ module.exports = {
installWitRelease,
getWdtLatestReleaseName,
getWitLatestReleaseName,
getWkoLatestReleaseImageName
getWkoLatestReleaseImageName,
getWkoLatestReleaseVersion
};
2 changes: 2 additions & 0 deletions electron/app/locales/en/webui.json
Original file line number Diff line number Diff line change
Expand Up @@ -403,6 +403,8 @@
"wko-design-k8s-service-account-help": "The name of the Kubernetes service account in the operator's namespace that the operator will use to make requests to the Kubernetes API server.",
"wko-design-wko-deploy-name-label": "Helm Release Name to Use for Operator Installation",
"wko-design-wko-deploy-name-help": "The Helm release name used to install the WebLogic Kubernetes Operator.",
"wko-design-version-label": "WebLogic Kubernetes Operator Version to Install",
"wko-design-version-help": "The version used to install the WebLogic Kubernetes Operator.",
"wko-design-image-tag-title": "WebLogic Kubernetes Operator Image",
"wko-design-image-tag-label": "Image Tag to Use",
"wko-design-image-tag-help": "The WebLogic Kubernetes Operator image to install.",
Expand Down
44 changes: 37 additions & 7 deletions electron/app/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ const kubectlUtils = require('./js/kubectlUtils');
const helmUtils = require('./js/helmUtils');
const openSSLUtils = require('./js/openSSLUtils');
const osUtils = require('./js/osUtils');
const githubUtils = require('./js/githubUtils');
const { initializeAutoUpdater, registerAutoUpdateListeners, installUpdates, getUpdateInformation } = require('./js/appUpdater');
const { startWebLogicRemoteConsoleBackend, getDefaultDirectoryForOpenDialog, setWebLogicRemoteConsoleHomeAndStart,
getDefaultWebLogicRemoteConsoleHome, getWebLogicRemoteConsoleBackendPort } = require('./js/wlRemoteConsoleUtils');
Expand All @@ -43,6 +44,7 @@ const { deployApplication, deployComponents, deployProject, getComponentNamesByN

const { getHttpsProxyUrl, getBypassProxyHosts } = require('./js/userSettings');
const { sendToWindow } = require('./js/windowUtils');
const {compareVersions} = require('./js/versionUtils');

const WKT_CONSOLE_STDOUT_CHANNEL = 'show-console-out-line';
const WKT_CONSOLE_STDERR_CHANNEL = 'show-console-err-line';
Expand Down Expand Up @@ -348,6 +350,10 @@ class Main {
return this._wktMode.isDevelopmentMode();
});

ipcMain.handle('get-latest-wko-version-number', async () => {
return wktTools.getLatestWkoVersion();
});

ipcMain.handle('get-latest-wko-image-name', async () => {
return wktTools.getLatestWkoImageName();
});
Expand Down Expand Up @@ -815,12 +821,17 @@ class Main {
return helmUtils.addOrUpdateWkoHelmChart(helmExe, helmOptions);
});

ipcMain.handle('helm-install-wko',async (event, helmExe, helmReleaseName, operatorNamespace, helmChartValues, helmOptions, kubectlExe, kubectlOptions) => {
const results = await helmUtils.installWko(helmExe, helmReleaseName, operatorNamespace, helmChartValues, helmOptions);
ipcMain.handle('helm-install-wko',async (event, helmExe, helmReleaseName, operatorVersion,
operatorNamespace, helmChartValues, helmOptions, kubectlExe, kubectlOptions) => {
const results = await helmUtils.installWko(helmExe, helmReleaseName, operatorVersion, operatorNamespace, helmChartValues, helmOptions);
if (results.isSuccess) {
const versionResults = await kubectlUtils.getOperatorVersion(kubectlExe, operatorNamespace, kubectlOptions);
if (versionResults.isSuccess) {
results.version = versionResults.version;
if (operatorVersion) {
results.version = operatorVersion;
} else {
const versionResults = await kubectlUtils.getOperatorVersion(kubectlExe, operatorNamespace, kubectlOptions);
if (versionResults.isSuccess) {
results.version = versionResults.version;
}
}
}
return Promise.resolve(results);
Expand All @@ -830,9 +841,9 @@ class Main {
return helmUtils.uninstallWko(helmExe, helmReleaseName, operatorNamespace, helmOptions);
});

ipcMain.handle('helm-update-wko', async (event, helmExe, operatorName,
ipcMain.handle('helm-update-wko', async (event, helmExe, operatorName, operatorVersion,
operatorNamespace, helmChartValues, helmOptions, kubectlExe = undefined, kubectlOptions = undefined) => {
const results = await helmUtils.updateWko(helmExe, operatorName, operatorNamespace, helmChartValues, helmOptions);
const results = await helmUtils.updateWko(helmExe, operatorName, operatorVersion, operatorNamespace, helmChartValues, helmOptions);
if (kubectlExe && results.isSuccess) {
const versionResults = await kubectlUtils.getOperatorVersion(kubectlExe, operatorNamespace, kubectlOptions);
if (versionResults.isSuccess) {
Expand Down Expand Up @@ -990,6 +1001,25 @@ class Main {
return getDefaultWebLogicRemoteConsoleHome();
});

// eslint-disable-next-line no-unused-vars
ipcMain.handle('get-wko-release-versions', async (event, minimumVersion = '3.3.0') => {
const ghApiWkoBaseUrl = 'https://api.github.com/repos/oracle/weblogic-kubernetes-operator';

return new Promise(resolve => {
githubUtils.getReleaseVersions('WebLogic Kubernetes Operator', ghApiWkoBaseUrl).then(results => {
const mappedResults = [];
results.forEach(result => {
const version = result.tag.slice(1);
// Filter out versions less than the minimum we want to support...
if (compareVersions(version, minimumVersion) >= 0) {
mappedResults.push({ ...result, version });
}
});
resolve(mappedResults);
});
});
});

// eslint-disable-next-line no-unused-vars
ipcMain.handle('get-verrazzano-release-versions', async (event, minimumVersion = undefined) => {
return getVerrazzanoReleaseVersions(minimumVersion);
Expand Down
4 changes: 3 additions & 1 deletion webui/src/js/models/wko-definition.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,9 @@ define(['utils/observable-properties', 'utils/validation-helper'],
this.k8sServiceAccount = props.createProperty('weblogic-operator-sa');
this.k8sServiceAccount.addValidator(...validationHelper.getK8sNameValidators());

this.operatorImage = props.createProperty(window.api.ipc.invoke('get-latest-wko-image-name'));
this.versionTag = props.createProperty(window.api.ipc.invoke('get-latest-wko-version-number'));

this.operatorImage = props.createProperty('ghcr.io/oracle/weblogic-kubernetes-operator:${1}', this.versionTag.observable);
const operatorImageValidators = validationHelper.getImageTagValidators();
this.operatorImage.addValidator(...operatorImageValidators);

Expand Down
5 changes: 4 additions & 1 deletion webui/src/js/utils/k8s-domain-deployer.js
Original file line number Diff line number Diff line change
Expand Up @@ -128,9 +128,10 @@ function (K8sDomainActionsBase, project, wktConsole, i18n, projectIo, dialogHelp
// Skip passing kubectlExe and kubectlOptions args since the installed version
// of operator was already set.
//
const operatorVersion = this.project.wko.installedVersion.value;
const helmOptions = helmHelper.getHelmOptions();
const upgradeResults = await window.api.ipc.invoke('helm-update-wko', helmExe, operatorName,
operatorNamespace, helmChartValues, helmOptions);
operatorVersion, operatorNamespace, helmChartValues, helmOptions);
if (!upgradeResults.isSuccess) {
const errMessage = i18n.t('k8s-domain-deployer-add-domain-error-message',
{
Expand Down Expand Up @@ -305,6 +306,8 @@ function (K8sDomainActionsBase, project, wktConsole, i18n, projectIo, dialogHelp
validationObject.addField('domain-design-uid-label', this.project.k8sDomain.uid.validate(true), domainFormConfig);
validationObject.addField('domain-design-namespace-label',
this.project.k8sDomain.kubernetesNamespace.validate(true), domainFormConfig);
validationObject.addField('domain-design-wko-installed-version-label',
validationHelper.validateRequiredField(this.project.wko.installedVersion.value), domainFormConfig);

const kubectlFormConfig = validationObject.getDefaultConfigObject();
kubectlFormConfig.formName = 'kubectl-form-name';
Expand Down
9 changes: 7 additions & 2 deletions webui/src/js/utils/wko-actions-base.js
Original file line number Diff line number Diff line change
Expand Up @@ -285,8 +285,13 @@ function(WktActionsBase, project, wktConsole, i18n, projectIo, dialogHelper, val
validationHelper.validateRequiredField(this.project.wko.k8sNamespace.value), wkoFormConfig);
validationObject.addField('wko-design-k8s-service-account-label',
validationHelper.validateRequiredField(this.project.wko.k8sServiceAccount.value), wkoFormConfig);
validationObject.addField('wko-design-image-tag-title',
this.project.wko.operatorImage.validate(true), wkoFormConfig);
validationObject.addField('wko-design-version-label',
validationHelper.validateRequiredField(this.project.wko.versionTag.value), wkoFormConfig);

if (this.project.wko.operatorImage.hasValue()) {
validationObject.addField('wko-design-image-tag-title',
this.project.wko.operatorImage.validate(true), wkoFormConfig);
}

if (this.project.wko.operatorImagePullRequiresAuthentication.value) {
validationObject.addField('wko-design-image-pull-secret-title',
Expand Down
3 changes: 2 additions & 1 deletion webui/src/js/utils/wko-installer.js
Original file line number Diff line number Diff line change
Expand Up @@ -137,11 +137,12 @@ function(WkoActionsBase, project, wktConsole, i18n, projectIo, dialogHelper, val

busyDialogMessage = i18n.t('wko-installer-install-in-progress', {helmReleaseName: helmReleaseName});
dialogHelper.updateBusyDialog(busyDialogMessage, 10 / totalSteps);
const operatorVersion = this.project.wko.versionTag.hasValue() ? this.project.wko.versionTag.value : undefined;
const helmChartValues = this.getWkoHelmChartValues(operatorServiceAccount);
wktLogger.debug('helmChartValues = %s', JSON.stringify(helmChartValues, null, 2));

const installResults = await window.api.ipc.invoke('helm-install-wko', helmExe, helmReleaseName,
operatorNamespace, helmChartValues, helmOptions, kubectlExe, kubectlOptions);
operatorVersion, operatorNamespace, helmChartValues, helmOptions, kubectlExe, kubectlOptions);

dialogHelper.closeBusyDialog();

Expand Down
3 changes: 2 additions & 1 deletion webui/src/js/utils/wko-updater.js
Original file line number Diff line number Diff line change
Expand Up @@ -136,11 +136,12 @@ function(WkoActionsBase, project, wktConsole, i18n, projectIo, dialogHelper, val

busyDialogMessage = i18n.t('wko-updater-update-in-progress', {helmReleaseName: helmReleaseName});
dialogHelper.updateBusyDialog(busyDialogMessage, 10 / totalSteps);
const operatorVersion = this.project.wko.installedVersion.version;
const helmChartValues = this.getWkoHelmChartValues(operatorServiceAccount);
wktLogger.debug('helmChartValues = %s', JSON.stringify(helmChartValues, null, 2));

const updateResults = await window.api.ipc.invoke('helm-update-wko', helmExe, helmReleaseName,
operatorNamespace, helmChartValues, helmOptions, kubectlExe, kubectlOptions);
operatorVersion, operatorNamespace, helmChartValues, helmOptions, kubectlExe, kubectlOptions);

dialogHelper.closeBusyDialog();
if (updateResults.isSuccess) {
Expand Down
12 changes: 12 additions & 0 deletions webui/src/js/viewModels/operator-design-view.js
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,18 @@ function (i18n, accUtils, ko, CoreRouter, ModuleRouterAdapter, ArrayDataProvider
value: ''
});
};

this.wkoVersions = ko.observableArray();
this.wkoVersionTags = new ArrayDataProvider(this.wkoVersions, {keyAttributes: 'version'});
window.api.ipc.invoke('get-wko-release-versions').then(versions => {
// Sort in descending order by version number.
//
versions.sort((a, b) => window.api.utils.compareVersions(a.version, b.version)).reverse();
this.wkoVersions.push(...versions.map(versionObject => {
const label = versionObject.version;
return { ...versionObject, label };
}));
});
}

/*
Expand Down
6 changes: 6 additions & 0 deletions webui/src/js/views/operator-design-view.html
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,12 @@ <h6 class="wkt-subheading"><oj-bind-text value="[[labelMapper('title')]]"></oj-b
validators="[[project.wko.wkoDeployName.validators()]]"
help.instruction="[[labelMapper('wko-deploy-name-help')]]">
</oj-input-text>
<oj-select-single label-hint="[[labelMapper('version-label')]]"
required
value="{{project.wko.versionTag.observable}}"
data="{{wkoVersionTags}}"
help.instruction="[[labelMapper('version-help')]]">
</oj-select-single>
</oj-form-layout>
</div>

Expand Down