Skip to content

Commit 64e9bc2

Browse files
adding support for working with older operator versions wiht the latest Helm chart (#192)
1 parent 210179e commit 64e9bc2

13 files changed

+121
-17
lines changed

electron/app/js/helmUtils.js

+8-2
Original file line numberDiff line numberDiff line change
@@ -121,17 +121,23 @@ async function uninstallIngressController(helmExe, ingressName, ingressNamespace
121121
});
122122
}
123123

124-
async function installWko(helmExe, name, namespace, helmChartValues, helmOptions) {
124+
async function installWko(helmExe, name, version, namespace, helmChartValues, helmOptions) {
125125
const args = [ 'install', name, _wkoHelmChartName, '--namespace', namespace ];
126+
if (version) {
127+
args.push('--version', version);
128+
}
126129
processHelmChartValues(args, helmChartValues);
127130
processHelmOptions(args, helmOptions);
128131
args.push('--wait');
129132

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

133-
async function updateWko(helmExe, name, namespace, helmChartValues, helmOptions) {
136+
async function updateWko(helmExe, name, version, namespace, helmChartValues, helmOptions) {
134137
const args = [ 'upgrade', name, _wkoHelmChartName, '--namespace', namespace, '--reuse-values' ];
138+
if (version) {
139+
args.push('--version', version);
140+
}
135141
processHelmChartValues(args, helmChartValues);
136142
processHelmOptions(args, helmOptions);
137143
args.push('--wait');

electron/app/js/ipcRendererPreload.js

+2
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,8 @@ contextBridge.exposeInMainWorld(
125125
'get-image-builder-exe',
126126
'get-kube-config-files',
127127
'get-latest-wko-image-name',
128+
'get-latest-wko-version-number',
129+
'get-wko-release-versions',
128130
'get-archive-entry-types',
129131
'get-archive-entry',
130132
'get-network-settings',

electron/app/js/wktTools.js

+25
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ const {
1919
getWdtLatestReleaseName,
2020
getWitLatestReleaseName,
2121
getWkoLatestReleaseImageName,
22+
getWkoLatestReleaseVersion,
2223
updateTools
2324
} = require('./wktToolsInstaller');
2425
const { getProxyOptionsFromPreferences } = require('./githubUtils');
@@ -29,6 +30,7 @@ const VERSION_FILE_NAME = 'VERSION.txt';
2930
let _toolsDirectory;
3031
let _wdtDirectory;
3132
let _witDirectory;
33+
let _wkoVersion;
3234
let _wkoImageName;
3335
let _wktMode;
3436

@@ -120,14 +122,36 @@ async function getWdtSupportedDomainTypes() {
120122
});
121123
}
122124

125+
async function getLatestWkoVersion() {
126+
if (_wkoVersion) {
127+
return Promise.resolve(_wkoVersion);
128+
}
129+
return new Promise((resolve, reject) => {
130+
getProxyOptionsFromPreferences().then(options => {
131+
getWkoLatestReleaseVersion(options).then(version => {
132+
_wkoVersion = version;
133+
_wkoImageName = `ghcr.io/oracle/weblogic-kubernetes-operator:${_wkoVersion}`;
134+
resolve(version);
135+
}).catch(err => reject(new Error(`Failed to get the latest WebLogic Kubernetes Operator Version: ${err}`)));
136+
}).catch(err => reject(err));
137+
});
138+
}
139+
123140
async function getLatestWkoImageName() {
124141
if (_wkoImageName) {
125142
return Promise.resolve(_wkoImageName);
143+
} else if (_wkoVersion) {
144+
return Promise.resolve(`ghcr.io/oracle/weblogic-kubernetes-operator:${_wkoVersion}`);
126145
}
127146
return new Promise((resolve, reject) => {
128147
getProxyOptionsFromPreferences().then(options => {
129148
getWkoLatestReleaseImageName(options).then(imageName => {
130149
_wkoImageName = imageName;
150+
const index = imageName.lastIndexOf(':');
151+
if (index > -1) {
152+
_wkoVersion = _wkoImageName.slice(index + 1);
153+
}
154+
_wkoVersion = imageName.split(':')[1];
131155
resolve(imageName);
132156
}).catch(err => reject(new Error(`Failed to get the latest WebLogic Kubernetes Operator Image Name: ${err}`)));
133157
}).catch(err => reject(err));
@@ -285,6 +309,7 @@ module.exports = {
285309
getInstalledWdtReleaseName,
286310
getInstalledWitReleaseName,
287311
getLatestWkoImageName,
312+
getLatestWkoVersion,
288313
getValidateModelShellScript,
289314
getWdtCustomConfigDirectory,
290315
getWdtSupportedDomainTypes,

electron/app/js/wktToolsInstaller.js

+11-2
Original file line numberDiff line numberDiff line change
@@ -102,10 +102,18 @@ async function getWitLatestReleaseName(options) {
102102
});
103103
}
104104

105-
async function getWkoLatestReleaseImageName(options) {
105+
async function getWkoLatestReleaseVersion(options) {
106106
return new Promise((resolve, reject) => {
107107
getLatestReleaseObject(wkoToolName, ghApiWkoBaseUrl, options).then(latestReleaseObj => {
108108
const version = latestReleaseObj['name'].split(' ')[1];
109+
resolve(version);
110+
}).catch(err => reject(new Error(`Failed to determine latest release version for ${wkoToolName}: ${err}`)));
111+
});
112+
}
113+
114+
async function getWkoLatestReleaseImageName(options) {
115+
return new Promise((resolve, reject) => {
116+
getWkoLatestReleaseVersion(options).then(version => {
109117
resolve(`${wkoImageName}:${version}`);
110118
}).catch(err => reject(new Error(`Failed to determine latest release name for ${wkoToolName}: ${err}`)));
111119
});
@@ -279,5 +287,6 @@ module.exports = {
279287
installWitRelease,
280288
getWdtLatestReleaseName,
281289
getWitLatestReleaseName,
282-
getWkoLatestReleaseImageName
290+
getWkoLatestReleaseImageName,
291+
getWkoLatestReleaseVersion
283292
};

electron/app/locales/en/webui.json

+2
Original file line numberDiff line numberDiff line change
@@ -403,6 +403,8 @@
403403
"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.",
404404
"wko-design-wko-deploy-name-label": "Helm Release Name to Use for Operator Installation",
405405
"wko-design-wko-deploy-name-help": "The Helm release name used to install the WebLogic Kubernetes Operator.",
406+
"wko-design-version-label": "WebLogic Kubernetes Operator Version to Install",
407+
"wko-design-version-help": "The version used to install the WebLogic Kubernetes Operator.",
406408
"wko-design-image-tag-title": "WebLogic Kubernetes Operator Image",
407409
"wko-design-image-tag-label": "Image Tag to Use",
408410
"wko-design-image-tag-help": "The WebLogic Kubernetes Operator image to install.",

electron/app/main.js

+37-7
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ const kubectlUtils = require('./js/kubectlUtils');
3333
const helmUtils = require('./js/helmUtils');
3434
const openSSLUtils = require('./js/openSSLUtils');
3535
const osUtils = require('./js/osUtils');
36+
const githubUtils = require('./js/githubUtils');
3637
const { initializeAutoUpdater, registerAutoUpdateListeners, installUpdates, getUpdateInformation } = require('./js/appUpdater');
3738
const { startWebLogicRemoteConsoleBackend, getDefaultDirectoryForOpenDialog, setWebLogicRemoteConsoleHomeAndStart,
3839
getDefaultWebLogicRemoteConsoleHome, getWebLogicRemoteConsoleBackendPort } = require('./js/wlRemoteConsoleUtils');
@@ -43,6 +44,7 @@ const { deployApplication, deployComponents, deployProject, getComponentNamesByN
4344

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

4749
const WKT_CONSOLE_STDOUT_CHANNEL = 'show-console-out-line';
4850
const WKT_CONSOLE_STDERR_CHANNEL = 'show-console-err-line';
@@ -348,6 +350,10 @@ class Main {
348350
return this._wktMode.isDevelopmentMode();
349351
});
350352

353+
ipcMain.handle('get-latest-wko-version-number', async () => {
354+
return wktTools.getLatestWkoVersion();
355+
});
356+
351357
ipcMain.handle('get-latest-wko-image-name', async () => {
352358
return wktTools.getLatestWkoImageName();
353359
});
@@ -815,12 +821,17 @@ class Main {
815821
return helmUtils.addOrUpdateWkoHelmChart(helmExe, helmOptions);
816822
});
817823

818-
ipcMain.handle('helm-install-wko',async (event, helmExe, helmReleaseName, operatorNamespace, helmChartValues, helmOptions, kubectlExe, kubectlOptions) => {
819-
const results = await helmUtils.installWko(helmExe, helmReleaseName, operatorNamespace, helmChartValues, helmOptions);
824+
ipcMain.handle('helm-install-wko',async (event, helmExe, helmReleaseName, operatorVersion,
825+
operatorNamespace, helmChartValues, helmOptions, kubectlExe, kubectlOptions) => {
826+
const results = await helmUtils.installWko(helmExe, helmReleaseName, operatorVersion, operatorNamespace, helmChartValues, helmOptions);
820827
if (results.isSuccess) {
821-
const versionResults = await kubectlUtils.getOperatorVersion(kubectlExe, operatorNamespace, kubectlOptions);
822-
if (versionResults.isSuccess) {
823-
results.version = versionResults.version;
828+
if (operatorVersion) {
829+
results.version = operatorVersion;
830+
} else {
831+
const versionResults = await kubectlUtils.getOperatorVersion(kubectlExe, operatorNamespace, kubectlOptions);
832+
if (versionResults.isSuccess) {
833+
results.version = versionResults.version;
834+
}
824835
}
825836
}
826837
return Promise.resolve(results);
@@ -830,9 +841,9 @@ class Main {
830841
return helmUtils.uninstallWko(helmExe, helmReleaseName, operatorNamespace, helmOptions);
831842
});
832843

833-
ipcMain.handle('helm-update-wko', async (event, helmExe, operatorName,
844+
ipcMain.handle('helm-update-wko', async (event, helmExe, operatorName, operatorVersion,
834845
operatorNamespace, helmChartValues, helmOptions, kubectlExe = undefined, kubectlOptions = undefined) => {
835-
const results = await helmUtils.updateWko(helmExe, operatorName, operatorNamespace, helmChartValues, helmOptions);
846+
const results = await helmUtils.updateWko(helmExe, operatorName, operatorVersion, operatorNamespace, helmChartValues, helmOptions);
836847
if (kubectlExe && results.isSuccess) {
837848
const versionResults = await kubectlUtils.getOperatorVersion(kubectlExe, operatorNamespace, kubectlOptions);
838849
if (versionResults.isSuccess) {
@@ -990,6 +1001,25 @@ class Main {
9901001
return getDefaultWebLogicRemoteConsoleHome();
9911002
});
9921003

1004+
// eslint-disable-next-line no-unused-vars
1005+
ipcMain.handle('get-wko-release-versions', async (event, minimumVersion = '3.3.0') => {
1006+
const ghApiWkoBaseUrl = 'https://api.github.com/repos/oracle/weblogic-kubernetes-operator';
1007+
1008+
return new Promise(resolve => {
1009+
githubUtils.getReleaseVersions('WebLogic Kubernetes Operator', ghApiWkoBaseUrl).then(results => {
1010+
const mappedResults = [];
1011+
results.forEach(result => {
1012+
const version = result.tag.slice(1);
1013+
// Filter out versions less than the minimum we want to support...
1014+
if (compareVersions(version, minimumVersion) >= 0) {
1015+
mappedResults.push({ ...result, version });
1016+
}
1017+
});
1018+
resolve(mappedResults);
1019+
});
1020+
});
1021+
});
1022+
9931023
// eslint-disable-next-line no-unused-vars
9941024
ipcMain.handle('get-verrazzano-release-versions', async (event, minimumVersion = undefined) => {
9951025
return getVerrazzanoReleaseVersions(minimumVersion);

webui/src/js/models/wko-definition.js

+3-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,9 @@ define(['utils/observable-properties', 'utils/validation-helper'],
1818
this.k8sServiceAccount = props.createProperty('weblogic-operator-sa');
1919
this.k8sServiceAccount.addValidator(...validationHelper.getK8sNameValidators());
2020

21-
this.operatorImage = props.createProperty(window.api.ipc.invoke('get-latest-wko-image-name'));
21+
this.versionTag = props.createProperty(window.api.ipc.invoke('get-latest-wko-version-number'));
22+
23+
this.operatorImage = props.createProperty('ghcr.io/oracle/weblogic-kubernetes-operator:${1}', this.versionTag.observable);
2224
const operatorImageValidators = validationHelper.getImageTagValidators();
2325
this.operatorImage.addValidator(...operatorImageValidators);
2426

webui/src/js/utils/k8s-domain-deployer.js

+4-1
Original file line numberDiff line numberDiff line change
@@ -128,9 +128,10 @@ function (K8sDomainActionsBase, project, wktConsole, i18n, projectIo, dialogHelp
128128
// Skip passing kubectlExe and kubectlOptions args since the installed version
129129
// of operator was already set.
130130
//
131+
const operatorVersion = this.project.wko.installedVersion.value;
131132
const helmOptions = helmHelper.getHelmOptions();
132133
const upgradeResults = await window.api.ipc.invoke('helm-update-wko', helmExe, operatorName,
133-
operatorNamespace, helmChartValues, helmOptions);
134+
operatorVersion, operatorNamespace, helmChartValues, helmOptions);
134135
if (!upgradeResults.isSuccess) {
135136
const errMessage = i18n.t('k8s-domain-deployer-add-domain-error-message',
136137
{
@@ -305,6 +306,8 @@ function (K8sDomainActionsBase, project, wktConsole, i18n, projectIo, dialogHelp
305306
validationObject.addField('domain-design-uid-label', this.project.k8sDomain.uid.validate(true), domainFormConfig);
306307
validationObject.addField('domain-design-namespace-label',
307308
this.project.k8sDomain.kubernetesNamespace.validate(true), domainFormConfig);
309+
validationObject.addField('domain-design-wko-installed-version-label',
310+
validationHelper.validateRequiredField(this.project.wko.installedVersion.value), domainFormConfig);
308311

309312
const kubectlFormConfig = validationObject.getDefaultConfigObject();
310313
kubectlFormConfig.formName = 'kubectl-form-name';

webui/src/js/utils/wko-actions-base.js

+7-2
Original file line numberDiff line numberDiff line change
@@ -285,8 +285,13 @@ function(WktActionsBase, project, wktConsole, i18n, projectIo, dialogHelper, val
285285
validationHelper.validateRequiredField(this.project.wko.k8sNamespace.value), wkoFormConfig);
286286
validationObject.addField('wko-design-k8s-service-account-label',
287287
validationHelper.validateRequiredField(this.project.wko.k8sServiceAccount.value), wkoFormConfig);
288-
validationObject.addField('wko-design-image-tag-title',
289-
this.project.wko.operatorImage.validate(true), wkoFormConfig);
288+
validationObject.addField('wko-design-version-label',
289+
validationHelper.validateRequiredField(this.project.wko.versionTag.value), wkoFormConfig);
290+
291+
if (this.project.wko.operatorImage.hasValue()) {
292+
validationObject.addField('wko-design-image-tag-title',
293+
this.project.wko.operatorImage.validate(true), wkoFormConfig);
294+
}
290295

291296
if (this.project.wko.operatorImagePullRequiresAuthentication.value) {
292297
validationObject.addField('wko-design-image-pull-secret-title',

webui/src/js/utils/wko-installer.js

+2-1
Original file line numberDiff line numberDiff line change
@@ -137,11 +137,12 @@ function(WkoActionsBase, project, wktConsole, i18n, projectIo, dialogHelper, val
137137

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

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

146147
dialogHelper.closeBusyDialog();
147148

webui/src/js/utils/wko-updater.js

+2-1
Original file line numberDiff line numberDiff line change
@@ -136,11 +136,12 @@ function(WkoActionsBase, project, wktConsole, i18n, projectIo, dialogHelper, val
136136

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

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

145146
dialogHelper.closeBusyDialog();
146147
if (updateResults.isSuccess) {

webui/src/js/viewModels/operator-design-view.js

+12
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,18 @@ function (i18n, accUtils, ko, CoreRouter, ModuleRouterAdapter, ArrayDataProvider
131131
value: ''
132132
});
133133
};
134+
135+
this.wkoVersions = ko.observableArray();
136+
this.wkoVersionTags = new ArrayDataProvider(this.wkoVersions, {keyAttributes: 'version'});
137+
window.api.ipc.invoke('get-wko-release-versions').then(versions => {
138+
// Sort in descending order by version number.
139+
//
140+
versions.sort((a, b) => window.api.utils.compareVersions(a.version, b.version)).reverse();
141+
this.wkoVersions.push(...versions.map(versionObject => {
142+
const label = versionObject.version;
143+
return { ...versionObject, label };
144+
}));
145+
});
134146
}
135147

136148
/*

webui/src/js/views/operator-design-view.html

+6
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,12 @@ <h6 class="wkt-subheading"><oj-bind-text value="[[labelMapper('title')]]"></oj-b
2020
validators="[[project.wko.wkoDeployName.validators()]]"
2121
help.instruction="[[labelMapper('wko-deploy-name-help')]]">
2222
</oj-input-text>
23+
<oj-select-single label-hint="[[labelMapper('version-label')]]"
24+
required
25+
value="{{project.wko.versionTag.observable}}"
26+
data="{{wkoVersionTags}}"
27+
help.instruction="[[labelMapper('version-help')]]">
28+
</oj-select-single>
2329
</oj-form-layout>
2430
</div>
2531

0 commit comments

Comments
 (0)