Skip to content
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
14 changes: 13 additions & 1 deletion Jenkinsfile
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
/*
* Copyright (c) 2021, 2022, Oracle and/or its affiliates.
* Copyright (c) 2021, 2023, Oracle and/or its affiliates.
* Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl.
*/
pipeline {
agent { label 'ol8' }
options {
timeout(time: 480, unit: 'MINUTES')
}
environment {
WKTUI_PROXY = "${env.ORACLE_HTTP_PROXY}"
ELECTRON_GET_USE_PROXY = "true"
Expand Down Expand Up @@ -54,6 +57,9 @@ pipeline {
parallel {
stage('Linux Build') {
agent { label 'ol8' }
options {
timeout(time: 300, unit: 'MINUTES')
}
environment {
linux_node_dir_name = "node-v${node_version}-linux-x64"
linux_node_installer = "${linux_node_dir_name}.tar.gz"
Expand Down Expand Up @@ -194,6 +200,9 @@ pipeline {
}
stage('MacOS Build') {
agent { label('macosx') }
options {
timeout(time: 300, unit: 'MINUTES')
}
environment {
mac_node_dir_name = "node-v${node_version}-darwin-x64"
mac_node_installer = "node-v${node_version}-darwin-x64.tar.gz"
Expand Down Expand Up @@ -301,6 +310,9 @@ pipeline {
}
stage('Windows Build') {
agent { label 'windows'}
options {
timeout(time: 300, unit: 'MINUTES')
}
environment {
windows_node_dir_name = "node-v${node_version}-win-x64"
windows_node_installer = "node-v${node_version}-win-x64.zip"
Expand Down
1 change: 1 addition & 0 deletions electron/app/js/ipcRendererPreload.js
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,7 @@ contextBridge.exposeInMainWorld(
'do-push-image',
'kubectl-get-current-context',
'kubectl-set-current-context',
'kubectl-get-contexts',
'validate-kubectl-exe',
'kubectl-verify-connection',
'validate-helm-exe',
Expand Down
101 changes: 100 additions & 1 deletion electron/app/js/kubectlUtils.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/**
* @license
* Copyright (c) 2021, 2022, Oracle and/or its affiliates.
* Copyright (c) 2021, 2023, Oracle and/or its affiliates.
* Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl.
*/
'use strict';
Expand Down Expand Up @@ -90,6 +90,30 @@ async function setCurrentContext(kubectlExe, context, options) {
});
}

async function getContexts(kubectlExe, options) {
const args = [ 'config', 'get-contexts', '--output=name' ];
const httpsProxyUrl = getHttpsProxyUrl();
const bypassProxyHosts = getBypassProxyHosts();
const env = getKubectlEnvironment(options, httpsProxyUrl, bypassProxyHosts);
const results = {
isSuccess: true
};

return new Promise(resolve => {
executeFileCommand(kubectlExe, args, env).then(currentContext => {
results['contexts'] = currentContext.trim().split('\n');
getLogger().debug('getContexts result = %s', results['contexts']);
resolve(results);
}).catch(err => {
// kubectl config get-contexts returns an error if the config file doesn't exist...
results.isSuccess = false;
results.reason =
i18n.t('kubectl-get-contexts-error-message',{ error: getErrorMessage(err) });
resolve(results);
});
});
}

async function getK8sConfigView(kubectlExe, options) {
const args = [ 'config', 'view', '-o', 'json'];
const httpsProxyUrl = getHttpsProxyUrl();
Expand Down Expand Up @@ -1018,6 +1042,78 @@ async function doCreateSecret(kubectlExe, createArgs, env, namespace, secret, re
});
}

async function getVerrazzanoIngressExternalAddress(kubectlExe, options) {
const gatewayService = 'istio-ingressgateway';
const gatewayNamespace = 'istio-system';

const args = [ 'get', 'service', gatewayService, '-n', gatewayNamespace, '-o', 'json'];
const httpsProxyUrl = getHttpsProxyUrl();
const bypassProxyHosts = getBypassProxyHosts();
const env = getKubectlEnvironment(options, httpsProxyUrl, bypassProxyHosts);
const results = {
isSuccess: true
};

return new Promise(resolve => {
executeFileCommand(kubectlExe, args, env).then(serviceJson => {
const service = JSON.parse(serviceJson);
const ingressArray = service.status?.loadBalancer?.ingress;

if (Array.isArray(ingressArray) && ingressArray.length > 0) {
results.externalAddress = ingressArray[0].ip;
}
if (!results.externalAddress) {
results.reason = i18n.t('kubectl-get-vz-ingress-external-address-not-found',
{ gatewayService, gatewayNamespace });
}
resolve(results);
}).catch(err => {
results.isSuccess = false;
results.reason =
i18n.t('kubectl-get-vz-ingress-external-address-error-message',
{ gatewayService, gatewayNamespace, error: getErrorMessage(err) });
resolve(results);
});
});
}

async function getVerrazzanoApplicationHostnames(kubectlExe, applicationName, applicationNamespace, options) {
const gatewayType = 'gateways.networking.istio.io';
const appGatewayName = `${applicationNamespace}-${applicationName}-gw`;

const args = [ 'get', gatewayType, appGatewayName, '-n', applicationNamespace, '-o', 'json'];
const httpsProxyUrl = getHttpsProxyUrl();
const bypassProxyHosts = getBypassProxyHosts();
const env = getKubectlEnvironment(options, httpsProxyUrl, bypassProxyHosts);
const results = {
isSuccess: true
};

return new Promise(resolve => {
executeFileCommand(kubectlExe, args, env).then(gatewayJson => {
const gateway = JSON.parse(gatewayJson);
const serversArray = gateway.spec?.servers;
if (Array.isArray(serversArray) && serversArray.length > 0) {
const hostsArray = serversArray[0].hosts;
if (Array.isArray(hostsArray) && hostsArray.length > 0) {
results.hostnames = hostsArray;
}
}
if (results.hostnames) {
results.reason = i18n.t('kubectl-get-vz-app-hostnames-not-found',
{ appName: applicationName, appNamespace: applicationNamespace });
}
resolve(results);
}).catch(err => {
results.isSuccess = false;
results.reason =
i18n.t('kubectl-get-vz-app-hostnames-error-message',
{ appName: applicationName, appNamespace: applicationNamespace, error: getErrorMessage(err) });
resolve(results);
});
});
}

function maskPasswordInCommand(err) {
// How about other cases?
return err.replace(/--docker-password=[^\s]+/, '--docker-password=*****');
Expand Down Expand Up @@ -1075,6 +1171,7 @@ module.exports = {
createOrReplacePullSecret,
createOrReplaceTLSSecret,
createServiceAccountIfNotExists,
getContexts,
getCurrentContext,
getOperatorVersion,
isOperatorAlreadyInstalled,
Expand All @@ -1086,6 +1183,8 @@ module.exports = {
getIngresses,
getK8sConfigView,
getK8sClusterInfo,
getVerrazzanoApplicationHostnames,
getVerrazzanoIngressExternalAddress,
getWkoDomainStatus,
getApplicationStatus,
getOperatorStatus,
Expand Down
2 changes: 1 addition & 1 deletion electron/app/js/vzUtils.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/**
* @license
* Copyright (c) 2022, Oracle and/or its affiliates.
* Copyright (c) 2022, 2023, Oracle and/or its affiliates.
* Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl.
*/
const kubectlUtils = require('./kubectlUtils');
Expand Down
3 changes: 3 additions & 0 deletions electron/app/locales/en/electron.json
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,7 @@

"kubectl-current-context-error-message": "Failed to get the current kubectl cluster context: {{error}}",
"kubectl-use-context-error-message": "Failed to change the current kubectl cluster context to {{context}}: {{error}}",
"kubectl-get-contexts-error-message": "Failed to get the available kubectl contexts: {{error}}",
"kubectl-not-specified-error-message": "Kubernetes client path was not provided",
"kubectl-not-exists-error-message": "Kubernetes client {{filePath}} does not exist",
"kubectl-exists-failed-error-message": "Unable to verify Kubernetes client {{filePath}} exists: {{error}}",
Expand Down Expand Up @@ -322,6 +323,8 @@
"kubectl-get-vz-application-status-error-message": "Unable to get Verrazzano application status: {{error}}",
"kubectl-get-operator-version-not-found-error-message": "Failed to find the operator version from its log entries",
"kubectl-verify-vz-components-deployed-error-message": "Unable to find one or more components in namespace {{namespace}}: {{missingComponents}}",
"kubectl-get-vz-ingress-external-address-not-found": "Unable to find the External IP Address in the Istio Gateway service {{gatewayService}} in Kubernetes namespace {{gatewayNamespace}}",
"kubectl-get-vz-ingress-external-address-error-message": "Failed to find the External IP Address in the Istio Gateway service {{gatewayService}} in Kubernetes namespace {{gatewayNamespace}}: {{error}}",

"helm-not-specified-error-message": "Helm executable path was not provided",
"helm-not-exists-error-message": "Helm executable {{filePath}} does not exist",
Expand Down
24 changes: 24 additions & 0 deletions electron/app/locales/en/webui.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,23 @@

"kubectl-form-name": "Kubernetes Client Configuration",
"kubectl-title": "Configure the Kubernetes Client",
"kubectl-instructions-heading": "Instructions",
"kubectl-executables-heading": "Client Executables",
"kubectl-wko-connectivity-heading": "Kubernetes Cluster Connectivity Configuration",
"kubectl-vz-connectivity-heading": "Verrazzano Admin Cluster Connectivity Configuration",
"kubectl-vz-managed-clusters-heading": "Verrazzano Managed Clusters Connectivity Configuration",
"kubectl-vz-managed-clusters-table-aria-label": "Verrazzano Managed Clusters Connectivity Table",
"kubectl-vz-managed-clusters-add-row-tooltip": "Add a new Verrazzano Managed Cluster Connectivity row",
"kubectl-vz-managed-clusters-delete-row-tooltip": "Delete the Verrazzano Managed Cluster Connectivity row",
"kubectl-vz-managed-cluster-name-heading": "Verrazzano Managed Cluster Name",
"kubectl-vz-managed-cluster-name-help": "Name of the Verrazzano Managed Cluster.",
"kubectl-vz-managed-cluster-kubeconfig-heading": "Kubernetes Client Config File(s)",
"kubectl-vz-managed-cluster-kubeconfig-help": "The Kubernetes client configuration file(s) to use for connecting to the Verrazzano Managed Cluster.",
"kubectl-vz-managed-cluster-kubecontext-heading": "Kubectl Config Context to Use",
"kubectl-vz-managed-cluster-kubecontext-help": "The Kubernetes client configuration context name to use for connecting to the Verrazzano Managed Cluster.",
"kubectl-vz-managed-cluster-choose-kubecontext-tooltip": "Choose the Kubernetes cluster context for the Verrazzano Managed Cluster from the available contexts in the Kubernetes Client Config File",
"kubectl-vz-managed-cluster-get-context-tooltip": "Get the current Kubernetes cluster context for the Verrazzano Managed Cluster from the Kubernetes Client Config File",

"kubectl-k8s-flavor-label": "Kubernetes Cluster Type",
"kubectl-k8s-flavor-help": "The Kubernetes cluster provider type where the Oracle Fusion Middleware domain will be deployed.",
"kubectl-exe-file-path-label": "Kubectl Executable to Use",
Expand All @@ -48,6 +65,8 @@
"kubectl-config-file-help": "The Kubernetes client configuration file(s) to use. Leave this empty to use the default location.",
"kubectl-config-file-tooltip": "Choose the Kubernetes Client Config File(s)",
"kubectl-config-context-label": "Kubectl Config Context to Use",
"kubectl-config-wko-choose-context-tooltip": "Choose the Kubernetes cluster context from the available contexts in the Kubernetes Client Config File",
"kubectl-config-vz-choose-admin-context-tooltip": "Choose the Kubernetes cluster context for the Verrazzano Admin Cluster from the available contexts in the Kubernetes Client Config File",
"kubectl-config-context-tooltip": "Get the current Kubernetes cluster context from the Kubernetes Client Config File",
"kubectl-config-context-help": "The Kubernetes config file context name for the cluster to which you want to connect. The default is to use whatever the current context is, if any.",
"kubectl-helm-exe-file-path-label": "Helm Executable to Use",
Expand Down Expand Up @@ -1126,6 +1145,11 @@

"kubectl-get-current-context-error-title": "Kubernetes Client Failed",
"kubectl-get-current-context-error-message": "kubectl failed to get the current Kubernetes cluster context: {{error}}.",
"kubectl-get-contexts-error-title": "Kubernetes Client Failed",
"kubectl-get-contexts-error-message": "kubectl failed to get the available Kubernetes cluster contexts: {{error}}.",
"kubectl-choose-context-dialog-title": "Kubernetes Client Choose Cluster Context",
"kubectl-choose-context-name-label": "Cluster Context Name",
"kubectl-choose-context-name-help": "Select the Kubernetes cluster context to use.",

"wko-get-install-version-aborted-error-title": "Getting Installed WebLogic Kubernetes Operator Version Aborted",
"wko-get-install-version-kubectl-exe-invalid-error-message": "Unable to get the installed WebLogic Kubernetes Operator version because the Kubernetes client executable is invalid: {{error}}.",
Expand Down
4 changes: 4 additions & 0 deletions electron/app/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -755,6 +755,10 @@ class Main {
return kubectlUtils.setCurrentContext(kubectlExe, context, kubectlOptions);
});

ipcMain.handle('kubectl-get-contexts', async (event, kubectlExe, kubectlOptions) => {
return kubectlUtils.getContexts(kubectlExe, kubectlOptions);
});

ipcMain.handle('validate-kubectl-exe', async (event, kubectlExe) => {
return kubectlUtils.validateKubectlExe(kubectlExe);
});
Expand Down
18 changes: 9 additions & 9 deletions electron/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions electron/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "wktui",
"productName": "WebLogic Kubernetes Toolkit UI",
"version": "1.4.2",
"version": "1.5.0",
"description": "WebLogic Kubernetes Toolkit UI",
"copyright": "Copyright (c) 2021, 2023, Oracle and/or its affiliates.",
"homepage": "https://github.com/oracle/weblogic-toolkit-ui",
Expand Down Expand Up @@ -51,7 +51,7 @@
"@electron/notarize": "^1.2.3",
"chai": "^4.3.7",
"chai-as-promised": "^7.1.1",
"electron": "^22.1.0",
"electron": "^22.2.0",
"electron-builder": "^23.6.0",
"eslint": "^8.33.0",
"mocha": "^10.2.0",
Expand Down
4 changes: 2 additions & 2 deletions webui/src/css/app.css
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2021, 2022, Oracle and/or its affiliates.
* Copyright (c) 2021, 2023, Oracle and/or its affiliates.
* Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl.
*/
.sendOffScreen {
Expand Down Expand Up @@ -257,7 +257,7 @@
border: 1px solid var(--oj-collection-border-color);
}

.wkt-paths-table, .wkt-domain-node-selectors-table {
.wkt-paths-table, .wkt-domain-node-selectors-table, .wkt-vz-managed-clusters-table {
border: 1px solid var(--oj-collection-border-color);
width: 100%;
}
Expand Down
3 changes: 2 additions & 1 deletion webui/src/js/models/kubectl-definition.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/**
* @license
* Copyright (c) 2021, 2022, Oracle and/or its affiliates.
* Copyright (c) 2021, 2023, Oracle and/or its affiliates.
* Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl.
*/
'use strict';
Expand All @@ -22,6 +22,7 @@ define(['utils/observable-properties'],
executableFilePath: props.createProperty(window.api.k8s.getKubectlFilePath()),
kubeConfigContextToUse: props.createProperty(),
helmExecutableFilePath: props.createProperty(window.api.k8s.getHelmFilePath()),
vzManagedClusters: props.createListProperty(['uid', 'name', 'kubeConfig', 'KubeContext']).persistByKey('uid'),

readFrom: function(json) {
props.createGroup(name, this).readFrom(json);
Expand Down
Loading