Skip to content

Commit

Permalink
Extract opening of the ssh session
Browse files Browse the repository at this point in the history
  • Loading branch information
petrovic-d committed Feb 3, 2025
1 parent b5b29a8 commit 7274ee1
Show file tree
Hide file tree
Showing 4 changed files with 175 additions and 125 deletions.
128 changes: 5 additions & 123 deletions java/java.lsp.server/vscode/src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,8 +66,7 @@ import { validateJDKCompatibility } from './jdk/validation/validation';
import * as sshGuide from './panels/SshGuidePanel';
import * as runImageGuide from './panels/RunImageGuidePanel';
import { shouldHideGuideFor } from './panels/guidesUtil';
import { promisify } from 'util';
import * as Handlebars from "handlebars";
import { SSHSession } from './ssh/ssh';

const API_VERSION : string = "1.0";
export const COMMAND_PREFIX : string = "nbls";
Expand Down Expand Up @@ -1060,8 +1059,8 @@ export function activate(context: ExtensionContext): VSNetBeansAPI {
ocid
});
}

openSSHSession("opc", publicIp, node.label);
const sshSession = new SSHSession("opc", publicIp);
sshSession.open(node.label);
}
));

Expand All @@ -1082,7 +1081,8 @@ export function activate(context: ExtensionContext): VSNetBeansAPI {
});
}

runDockerSSH(context, "opc", publicIp, imageUrl, isRepositoryPrivate);
const sshSession = new SSHSession("opc", publicIp);
sshSession.runDocker(context, imageUrl, isRepositoryPrivate);
}
));

Expand Down Expand Up @@ -1155,124 +1155,6 @@ function activateWithJDK(specifiedJDK: string | null, context: ExtensionContext,
}
}

function runCommandInTerminal(command: string, name: string) {
const isWindows = process.platform === 'win32';

const shell = process.env.SHELL || '/bin/bash';
const shellName = shell.split('/').pop();
const isZsh = shellName === 'zsh';

const defaultShell = isWindows
? process.env.ComSpec || 'cmd.exe'
: shell;

const pauseCommand = isWindows
? 'pause'
: 'echo "Press any key to close..."; ' + (isZsh
? 'read -rs -k1'
: 'read -rsn1');

const commandWithPause = `${command} && ${pauseCommand}`;

const terminal = vscode.window.createTerminal({
name: name,
shellPath: defaultShell,
shellArgs: isWindows ? ['/c', commandWithPause] : ['-c', commandWithPause],
});
terminal.show();
}

function openSSHSession(username: string, host: string, name?: string) {
let sessionName;
if (name === undefined) {
sessionName =`${username}@${host}`;
} else {
sessionName = name;
}

const sshCommand = `ssh ${username}@${host}`;

runCommandInTerminal(sshCommand, `SSH: ${username}@${host}`);
}

interface ConfigFiles {
applicationProperties : string | null;
bootstrapProperties: string | null;
}

async function runDockerSSH(context: ExtensionContext, username: string, host: string, dockerImage: string, isRepositoryPrivate: boolean) {
const configFiles: ConfigFiles = await vscode.commands.executeCommand('nbls.config.file.path') as ConfigFiles;
const { applicationProperties, bootstrapProperties } = configFiles;
let bearerTokenFile: string | undefined;

const applicationPropertiesRemotePath = `/home/${username}/application.properties`;
const bootstrapPropertiesRemotePath = `/home/${username}/bootstrap.properties`;
const bearerTokenRemotePath = `/home/${username}/token.txt`;
const applicationPropertiesContainerPath = "/home/app/application.properties";
const bootstrapPropertiesContainerPath = "/home/app/bootstrap.properties";
const ocirServer = dockerImage.split('/')[0];
const remotePathToCopyTo = `/home/${username}/`;

let sshCommand = "";
let mountVolume = "";
let micronautConfigFilesEnv = "";
let filesToCopy = "";
let renameFilesCommand = "";

if (isRepositoryPrivate) {
bearerTokenFile = await commands.executeCommand(COMMAND_PREFIX + '.cloud.assets.createBearerToken', ocirServer);
if (bearerTokenFile) {
filesToCopy = bearerTokenFile;
renameFilesCommand = `mv ${remotePathToCopyTo}${path.basename(bearerTokenFile)} ${bearerTokenRemotePath}\n`;
}
}

if (bootstrapProperties) {
filesToCopy = `${filesToCopy} ${bootstrapProperties}`;
renameFilesCommand += `mv ${remotePathToCopyTo}${path.basename(bootstrapProperties)} ${bootstrapPropertiesRemotePath}\n`;
mountVolume = `-v ${bootstrapPropertiesRemotePath}:${bootstrapPropertiesContainerPath}:Z `;
micronautConfigFilesEnv = `${bootstrapPropertiesContainerPath}`;
}

if (applicationProperties) {
filesToCopy = `${filesToCopy} ${applicationProperties}`;
renameFilesCommand += `mv ${remotePathToCopyTo}${path.basename(applicationProperties)} ${applicationPropertiesRemotePath}\n`;
mountVolume += ` -v ${applicationPropertiesRemotePath}:${applicationPropertiesContainerPath}:Z`;
micronautConfigFilesEnv += `${bootstrapProperties ? "," : ""}${applicationPropertiesContainerPath}`;
}

let templateFilePath = path.join(context.extensionPath, "templates", "run-container.sh.handlebars");
const template = await getTemplateFromPath(templateFilePath);
const script = template({
username,
filesToRemove: `${bootstrapPropertiesRemotePath} ${applicationPropertiesRemotePath} ${bearerTokenRemotePath}`,
renameFilesCommand,
isRepositoryPrivate,
bearerTokenRemotePath,
ocirServer,
dockerImage,
mountVolume,
micronautConfigFilesEnv
});

const tempDir = process.env.TEMP || process.env.TMP || '/tmp';
const scriptName = `run-container-${Date.now()}.sh`;
const runContainerScript = path.join(tempDir, scriptName);
fs.writeFileSync(runContainerScript, script);

sshCommand = `scp ${filesToCopy} ${runContainerScript} ${username}@${host}:${remotePathToCopyTo} && `
sshCommand += `ssh ${username}@${host} "mv -f ${scriptName} run-container.sh && chmod +x run-container.sh && ./run-container.sh" `

runCommandInTerminal(sshCommand, `Container: ${username}@${host}`)
}

const readFile = promisify(fs.readFile);

async function getTemplateFromPath(path: string): Promise<HandlebarsTemplateDelegate<any>> {
const templateFile = await readFile(path, "utf-8");
return Handlebars.compile(templateFile);
}

function killNbProcess(notifyKill : boolean, log : vscode.OutputChannel, specProcess?: ChildProcess) : Promise<void> {
const p = nbProcess;
handleLog(log, "Request to kill LSP server.");
Expand Down
123 changes: 123 additions & 0 deletions java/java.lsp.server/vscode/src/ssh/ssh.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

import * as vscode from "vscode";
import * as fs from 'fs';
import { runCommandInTerminal } from "./terminalRunner";
import { COMMAND_PREFIX } from "../extension";
import path = require("path");
import { promisify } from "util";
import * as Handlebars from "handlebars";

interface ConfigFiles {
applicationProperties : string | null;
bootstrapProperties: string | null;
}

const readFile = promisify(fs.readFile);

export class SSHSession {

private readonly username: string;
private readonly host: string;

constructor(username: string, host: string) {
this.username = username;
this.host = host;
}

open(sessionName?: string) {
let terminalName = sessionName || `${this.username}@${this.host}`;
const sshCommand = `ssh ${this.username}@${this.host}`;

runCommandInTerminal(sshCommand, `SSH: ${terminalName}`);
}

async runDocker(context: vscode.ExtensionContext, dockerImage: string, isRepositoryPrivate: boolean) {
const configFiles: ConfigFiles = await vscode.commands.executeCommand(COMMAND_PREFIX + '.config.file.path') as ConfigFiles;
const { applicationProperties, bootstrapProperties } = configFiles;
let bearerTokenFile: string | undefined;

const applicationPropertiesRemotePath = `/home/${this.username}/application.properties`;
const bootstrapPropertiesRemotePath = `/home/${this.username}/bootstrap.properties`;
const bearerTokenRemotePath = `/home/${this.username}/token.txt`;
const applicationPropertiesContainerPath = "/home/app/application.properties";
const bootstrapPropertiesContainerPath = "/home/app/bootstrap.properties";
const ocirServer = dockerImage.split('/')[0];
const remotePathToCopyTo = `/home/${this.username}/`;

let sshCommand = "";
let mountVolume = "";
let micronautConfigFilesEnv = "";
let filesToCopy = "";
let renameFilesCommand = "";
const removeOldFilesCommand = `rm -f ${bootstrapPropertiesRemotePath} ${applicationPropertiesRemotePath} ${bearerTokenRemotePath}`;

if (isRepositoryPrivate) {
bearerTokenFile = await vscode.commands.executeCommand(COMMAND_PREFIX + '.cloud.assets.createBearerToken', ocirServer);
if (bearerTokenFile) {
filesToCopy = bearerTokenFile;
renameFilesCommand = `mv ${remotePathToCopyTo}${path.basename(bearerTokenFile)} ${bearerTokenRemotePath} && `;
}
}

if (bootstrapProperties) {
filesToCopy += ` ${bootstrapProperties}`;
renameFilesCommand += ` mv ${remotePathToCopyTo}${path.basename(bootstrapProperties)} ${bootstrapPropertiesRemotePath} && `;
mountVolume = `-v ${bootstrapPropertiesRemotePath}:${bootstrapPropertiesContainerPath}:Z `;
micronautConfigFilesEnv = `${bootstrapPropertiesContainerPath}`;
}

if (applicationProperties) {
filesToCopy += ` ${applicationProperties}`;
renameFilesCommand += ` mv ${remotePathToCopyTo}${path.basename(applicationProperties)} ${applicationPropertiesRemotePath} && `;
mountVolume += ` -v ${applicationPropertiesRemotePath}:${applicationPropertiesContainerPath}:Z`;
micronautConfigFilesEnv += `${bootstrapProperties ? "," : ""}${applicationPropertiesContainerPath}`;
}

let templateFilePath = path.join(context.extensionPath, "templates", "run-container.sh.handlebars");
const template = await this.getTemplateFromPath(templateFilePath);
const script = template({
username: this.username,
isRepositoryPrivate,
bearerTokenRemotePath,
ocirServer,
dockerImage,
mountVolume,
micronautConfigFilesEnv
});

const tempDir = process.env.TEMP || process.env.TMP || '/tmp';
const scriptName = `run-container-${Date.now()}.sh`;
const runContainerScript = path.join(tempDir, scriptName);
fs.writeFileSync(runContainerScript, script);
renameFilesCommand += ` mv -f ${scriptName} run-container.sh `;

sshCommand = `scp ${filesToCopy} ${runContainerScript} ${this.username}@${this.host}:${remotePathToCopyTo} && `
sshCommand += `ssh ${this.username}@${this.host} "${removeOldFilesCommand} && ${renameFilesCommand} && rm -f ${scriptName} && chmod +x run-container.sh && ./run-container.sh" `

runCommandInTerminal(sshCommand, `Container: ${this.username}@${this.host}`)
}


private async getTemplateFromPath(path: string): Promise<HandlebarsTemplateDelegate<any>> {
const templateFile = await readFile(path, "utf-8");
return Handlebars.compile(templateFile);
}
}
47 changes: 47 additions & 0 deletions java/java.lsp.server/vscode/src/ssh/terminalRunner.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

import * as vscode from 'vscode';

export function runCommandInTerminal(command: string, name: string) {
const isWindows = process.platform === 'win32';

const shell = process.env.SHELL || '/bin/bash';
const shellName = shell.split('/').pop();
const isZsh = shellName === 'zsh';

const defaultShell = isWindows
? process.env.ComSpec || 'cmd.exe'
: shell;

const pauseCommand = isWindows
? 'pause'
: 'echo "Press any key to close..."; ' + (isZsh
? 'read -rs -k1'
: 'read -rsn1');

const commandWithPause = `${command} && ${pauseCommand}`;

const terminal = vscode.window.createTerminal({
name,
shellPath: defaultShell,
shellArgs: isWindows ? ['/c', commandWithPause] : ['-c', commandWithPause],
});
terminal.show();
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,6 @@ under the License. --}}
#!/bin/sh
set -e
CONTAINER_ID_FILE="/home/{{username}}/.vscode.container.id"
rm -f {{filesToRemove}}
{{renameFilesCommand}}
if [ -f "$CONTAINER_ID_FILE" ]; then
CONTAINER_ID=$(cat "$CONTAINER_ID_FILE")
if [ ! -z "$CONTAINER_ID" ] && docker ps -q --filter "id=$CONTAINER_ID" | grep -q .; then
Expand Down

0 comments on commit 7274ee1

Please sign in to comment.