Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 49c41ae

Browse files
Add Verrazzano application status button and dialog (#168)
1 parent e34fb6c commit 49c41ae

14 files changed

+572
-136
lines changed

‎electron/app/js/ipcRendererPreload.js‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,8 @@ contextBridge.exposeInMainWorld(
213213
'openssl-generate-certs',
214214
'validate-k8s-namespaces-exist',
215215
'validate-wko-domain-exist',
216+
'validate-vz-application-exist',
217+
'vz-get-application-status',
216218
'get-wrc-home-directory',
217219
'get-wrc-app-image',
218220
'wrc-get-home-default-value',

‎electron/app/js/kubectlUtils.js‎

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,14 @@ async function getWkoDomainStatus(kubectlExe, domainUID, domainNamespace, option
156156
});
157157
}
158158

159+
// Currently, this call returns the status of the domain component with domainUID, similar to getWkoDomainStatus.
160+
// In future releases, there may be additional information about the application and other components.
161+
async function getApplicationStatus(kubectlExe, application, domainUID, namespace, options) {
162+
const results = await getWkoDomainStatus(kubectlExe, domainUID, namespace, options);
163+
results['application'] = application;
164+
return results;
165+
}
166+
159167
async function getOperatorStatus(kubectlExe, operatorNamespace, options) {
160168
const args = [ 'get', 'pods', '-n', operatorNamespace, '-o', 'json'];
161169
const httpsProxyUrl = getHttpsProxyUrl();
@@ -312,6 +320,32 @@ async function validateDomainExist(kubectlExe, options, domain, namespace) {
312320
return Promise.resolve(result);
313321
}
314322

323+
async function validateApplicationExist(kubectlExe, options, application, namespace) {
324+
const httpsProxyUrl = getHttpsProxyUrl();
325+
const bypassProxyHosts = getBypassProxyHosts();
326+
const env = getKubectlEnvironment(options, httpsProxyUrl, bypassProxyHosts);
327+
328+
const result = {
329+
isSuccess: true,
330+
isValid: true,
331+
};
332+
333+
const args = [ 'get', 'appconfig', application, '-n', namespace ];
334+
335+
try {
336+
await executeFileCommand(kubectlExe, args, env);
337+
} catch (err) {
338+
if (isNotFoundError(err)) {
339+
result.isValid = false;
340+
} else {
341+
result.isSuccess = false;
342+
result.reason = getErrorMessage(err);
343+
return Promise.resolve(result);
344+
}
345+
}
346+
return Promise.resolve(result);
347+
}
348+
315349
async function isOperatorAlreadyInstalled(kubectlExe, operatorName, operatorNamespace, options) {
316350
// We are currently using kubectl to see if the operator deployment exists. The operator deployment
317351
// name is always weblogic-operator...
@@ -958,6 +992,7 @@ module.exports = {
958992
getK8sConfigView,
959993
getK8sClusterInfo,
960994
getWkoDomainStatus,
995+
getApplicationStatus,
961996
getOperatorStatus,
962997
getOperatorVersionFromDomainConfigMap,
963998
getOperatorLogs,
@@ -966,6 +1001,7 @@ module.exports = {
9661001
getKubernetesObjectsFromAllNamespaces,
9671002
validateNamespacesExist,
9681003
validateDomainExist,
1004+
validateApplicationExist,
9691005
verifyClusterConnectivity,
9701006
verifyVerrazzanoPlatformOperatorRollout,
9711007
};

‎electron/app/locales/en/electron.json‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -322,6 +322,7 @@
322322
"kubectl-tlsfile-failed-error-message": "Unable to verify TLS file {{filePath}} exists: {{error}}",
323323
"kubectl-get-vz-install-failed-error-message": "Unable to get Verrazzano installation: {{error}}",
324324
"kubectl-get-named-vz-install-error-message": "Unable to get Verrazzano installation with name {{name}}: {{error}}",
325+
"kubectl-get-vz-application-status-error-message": "Unable to get Verrazzano application status: {{error}}",
325326

326327
"helm-not-specified-error-message": "Helm executable path was not provided",
327328
"helm-not-exists-error-message": "Helm executable {{filePath}} does not exist",

‎electron/app/locales/en/webui.json‎

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1301,6 +1301,7 @@
13011301
"flow-validate-k8s-domain-in-progress": "Validating domain {{domain}} exists",
13021302
"flow-get-domain-status-name": "Get Domain Status",
13031303
"flow-getting-k8s-domain-status-in-progress": "Getting domain {{domain}} status",
1304+
"flow-getting-vz-application-status-in-progress": "Getting Application Status",
13041305
"flow-checking-operator-version-in-progress": "Checking operator version",
13051306
"flow-checking-vz-already-installed-in-progress": "Checking if Verrazzano is already installed.",
13061307
"flow-install-verrazzano-name": "Install Verrazzano",
@@ -1310,6 +1311,10 @@
13101311
"flow-verrazzano-undeploy-component-name": "Undeploy Verrazzano Component",
13111312
"flow-verrazzano-deploy-application-name": "Deploy Verrazzano Application",
13121313
"flow-verrazzano-undeploy-application-name": "Undeploy Verrazzano Application",
1314+
"flow-verrazzano-get-application-status-name": "Get Application Status",
1315+
"flow-validate-vz-application-namespace-in-progress": "Validating application namespace {{namespace}} exists",
1316+
"flow-validate-vz-application-in-progress": "Validating application {{application}} exists",
1317+
"flow-validate-vz-domain-in-progress": "Validating domain UID {{domain}} exists",
13131318

13141319
"add-archive-file-title": "Add Archive File",
13151320
"add-archive-file-replace-message": "This will replace the existing archive, continue?",
@@ -1517,6 +1522,8 @@
15171522

15181523
"vz-application-page-button-deployApplication": "Deploy Application",
15191524
"vz-application-page-hints-deployApplication": "Deploy Application to Verrazzano",
1525+
"vz-application-page-button-applicationStatus": "Get Application Status",
1526+
"vz-application-page-hints-applicationStatus": "Check Application Deployment Status",
15201527
"vz-application-page-button-undeployApplication": "Undeploy Application",
15211528
"vz-application-page-hints-undeployApplication": "Undeploy Application from Verrazzano",
15221529

@@ -1692,6 +1699,15 @@
16921699
"vz-application-undeployer-undeploy-failed-error-message":"Unable to undeploy Verrazzano application {{name}} from Kubernetes namespace {{namespace}}: {{error}}.",
16931700
"vz-application-undeployer-undeploy-catch-all-error-message": "Verrazzano application undeployment from Kubernetes failed with an unexpected error: {{error}}",
16941701

1702+
"vz-application-status-checker-get-status-failed-title-message": "Get Application Status Failed",
1703+
"vz-application-status-checker-get-status-failed-error-message": "Unable to get the application status due to an error: {{error}}.",
1704+
"vz-application-status-checker-application-not-exist-error-message": "Unable to get the application status because the application {{application}} does not exist.",
1705+
"vz-application-status-checker-ns-not-exist-error-message": "Unable to get the application status because the application namespace {{namespace}} does not exist.",
1706+
"vz-application-status-checker-domain-not-exist-error-message": "Unable to get the application status because the domain UID {{domain}} does not exist.",
1707+
1708+
"vz-application-status-title": "Application Status for \"{{application}}\"",
1709+
"vz-application-status-domain-title": "Domain \"{{domain}}\"",
1710+
16951711
"app-update-title": "Application Update",
16961712
"app-update-new-release": "A new release is available: {{releaseName}}",
16971713
"app-update-release-notes": "Release Notes",

‎electron/app/main.js‎

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -757,6 +757,14 @@ class Main {
757757
return kubectlUtils.validateDomainExist(kubectlExe, kubectlOptions, domain, namespace);
758758
});
759759

760+
ipcMain.handle('validate-vz-application-exist', async (event, kubectlExe, kubectlOptions, application, namespace) => {
761+
return kubectlUtils.validateApplicationExist(kubectlExe, kubectlOptions, application, namespace);
762+
});
763+
764+
ipcMain.handle('vz-get-application-status', async (event, kubectlExe, application, namespace, options) => {
765+
return kubectlUtils.getApplicationStatus(kubectlExe, application, namespace, options);
766+
});
767+
760768
ipcMain.handle('is-wko-installed', async (event, kubectlExe, operatorName, operatorNamespace, kubectlOptions) => {
761769
return kubectlUtils.isOperatorAlreadyInstalled(kubectlExe, operatorName, operatorNamespace, kubectlOptions);
762770
});

‎webui/src/css/app.css‎

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -705,6 +705,18 @@ h6.wkt-panel-heading {
705705
color: red !important;
706706
}
707707

708+
.wkt-status-paragraph {
709+
margin: 1rem 0 0 0;
710+
}
711+
712+
.wkt-status-paragraph.domainError {
713+
color:red;
714+
}
715+
716+
.wkt-status-paragraph.preformat {
717+
white-space: pre-wrap;
718+
}
719+
708720
.wkt-dialog-content {
709721
box-sizing: border-box;
710722
display: flex;

‎webui/src/js/utils/k8s-domain-actions-base.js‎

Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,137 @@ function (WktActionsBase, project, wktConsole, i18n, projectIo, dialogHelper) {
3838
}
3939
return Promise.resolve(true);
4040
}
41+
42+
// create a data structure with readable details about domain status.
43+
// wkoDomainStatus is the domainStatus value from the k8s-get-wko-domain-status IPC result.
44+
buildDomainStatus(wkoDomainStatus, operatorMajorVersion) {
45+
const status = wkoDomainStatus.status;
46+
let result = {isSuccess: true, domainOverallStatus: 'Unknown'};
47+
48+
if (typeof status !== 'undefined' && 'conditions' in status && status['conditions'].length > 0) {
49+
const conditions = status['conditions'];
50+
// default status
51+
result['domainOverallStatus'] = i18n.t('k8s-domain-status-checker-domain-status-unknown');
52+
conditions.sort((a, b) => {
53+
if (a.lastTransitionTime < b.lastTransitionTime) {
54+
return 1;
55+
}
56+
if (a.lastTransitionTime > b.lastTransitionTime) {
57+
return -1;
58+
}
59+
return 0;
60+
});
61+
62+
if (operatorMajorVersion < 4) {
63+
const hasErrors = this.hasErrorConditions(conditions);
64+
const latestCondition = conditions[0];
65+
66+
if (hasErrors.error) {
67+
// There seems to be a problem in the operator where the latest condition is progressing but
68+
// there is an error previously but
69+
result['domainOverallStatus'] = i18n.t('k8s-domain-status-checker-domain-status-failed',
70+
{reason: hasErrors.reason});
71+
} else if (latestCondition.type === 'Failed') {
72+
result['domainOverallStatus'] = i18n.t('k8s-domain-status-checker-domain-status-failed',
73+
{reason: latestCondition.reason});
74+
} else if (latestCondition.type === 'Progressing') {
75+
// Progressing maybe the domain is coming up, maybe the introspector is running
76+
result['domainOverallStatus'] = i18n.t('k8s-domain-status-checker-domain-status-progressing',
77+
{reason: latestCondition.reason});
78+
} else if (latestCondition.type === 'Available') {
79+
result['domainOverallStatus'] = 'Progressing';
80+
if (status['clusters'].length > 0) {
81+
const clusters = status['clusters'];
82+
let ready = true;
83+
clusters.forEach((cluster) => {
84+
if (Number(cluster['replicasGoal']) !== Number(cluster['readyReplicas'])) {
85+
ready = false;
86+
}
87+
});
88+
89+
if (ready) {
90+
result['domainOverallStatus'] = i18n.t('k8s-domain-status-checker-domain-status-complete');
91+
} else {
92+
result['domainOverallStatus'] = i18n.t('k8s-domain-status-checker-domain-status-available',
93+
{reason: latestCondition.reason});
94+
}
95+
} else {
96+
// remain in progressing
97+
}
98+
}
99+
} else {
100+
///
101+
const hasErrors = this.hasErrorConditions(conditions);
102+
const completeCondition = this.getCompletedCondition(conditions);
103+
const availableCondition = this.getAvailableCondition(conditions);
104+
const latestCondition = conditions[0];
105+
106+
if (hasErrors.error) {
107+
result['domainOverallStatus'] = i18n.t('k8s-domain-status-checker-domain-status-failed',
108+
{reason: hasErrors.reason});
109+
} else if (completeCondition.status === 'True' && availableCondition.status === 'True') {
110+
result['domainOverallStatus'] = i18n.t('k8s-domain-status-checker-domain-status-complete');
111+
} else {
112+
// Assume this is introspection progressing
113+
114+
if (completeCondition.status === 'False' && !this.hasAvailableCondition(conditions)) {
115+
result['domainOverallStatus'] = i18n.t('k8s-domain-status-checker-domain-status-progressing',
116+
{reason: latestCondition.reason});
117+
} else if (completeCondition.status === 'False' && availableCondition.status === 'False') {
118+
result['domainOverallStatus'] = i18n.t('k8s-domain-status-checker-domain-status-available',
119+
{reason: latestCondition.reason});
120+
} else {
121+
// should never happened?
122+
result['domainOverallStatus'] = i18n.t('k8s-domain-status-checker-domain-status-unknown',
123+
{reason: latestCondition.reason});
124+
}
125+
}
126+
}
127+
128+
} else {
129+
// status not defined or no conditions - error in operator or namespace is not monitored
130+
result['domainOverallStatus'] = i18n.t('k8s-domain-status-checker-domain-status-unknown');
131+
}
132+
return result;
133+
}
134+
135+
hasErrorConditions(conditions) {
136+
for (const condition of conditions) {
137+
if (condition.type === 'Failed') {
138+
return {error: true, reason: condition.reason};
139+
}
140+
}
141+
return {error: false, reason: ''};
142+
}
143+
144+
getCompletedCondition(conditions) {
145+
const defaultCondition = {type: 'Completed', status: 'False'};
146+
for (const condition of conditions) {
147+
if (condition.type === 'Completed') {
148+
return condition;
149+
}
150+
}
151+
return defaultCondition;
152+
}
153+
154+
getAvailableCondition(conditions) {
155+
const defaultCondition = {type: 'Available', status: 'False'};
156+
for (const condition of conditions) {
157+
if (condition.type === 'Available') {
158+
return condition;
159+
}
160+
}
161+
return defaultCondition;
162+
}
163+
164+
hasAvailableCondition(conditions) {
165+
for (const condition of conditions) {
166+
if (condition.type === 'Available') {
167+
return true;
168+
}
169+
}
170+
return false;
171+
}
41172
}
42173

43174
return K8sDomainActionsBase;

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /