Skip to content

Commit

Permalink
Add an ability to execute commands on K8s (minikube) using Kubectl (#…
Browse files Browse the repository at this point in the history
…22168)

* Add an ability to execute commands on K8s (minikube) using Kubectl (#22167)

Signed-off-by: mdolhalo <mdolhalo@redhat.com>

* KubernetesCommandLineToolsExecutor.setNamespace() method updated

Signed-off-by: mdolhalo <mdolhalo@redhat.com>

---------

Signed-off-by: mdolhalo <mdolhalo@redhat.com>
Co-authored-by: mdolhalo <mdolhalo@redhat.com>
  • Loading branch information
nallikaea and mdolhalo committed Apr 19, 2023
1 parent eccb0df commit 831d71f
Show file tree
Hide file tree
Showing 6 changed files with 169 additions and 126 deletions.
15 changes: 14 additions & 1 deletion tests/e2e/constants/TestConstants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,11 @@ export enum GitProviderType {
BITBUCKET = 'bitbucket'
}

export enum KubernetesCommandLineTool {
OC = 'oc',
KUBECTL = 'kubectl',
}

export const TestConstants: any = {
/**
* Base URL of the application which should be checked
Expand Down Expand Up @@ -228,7 +233,15 @@ export const TestConstants: any = {

TS_SELENIUM_PROJECT_ROOT_FILE_NAME: process.env.TS_SELENIUM_PROJECT_ROOT_FILE_NAME || 'devfile.yaml',

/* -------------------------------------------
| The api tests related constants
----------------------------------------------*/

TS_API_TEST_KUBERNETES_COMMAND_LINE_TOOL: process.env.TS_API_TEST_KUBERNETES_COMMAND_LINE_TOOL || KubernetesCommandLineTool.OC,

TS_API_TEST_UDI_IMAGE: process.env.TS_API_TEST_UDI_IMAGE || 'quay.io/devfile/universal-developer-image:latest',

TS_API_TEST_CHE_CODE_EDITOR_DEVFILE_URI: process.env.TS_API_TEST_CHE_CODE_EDITOR_DEVFILE_URI || `https://eclipse-che.github.io/che-plugin-registry/main/v3/plugins/che-incubator/che-code/latest/devfile.yaml`
TS_API_TEST_CHE_CODE_EDITOR_DEVFILE_URI: process.env.TS_API_TEST_CHE_CODE_EDITOR_DEVFILE_URI || `https://eclipse-che.github.io/che-plugin-registry/main/v3/plugins/che-incubator/che-code/latest/devfile.yaml`,

TS_API_TEST_NAMESPACE: process.env.TS_API_TEST_NAMESPACE || undefined
};
3 changes: 2 additions & 1 deletion tests/e2e/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,14 @@ export * from './driver/ChromeDriver';
export * from './driver/IDriver';
export * from './utils/BrowserTabsUtil';
export * from './utils/DriverHelper';
export * from './utils/KubernetesCommandLineToolsExecutor';
export * from './utils/Logger';
export * from './utils/OpenshiftClientExecutor';
export * from './utils/request-handlers/CheApiRequestHandler';
export * from './utils/request-handlers/headers/CheMultiuserAuthorizationHeaderHandler';
export * from './utils/request-handlers/headers/IAuthorizationHeaderHandler';
export * from './utils/Sanitizer';
export * from './utils/ScreenCatcher';
export * from './utils/ShellExecutor';
export * from './utils/vsc/GitUtil';
export * from './utils/workspace/ApiUrlResolver';
export * from './utils/workspace/ITestWorkspaceUtil';
Expand Down
15 changes: 8 additions & 7 deletions tests/e2e/specs/api/CloneGitRepoAPI.spec.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,21 @@
import { OpenshiftClientExecutor } from '../../utils/OpenshiftClientExecutor';
import { KubernetesCommandLineToolsExecutor } from '../../utils/KubernetesCommandLineToolsExecutor';
import { expect } from 'chai';
import { ShellString } from 'shelljs';
import { GitUtil } from '../../utils/vsc/GitUtil';
import { TestConstants } from '../../constants/TestConstants';


const gitRepository: string = 'https://github.com/crw-qe/web-nodejs-sample';

suite(`Test cloning of repo "${gitRepository}" into empty workspace.`, async function (): Promise<void> {
// works only for root user
const namespace: string = 'admin-devspaces';
const namespace: string = TestConstants.TS_API_TEST_NAMESPACE ? TestConstants.TS_API_TEST_NAMESPACE : undefined;
const workspaceName: string = 'empty-' + Math.floor(Math.random() * 1000);
const clonedProjectName: string = GitUtil.getProjectNameFromGitUrl(gitRepository);
let containerWorkDir: string = '';

const openshiftClientExecutor: OpenshiftClientExecutor = new OpenshiftClientExecutor(workspaceName, namespace);
const containerTerminal: OpenshiftClientExecutor.ContainerTerminal = new OpenshiftClientExecutor.ContainerTerminal(openshiftClientExecutor);
const kubernetesCommandLineToolsExecutor: KubernetesCommandLineToolsExecutor = new KubernetesCommandLineToolsExecutor(workspaceName, namespace);
const containerTerminal: KubernetesCommandLineToolsExecutor.ContainerTerminal = new KubernetesCommandLineToolsExecutor.ContainerTerminal(kubernetesCommandLineToolsExecutor);

const emptyYaml: string =
'apiVersion: workspace.devfile.io/v1alpha2\n' +
Expand All @@ -39,12 +40,12 @@ suite(`Test cloning of repo "${gitRepository}" into empty workspace.`, async fun
' value: 0.0.0.0';

suiteSetup('Create empty workspace with OC client', function (): void {
openshiftClientExecutor.loginToOcp();
openshiftClientExecutor.applyAndWaitDevWorkspace(emptyYaml);
kubernetesCommandLineToolsExecutor.loginToOcp();
kubernetesCommandLineToolsExecutor.applyAndWaitDevWorkspace(emptyYaml);
});

suiteTeardown('Delete workspace', function (): void {
openshiftClientExecutor.deleteDevWorkspace();
kubernetesCommandLineToolsExecutor.deleteDevWorkspace();
});

suite('Clone public repo without previous setup', function (): void {
Expand Down
136 changes: 136 additions & 0 deletions tests/e2e/utils/KubernetesCommandLineToolsExecutor.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
import { echo, exec, ShellString } from 'shelljs';
import { KubernetesCommandLineTool, TestConstants } from '../constants/TestConstants';
import { Logger } from './Logger';
import { ShellExecutor } from './ShellExecutor';

export class KubernetesCommandLineToolsExecutor extends ShellExecutor {
private static container: string;
private static pod: string;
private readonly namespace: string;
private readonly workspaceName: string | undefined;
private readonly KUBERNETES_COMMAND_LINE_TOOL: string = TestConstants.TS_API_TEST_KUBERNETES_COMMAND_LINE_TOOL;

constructor(_workspaceName?: string, _namespace?: string) {
super();
this.workspaceName = _workspaceName;
this.namespace = this.setNamespace(_namespace);
}

get getWorkspaceName(): string {
return <string>this.workspaceName;
}

get getNamespace(): string {
return this.namespace;
}

// login to Openshift cluster with username and password
loginToOcp(): void {
if (this.KUBERNETES_COMMAND_LINE_TOOL === KubernetesCommandLineTool.OC) {
Logger.debug(`${this.getLoggingName(this.loginToOcp.name)}: Login to the "OC" client`);
const url: string = this.getServerUrl();
Logger.debug(url, TestConstants.TS_SELENIUM_OCP_USERNAME);
exec(`sleep 5
oc login --server=${url} -u=${TestConstants.TS_SELENIUM_OCP_USERNAME} -p=${TestConstants.TS_SELENIUM_OCP_PASSWORD} --insecure-skip-tls-verify`);
} else {
Logger.debug(`${this.getLoggingName(this.loginToOcp.name)}: doesn't support login command`);
}
}

getContainerName(): string {
Logger.debug(`${this.getLoggingName(this.getContainerName.name)}: Get container name.`);
const output: ShellString = this.execWithLog(`${(this.KUBERNETES_COMMAND_LINE_TOOL)} get ${(KubernetesCommandLineToolsExecutor.pod)} -o jsonpath='{.spec.containers[*].name}' -n ${this.namespace}`);
echo('\n');
return output.stderr ? output.stderr : output.stdout;
}

getWorkspacePodName(): string {
Logger.debug(`${this.getLoggingName(this.getWorkspacePodName.name)}: Get workspace pod name.`);
const output: ShellString = this.execWithLog(`${(this.KUBERNETES_COMMAND_LINE_TOOL)} get pod -l controller.devfile.io/devworkspace_name=${this.workspaceName} -n ${this.namespace} -o name`);
return output.stderr ? output.stderr : output.stdout.replace('\n', '');
}

deleteDevWorkspace(): void {
Logger.debug(`${this.getLoggingName(this.deleteDevWorkspace.name)}: Delete '${this.workspaceName}' workspace`);
this.execWithLog(`${(this.KUBERNETES_COMMAND_LINE_TOOL)} patch dw ${this.workspaceName} -n ${this.namespace} -p '{ "metadata": { "finalizers": null }}' --type merge || true`);
this.execWithLog(`${(this.KUBERNETES_COMMAND_LINE_TOOL)} delete dw ${this.workspaceName} -n ${this.namespace} || true`);
}

applyAndWaitDevWorkspace(yamlConfiguration: string): ShellString {
if (this.KUBERNETES_COMMAND_LINE_TOOL === KubernetesCommandLineTool.KUBECTL) {
this.createNamespace();
}
this.applyYamlConfigurationAsStringOutput(yamlConfiguration);
const output: ShellString = this.waitDevWorkspace();
KubernetesCommandLineToolsExecutor.pod = this.getWorkspacePodName();
KubernetesCommandLineToolsExecutor.container = this.getContainerName();
return output;
}

executeCommand(commandToExecute: string): ShellString {
Logger.debug(`${this.getLoggingName(this.executeCommand.name)}:`);
return this.execWithLog(`${(this.KUBERNETES_COMMAND_LINE_TOOL)} exec -i ${KubernetesCommandLineToolsExecutor.pod} -n ${this.namespace} -c ${KubernetesCommandLineToolsExecutor.container} -- sh -c "${commandToExecute}"`);
}

applyYamlConfigurationAsStringOutput(yamlConfiguration: string): void {
Logger.debug(`${this.getLoggingName(this.applyYamlConfigurationAsStringOutput.name)}:`);
this.execWithLog(`cat <<EOF | ${this.KUBERNETES_COMMAND_LINE_TOOL} apply -n ${this.namespace} -f - \n` +
yamlConfiguration + '\n' +
'EOF');
}

waitDevWorkspace(timeout: number = 360): ShellString {
Logger.debug(`${this.getLoggingName(this.waitDevWorkspace.name)}: Wait till workspace ready.`);
return this.execWithLog(`${(this.KUBERNETES_COMMAND_LINE_TOOL)} wait -n ${this.namespace} --for=condition=Ready dw ${this.workspaceName} --timeout=${timeout}s`);
}

createNamespace(): void {
Logger.debug(`${this.getLoggingName(this.createNamespace.name)}: Create namespace "${this.namespace}".`);
this.execWithLog(`${this.KUBERNETES_COMMAND_LINE_TOOL} create namespace ${this.namespace}`);
}

private getLoggingName(methodName: string): string {
return `${this.constructor.name}.${methodName} - ${(this.KUBERNETES_COMMAND_LINE_TOOL)}`;
}

private setNamespace(_namespace: string | undefined): string {
_namespace = _namespace !== undefined ? _namespace
: TestConstants.TS_SELENIUM_BASE_URL.includes('devspaces') ? TestConstants.TS_SELENIUM_OCP_USERNAME + '-devspaces'
: TestConstants.TS_SELENIUM_BASE_URL.includes('che') ? TestConstants.TS_SELENIUM_OCP_USERNAME + '-che'
: 'default';
return _namespace;
}

private getServerUrl(): string {
Logger.debug(`${this.getLoggingName(this.getServerUrl.name)}: Get server api url.`);
return TestConstants.TS_SELENIUM_BASE_URL.replace('devspaces.apps', 'api') + ':6443';
}
}

export namespace KubernetesCommandLineToolsExecutor {
export class ContainerTerminal extends KubernetesCommandLineToolsExecutor {
constructor(cluster: KubernetesCommandLineToolsExecutor) {
super(cluster.getWorkspaceName, cluster.getNamespace);
}

ls(path: string = ''): ShellString {
return this.executeCommand('ls ' + path);
}

pwd(): ShellString {
return this.executeCommand('pwd');
}

cd(path: string): ShellString {
return this.executeCommand('cd ' + path);
}

gitClone(repository: string): ShellString {
return this.executeCommand('git clone ' + repository);
}

removeFolder(path: string): ShellString {
return this.executeCommand('rm -rf ' + path);
}
}
}
117 changes: 0 additions & 117 deletions tests/e2e/utils/OpenshiftClientExecutor.ts

This file was deleted.

9 changes: 9 additions & 0 deletions tests/e2e/utils/ShellExecutor.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { echo, exec, ShellString } from 'shelljs';

export class ShellExecutor {

protected execWithLog(command: string): ShellString {
echo(command);
return exec(command);
}
}

0 comments on commit 831d71f

Please sign in to comment.