@milaboratories/pl-deployments 1.1.3 → 1.1.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,11 +1,11 @@
1
- "use strict";var W=Object.defineProperty;var K=(n,r,t)=>r in n?W(n,r,{enumerable:!0,configurable:!0,writable:!0,value:t}):n[r]=t;var w=(n,r,t)=>K(n,typeof r!="symbol"?r+"":r,t);Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const G=require("node:child_process"),d=require("@milaboratories/ts-helpers"),E=require("node:fs"),p=require("node:fs/promises"),u=require("upath"),V=require("undici"),F=require("node:stream"),Y=require("node:stream/consumers"),Z=require("tar"),Q=require("decompress"),A=require("node:os"),g=require("ssh2"),N=require("node:net"),X=require("node:dns"),m=require("@milaboratories/pl-config"),tt=require("node:crypto");function rt(n){const r=Object.create(null,{[Symbol.toStringTag]:{value:"Module"}});if(n){for(const t in n)if(t!=="default"){const e=Object.getOwnPropertyDescriptor(n,t);Object.defineProperty(r,t,e.get?e:{enumerable:!0,get:()=>n[t]})}}return r.default=n,Object.freeze(r)}const et=rt(Z);function it(n,r){return n.info(`Running:
1
+ "use strict";var G=Object.defineProperty;var V=(s,r,t)=>r in s?G(s,r,{enumerable:!0,configurable:!0,writable:!0,value:t}):s[r]=t;var f=(s,r,t)=>V(s,typeof r!="symbol"?r+"":r,t);Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const Y=require("node:child_process"),d=require("@milaboratories/ts-helpers"),C=require("node:fs"),p=require("node:fs/promises"),h=require("upath"),Z=require("undici"),A=require("node:stream"),Q=require("node:stream/consumers"),X=require("tar"),tt=require("decompress"),k=require("node:os"),P=require("ssh2"),T=require("node:net"),rt=require("node:dns"),F=require("node:crypto"),m=require("@milaboratories/pl-config");function et(s){const r=Object.create(null,{[Symbol.toStringTag]:{value:"Module"}});if(s){for(const t in s)if(t!=="default"){const e=Object.getOwnPropertyDescriptor(s,t);Object.defineProperty(r,t,e.get?e:{enumerable:!0,get:()=>s[t]})}}return r.default=s,Object.freeze(r)}const it=et(X);function ot(s,r){return s.info(`Running:
2
2
  cmd: ${JSON.stringify([r.cmd,...r.args])}
3
- wd: ${r.opts.cwd}`),n.info(" spawning child process"),G.spawn(r.cmd,r.args,r.opts)}async function C(n){try{return process.kill(n,0),!0}catch{return!1}}function T(n){return process.kill(n,"SIGINT")}async function _(n,r){let e=0;for(;await C(n);)if(await d.sleep(100),e+=100,e>r)throw new Error(`The process did not stopped after ${r} ms.`)}const ot=["linux","macos","windows"];function U(n){switch(n.toLowerCase()){case"darwin":return"macos";case"linux":return"linux";case"win32":return"windows";default:throw new Error(`operating system '${n}' is not currently supported by Platforma ecosystem. The list of OSes supported: `+JSON.stringify(ot))}}const nt=["amd64","arm64"];function y(n){switch(n){case"aarch64":case"aarch64_be":case"arm64":return"arm64";case"x86_64":case"x64":return"amd64";default:throw new Error(`processor architecture '${n}' is not currently supported by Platforma ecosystem. The list of architectures supported: `+JSON.stringify(nt))}}async function st(n,r,t,e,i,o){const s=ct(t,e,r,y(i),U(o)),{archiveUrl:a,archivePath:c}=s;return await B(n,a,c),s}async function at(n,r,t,e,i){const o=lt(t,r,y(e),U(i)),{archiveUrl:s,archivePath:a,archiveType:c,targetFolder:l,binaryPath:h}=o;return await B(n,s,a),await ht(n,a,c,l),o}function ct(n,r,t,e,i){const o=`${r}-${e}`,s=j[i],a=`${o}.${s}`,c=`https://cdn.platforma.bio/software/${n}/${i}/${a}`,l=u.join(t,a),h=u.join(t,o);return{archiveUrl:c,archivePath:l,archiveType:s,targetFolder:h,baseName:o}}function lt(n,r,t,e){const i=`pl-${n}-${t}`,o=j[e],s=`${i}.${o}`,a=`https://cdn.platforma.bio/software/pl/${e}/${s}`,c=u.join(r,s),l=u.join(r,i),h=u.join(i,"binaries",dt[e]);return{archiveUrl:a,archivePath:c,archiveType:o,targetFolder:l,binaryPath:h,baseName:i}}async function B(n,r,t){const e={};e.dstArchive=t;try{if(e.fileExisted=await d.fileExists(t),e.fileExisted)return n.info(`Platforma Backend archive download skipped: '${t}' already exists`),e;await p.mkdir(u.dirname(t),{recursive:!0}),e.dirnameCreated=!0,n.info(`Downloading archive:
3
+ wd: ${r.opts.cwd}`),s.info(" spawning child process"),Y.spawn(r.cmd,r.args,r.opts)}async function b(s){try{return process.kill(s,0),!0}catch{return!1}}function U(s){return process.kill(s,"SIGINT")}async function B(s,r){let e=0;for(;await b(s);)if(await d.sleep(100),e+=100,e>r)throw new Error(`The process did not stopped after ${r} ms.`)}const st=["linux","macos","windows"];function j(s){switch(s.toLowerCase()){case"darwin":return"macos";case"linux":return"linux";case"win32":return"windows";default:throw new Error(`operating system '${s}' is not currently supported by Platforma ecosystem. The list of OSes supported: `+JSON.stringify(st))}}const nt=["amd64","arm64"];function $(s){switch(s){case"aarch64":case"aarch64_be":case"arm64":return"arm64";case"x86_64":case"x64":return"amd64";default:throw new Error(`processor architecture '${s}' is not currently supported by Platforma ecosystem. The list of architectures supported: `+JSON.stringify(nt))}}async function at(s,r,t,e,i,o){const n=lt(t,e,r,$(i),j(o)),{archiveUrl:c,archivePath:a}=n;return await I(s,c,a),n}async function ct(s,r,t,e,i){const o=ut(t,r,$(e),j(i)),{archiveUrl:n,archivePath:c,archiveType:a,targetFolder:l,binaryPath:u}=o;return await I(s,n,c),await dt(s,c,a,l),o}function lt(s,r,t,e,i){const o=`${r}-${e}`,n=H[i],c=`${o}.${n}`,a=`https://cdn.platforma.bio/software/${s}/${i}/${c}`,l=h.join(t,c),u=h.join(t,o);return{archiveUrl:a,archivePath:l,archiveType:n,targetFolder:u,baseName:o}}function ut(s,r,t,e){const i=`pl-${s}-${t}`,o=H[e],n=`${i}.${o}`,c=`https://cdn.platforma.bio/software/pl/${e}/${n}`,a=h.join(r,n),l=h.join(r,i),u=h.join(i,"binaries",wt[e]);return{archiveUrl:c,archivePath:a,archiveType:o,targetFolder:l,binaryPath:u,baseName:i}}async function I(s,r,t){const e={};e.dstArchive=t;try{if(e.fileExisted=await d.fileExists(t),e.fileExisted)return s.info(`Platforma Backend archive download skipped: '${t}' already exists`),e;await p.mkdir(h.dirname(t),{recursive:!0}),e.dirnameCreated=!0,s.info(`Downloading archive:
4
4
  URL: ${r}
5
- Save to: ${t}`);const{body:i,statusCode:o}=await V.request(r);if(e.statusCode=o,o!=200){const s=await Y.text(i);throw e.errorMsg=`failed to download archive: ${o}, response: ${s.slice(0,1e3)}`,n.error(e.errorMsg),new Error(e.errorMsg)}return e.tmpPath=t+".tmp",await F.Readable.toWeb(i).pipeTo(F.Writable.toWeb(E.createWriteStream(e.tmpPath))),e.wroteTmp=!0,e.tmpExisted=await d.fileExists(e.tmpPath),await p.rename(e.tmpPath,t),e.renamed=!0,e.newExisted=await d.fileExists(t),e}catch(i){const o=`downloadArchive: error ${JSON.stringify(i)} occurred, state: ${JSON.stringify(e)}`;throw n.error(o),new Error(o)}}const ut=".ok";async function ht(n,r,t,e){if(n.info("extracting archive..."),n.info(` archive path: '${r}'`),n.info(` target dir: '${e}'`),!await d.fileExists(r)){const o=`Platforma Backend binary archive not found at '${r}'`;throw n.error(o),new Error(o)}const i=u.join(e,ut);if(await d.fileExists(i)){n.info(`Platforma Backend binaries unpack skipped: '${e}' exists`);return}switch(await d.fileExists(e)&&(n.info(`Removing previous incompletely unpacked folder: '${e}'`),await p.rm(e,{recursive:!0})),n.info(` creating target dir '${e}'`),await p.mkdir(e,{recursive:!0}),n.info(`Unpacking Platforma Backend archive:
5
+ Save to: ${t}`);const{body:i,statusCode:o}=await Z.request(r);if(e.statusCode=o,o!=200){const n=await Q.text(i);throw e.errorMsg=`failed to download archive: ${o}, response: ${n.slice(0,1e3)}`,s.error(e.errorMsg),new Error(e.errorMsg)}return e.tmpPath=t+".tmp",await A.Readable.toWeb(i).pipeTo(A.Writable.toWeb(C.createWriteStream(e.tmpPath))),e.wroteTmp=!0,e.tmpExisted=await d.fileExists(e.tmpPath),await p.rename(e.tmpPath,t),e.renamed=!0,e.newExisted=await d.fileExists(t),e}catch(i){const o=`downloadArchive: error ${JSON.stringify(i)} occurred, state: ${JSON.stringify(e)}`;throw s.error(o),new Error(o)}}const ht=".ok";async function dt(s,r,t,e){if(s.info("extracting archive..."),s.info(` archive path: '${r}'`),s.info(` target dir: '${e}'`),!await d.fileExists(r)){const o=`Platforma Backend binary archive not found at '${r}'`;throw s.error(o),new Error(o)}const i=h.join(e,ht);if(await d.fileExists(i)){s.info(`Platforma Backend binaries unpack skipped: '${e}' exists`);return}switch(await d.fileExists(e)&&(s.info(`Removing previous incompletely unpacked folder: '${e}'`),await p.rm(e,{recursive:!0})),s.info(` creating target dir '${e}'`),await p.mkdir(e,{recursive:!0}),s.info(`Unpacking Platforma Backend archive:
6
6
  Archive: ${r}
7
- Target dir: ${e}`),t){case"tgz":await et.x({file:r,cwd:e,gzip:!0});break;case"zip":await Q(r,e);break;default:d.assertNever(t)}await p.writeFile(i,"ok"),n.info(" ... unpack done.")}const j={linux:"tgz",macos:"tgz",windows:"zip"},dt={linux:"platforma",macos:"platforma",windows:"platforma.exe"};function $(){return"1.18.3"}function wt(){return{type:"Download",version:$()}}async function pt(n,r,t){switch(t.type){case"Download":return(await at(n,r,t.version,A.arch(),A.platform())).binaryPath;case"Local":return t.path;default:d.assertNever(t)}}function H(n){return u.join(n,"pl_pid")}async function ft(n){if(!await d.fileExists(n))return;const r=await p.readFile(n);return Number(r.toString())}async function mt(n,r){await p.writeFile(n,JSON.stringify(r))}function yt(){return{}}function gt(n,r,t){return n[r]=t,t}async function b(n,r){const t=yt();try{return await r((i,o)=>gt(t,i,o),t)}catch(e){throw n.error(`error ${e} while doing traced operation, state: ${JSON.stringify(t)}`),e}}const I="config-local.yaml";class q{constructor(r,t,e,i,o,s,a,c){w(this,"instance");w(this,"pid");w(this,"nRuns",0);w(this,"lastRunHistory",{});w(this,"wasStopped",!1);this.logger=r,this.workingDir=t,this.startOptions=e,this.initialStartHistory=i,this.onClose=o,this.onError=s,this.onCloseAndError=a,this.onCloseAndErrorNoStop=c}async start(){await b(this.logger,async(r,t)=>{this.wasStopped=!1;const e=it(this.logger,this.startOptions);e.on("error",o=>{this.logger.error(`error '${o}', while running platforma, started opts: ${JSON.stringify(this.debugInfo())}`),this.onError!==void 0&&this.onError(this),this.onCloseAndError!==void 0&&this.onCloseAndError(this),this.onCloseAndErrorNoStop!==void 0&&!this.wasStopped&&this.onCloseAndErrorNoStop(this)}),e.on("close",()=>{this.logger.warn(`platforma was closed, started opts: ${JSON.stringify(this.debugInfo())}`),this.onClose!==void 0&&this.onClose(this),this.onCloseAndError!==void 0&&this.onCloseAndError(this),this.onCloseAndErrorNoStop!==void 0&&!this.wasStopped&&this.onCloseAndErrorNoStop(this)}),r("started",!0);const i=r("pidFile",H(this.workingDir));r("pid",d.notEmpty(e.pid)),r("pidWritten",await mt(i,d.notEmpty(e.pid))),this.nRuns++,this.instance=e,this.pid=e.pid,this.lastRunHistory=t})}stop(){this.wasStopped=!0,T(d.notEmpty(this.pid))}async waitStopped(){await _(d.notEmpty(this.pid),15e3)}stopped(){return this.wasStopped}async isAlive(){return await C(d.notEmpty(this.pid))}debugInfo(){return{lastRunHistory:this.lastRunHistory,nRuns:this.nRuns,pid:this.pid,workingDir:this.workingDir,initialStartHistory:this.initialStartHistory,wasStopped:this.wasStopped}}}async function Pt(n,r){const t={plBinary:wt(),spawnOptions:{},closeOld:!0,...r};return await b(n,async(e,i)=>{e("startOptions",{...t,config:"too wordy"});const o=u.resolve(t.workingDir);t.closeOld&&e("closeOld",await $t(n,o));const s=u.join(o,I);n.info(`writing configuration '${s}'...`),await p.writeFile(s,t.config);const a=await pt(n,u.join(o,"binaries"),t.plBinary),l={cmd:e("binaryPath",u.join("binaries",a)),args:["-config",s],opts:{env:{...process.env},cwd:o,stdio:["pipe","ignore","inherit"],windowsHide:!0,...t.spawnOptions}};e("processOpts",{cmd:l.cmd,args:l.args,cwd:l.opts.cwd});const h=new q(n,t.workingDir,l,i,t.onClose,t.onError,t.onCloseAndError,t.onCloseAndErrorNoStop);return await h.start(),h})}async function $t(n,r){return await b(n,async(t,e)=>{const i=t("pidFilePath",H(r)),o=t("pid",await ft(i)),s=t("wasAlive",await C(o));return o!==void 0&&s&&(t("stopped",T(o)),t("waitStopped",await _(o,1e4))),e})}const vt={keepaliveInterval:6e4,keepaliveCountMax:10};class v{constructor(r,t){w(this,"config");w(this,"homeDir");this.logger=r,this.client=t}static async init(r,t){const e={...vt,...t},i=new v(r,new g.Client);return await i.connect(e),i}async connect(r){return this.config=r,new Promise((t,e)=>{this.client.on("ready",()=>{t(void 0)}).on("error",i=>{e(new Error(`ssh.connect: error occurred: ${i}`))}).on("timeout",()=>{e(new Error("timeout was occurred while waiting for SSH connection."))}).connect(r)})}async exec(r){return new Promise((t,e)=>{this.client.exec(r,(i,o)=>{if(i)return e(`ssh.exec: ${r}, error occurred: ${i}`);let s="",a="";o.on("close",c=>{c===0?t({stdout:s,stderr:a}):e(new Error(`Command ${r} exited with code ${c}`))}).on("data",c=>{s+=c.toString()}).stderr.on("data",c=>{a+=c.toString()})})})}static async getAuthTypes(r,t){return new Promise(e=>{let i="";const o=new g.Client;o.on("ready",()=>{o.end();const s=this.extractAuthMethods(i);e(s.length===0?["publickey","password"]:s)}),o.on("error",()=>{o.end(),e(["publickey","password"])}),o.connect({host:r,port:t,username:new Date().getTime().toString(),debug:s=>{i+=`${s}
8
- `}})})}static extractAuthMethods(r){const t=r.match(/Inbound: Received USERAUTH_FAILURE \((.+)\)/);return t&&t[1]?t[1].split(",").map(e=>e.trim()):[]}async forwardPort(r,t){return t=t??this.config,new Promise((e,i)=>{if(!t){i("No config defined");return}const o=new g.Client;let s;o.on("ready",()=>{this.logger.info(`[SSH] Connection to ${t.host}. Remote port ${r.remotePort} will be available locally on the ${r.localPort}`),s=N.createServer({pauseOnConnect:!0},a=>{o.forwardOut("127.0.0.1",0,"127.0.0.1",r.remotePort,(c,l)=>{if(c){console.error("Error opening SSH channel:",c.message),a.end();return}a.pipe(l),l.pipe(a),a.resume()})}),s.listen(r.localPort,"127.0.0.1",()=>{this.logger.info(`[+] Port local ${r.localPort} available locally for remote port → :${r.remotePort}`),e({server:s})}),s.on("error",a=>{o.end(),s.close(),i(new Error(`ssh.forwardPort: server error: ${a}`))}),s.on("close",()=>{this.logger.info(`Server closed ${JSON.stringify(r)}`),o&&(this.logger.info("End SSH connection"),o.end())})}),o.on("error",a=>{this.logger.error(`[SSH] SSH connection error, ports: ${JSON.stringify(r)}, err: ${a.message}`),s==null||s.close(),i(`ssh.forwardPort: conn.err: ${a}`)}),o.on("close",()=>{this.logger.info(`[SSH] Connection closed, ports: ${JSON.stringify(r)}`)}),o.connect(t)})}static async checkHostAvailability(r){return new Promise(t=>{X.lookup(r,e=>{t(!e)})})}static async isPassphraseRequiredForKey(r){return new Promise((t,e)=>{try{return g.utils.parseKey(r)instanceof Error&&t(!0),t(!1)}catch(i){console.log("Error parsing privateKey"),e(new Error(`ssh.isPassphraseRequiredForKey: err ${i}`))}})}async uploadFile(r,t){return await this.withSftp(async e=>new Promise((i,o)=>{e.fastPut(r,t,s=>{if(s){const a=new Error(`ssh.uploadFile: err: ${s}, localPath: ${r}, remotePath: ${t}`);return o(a)}i(!0)})}))}delay(r){return new Promise((t,e)=>{setTimeout(()=>t(),r)})}async withSftp(r){return new Promise((t,e)=>{this.client.sftp((i,o)=>{if(i)return e(new Error(`ssh.withSftp: sftp err: ${i}`));r(o).then(t).catch(s=>{e(new Error(`ssh.withSftp.callback: err ${s}`))}).finally(()=>{o==null||o.end()})})})}async writeFileOnTheServer(r,t,e=432){return this.withSftp(async i=>this.writeFile(i,r,t,e))}async readFile(r){return this.withSftp(async t=>new Promise((e,i)=>{t.readFile(r,(o,s)=>{if(o)return i(new Error(`ssh.readFile: err occurred ${o}`));e(s.toString())})}))}async chmod(r,t){return this.withSftp(async e=>new Promise((i,o)=>{e.chmod(r,t,s=>s?o(new Error(`ssh.chmod: ${s}, path: ${r}, mode: ${t}`)):i(void 0))}))}async checkFileExists(r){return this.withSftp(async t=>new Promise((e,i)=>{t.stat(r,(o,s)=>{if(o)return o.code===2?e(!1):i(new Error(`ssh.checkFileExists: err ${o}`));e(s.isFile())})}))}async checkPathExists(r){return this.withSftp(async t=>new Promise((e,i)=>{t.stat(r,(o,s)=>{if(o)return o.code===2?e({exists:!1,isFile:!1,isDirectory:!1}):i(new Error(`ssh.checkPathExists: ${o}`));e({exists:!0,isFile:s.isFile(),isDirectory:s.isDirectory()})})}))}async writeFile(r,t,e,i=432){return new Promise((o,s)=>{r.writeFile(t,e,{mode:i},a=>{if(a)return s(new Error(`ssh.writeFile: err ${a}, remotePath: ${t}`));o(!0)})})}uploadFileUsingExistingSftp(r,t,e,i=432){return new Promise((o,s)=>{p.readFile(t).then(async a=>{this.writeFile(r,e,a,i).then(()=>{o(void 0)}).catch(c=>{const l=`uploadFileUsingExistingSftp: error ${c} occurred`;this.logger.error(l),s(new Error(l))})})})}async __uploadDirectory(r,t,e,i=432){return new Promise((o,s)=>{E.readdir(t,async(a,c)=>{if(a)return s(new Error(`ssh.__uploadDir: err ${a}, localDir: ${t}, remoteDir: ${e}`));try{await this.__createRemoteDirectory(r,e);for(const l of c){const h=u.join(t,l),f=`${e}/${l}`;E.lstatSync(h).isDirectory()?await this.__uploadDirectory(r,h,f,i):await this.uploadFileUsingExistingSftp(r,h,f,i)}o()}catch(l){const h=`ssh.__uploadDir: catched err ${l}`;this.logger.error(h),s(new Error(h))}})})}async uploadDirectory(r,t,e=432){return new Promise((i,o)=>{this.withSftp(async s=>{await this.__uploadDirectory(s,r,t,e),i()})})}__createRemoteDirectory(r,t){return new Promise((e,i)=>{const o=t.split("/");let s="";const a=c=>{if(c>=o.length)return e();s+=`${o[c]}/`,r.stat(s,l=>{l?r.mkdir(s,h=>{if(h)return i(new Error(`ssh.__createRemDir: err ${h}, remotePath: ${t}`));a(c+1)}):a(c+1)})};a(0)})}createRemoteDirectory(r,t=493){return this.withSftp(async e=>{const i=r.split("/");let o="";for(const s of i){o+=`${s}/`;try{await new Promise((a,c)=>{e.stat(o,l=>{if(!l)return a();e.mkdir(o,{mode:t},h=>{if(h)return c(new Error(`ssh.createRemoteDir: err ${h}, remotePath: ${r}`));a()})})})}catch(a){throw console.error(`Failed to create directory: ${o}`,a),a}}})}async downloadFile(r,t){return this.withSftp(async e=>new Promise((i,o)=>{e.fastGet(r,t,s=>{if(s)return o(new Error(`ssh.downloadFile: err ${s}, remotePath: ${r}, localPath: ${t}`));i(!0)})}))}close(){this.client.end()}}const St="minio-2024-12-18T13-15-44Z",Et="supervisord-0.7.3",Ct="supervisord_0.7.3_Linux_64-bit";function P(n){return u.join(n,"platforma_ssh")}function S(n){return u.join(n,"platforma_ssh","binaries")}function bt(n,r){return u.join(S(n),`pl-${$()}-${y(r)}`)}function M(n,r){return u.join(bt(n,r),"binaries")}function D(n,r){return u.join(M(n,r),"platforma")}function Ot(n,r){return u.join(M(n,r),"free-port")}function J(n,r){return u.join(S(n),`minio-2024-12-18T13-15-44Z-${y(r)}`)}function xt(n,r){return u.join(J(n,r),"minio")}function Ft(n,r){return u.join(S(n),`supervisord-0.7.3-${y(r)}`,Ct)}function L(n,r){return u.join(Ft(n,r),"supervisord")}function z(n){return u.join(P(n),"supervisor.conf")}function k(n){return u.join(P(n),"connection.txt")}async function At(n,r,t){const e=await O(n,r,t,"--daemon");if(e.stderr)throw new Error(`Can not run ssh Platforma ${e.stderr}`)}async function Dt(n,r,t){const e=await O(n,r,t,"ctl shutdown");if(e.stderr)throw new Error(`Can not stop ssh Platforma ${e.stderr}`)}async function kt(n,r,t,e){const i=await O(r,t,e,"ctl status");if(i.stderr)return n.info(`supervisord ctl status: stderr occurred: ${i.stderr}, stdout: ${i.stdout}`),!1;const o={platforma:R(i.stdout,"platforma"),minio:R(i.stdout,"minio")};return o.platforma&&o.minio?!0:(o.minio||n.warn("Minio is not running on the server"),o.platforma||n.warn("Platforma is not running on the server"),!1)}function Rt(n,r,t,e,i,o,s){const a=Object.entries(r).map(([h,f])=>`${h}="${f}"`).join(","),c=tt.randomBytes(16).toString("hex"),l=t;return`
7
+ Target dir: ${e}`),t){case"tgz":await it.x({file:r,cwd:e,gzip:!0});break;case"zip":await tt(r,e);break;default:d.assertNever(t)}await p.writeFile(i,"ok"),s.info(" ... unpack done.")}const H={linux:"tgz",macos:"tgz",windows:"zip"},wt={linux:"platforma",macos:"platforma",windows:"platforma.exe"};function v(){return"1.18.3"}function ft(){return{type:"Download",version:v()}}async function pt(s,r,t){switch(t.type){case"Download":return(await ct(s,r,t.version,k.arch(),k.platform())).binaryPath;case"Local":return t.path;default:d.assertNever(t)}}function q(s){return h.join(s,"pl_pid")}async function mt(s){if(!await d.fileExists(s))return;const r=await p.readFile(s);return Number(r.toString())}async function gt(s,r){await p.writeFile(s,JSON.stringify(r))}function yt(){return{}}function $t(s,r,t){return s[r]=t,t}async function D(s,r){const t=yt();try{return await r((i,o)=>$t(t,i,o),t)}catch(e){throw s.error(`error ${e} while doing traced operation, state: ${JSON.stringify(t)}`),e}}const M="config-local.yaml";class J{constructor(r,t,e,i,o,n,c,a){f(this,"instance");f(this,"pid");f(this,"nRuns",0);f(this,"lastRunHistory",{});f(this,"wasStopped",!1);this.logger=r,this.workingDir=t,this.startOptions=e,this.initialStartHistory=i,this.onClose=o,this.onError=n,this.onCloseAndError=c,this.onCloseAndErrorNoStop=a}async start(){await D(this.logger,async(r,t)=>{this.wasStopped=!1;const e=ot(this.logger,this.startOptions);e.on("error",o=>{this.logger.error(`error '${o}', while running platforma, started opts: ${JSON.stringify(this.debugInfo())}`),this.onError!==void 0&&this.onError(this),this.onCloseAndError!==void 0&&this.onCloseAndError(this),this.onCloseAndErrorNoStop!==void 0&&!this.wasStopped&&this.onCloseAndErrorNoStop(this)}),e.on("close",()=>{this.logger.warn(`platforma was closed, started opts: ${JSON.stringify(this.debugInfo())}`),this.onClose!==void 0&&this.onClose(this),this.onCloseAndError!==void 0&&this.onCloseAndError(this),this.onCloseAndErrorNoStop!==void 0&&!this.wasStopped&&this.onCloseAndErrorNoStop(this)}),r("started",!0);const i=r("pidFile",q(this.workingDir));r("pid",d.notEmpty(e.pid)),r("pidWritten",await gt(i,d.notEmpty(e.pid))),this.nRuns++,this.instance=e,this.pid=e.pid,this.lastRunHistory=t})}stop(){this.wasStopped=!0,U(d.notEmpty(this.pid))}async waitStopped(){await B(d.notEmpty(this.pid),15e3)}stopped(){return this.wasStopped}async isAlive(){return await b(d.notEmpty(this.pid))}debugInfo(){return{lastRunHistory:this.lastRunHistory,nRuns:this.nRuns,pid:this.pid,workingDir:this.workingDir,initialStartHistory:this.initialStartHistory,wasStopped:this.wasStopped}}}async function Pt(s,r){const t={plBinary:ft(),spawnOptions:{},closeOld:!0,...r};return await D(s,async(e,i)=>{e("startOptions",{...t,config:"too wordy"});const o=h.resolve(t.workingDir);t.closeOld&&e("closeOld",await vt(s,o));const n=h.join(o,M);s.info(`writing configuration '${n}'...`),await p.writeFile(n,t.config);const c=await pt(s,h.join(o,"binaries"),t.plBinary),l={cmd:e("binaryPath",h.join("binaries",c)),args:["-config",n],opts:{env:{...process.env},cwd:o,stdio:["pipe","ignore","inherit"],windowsHide:!0,...t.spawnOptions}};e("processOpts",{cmd:l.cmd,args:l.args,cwd:l.opts.cwd});const u=new J(s,t.workingDir,l,i,t.onClose,t.onError,t.onCloseAndError,t.onCloseAndErrorNoStop);return await u.start(),u})}async function vt(s,r){return await D(s,async(t,e)=>{const i=t("pidFilePath",q(r)),o=t("pid",await mt(i)),n=t("wasAlive",await b(o));return o!==void 0&&n&&(t("stopped",U(o)),t("waitStopped",await B(o,1e4))),e})}const St={keepaliveInterval:6e4,keepaliveCountMax:10};class S{constructor(r,t){f(this,"config");f(this,"homeDir");this.logger=r,this.client=t}static async init(r,t){const e={...St,...t},i=new S(r,new P.Client);return await i.connect(e),i}getFullHostName(){var r,t;return`${(r=this.config)==null?void 0:r.host}:${(t=this.config)==null?void 0:t.port}`}getUserName(){var r;return(r=this.config)==null?void 0:r.username}async connect(r){return this.config=r,await Et(this.client,r)}async exec(r){return new Promise((t,e)=>{this.client.exec(r,(i,o)=>{if(i)return e(`ssh.exec: ${r}, error occurred: ${i}`);let n="",c="";o.on("close",a=>{a===0?t({stdout:n,stderr:c}):e(new Error(`Command ${r} exited with code ${a}`))}).on("data",a=>{n+=a.toString()}).stderr.on("data",a=>{c+=a.toString()})})})}static async getAuthTypes(r,t){return new Promise(e=>{let i="";const o=new P.Client;o.on("ready",()=>{o.end();const n=this.extractAuthMethods(i);e(n.length===0?["publickey","password"]:n)}),o.on("error",()=>{o.end(),e(["publickey","password"])}),o.connect({host:r,port:t,username:new Date().getTime().toString(),debug:n=>{i+=`${n}
8
+ `}})})}static extractAuthMethods(r){const t=r.match(/Inbound: Received USERAUTH_FAILURE \((.+)\)/);return t&&t[1]?t[1].split(",").map(e=>e.trim()):[]}async forwardPort(r,t){const e=`ssh.forward:${r.localPort}:${r.remotePort}.id_${F.randomBytes(1).toString("hex")}`;t=t??this.config;const i=new d.RetryablePromise(o=>new Promise((n,c)=>{const a=new P.Client;a.on("ready",()=>{this.logger.info(`${e}.client.ready`),n(a)}),a.on("error",l=>{this.logger.info(`${e}.client.error: ${l}`),o.reset(),c(l)}),a.on("close",()=>{this.logger.info(`${e}.client.closed`),o.reset()}),a.connect(t)}));return await i.ensure(),new Promise((o,n)=>{const c=T.createServer({pauseOnConnect:!0},async a=>{const l=`${e}.sock_${F.randomBytes(1).toString("hex")}`;let u;try{u=await i.ensure()}catch(g){this.logger.info(`${l}.persistentClient.catch: ${g}`),a.end();return}let w;try{w=await Ct(this.logger,u,"127.0.0.1",0,"127.0.0.1",r.remotePort)}catch(g){this.logger.error(`${l}.forwardOut.err: ${g}`),a.end();return}a.pipe(w),w.pipe(a),a.resume(),w.on("error",g=>{this.logger.error(`${l}.stream.error: ${g}`),a.end(),w.end()}),w.on("close",()=>{a.end(),w.end()}),a.on("close",()=>{this.logger.info(`${l}.localSocket: closed`),a.end(),w.end()})});c.listen(r.localPort,"127.0.0.1",()=>{this.logger.info(`${e}.server: started listening`),o({server:c})}),c.on("error",a=>{c.close(),n(new Error(`${e}.server: error: ${JSON.stringify(a)}`))}),c.on("close",()=>{this.logger.info(`${e}.server: closed ${JSON.stringify(r)}`)})})}static async checkHostAvailability(r){return new Promise(t=>{rt.lookup(r,e=>{t(!e)})})}static async isPassphraseRequiredForKey(r){return new Promise((t,e)=>{try{return P.utils.parseKey(r)instanceof Error&&t(!0),t(!1)}catch(i){console.log("Error parsing privateKey"),e(new Error(`ssh.isPassphraseRequiredForKey: err ${i}`))}})}async uploadFile(r,t){return await this.withSftp(async e=>new Promise((i,o)=>{e.fastPut(r,t,n=>{if(n){const c=new Error(`ssh.uploadFile: err: ${n}, localPath: ${r}, remotePath: ${t}`);return o(c)}i(!0)})}))}delay(r){return new Promise((t,e)=>{setTimeout(()=>t(),r)})}async withSftp(r){return new Promise((t,e)=>{this.client.sftp((i,o)=>{if(i)return e(new Error(`ssh.withSftp: sftp err: ${i}`));r(o).then(t).catch(n=>{e(new Error(`ssh.withSftp.callback: err ${n}`))}).finally(()=>{o==null||o.end()})})})}async writeFileOnTheServer(r,t,e=432){return this.withSftp(async i=>this.writeFile(i,r,t,e))}async getForderStructure(r,t,e={files:[],directories:[]}){return new Promise((i,o)=>{r.readdir(t,async(n,c)=>{if(n)return o(n);for(const a of c){const l=`${t}/${a.filename}`;if(a.attrs.isDirectory()){e.directories.push(l);try{await this.getForderStructure(r,l,e)}catch(u){return o(u)}}else e.files.push(l)}i(e)})})}rmdir(r,t){return new Promise((e,i)=>{r.rmdir(t,o=>o?i(o):e(!0))})}unlink(r,t){return new Promise((e,i)=>{r.unlink(t,o=>o?i(o):e(!0))})}async deleteFolder(r){return this.withSftp(async t=>{try{const e=await this.getForderStructure(t,r);this.logger.info("ssh.deleteFolder list of files and directories"),this.logger.info(`ssh.deleteFolder list of files: ${e.files}`),this.logger.info(`ssh.deleteFolder list of directories: ${e.directories}`);for(const i of e.files)this.logger.info(`ssh.deleteFolder unlink file ${i}`),await this.unlink(t,i);e.directories.sort((i,o)=>o.length-i.length);for(const i of e.directories)this.logger.info(`ssh.deleteFolder rmdir ${i}`),await this.rmdir(t,i);return await this.rmdir(t,r),!0}catch(e){this.logger.error(e);const i=e instanceof Error?e.message:"";throw new Error(`ssh.deleteFolder: path: ${r}, message: ${i}`)}})}async readFile(r){return this.withSftp(async t=>new Promise((e,i)=>{t.readFile(r,(o,n)=>{if(o)return i(new Error(`ssh.readFile: err occurred ${o}`));e(n.toString())})}))}async chmod(r,t){return this.withSftp(async e=>new Promise((i,o)=>{e.chmod(r,t,n=>n?o(new Error(`ssh.chmod: ${n}, path: ${r}, mode: ${t}`)):i(void 0))}))}async checkFileExists(r){return this.withSftp(async t=>new Promise((e,i)=>{t.stat(r,(o,n)=>{if(o)return o.code===2?e(!1):i(new Error(`ssh.checkFileExists: err ${o}`));e(n.isFile())})}))}async checkPathExists(r){return this.withSftp(async t=>new Promise((e,i)=>{t.stat(r,(o,n)=>{if(o)return o.code===2?e({exists:!1,isFile:!1,isDirectory:!1}):i(new Error(`ssh.checkPathExists: ${o}`));e({exists:!0,isFile:n.isFile(),isDirectory:n.isDirectory()})})}))}async writeFile(r,t,e,i=432){return new Promise((o,n)=>{r.writeFile(t,e,{mode:i},c=>{if(c)return n(new Error(`ssh.writeFile: err ${c}, remotePath: ${t}`));o(!0)})})}uploadFileUsingExistingSftp(r,t,e,i=432){return new Promise((o,n)=>{p.readFile(t).then(async c=>{this.writeFile(r,e,c,i).then(()=>{o(void 0)}).catch(a=>{const l=`uploadFileUsingExistingSftp: error ${a} occurred`;this.logger.error(l),n(new Error(l))})})})}async __uploadDirectory(r,t,e,i=432){return new Promise((o,n)=>{C.readdir(t,async(c,a)=>{if(c)return n(new Error(`ssh.__uploadDir: err ${c}, localDir: ${t}, remoteDir: ${e}`));try{await this.__createRemoteDirectory(r,e);for(const l of a){const u=h.join(t,l),w=`${e}/${l}`;C.lstatSync(u).isDirectory()?await this.__uploadDirectory(r,u,w,i):await this.uploadFileUsingExistingSftp(r,u,w,i)}o()}catch(l){const u=`ssh.__uploadDir: catched err ${l}`;this.logger.error(u),n(new Error(u))}})})}async uploadDirectory(r,t,e=432){return new Promise((i,o)=>{this.withSftp(async n=>{await this.__uploadDirectory(n,r,t,e),i()})})}__createRemoteDirectory(r,t){return new Promise((e,i)=>{const o=t.split("/");let n="";const c=a=>{if(a>=o.length)return e();n+=`${o[a]}/`,r.stat(n,l=>{l?r.mkdir(n,u=>{if(u)return i(new Error(`ssh.__createRemDir: err ${u}, remotePath: ${t}`));c(a+1)}):c(a+1)})};c(0)})}createRemoteDirectory(r,t=493){return this.withSftp(async e=>{const i=r.split("/");let o="";for(const n of i){o+=`${n}/`;try{await new Promise((c,a)=>{e.stat(o,l=>{if(!l)return c();e.mkdir(o,{mode:t},u=>{if(u)return a(new Error(`ssh.createRemoteDir: err ${u}, remotePath: ${r}`));c()})})})}catch(c){throw console.error(`Failed to create directory: ${o}`,c),c}}})}async downloadFile(r,t){return this.withSftp(async e=>new Promise((i,o)=>{e.fastGet(r,t,n=>{if(n)return o(new Error(`ssh.downloadFile: err ${n}, remotePath: ${r}, localPath: ${t}`));i(!0)})}))}close(){this.client.end()}}async function Et(s,r,t,e){return new Promise((i,o)=>{s.on("ready",()=>{i(s)}),s.on("error",n=>{o(new Error(`ssh.connect: error occurred: ${n}`))}),s.on("close",()=>{}),s.connect(r)})}async function Ct(s,r,t,e,i,o){return new Promise((n,c)=>{r.forwardOut(t,e,i,o,(a,l)=>a?(s.error(`forwardOut.error: ${a}`),c(a)):n(l))})}const Ft="minio-2024-12-18T13-15-44Z",bt="supervisord-0.7.3",Dt="supervisord_0.7.3_Linux_64-bit";function y(s){return h.join(s,"platforma_ssh")}function E(s){return h.join(s,"platforma_ssh","binaries")}function Ot(s,r){return h.join(E(s),`pl-${v()}-${$(r)}`)}function L(s,r){return h.join(Ot(s,r),"binaries")}function R(s,r){return h.join(L(s,r),"platforma")}function xt(s,r){return h.join(L(s,r),"free-port")}function z(s,r){return h.join(E(s),`minio-2024-12-18T13-15-44Z-${$(r)}`)}function At(s,r){return h.join(z(s,r),"minio")}function kt(s,r){return h.join(E(s),`supervisord-0.7.3-${$(r)}`,Dt)}function W(s,r){return h.join(kt(s,r),"supervisord")}function K(s){return h.join(y(s),"supervisor.conf")}function N(s){return h.join(y(s),"connection.txt")}async function Rt(s,r,t){const e=await O(s,r,t,"--daemon");if(e.stderr)throw new Error(`Can not run ssh Platforma ${e.stderr}`)}async function Nt(s,r,t){const e=await O(s,r,t,"ctl shutdown");if(e.stderr)throw new Error(`Can not stop ssh Platforma ${e.stderr}`)}async function _t(s,r,t,e){const i=await O(r,t,e,"ctl status");if(i.stderr)return s.info(`supervisord ctl status: stderr occurred: ${i.stderr}, stdout: ${i.stdout}`),!1;const o={platforma:_(i.stdout,"platforma"),minio:_(i.stdout,"minio")};return o.platforma&&o.minio?!0:(o.minio||s.warn("Minio is not running on the server"),o.platforma||s.warn("Platforma is not running on the server"),!1)}function Tt(s,r,t,e,i,o,n){const c=Object.entries(r).map(([u,w])=>`${u}="${w}"`).join(","),a=F.randomBytes(16).toString("hex"),l=t;return`
9
9
  [supervisord]
10
10
  logfile=${e}/supervisord.log
11
11
  loglevel=info
@@ -14,27 +14,27 @@ pidfile=${e}/supervisord.pid
14
14
  [inet_http_server]
15
15
  port=127.0.0.1:${l}
16
16
  username=default-user
17
- password=${c}
17
+ password=${a}
18
18
 
19
19
  [supervisorctl]
20
20
  serverurl=http://127.0.0.1:${l}
21
21
  username=default-user
22
- password=${c}
22
+ password=${a}
23
23
 
24
24
  [program:platforma]
25
25
  autostart=true
26
26
  depends_on=minio
27
- command=${s} --config ${i}
27
+ command=${n} --config ${i}
28
28
  directory=${e}
29
29
  autorestart=true
30
30
 
31
31
  [program:minio]
32
32
  autostart=true
33
- environment=${a}
34
- command=${o} server ${n}
33
+ environment=${c}
34
+ command=${o} server ${s}
35
35
  directory=${e}
36
36
  autorestart=true
37
- `}async function O(n,r,t,e){const i=L(r,t),o=z(r),s=`${i} --configuration ${o} ${e}`;return await n.exec(s)}function R(n,r){return(i=>i.replace(/\x1B\[[0-9;]*m/g,""))(n).split(`
38
- `).some(i=>{const[o,s]=i.trim().split(/\s{2,}/);return o===r&&s==="Running"})}class x{constructor(r,t,e){w(this,"initState",{});this.logger=r,this.sshClient=t,this.username=e}info(){return{username:this.username,initState:this.initState}}static async init(r,t){try{const e=await v.init(r,t);return new x(r,e,d.notEmpty(t.username))}catch(e){throw r.error(`Connection error in SshClient.init: ${e}`),e}}async isAlive(){const r=await this.getArch(),t=await this.getUserHomeDirectory();try{return await kt(this.logger,this.sshClient,t,r.arch)}catch{return!1}}async start(){const r=await this.getArch(),t=await this.getUserHomeDirectory();try{return await At(this.sshClient,t,r.arch),await this.checkIsAliveWithInterval()}catch(e){const i=`ssh.start: error occurred ${e}`;throw this.logger.error(i),new Error(i)}}async stop(){const r=await this.getArch(),t=await this.getUserHomeDirectory();try{return await Dt(this.sshClient,t,r.arch),await this.checkIsAliveWithInterval(void 0,void 0,!1)}catch(e){const i=`ssh.stop: error occurred ${e}`;throw this.logger.error(i),new Error(i)}}async platformaInit(r){const t={localWorkdir:r};try{if(t.arch=await this.getArch(),t.remoteHome=await this.getUserHomeDirectory(),t.isAlive=await this.isAlive(),t.isAlive){if(t.userCredentials=await this.getUserCredentials(t.remoteHome),!t.userCredentials)throw new Error("SshPl.platformaInit: platforma is alive but userCredentials are not found");return t.userCredentials}const e=await this.downloadBinariesAndUploadToTheServer(r,t.remoteHome,t.arch);if(t.binPaths={...e,history:void 0},t.downloadedBinaries=e.history,t.ports=await this.fetchPorts(t.remoteHome,t.arch),!t.ports.debug.remote||!t.ports.grpc.remote||!t.ports.minioPort.remote||!t.ports.minioConsolePort.remote||!t.ports.monitoring.remote)throw new Error("SshPl.platformaInit: remote ports are not defined");const i=await m.generateSshPlConfigs({logger:this.logger,workingDir:P(t.remoteHome),portsMode:{type:"customWithMinio",ports:{debug:t.ports.debug.remote,grpc:t.ports.grpc.remote,minio:t.ports.minioPort.remote,minioConsole:t.ports.minioConsolePort.remote,monitoring:t.ports.monitoring.remote,grpcLocal:t.ports.grpc.local,minioLocal:t.ports.minioPort.local}},licenseMode:{type:"env"}});t.generatedConfig={...i,filesToCreate:{skipped:"it is too wordy"}};for(const[a,c]of Object.entries(i.filesToCreate))await this.sshClient.writeFileOnTheServer(a,c),this.logger.info(`Created file ${a}`);for(const a of i.dirsToCreate)await this.sshClient.createRemoteDirectory(a),this.logger.info(`Created directory ${a}`);const o=Rt(i.minioConfig.storageDir,i.minioConfig.envs,await this.getFreePortForPlatformaOnServer(t.remoteHome,t.arch),i.workingDir,i.plConfig.configPath,t.binPaths.minioRelPath,t.binPaths.downloadedPl);if(!await this.sshClient.writeFileOnTheServer(z(t.remoteHome),o))throw new Error(`Can not write supervisord config on the server ${P(t.remoteHome)}`);return t.connectionInfo={plUser:i.plUser,plPassword:i.plPassword,ports:t.ports},await this.sshClient.writeFileOnTheServer(k(t.remoteHome),JSON.stringify(t.connectionInfo,void 0,2)),await this.start(),t.started=!0,this.initState=t,{plUser:i.plUser,plPassword:i.plPassword,ports:t.ports}}catch(e){const i=`SshPl.platformaInit: error occurred: ${e}, state: ${JSON.stringify(t)}`;throw this.logger.error(i),new Error(i)}}async downloadBinariesAndUploadToTheServer(r,t,e){const i=[];try{const o=await this.downloadAndUntar(r,t,e,"pl",`pl-${$()}`);i.push(o);const s=await this.downloadAndUntar(r,t,e,"supervisord",Et);i.push(s);const a=xt(t,e.arch),c=await this.downloadAndUntar(r,t,e,"minio",St);return i.push(c),await this.sshClient.chmod(a,488),{history:i,minioRelPath:a,downloadedPl:D(t,e.arch)}}catch(o){const s=`SshPl.downloadBinariesAndUploadToServer: error ${o} occurred, state: ${JSON.stringify(i)}`;throw this.logger.error(s),o}}async downloadAndUntar(r,t,e,i,o){const s={};s.binBasePath=S(t),await this.sshClient.createRemoteDirectory(s.binBasePath),s.binBasePathCreated=!0;let a=null;const c=5;for(let h=1;h<=c;h++)try{a=await st(this.logger,r,i,o,e.arch,e.platform);break}catch(f){if(await d.sleep(300),h==c)throw new Error(`downloadAndUntar: ${c} attempts, last error: ${f}`)}s.downloadResult=d.notEmpty(a),s.localArchivePath=u.resolve(s.downloadResult.archivePath),s.remoteDir=u.join(s.binBasePath,s.downloadResult.baseName),s.remoteArchivePath=s.remoteDir+".tgz",await this.sshClient.createRemoteDirectory(s.remoteDir),await this.sshClient.uploadFile(s.localArchivePath,s.remoteArchivePath);const l=await this.sshClient.exec(`tar xvf ${s.remoteArchivePath} --directory=${s.remoteDir}`);if(l.stderr)throw new Error(`downloadAndUntar: untar: stderr occurred: ${l.stderr}, stdout: ${l.stdout}`);return s.plUntarDone=!0,s}async needDownload(r,t){const e=L(r,t.arch),i=J(r,t.arch),o=D(r,t.arch);return!await this.sshClient.checkFileExists(o)||!await this.sshClient.checkFileExists(i)||!await this.sshClient.checkFileExists(e)}async checkIsAliveWithInterval(r=1e3,t=15,e=!0){const i=t*r;let o=0,s=await this.isAlive();for(;e?!s:s;){if(await d.sleep(r),o+=r,o>i)throw new Error(`isAliveWithInterval: The process did not ${e?"started":"stopped"} after ${i} ms.`);s=await this.isAlive()}}async getUserCredentials(r){const t=await this.sshClient.readFile(k(r));return JSON.parse(t)}async fetchPorts(r,t){return{grpc:{local:await m.getFreePort(),remote:await this.getFreePortForPlatformaOnServer(r,t)},monitoring:{local:await m.getFreePort(),remote:await this.getFreePortForPlatformaOnServer(r,t)},debug:{local:await m.getFreePort(),remote:await this.getFreePortForPlatformaOnServer(r,t)},minioPort:{local:await m.getFreePort(),remote:await this.getFreePortForPlatformaOnServer(r,t)},minioConsolePort:{local:await m.getFreePort(),remote:await this.getFreePortForPlatformaOnServer(r,t)}}}async getLocalFreePort(){return new Promise(r=>{const t=N.createServer();t.listen(0,()=>{const e=t.address().port;t.close(i=>r(e))})})}async getFreePortForPlatformaOnServer(r,t){const e=Ot(r,t.arch),{stdout:i,stderr:o}=await this.sshClient.exec(`${e}`);if(o)throw new Error(`getFreePortForPlatformaOnServer: stderr is not empty: ${o}, stdout: ${i}`);return+i}async getArch(){const{stdout:r,stderr:t}=await this.sshClient.exec("uname -s && uname -m");if(t)throw new Error(`getArch: stderr is not empty: ${t}, stdout: ${r}`);const e=r.split(`
39
- `);return{platform:e[0],arch:e[1]}}async getUserHomeDirectory(){const{stdout:r,stderr:t}=await this.sshClient.exec("echo $HOME");if(t){const e=`/home/${this.username}`;return console.warn(`getUserHomeDirectory: stderr is not empty: ${t}, stdout: ${r}, will get a default home: ${e}`),e}return r.trim()}}exports.LocalConfigYaml=I;exports.LocalPl=q;exports.SshClient=v;exports.SshPl=x;exports.getDefaultPlVersion=$;exports.localPlatformaInit=Pt;
37
+ `}async function O(s,r,t,e){const i=W(r,t),o=K(r),n=`${i} --configuration ${o} ${e}`;return await s.exec(n)}function _(s,r){return(i=>i.replace(/\x1B\[[0-9;]*m/g,""))(s).split(`
38
+ `).some(i=>{const[o,n]=i.trim().split(/\s{2,}/);return o===r&&n==="Running"})}class x{constructor(r,t,e){f(this,"initState",{});this.logger=r,this.sshClient=t,this.username=e}info(){return{username:this.username,initState:this.initState}}static async init(r,t){try{const e=await S.init(r,t);return new x(r,e,d.notEmpty(t.username))}catch(e){throw r.error(`Connection error in SshClient.init: ${e}`),e}}async isAlive(){const r=await this.getArch(),t=await this.getUserHomeDirectory();try{return await _t(this.logger,this.sshClient,t,r.arch)}catch{return!1}}async start(){const r=await this.getArch(),t=await this.getUserHomeDirectory();try{return await Rt(this.sshClient,t,r.arch),await this.checkIsAliveWithInterval()}catch(e){const i=`ssh.start: error occurred ${e}`;throw this.logger.error(i),new Error(i)}}async stop(){const r=await this.getArch(),t=await this.getUserHomeDirectory();try{return await Nt(this.sshClient,t,r.arch),await this.checkIsAliveWithInterval(void 0,void 0,!1)}catch(e){const i=`ssh.stop: error occurred ${e}`;throw this.logger.error(i),new Error(i)}}async reset(){const r=await this.getUserHomeDirectory();return this.logger.info("pl.reset: Stop Platforma on the server"),await this.stop(),this.logger.info(`pl.reset: Deleting Platforma workDir ${r} on the server`),await this.sshClient.deleteFolder(y(r)),!0}async platformaInit(r){const t={localWorkdir:r};try{if(t.arch=await this.getArch(),t.remoteHome=await this.getUserHomeDirectory(),t.isAlive=await this.isAlive(),t.isAlive){if(t.userCredentials=await this.getUserCredentials(t.remoteHome),!t.userCredentials)throw new Error("SshPl.platformaInit: platforma is alive but userCredentials are not found");return t.userCredentials}const e=await this.downloadBinariesAndUploadToTheServer(r,t.remoteHome,t.arch);if(t.binPaths={...e,history:void 0},t.downloadedBinaries=e.history,t.ports=await this.fetchPorts(t.remoteHome,t.arch),!t.ports.debug.remote||!t.ports.grpc.remote||!t.ports.minioPort.remote||!t.ports.minioConsolePort.remote||!t.ports.monitoring.remote)throw new Error("SshPl.platformaInit: remote ports are not defined");const i=await m.generateSshPlConfigs({logger:this.logger,workingDir:y(t.remoteHome),portsMode:{type:"customWithMinio",ports:{debug:t.ports.debug.remote,grpc:t.ports.grpc.remote,minio:t.ports.minioPort.remote,minioConsole:t.ports.minioConsolePort.remote,monitoring:t.ports.monitoring.remote,grpcLocal:t.ports.grpc.local,minioLocal:t.ports.minioPort.local}},licenseMode:{type:"env"}});t.generatedConfig={...i,filesToCreate:{skipped:"it is too wordy"}};for(const[c,a]of Object.entries(i.filesToCreate))await this.sshClient.writeFileOnTheServer(c,a),this.logger.info(`Created file ${c}`);for(const c of i.dirsToCreate)await this.sshClient.createRemoteDirectory(c),this.logger.info(`Created directory ${c}`);const o=Tt(i.minioConfig.storageDir,i.minioConfig.envs,await this.getFreePortForPlatformaOnServer(t.remoteHome,t.arch),i.workingDir,i.plConfig.configPath,t.binPaths.minioRelPath,t.binPaths.downloadedPl);if(!await this.sshClient.writeFileOnTheServer(K(t.remoteHome),o))throw new Error(`Can not write supervisord config on the server ${y(t.remoteHome)}`);return t.connectionInfo={plUser:i.plUser,plPassword:i.plPassword,ports:t.ports},await this.sshClient.writeFileOnTheServer(N(t.remoteHome),JSON.stringify(t.connectionInfo,void 0,2)),await this.start(),t.started=!0,this.initState=t,{plUser:i.plUser,plPassword:i.plPassword,ports:t.ports}}catch(e){const i=`SshPl.platformaInit: error occurred: ${e}, state: ${JSON.stringify(t)}`;throw this.logger.error(i),new Error(i)}}async downloadBinariesAndUploadToTheServer(r,t,e){const i=[];try{const o=await this.downloadAndUntar(r,t,e,"pl",`pl-${v()}`);i.push(o);const n=await this.downloadAndUntar(r,t,e,"supervisord",bt);i.push(n);const c=At(t,e.arch),a=await this.downloadAndUntar(r,t,e,"minio",Ft);return i.push(a),await this.sshClient.chmod(c,488),{history:i,minioRelPath:c,downloadedPl:R(t,e.arch)}}catch(o){const n=`SshPl.downloadBinariesAndUploadToServer: error ${o} occurred, state: ${JSON.stringify(i)}`;throw this.logger.error(n),o}}async downloadAndUntar(r,t,e,i,o){const n={};n.binBasePath=E(t),await this.sshClient.createRemoteDirectory(n.binBasePath),n.binBasePathCreated=!0;let c=null;const a=5;for(let u=1;u<=a;u++)try{c=await at(this.logger,r,i,o,e.arch,e.platform);break}catch(w){if(await d.sleep(300),u==a)throw new Error(`downloadAndUntar: ${a} attempts, last error: ${w}`)}n.downloadResult=d.notEmpty(c),n.localArchivePath=h.resolve(n.downloadResult.archivePath),n.remoteDir=h.join(n.binBasePath,n.downloadResult.baseName),n.remoteArchivePath=n.remoteDir+".tgz",await this.sshClient.createRemoteDirectory(n.remoteDir),await this.sshClient.uploadFile(n.localArchivePath,n.remoteArchivePath);const l=await this.sshClient.exec(`tar xvf ${n.remoteArchivePath} --directory=${n.remoteDir}`);if(l.stderr)throw new Error(`downloadAndUntar: untar: stderr occurred: ${l.stderr}, stdout: ${l.stdout}`);return n.plUntarDone=!0,n}async needDownload(r,t){const e=W(r,t.arch),i=z(r,t.arch),o=R(r,t.arch);return!await this.sshClient.checkFileExists(o)||!await this.sshClient.checkFileExists(i)||!await this.sshClient.checkFileExists(e)}async checkIsAliveWithInterval(r=1e3,t=15,e=!0){const i=t*r;let o=0,n=await this.isAlive();for(;e?!n:n;){if(await d.sleep(r),o+=r,o>i)throw new Error(`isAliveWithInterval: The process did not ${e?"started":"stopped"} after ${i} ms.`);n=await this.isAlive()}}async getUserCredentials(r){const t=await this.sshClient.readFile(N(r));return JSON.parse(t)}async fetchPorts(r,t){return{grpc:{local:await m.getFreePort(),remote:await this.getFreePortForPlatformaOnServer(r,t)},monitoring:{local:await m.getFreePort(),remote:await this.getFreePortForPlatformaOnServer(r,t)},debug:{local:await m.getFreePort(),remote:await this.getFreePortForPlatformaOnServer(r,t)},minioPort:{local:await m.getFreePort(),remote:await this.getFreePortForPlatformaOnServer(r,t)},minioConsolePort:{local:await m.getFreePort(),remote:await this.getFreePortForPlatformaOnServer(r,t)}}}async getLocalFreePort(){return new Promise(r=>{const t=T.createServer();t.listen(0,()=>{const e=t.address().port;t.close(i=>r(e))})})}async getFreePortForPlatformaOnServer(r,t){const e=xt(r,t.arch),{stdout:i,stderr:o}=await this.sshClient.exec(`${e}`);if(o)throw new Error(`getFreePortForPlatformaOnServer: stderr is not empty: ${o}, stdout: ${i}`);return+i}async getArch(){const{stdout:r,stderr:t}=await this.sshClient.exec("uname -s && uname -m");if(t)throw new Error(`getArch: stderr is not empty: ${t}, stdout: ${r}`);const e=r.split(`
39
+ `);return{platform:e[0],arch:e[1]}}async getUserHomeDirectory(){const{stdout:r,stderr:t}=await this.sshClient.exec("echo $HOME");if(t){const e=`/home/${this.username}`;return console.warn(`getUserHomeDirectory: stderr is not empty: ${t}, stdout: ${r}, will get a default home: ${e}`),e}return r.trim()}}exports.LocalConfigYaml=M;exports.LocalPl=J;exports.SshClient=S;exports.SshPl=x;exports.getDefaultPlVersion=v;exports.localPlatformaInit=Pt;
40
40
  //# sourceMappingURL=index.js.map