Skip to content
Snippets Groups Projects
Commit 9e8dc3f5 authored by Guillaume WEBER's avatar Guillaume WEBER
Browse files

refactor(mission): create package mission to split mission.ts

parent 6f6a5ffb
No related branches found
No related tags found
2 merge requests!14feat: added mounted, .bashrc, .zshrc, added tests, added keycloak tests,!8feat(extension): login, open in devcontainer, automaticly save code, open briefing, publish extension
......@@ -4,7 +4,6 @@ export const KEYCLOAK_TOKEN_CREATE_URL =
'https://auth.dev.deadlock.io/auth/realms/Deadlock/protocol/openid-connect/token';
export const KEYCLOAK_USER_INFO_URL =
'https://auth.dev.deadlock.io/auth/realms/Deadlock/protocol/openid-connect/userinfo';
export const REGISTRY_MISSION_URL = 'registry.takima.io/deadlock/deadlock-challenges';
export const REJECT_UNAUTHORIZED = false;
export const ENABLE_AUTOMATIC_SAVE = true;
export const ENABLE_RECORDER_HTTP_SERVER = false;
......
import * as vscode from 'vscode';
import {
KEYCLOAK_DEVICE_AUTH_URL,
KEYCLOAK_TOKEN_CREATE_URL,
KEYCLOAK_USER_INFO_URL,
REGISTRY_MISSION_URL,
} from '../config';
import { KEYCLOAK_DEVICE_AUTH_URL, KEYCLOAK_TOKEN_CREATE_URL, KEYCLOAK_USER_INFO_URL } from '../config';
import { log } from '../recorder/utils';
import { OPEN_QUICK_SETUP_COMMAND } from '../theia/command';
......@@ -13,7 +8,7 @@ import QuickSetupView from '../view/quickSetupView';
import { CHOOSE_MISSION_WORKDIR_COMMAND, CommandHandler, OPEN_URL_IN_BROWSER_COMMAND } from './commandHandler';
import ExtensionStore from './extensionStore';
import KeycloakOAuth2DeviceFlowConnection from './keycloakOAuth2DeviceFlowConnection';
import Mission from './mission';
import Mission from './mission/mission';
import ApiService from './api.service';
import SshKeyManager from './sshKeyManager';
import { GiteaPublicProperties } from '../model/giteaPublicProperties.model';
......@@ -131,9 +126,9 @@ export default class Controller {
const user: User = await this.callApiService.getUser();
const giteaPublicProperties: GiteaPublicProperties = await this.callApiService.getGiteaPublicProperties();
const mission = new Mission(
{
registryBaseURL: REGISTRY_MISSION_URL,
missionId: missionId,
missionVersion: missionVersion,
},
......
export interface DockerfileSpecific {
image?: string;
dockerFile?: string;
context?: string;
'build.args'?: string[];
'build.target'?: string;
'build.cacheFrom'?: string;
containerEnv?: string;
containerUser?: string;
mounts?: string[];
workspaceMount?: string;
workspaceFolder?: string;
runArgs?: string[];
}
export interface Base {
name?: string;
forwardPorts?: string[];
portsAttributes?: string[];
otherPortsAttributes?: string[];
remoteEnv?: string;
remoteUser?: string;
updateRemoteUserUID?: string;
userEnvProbe?: string;
overrideCommand?: boolean;
features?: string[];
shutdownAction?: string;
}
export interface VSCodespecific {
extensions?: string[];
settings?: object;
devPort?: string;
}
export interface LifecycleScripts {
initializeCommand?: string;
onCreateCommand?: string;
updateContentCommand?: string;
postCreateCommand?: string;
postStartCommand?: string;
postAttachCommand?: string;
waitFor?: string;
}
......@@ -2,11 +2,15 @@ import { exec as _exec } from 'child_process';
import * as fs from 'fs';
import * as util from 'util';
import * as vscode from 'vscode';
import { error as err, log } from '../recorder/utils';
import ExtensionStore from './extensionStore';
import { userSshKeyFolderPath } from './config';
import { GiteaPublicProperties } from '../model/giteaPublicProperties.model';
import { User, UserChallengeJson } from '../model/user.model';
import { error as err, log } from '../../recorder/utils';
import ExtensionStore from '../extensionStore';
import { userSshKeyFolderPath } from '../config';
import { GiteaPublicProperties } from '../../model/giteaPublicProperties.model';
import { User, UserChallengeJson } from '../../model/user.model';
import { createDevContainerFile } from './missionDevContainer';
import { DockerfileSpecific, Base, VSCodespecific, LifecycleScripts } from './devContainer';
import { MissionResource } from './missionResources';
import { createUserChallengeJsonFile } from './missionUserChallenge';
/**
* {@link https://nodejs.org/api/child_process.html#child_process_child_process_exec_command_options_callback}
......@@ -15,105 +19,36 @@ const exec = util.promisify(_exec);
export default class Mission {
private readonly hostBaseWorkDir: string;
private readonly dockerImageURL: string;
private readonly hostMissionDir: string;
private readonly hostMissionDevcontainerDir: string;
private readonly hostMissionDevcontainerFileDir: string;
private readonly hostMissionMountDir: string;
private readonly remoteUserHomeDir: string;
private readonly remoteMissionDir: any;
private readonly remoteGiteaWorkDir: string;
private readonly userMissionConfigPath: string;
private readonly user: User;
private readonly giteaPublicProperties: GiteaPublicProperties;
private readonly missionRessource: MissionResource;
constructor(
private params: { registryBaseURL: string; missionId: string; missionVersion: string },
private params: { missionId: string; missionVersion: string },
user: User,
giteaPublicProperties: GiteaPublicProperties,
) {
const { registryBaseURL, missionId, missionVersion } = params;
const { missionId, missionVersion } = params;
this.hostBaseWorkDir = ExtensionStore.getInstance().getMissionWorkdir() ?? '';
this.hostMissionDir = `${this.hostBaseWorkDir}/${missionId}`;
this.userMissionConfigPath = `${this.hostMissionDir}/.config`;
this.hostMissionDevcontainerDir = `${this.hostMissionDir}/.devcontainer`;
this.hostMissionDevcontainerFileDir = `${this.hostMissionDevcontainerDir}/devcontainer.json`;
this.hostMissionMountDir = `${this.hostMissionDir}/mounted`;
this.dockerImageURL = getDockerImageURL(registryBaseURL, missionId, missionVersion);
this.remoteUserHomeDir = '/home/deadlock';
this.remoteMissionDir = `${this.remoteUserHomeDir}/mission/`;
this.remoteGiteaWorkDir = `/src`;
this.user = user;
this.giteaPublicProperties = giteaPublicProperties;
}
static async pullImage(url) {
const { stdout, stderr } = await exec(`docker pull ${url}`);
log(stdout);
err(stderr);
this.missionRessource = new MissionResource(this.hostMissionDir, missionId, missionVersion);
}
public async setup(options?: Partial<DockerfileSpecific & Base & VSCodespecific & LifecycleScripts>) {
await fs.promises.mkdir(this.hostMissionDevcontainerDir, { recursive: true });
await fs.promises.mkdir(this.hostMissionMountDir, { recursive: true });
await fs.promises.mkdir(this.userMissionConfigPath, { recursive: true });
await this.createDevContainerFile(options);
await this.createUserChallengeJsonFile();
}
private createDevContainerFile(options?: Partial<DockerfileSpecific & Base & VSCodespecific & LifecycleScripts>) {
return fs.promises.writeFile(
this.hostMissionDevcontainerFileDir,
(() => {
const devcontainer: Partial<DockerfileSpecific & Base & VSCodespecific & LifecycleScripts> = {
name: `deadlock-${this.params.missionId}`,
image: this.dockerImageURL,
extensions: ['Deadlock.deadlock-coding'],
remoteUser: 'deadlock',
mounts: [
`source=${userSshKeyFolderPath},target=/tmp/.ssh,type=bind,consistency=cached,readonly`,
`source=${this.userMissionConfigPath},target=/home/config/,type=bind,consistency=cached,readonly`,
'source=/etc/hosts,target=/etc/hosts,type=bind,consistency=cached,readonly',
],
userEnvProbe: 'interactiveShell',
settings: {
'terminal.integrated.defaultProfile.linux': 'bash',
'terminal.integrated.profiles.linux': {
bash: {
path: '/bin/bash',
},
},
},
overrideCommand: false,
shutdownAction: 'stopContainer',
workspaceMount: `source=${this.hostMissionMountDir},target=${this.remoteMissionDir},type=bind`,
workspaceFolder: `${this.remoteMissionDir}`,
onCreateCommand: `cp -R ${this.remoteGiteaWorkDir}/. ${this.remoteMissionDir}`,
runArgs: ['--privileged'],
...options,
};
return JSON.stringify(devcontainer, null, 2);
})(),
);
}
private createUserChallengeJsonFile() {
return fs.promises.writeFile(
`${this.userMissionConfigPath}/user-challenge.json`,
(() => {
const userChallengeJson: UserChallengeJson = {
giteaHost: this.giteaPublicProperties.sshHost,
giteaSshPort: this.giteaPublicProperties.sshPort,
username: this.user.id.split('-').join(''),
email: `${this.user.id.split('-').join('')}@deadlock.io`,
missionId: this.params.missionId,
remoteGitUsername: this.user.id.split('-').join(''),
currentUserDetails: this.user.details,
remoteUserDetails: this.user.details,
};
return JSON.stringify(userChallengeJson, null, 2);
})(),
);
await createDevContainerFile(this.missionRessource, options);
await createUserChallengeJsonFile(this.user, this.missionRessource, this.giteaPublicProperties);
}
public async openEditorInFolder(arbitraryPath?: string) {
......@@ -127,51 +62,3 @@ export default class Mission {
await vscode.commands.executeCommand('remote-containers.openFolder', vscode.Uri.file(this.hostMissionDir));
}
}
export function getDockerImageURL(base, missionId, missionVersion) {
return `${base}/${missionId}:${missionVersion}`;
}
interface DockerfileSpecific {
image?;
dockerFile?;
context?;
'build.args'?;
'build.target'?;
'build.cacheFrom'?;
containerEnv?;
containerUser?;
mounts?;
workspaceMount?;
workspaceFolder?;
runArgs?;
}
interface Base {
name?;
forwardPorts?;
portsAttributes?;
otherPortsAttributes?;
remoteEnv?;
remoteUser?;
updateRemoteUserUID?;
userEnvProbe?;
overrideCommand?;
features?;
shutdownAction?;
}
interface VSCodespecific {
extensions?;
settings?;
devPort?;
}
interface LifecycleScripts {
initializeCommand?;
onCreateCommand?;
updateContentCommand?;
postCreateCommand?;
postStartCommand?;
postAttachCommand?;
waitFor?;
}
import { userSshKeyFolderPath } from '../config';
import ExtensionStore from '../extensionStore';
import { Base, DockerfileSpecific, LifecycleScripts, VSCodespecific } from './devContainer';
import * as fs from 'fs';
import { MissionResource } from './missionResources';
const DOCKER_IMAGE_URL = 'registry.takima.io/deadlock/deadlock-challenges';
export function createDevContainerFile(
mission: MissionResource,
options?: Partial<DockerfileSpecific & Base & VSCodespecific & LifecycleScripts>,
) {
const hostBaseWorkDir = ExtensionStore.getInstance().getMissionWorkdir() ?? '';
const hostMissionDir = `${hostBaseWorkDir}/${mission.id}`;
const userMissionConfigPath = `${hostMissionDir}/.config`;
const hostMissionDevcontainerDir = `${hostMissionDir}/.devcontainer`;
const hostMissionDevcontainerFileDir = `${hostMissionDevcontainerDir}/devcontainer.json`;
const hostMissionMountDir = `${hostMissionDir}/mounted`;
const dockerImageURL = `${DOCKER_IMAGE_URL}/${mission.id}:${mission.version}`;
const remoteUserHomeDir = '/home/deadlock';
const remoteMissionDir = `${remoteUserHomeDir}/mission/`;
const remoteGiteaWorkDir = `/src`;
return fs.promises.writeFile(
hostMissionDevcontainerFileDir,
(() => {
const devcontainer: Partial<DockerfileSpecific & Base & VSCodespecific & LifecycleScripts> = {
name: `deadlock-${mission.id}`,
image: dockerImageURL,
extensions: ['Deadlock.deadlock-coding'],
remoteUser: 'deadlock',
mounts: [
`source=${userSshKeyFolderPath},target=/tmp/.ssh,type=bind,consistency=cached,readonly`,
`source=${userMissionConfigPath},target=/home/config/,type=bind,consistency=cached,readonly`,
'source=/etc/hosts,target=/etc/hosts,type=bind,consistency=cached,readonly',
],
userEnvProbe: 'interactiveShell',
settings: {
'terminal.integrated.defaultProfile.linux': 'bash',
'terminal.integrated.profiles.linux': {
bash: {
path: '/bin/bash',
},
},
},
overrideCommand: false,
shutdownAction: 'stopContainer',
workspaceMount: `source=${hostMissionMountDir},target=${remoteMissionDir},type=bind`,
workspaceFolder: `${remoteMissionDir}`,
onCreateCommand: `cp -R ${remoteGiteaWorkDir}/. ${remoteMissionDir}`,
runArgs: ['--privileged'],
...options,
};
return JSON.stringify(devcontainer, null, 2);
})(),
);
}
export class MissionResource {
constructor(public missionDir: string, public id: string, public version: string) {
this.missionDir = missionDir;
this.id = id;
this.version = version;
}
}
import { User, UserChallengeJson } from '../../model/user.model';
import * as fs from 'fs';
import { GiteaPublicProperties } from '../../model/giteaPublicProperties.model';
import { MissionResource } from './missionResources';
export function createUserChallengeJsonFile(
user: User,
mission: MissionResource,
giteaPublicProperties: GiteaPublicProperties,
) {
return fs.promises.writeFile(
`${mission.missionDir}/.config/user-challenge.json`,
(() => {
const userChallengeJson: UserChallengeJson = {
giteaHost: giteaPublicProperties.sshHost,
giteaSshPort: giteaPublicProperties.sshPort,
username: user.id.split('-').join(''),
email: `${user.id.split('-').join('')}@deadlock.io`,
missionId: mission.id,
remoteGitUsername: user.id.split('-').join(''),
currentUserDetails: user.details,
remoteUserDetails: user.details,
};
return JSON.stringify(userChallengeJson, null, 2);
})(),
);
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment