From 3b9ff6fb3b06bd58b7f808686fa29749c7987d58 Mon Sep 17 00:00:00 2001 From: The Nomo App's core developer team <142992428+nomo-app@users.noreply.github.com> Date: Wed, 21 Feb 2024 14:01:35 +0100 Subject: [PATCH] add hybrid deployments via rsync (#8) * implement hybrid deployments via rsync * final fixes * missing awaits --- README.md | 13 +++++++++---- package-lock.json | 4 ++-- package.json | 2 +- src/deploy-webon/deploy-webon.ts | 2 +- src/init/init.ts | 1 + src/init/interface.ts | 3 ++- src/services/ssh-manager.ts | 17 +++++++++++++++-- src/services/ssh-operations.ts | 25 +++++++++++++------------ src/util/extract-tar-gz.ts | 7 ++++++- src/util/validate-manifest.ts | 2 +- 10 files changed, 51 insertions(+), 25 deletions(-) diff --git a/README.md b/README.md index 1da3f3e..e99e2a2 100644 --- a/README.md +++ b/README.md @@ -66,14 +66,19 @@ const nomoCliConfig = { /** * sshBaseDir is a remote-directory for deploying your WebOn. */ - sshBaseDir: "/var/www/production_webons/${webon_id}", + sshBaseDir: "/var/www/production_webons/my_webon", /** * publicBaseUrl is a URL where sshBaseDir gets exposed to the Internet. * publicBaseUrl is needed to generate a deeplink for installing your WebOn. * For example, you could configure an nginx-server to map sshBaseDir to a publicBaseUrl. */ - publicBaseUrl: "https://w.nomo.app/${webon_id}", + publicBaseUrl: "https://w.nomo.app/my_webon", + + /** + * If true, the WebOn will be deployed both as a tar.gz as well as a normal website. + */ + hybrid: true, }, }, staging: { @@ -82,8 +87,8 @@ const nomoCliConfig = { * sshHost could be taken from an environment-variable to hide your target IP address. */ sshHost: process.env.SSH_TARGET, - sshBaseDir: "/var/www/staging_webons/${webon_id}", - publicBaseUrl: "https://staging.nomo.app/${webon_id}", + sshBaseDir: "/var/www/staging_webons/my_webon", + publicBaseUrl: "https://staging.nomo.app/my_webon", /** * Optional. The default sshPort is 22. diff --git a/package-lock.json b/package-lock.json index 20b4f8f..98759a7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "nomo-webon-cli", - "version": "0.1.8", + "version": "0.1.9", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "nomo-webon-cli", - "version": "0.1.8", + "version": "0.1.9", "dependencies": { "commander": "^6.1.0", "inquirer": "^7.3.3", diff --git a/package.json b/package.json index 2343955..0a324a1 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "nomo-webon-cli", - "version": "0.1.8", + "version": "0.1.9", "description": "A CLI for building and deploying Nomo WebOns", "repository": { "type": "git", diff --git a/src/deploy-webon/deploy-webon.ts b/src/deploy-webon/deploy-webon.ts index ba58f7a..49b6aed 100644 --- a/src/deploy-webon/deploy-webon.ts +++ b/src/deploy-webon/deploy-webon.ts @@ -34,7 +34,7 @@ export async function deployWebOn(args: { await logs(); await connectAndDeploy({ rawSSH, deployTarget, archive }); } catch (e) { - logFatal("Failed to connect to SSH" + e); + logFatal("SSH-deployment failed: " + e); } async function logs() { diff --git a/src/init/init.ts b/src/init/init.ts index e06edd5..a84fa0a 100644 --- a/src/init/init.ts +++ b/src/init/init.ts @@ -74,6 +74,7 @@ function generateNomoCliConfigContent({ sshHost: "root@", sshBaseDir: `/var/www/production_webons/${pathSuggestion}/`, publicBaseUrl: `https://w.nomo.app/${pathSuggestion}`, + hybrid: true, }, }, staging: { diff --git a/src/init/interface.ts b/src/init/interface.ts index 7a56911..d9f7c6e 100644 --- a/src/init/interface.ts +++ b/src/init/interface.ts @@ -45,7 +45,8 @@ export interface RawSSHConfig { sshHost: string; sshBaseDir: string; publicBaseUrl: string; - sshPort?: number; // Make the sshPort optional + sshPort?: number; + hybrid?: boolean; } export interface DeployTargetConfig { diff --git a/src/services/ssh-manager.ts b/src/services/ssh-manager.ts index b56ac76..ef2c115 100644 --- a/src/services/ssh-manager.ts +++ b/src/services/ssh-manager.ts @@ -4,6 +4,7 @@ import { getCachedNomoIconPath, getCachedNomoManifestPath, clearCache, + getCachedOutDirectory, } from "../util/extract-tar-gz"; import { NomoConfigValidator } from "../util/validate-nomo-config"; import { manifestChecks } from "../util/validate-manifest"; @@ -51,9 +52,21 @@ export async function connectAndDeploy(args: { } } + if (args.rawSSH.hybrid) { + console.log( + "Finished tar.gz-deployment. Starting hybrid deployment via rsync..." + ); + const webAssetsPath = getCachedOutDirectory(); + const cmd = sshOperations.rsyncDeployment({ + webAssetsPath, + sshConfig: args.rawSSH, + }); + await runCommand({ cmd }); + } + const deploymentText = `Deployment successful! Your WebOn has been deployed to the following deeplink:`; - const webonUrl = `${publicBaseUrl.trim()}/nomo.tar.gz`; + const webonUrl = `${publicBaseUrl.trim()}`; const deeplink = webonUrl .replace("http://", "http://nomo.app/webon/") .replace("https://", "https://nomo.app/webon/"); @@ -111,7 +124,7 @@ async function validateDeploymentConfig(deployTarget: string, rawSSH: any) { } } - manifestChecks({ + await manifestChecks({ manifestFilePath: manifestPath, serverWebOnVersion, serverWebOnId, diff --git a/src/services/ssh-operations.ts b/src/services/ssh-operations.ts index ac7b55b..75c85e2 100644 --- a/src/services/ssh-operations.ts +++ b/src/services/ssh-operations.ts @@ -65,7 +65,7 @@ export class SSHOperations { sshConfig: RawSSHConfig; }) { const manifestDeployCommand = this.scpCommand({ - filePath: filePath, + filePath, sshConfig, }); // Rename the file to "manifest" on the remote server @@ -77,8 +77,16 @@ export class SSHOperations { return `${manifestDeployCommand} && ${renameManifestCommand}`; } - public executeCommand({ command }: { command: string }): string { - return command; + public rsyncDeployment({ + webAssetsPath, + sshConfig, + }: { + webAssetsPath: string; + sshConfig: RawSSHConfig; + }) { + const rsyncSourcePath = webAssetsPath + "/"; // the behavior of rsync is different with and without trailing slash! + const rsyncTargetPath = sshConfig.sshBaseDir; + return `rsync -avz --progress ${rsyncSourcePath} ${sshConfig.sshHost}:${rsyncTargetPath}`; } public getRemoteManifest({ @@ -87,18 +95,11 @@ export class SSHOperations { remoteManifestPath: string; }) { const catManifestCommand = `${this.sshConnect} "[ -e ${remoteManifestPath} ] && cat ${remoteManifestPath} || echo 'not_found'"`; - return this.executeCommand({ command: catManifestCommand }); + return catManifestCommand; } public checkSshBaseDirExists({ sshBaseDir }: { sshBaseDir: string }) { const checkDirCommand = `${this.sshConnect} "[ -d ${sshBaseDir} ] && echo 'sshDir exists' || echo 'not_found'"`; - return this.executeCommand({ command: checkDirCommand }); + return checkDirCommand; } } - -export function executeCommand( - command: string, - sshCommands: SSHOperations -): string { - return sshCommands.executeCommand({ command }); -} diff --git a/src/util/extract-tar-gz.ts b/src/util/extract-tar-gz.ts index dbb0acf..f84f1ea 100644 --- a/src/util/extract-tar-gz.ts +++ b/src/util/extract-tar-gz.ts @@ -57,6 +57,11 @@ export function getCachedIndexHtmlPath(): string { return path; } +export function getCachedOutDirectory(): string { + const path = resolve(cacheOutDirectory); + return path; +} + export function getCachedNomoIconPath(): string { const path = join(resolve(cacheOutDirectory), "nomo_icon.svg"); return path; @@ -72,7 +77,7 @@ export function clearCache() { const cacheOutPath = resolve(cacheOutDirectory); if (!existsSync(cachePath)) { - mkdirSync(cachePath); + return; } try { diff --git a/src/util/validate-manifest.ts b/src/util/validate-manifest.ts index 6e9788a..be47961 100644 --- a/src/util/validate-manifest.ts +++ b/src/util/validate-manifest.ts @@ -129,7 +129,7 @@ export async function manifestChecks({ }): Promise { const nomoManifestContent = fs.readFileSync(manifestFilePath, "utf-8"); const nomoManifest: NomoManifest = JSON.parse(nomoManifestContent); - validateManifest({ + await validateManifest({ manifest: nomoManifest, serverWebOnVersion, serverWebOnId,