Skip to content

Commit eb06f1c

Browse files
datho7561vrubezhny
authored andcommitted
Switch to service account after logging into OpenShift Sandbox
The service account will remain authenticated for longer than 15 minutes. To try this out: 1. Log into an OpenShift Sandbox cluster using the Login workflow 2. Run `oc whoami`. You should see a reference to `pipeline`, which is the serviceaccount that's being used 3. The Application Explorer should display you as logged in and work as expected Closes #3838 Signed-off-by: David Thompson <davthomp@redhat.com>
1 parent bb366f5 commit eb06f1c

File tree

1 file changed

+62
-16
lines changed

1 file changed

+62
-16
lines changed

src/openshift/cluster.ts

Lines changed: 62 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@
44
*-----------------------------------------------------------------------------------------------*/
55

66
import { KubernetesObject } from '@kubernetes/client-node';
7+
import { Cluster as KcuCluster, Context as KcuContext } from '@kubernetes/client-node/dist/config_types';
8+
import * as fs from 'fs/promises';
9+
import * as YAML from 'js-yaml';
710
import { ExtensionContext, QuickInputButtons, QuickPickItem, QuickPickItemButtonEvent, ThemeIcon, Uri, commands, env, window, workspace } from 'vscode';
811
import { CommandText } from '../base/command';
912
import { CliChannel } from '../cli';
@@ -14,15 +17,14 @@ import * as NameValidator from '../openshift/nameValidator';
1417
import { TokenStore } from '../util/credentialManager';
1518
import { Filters } from '../util/filters';
1619
import { inputValue, quickBtn } from '../util/inputValue';
17-
import { KubeConfigUtils } from '../util/kubeUtils';
20+
import { KubeConfigUtils, getKubeConfigFiles } from '../util/kubeUtils';
1821
import { LoginUtil } from '../util/loginUtil';
1922
import { Platform } from '../util/platform';
2023
import { Progress } from '../util/progress';
2124
import { VsCommandError, vsCommand } from '../vscommand';
2225
import { OpenShiftTerminalManager } from '../webview/openshift-terminal/openShiftTerminal';
2326
import OpenShiftItem, { clusterRequired } from './openshiftItem';
2427
import fetch = require('make-fetch-happen');
25-
import { Cluster as KcuCluster, Context as KcuContext } from '@kubernetes/client-node/dist/config_types';
2628

2729
export interface QuickPickItemExt extends QuickPickItem {
2830
name: string,
@@ -838,20 +840,26 @@ export class Cluster extends OpenShiftItem {
838840
} else {
839841
ocToken = userToken;
840842
}
841-
return Progress.execFunctionWithProgress(`Login to the cluster: ${clusterURL}`, () =>
842-
Oc.Instance.loginWithToken(clusterURL, ocToken)
843-
.then(() => Cluster.loginMessage(clusterURL))
844-
.catch((error) =>
845-
Promise.reject(
846-
new VsCommandError(
847-
`Failed to login to cluster '${clusterURL}' with '${Filters.filterToken(
848-
error.message,
849-
)}'!`,
850-
'Failed to login to cluster',
851-
),
852-
),
853-
),
854-
);
843+
return Progress.execFunctionWithProgress(`Login to the cluster: ${clusterURL}`, async () => {
844+
try {
845+
await Oc.Instance.loginWithToken(clusterURL, ocToken);
846+
if (Cluster.isOpenShiftSandbox(clusterURL)) {
847+
const YES = 'Yes';
848+
const result = await window.showInformationMessage('OpenShift Sandbox logs you out after 15 minutes. Would you like to switch to a service account to prevent this?', YES, 'No');
849+
if (result === YES) {
850+
await Cluster.installPipelineUserContext();
851+
}
852+
}
853+
return Cluster.loginMessage(clusterURL);
854+
} catch (error) {
855+
throw new VsCommandError(
856+
`Failed to login to cluster '${clusterURL}' with '${Filters.filterToken(
857+
error.message,
858+
)}'!`,
859+
'Failed to login to cluster',
860+
);
861+
}
862+
});
855863
}
856864

857865
static validateLoginToken(token: string): boolean {
@@ -878,6 +886,39 @@ export class Cluster extends OpenShiftItem {
878886
return Cluster.tokenLogin(apiEndpointUrl, true, clipboard);
879887
}
880888

889+
static async installPipelineUserContext(): Promise<void> {
890+
const kcu = new KubeConfigUtils();
891+
const kcFiles = getKubeConfigFiles();
892+
if (kcFiles.length === 0) {
893+
throw new Error('Could not locate Kube Config when trying to replace OpenShift Sandbox token with a longer-lived token');
894+
}
895+
const kcPath = kcFiles[0];
896+
const kcActual = YAML.load((await fs.readFile(kcPath)).toString('utf-8')) as {
897+
users: { name: string; user: { token: string } }[];
898+
contexts: {
899+
context: { cluster: string; user: string; namespace: string };
900+
name: string;
901+
}[];
902+
'current-context': string;
903+
clusters: object[];
904+
};
905+
906+
const currentCtx = kcu.getCurrentContext();
907+
const currentCtxObj = kcActual.contexts.find(ctx => ctx.name === currentCtx);
908+
const sandboxUser = currentCtxObj.context.user;
909+
const sandboxUserObj = kcActual.users.find(user => user.name === sandboxUser);
910+
911+
const secrets = await Oc.Instance.getKubernetesObjects('Secret');
912+
const pipelineTokenSecret = secrets.find((secret) => secret.metadata.name.startsWith('pipeline-token')) as any;
913+
const pipelineToken = Buffer.from(pipelineTokenSecret.data.token, 'base64').toString();
914+
915+
sandboxUserObj.user = {
916+
token: pipelineToken
917+
}
918+
919+
await fs.writeFile(kcPath, YAML.dump(kcActual, { lineWidth: Number.POSITIVE_INFINITY }));
920+
}
921+
881922
static async loginUsingClipboardInfo(dashboardUrl: string): Promise<string | null> {
882923
const clipboard = await Cluster.readFromClipboard();
883924
if (!NameValidator.ocLoginCommandMatches(clipboard)) {
@@ -899,4 +940,9 @@ export class Cluster extends OpenShiftItem {
899940
await commands.executeCommand('setContext', 'isLoggedIn', true);
900941
return `Successfully logged in to '${clusterURL}'`;
901942
}
943+
944+
static isOpenShiftSandbox(url :string): boolean {
945+
const asUrl = new URL(url);
946+
return asUrl.hostname.endsWith('openshiftapps.com');
947+
}
902948
}

0 commit comments

Comments
 (0)