@milaboratories/pl-deployments 2.4.4 → 2.4.6

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/README.md CHANGED
@@ -15,4 +15,27 @@ require("fs").writeFileSync('test-assets/private-key.pem', keys.private);
15
15
  ```
16
16
 
17
17
  ### Clean docker containers
18
- If something went wrong with testcontainers, use `pnpm run cleanup-docker` from pl-deployments root.
18
+ If something went wrong with testcontainers, use `pnpm run cleanup-docker` from pl-deployments root.
19
+
20
+ ### Dev container
21
+ The command starts a docker container for dev:
22
+ ```sh
23
+ pnpm run dev-docker
24
+ # in another terminal you can start bash
25
+ pnpm run exec-dev-docker
26
+ ```
27
+ Credentials:
28
+ 127.0.0.1:4343
29
+ pl-doctor
30
+ password
31
+
32
+ ### supervisor commands
33
+ Go to SSH server, then to `~/.platforma_ssh` and check the status of binary:
34
+ ```sh
35
+ ./binaries/supervisord-0.7.3-amd64/supervisord_0.7.3_Linux_64-bit/supervisord -c supervisor.conf ctl status
36
+ ```
37
+
38
+ To shutdown platforma:
39
+ ```sh
40
+ ./binaries/supervisord-0.7.3-amd64/supervisord_0.7.3_Linux_64-bit/supervisord -c supervisor.conf ctl shutdown
41
+ ```
package/dist/index.js CHANGED
@@ -1,11 +1,11 @@
1
- "use strict";var at=Object.defineProperty;var ct=(n,t,e)=>t in n?at(n,t,{enumerable:!0,configurable:!0,writable:!0,value:e}):n[t]=e;var w=(n,t,e)=>ct(n,typeof t!="symbol"?t+"":t,e);Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const lt=require("node:child_process"),p=require("@milaboratories/ts-helpers"),x=require("node:fs"),y=require("node:fs/promises"),u=require("upath"),dt=require("undici"),U=require("node:stream"),ut=require("node:stream/consumers"),ht=require("tar"),pt=require("decompress"),P=require("node:os"),C=require("ssh2"),H=require("node:net"),wt=require("node:dns"),b=require("node:crypto"),g=require("@milaboratories/pl-config"),f=require("zod");function q(n){const t=Object.create(null,{[Symbol.toStringTag]:{value:"Module"}});if(n){for(const e in n)if(e!=="default"){const r=Object.getOwnPropertyDescriptor(n,e);Object.defineProperty(t,e,r.get?r:{enumerable:!0,get:()=>n[e]})}}return t.default=n,Object.freeze(t)}const ft=q(ht),mt=q(P);function yt(n,t){return n.info(`Running:
1
+ "use strict";var at=Object.defineProperty;var ct=(n,t,e)=>t in n?at(n,t,{enumerable:!0,configurable:!0,writable:!0,value:e}):n[t]=e;var f=(n,t,e)=>ct(n,typeof t!="symbol"?t+"":t,e);Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const lt=require("node:child_process"),p=require("@milaboratories/ts-helpers"),D=require("node:fs"),y=require("node:fs/promises"),u=require("upath"),dt=require("undici"),I=require("node:stream"),ut=require("node:stream/consumers"),ht=require("tar"),pt=require("decompress"),P=require("node:os"),C=require("ssh2"),H=require("node:net"),ft=require("node:dns"),b=require("node:crypto"),v=require("@milaboratories/pl-config"),w=require("zod");function q(n){const t=Object.create(null,{[Symbol.toStringTag]:{value:"Module"}});if(n){for(const e in n)if(e!=="default"){const r=Object.getOwnPropertyDescriptor(n,e);Object.defineProperty(t,e,r.get?r:{enumerable:!0,get:()=>n[e]})}}return t.default=n,Object.freeze(t)}const wt=q(ht),mt=q(P);function yt(n,t){return n.info(`Running:
2
2
  cmd: ${JSON.stringify([t.cmd,...t.args])}
3
- wd: ${t.opts.cwd}`),n.info(" spawning child process"),lt.spawn(t.cmd,t.args,t.opts)}async function k(n){try{return process.kill(n,0),!0}catch{return!1}}function G(n){return process.kill(n,"SIGINT")}async function z(n,t){let r=0;for(;await k(n);)if(await p.sleep(100),r+=100,r>t)throw new Error(`The process did not stopped after ${t} ms.`)}const gt=["linux","macos","windows"];function R(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(gt))}}const vt=["amd64","arm64"];function S(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(vt))}}const $t="https://cdn.platforma.bio/software",St="https://cdn-ga.pl-open.science/software";async function Ct(n,t,e,r,i,o){const s=J(e,r,t,S(i),R(o)),{archiveUrl:a,alternativeArchiveGAUrl:c,archivePath:l}=s;try{await F(n,a,l),s.wasDownloadedFrom=a}catch{await F(n,c,l),s.wasDownloadedFrom=c}return s}async function Et(n,t,e,r,i,o){const s=J(e,r,t,S(i),R(o)),{archiveUrl:a,alternativeArchiveGAUrl:c,archivePath:l,archiveType:d,targetFolder:h}=s;try{await F(n,a,l),s.wasDownloadedFrom=a}catch{await F(n,c,l),s.wasDownloadedFrom=c}return await bt(n,l,d,h),s}function J(n,t,e,r,i){const o=`${t}-${r}`,s=Ft[i],a=`${o}.${s}`,c=`${$t}/${n}/${i}/${a}`,l=`${St}/${n}/${i}/${a}`,d=u.join(e,a),h=u.join(e,o);return{archiveUrl:c,alternativeArchiveGAUrl:l,archivePath:d,archiveType:s,targetFolder:h,baseName:o}}async function F(n,t,e){const r={};r.dstArchive=e;try{if(r.fileExisted=await p.fileExists(e),r.fileExisted)return n.info(`Platforma Backend archive download skipped: '${e}' already exists`),r;await y.mkdir(u.dirname(e),{recursive:!0}),r.dirnameCreated=!0,n.info(`Downloading archive:
3
+ wd: ${t.opts.cwd}`),n.info(" spawning child process"),lt.spawn(t.cmd,t.args,t.opts)}async function k(n){try{return process.kill(n,0),!0}catch{return!1}}function G(n){return process.kill(n,"SIGINT")}async function z(n,t){let r=0;for(;await k(n);)if(await p.sleep(100),r+=100,r>t)throw new Error(`The process did not stopped after ${t} ms.`)}const gt=["linux","macos","windows"];function _(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(gt))}}const vt=["amd64","arm64"];function S(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(vt))}}const $t="https://cdn.platforma.bio/software",St="https://cdn-ga.pl-open.science/software";async function Ct(n,t,e,r,i,o){const s=L(e,r,t,S(i),_(o)),{archiveUrl:a,alternativeArchiveGAUrl:c,archivePath:l}=s;try{await F(n,a,l),s.wasDownloadedFrom=a}catch{await F(n,c,l),s.wasDownloadedFrom=c}return s}async function Et(n,t,e,r,i,o){const s=L(e,r,t,S(i),_(o)),{archiveUrl:a,alternativeArchiveGAUrl:c,archivePath:l,archiveType:d,targetFolder:h}=s;try{await F(n,a,l),s.wasDownloadedFrom=a}catch{await F(n,c,l),s.wasDownloadedFrom=c}return await bt(n,l,d,h),s}function L(n,t,e,r,i){const o=`${t}-${r}`,s=Ft[i],a=`${o}.${s}`,c=`${$t}/${n}/${i}/${a}`,l=`${St}/${n}/${i}/${a}`,d=u.join(e,a),h=u.join(e,o);return{archiveUrl:c,alternativeArchiveGAUrl:l,archivePath:d,archiveType:s,targetFolder:h,baseName:o}}async function F(n,t,e){const r={};r.dstArchive=e;try{if(r.fileExisted=await p.fileExists(e),r.fileExisted)return n.info(`Platforma Backend archive download skipped: '${e}' already exists`),r;await y.mkdir(u.dirname(e),{recursive:!0}),r.dirnameCreated=!0,n.info(`Downloading archive:
4
4
  URL: ${t}
5
- Save to: ${e}`);const{body:i,statusCode:o}=await dt.request(t);if(r.statusCode=o,o!=200){const s=await ut.text(i);throw r.errorMsg=`failed to download archive: ${o}, response: ${s.slice(0,1e3)}`,n.error(r.errorMsg),new Error(r.errorMsg)}return r.tmpPath=e+".tmp",await U.Readable.toWeb(i).pipeTo(U.Writable.toWeb(x.createWriteStream(r.tmpPath))),r.wroteTmp=!0,r.tmpExisted=await p.fileExists(r.tmpPath),await y.rename(r.tmpPath,e),r.renamed=!0,r.newExisted=await p.fileExists(e),r}catch(i){const o=`downloadArchive: ${JSON.stringify(i)}, state: ${JSON.stringify(r)}`;throw n.error(o),new Error(o)}}const Pt=".ok";async function bt(n,t,e,r){if(n.info("extracting archive..."),n.info(` archive path: '${t}'`),n.info(` target dir: '${r}'`),!await p.fileExists(t)){const o=`Platforma Backend binary archive not found at '${t}'`;throw n.error(o),new Error(o)}const i=u.join(r,Pt);if(await p.fileExists(i)){n.info(`Platforma Backend binaries unpack skipped: '${r}' exists`);return}switch(await p.fileExists(r)&&(n.info(`Removing previous incompletely unpacked folder: '${r}'`),await y.rm(r,{recursive:!0})),n.info(` creating target dir '${r}'`),await y.mkdir(r,{recursive:!0}),n.info(`Unpacking Platforma Backend archive:
5
+ Save to: ${e}`);const{body:i,statusCode:o}=await dt.request(t);if(r.statusCode=o,o!=200){const s=await ut.text(i);throw r.errorMsg=`failed to download archive: ${o}, response: ${s.slice(0,1e3)}`,n.error(r.errorMsg),new Error(r.errorMsg)}return r.tmpPath=e+".tmp",await I.Readable.toWeb(i).pipeTo(I.Writable.toWeb(D.createWriteStream(r.tmpPath))),r.wroteTmp=!0,r.tmpExisted=await p.fileExists(r.tmpPath),await y.rename(r.tmpPath,e),r.renamed=!0,r.newExisted=await p.fileExists(e),r}catch(i){const o=`downloadArchive: ${JSON.stringify(i)}, state: ${JSON.stringify(r)}`;throw n.error(o),new Error(o)}}const Pt=".ok";async function bt(n,t,e,r){if(n.info("extracting archive..."),n.info(` archive path: '${t}'`),n.info(` target dir: '${r}'`),!await p.fileExists(t)){const o=`Platforma Backend binary archive not found at '${t}'`;throw n.error(o),new Error(o)}const i=u.join(r,Pt);if(await p.fileExists(i)){n.info(`Platforma Backend binaries unpack skipped: '${r}' exists`);return}switch(await p.fileExists(r)&&(n.info(`Removing previous incompletely unpacked folder: '${r}'`),await y.rm(r,{recursive:!0})),n.info(` creating target dir '${r}'`),await y.mkdir(r,{recursive:!0}),n.info(`Unpacking Platforma Backend archive:
6
6
  Archive: ${t}
7
- Target dir: ${r}`),e){case"tgz":await ft.x({file:t,cwd:r,gzip:!0});break;case"zip":await pt(t,r);break;default:p.assertNever(e)}await y.writeFile(i,"ok"),n.info(" ... unpack done.")}const Ft={linux:"tgz",macos:"tgz",windows:"zip"};function A(){return"1.35.2"}function At(){return{type:"Download",version:A()}}async function Dt(n,t,e){switch(e.type){case"Download":const r=await Et(n,t,"pl",`pl-${e.version}`,P.arch(),P.platform());return u.join(r.baseName,"binaries",Ot[R(P.platform())]);case"Local":return e.path;default:p.assertNever(e)}}const Ot={linux:"platforma",macos:"platforma",windows:"platforma.exe"};function L(n){return u.join(n,"pl_pid")}async function xt(n){if(!await p.fileExists(n))return;const t=await y.readFile(n);return Number(t.toString())}async function kt(n,t){await y.writeFile(n,JSON.stringify(t))}function Rt(){return{}}function Nt(n,t,e){return n[t]=e,e}async function N(n,t){const e=Rt();try{return await t((i,o)=>Nt(e,i,o),e)}catch(r){throw n.error(`error ${r} while doing traced operation, state: ${JSON.stringify(e)}`),r}}const V="config-local.yaml";class W{constructor(t,e,r,i,o,s,a,c){w(this,"instance");w(this,"pid");w(this,"nRuns",0);w(this,"lastRunHistory",{});w(this,"wasStopped",!1);this.logger=t,this.workingDir=e,this.startOptions=r,this.initialStartHistory=i,this.onClose=o,this.onError=s,this.onCloseAndError=a,this.onCloseAndErrorNoStop=c}async start(){await N(this.logger,async(t,e)=>{this.wasStopped=!1;const r=yt(this.logger,this.startOptions);r.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)}),r.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)}),t("started",!0);const i=t("pidFile",L(this.workingDir));t("pid",p.notEmpty(r.pid)),t("pidWritten",await kt(i,p.notEmpty(r.pid))),this.nRuns++,this.instance=r,this.pid=r.pid,this.lastRunHistory=e})}stop(){this.wasStopped=!0,G(p.notEmpty(this.pid))}async waitStopped(){await z(p.notEmpty(this.pid),15e3)}stopped(){return this.wasStopped}async isAlive(){return await k(p.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 Bt(n,t){const e=Math.max(mt.cpus().length-2,1),r=K(t,e);return await N(n,async(i,o)=>{i("startOptions",{...r,config:"too wordy"});const s=u.resolve(r.workingDir);r.closeOld&&i("closeOld",await It(n,s));const a=u.join(s,V);n.info(`writing configuration '${a}'...`),await y.writeFile(a,r.config);const c=u.join(s,"binaries"),l=await Dt(n,c,r.plBinary),d=i("binaryPath",u.join("binaries",l)),h=Y(d,a,r,s,process.env);i("processOpts",{cmd:h.cmd,args:h.args,cwd:h.opts.cwd});const m=new W(n,r.workingDir,h,o,r.onClose,r.onError,r.onCloseAndError,r.onCloseAndErrorNoStop);return await m.start(),m})}async function It(n,t){return await N(n,async(e,r)=>{const i=e("pidFilePath",L(t)),o=e("pid",await xt(i)),s=e("wasAlive",await k(o));return o!==void 0&&s&&(e("stopped",G(o)),e("waitStopped",await z(o,1e4))),r})}function K(n,t){var i;const e={plBinary:At(),spawnOptions:{env:{GOMAXPROCS:String(t)}},closeOld:!0};if((i=n.spawnOptions)!=null&&i.env&&(e.spawnOptions.env={...e.spawnOptions.env,...n.spawnOptions.env}),n.spawnOptions){const o={...n.spawnOptions};delete o.env,e.spawnOptions={...e.spawnOptions,...o}}const r={...n};return delete r.spawnOptions,{...e,...r}}function Y(n,t,e,r,i){var a;const o={cmd:n,args:["--config",t],opts:{env:{...i},cwd:r,stdio:["pipe","ignore","inherit"],windowsHide:!0}};(a=e.spawnOptions)!=null&&a.env&&(o.opts.env={...o.opts.env,...e.spawnOptions.env});const s={...e.spawnOptions};return delete s.env,o.opts={...o.opts,...s},o}const Ut={keepaliveInterval:6e4,keepaliveCountMax:10};class D{constructor(t,e){w(this,"config");w(this,"homeDir");w(this,"forwardedServers",[]);this.logger=t,this.client=e}static async init(t,e){const r={...Ut,...e},i=new D(t,new C.Client);return await i.connect(r),i}getForwardedServers(){return this.forwardedServers}getFullHostName(){var t,e;return`${(t=this.config)==null?void 0:t.host}:${(e=this.config)==null?void 0:e.port}`}getUserName(){var t;return(t=this.config)==null?void 0:t.username}async connect(t){return this.config=t,await _t(this.client,t)}async exec(t){return new Promise((e,r)=>{this.client.exec(t,(i,o)=>{if(i)return r(new Error(`ssh.exec: ${t}: ${i}`));let s="",a="";o.on("close",c=>{c===0?e({stdout:s,stderr:a}):r(new Error(`Command ${t} exited with code ${c}, stdout: ${s}, stderr: ${a}`))}).on("data",c=>{s+=c.toString()}).stderr.on("data",c=>{a+=c.toString()})})})}static async getAuthTypes(t,e){return new Promise(r=>{let i="";const o=new C.Client;o.on("ready",()=>{o.end();const s=this.extractAuthMethods(i);r(s.length===0?["publickey","password"]:s)}),o.on("error",()=>{o.end(),r(["publickey","password"])}),o.connect({host:t,port:e,username:new Date().getTime().toString(),debug:s=>{i+=`${s}
8
- `}})})}static extractAuthMethods(t){const e=t.match(/Inbound: Received USERAUTH_FAILURE \((.+)\)/);return e&&e[1]?e[1].split(",").map(r=>r.trim()):[]}async forwardPort(t,e){const r=`ssh.forward:${t.localPort}:${t.remotePort}.id_${b.randomBytes(1).toString("hex")}`;e=e??this.config;const i=new p.RetryablePromise(o=>new Promise((s,a)=>{const c=new C.Client;c.on("ready",()=>{this.logger.info(`${r}.client.ready`),s(c)}),c.on("error",l=>{this.logger.info(`${r}.client.error: ${l}`),o.reset(),a(l)}),c.on("close",()=>{this.logger.info(`${r}.client.closed`),o.reset()}),c.connect(e)}));return await i.ensure(),new Promise((o,s)=>{const a=H.createServer({pauseOnConnect:!0},async c=>{const l=`${r}.sock_${b.randomBytes(1).toString("hex")}`;let d;try{d=await i.ensure()}catch(m){this.logger.info(`${l}.persistentClient.catch: ${m}`),c.end();return}d.setNoDelay(!0),c.setNoDelay(!0);let h;try{h=await Tt(this.logger,d,"127.0.0.1",0,"127.0.0.1",t.remotePort)}catch(m){this.logger.error(`${l}.forwardOut.err: ${m}`),c.end();return}c.pipe(h),h.pipe(c),c.resume(),h.on("error",m=>{this.logger.error(`${l}.stream.error: ${m}`),c.end(),h.end()}),h.on("close",()=>{c.end(),h.end()}),c.on("close",()=>{this.logger.info(`${l}.localSocket: closed`),c.end(),h.end()})});a.listen(t.localPort,"127.0.0.1",()=>{this.logger.info(`${r}.server: started listening`),this.forwardedServers.push(a),o({server:a})}),a.on("error",c=>{a.close(),s(new Error(`${r}.server: error: ${JSON.stringify(c)}`))}),a.on("close",()=>{this.logger.info(`${r}.server: closed ${JSON.stringify(t)}`),this.forwardedServers=this.forwardedServers.filter(c=>c!==a)})})}closeForwardedPorts(){this.logger.info("[SSH] Closing all forwarded ports..."),this.forwardedServers.forEach(t=>{const e=t.address();if(e&&typeof e!="string"){const r=e;this.logger.info(`[SSH] Closing port forward for server ${r.address}:${r.port}`)}t.close()}),this.forwardedServers=[]}static async checkHostAvailability(t){return new Promise(e=>{wt.lookup(t,r=>{e(!r)})})}static async isPassphraseRequiredForKey(t){return new Promise((e,r)=>{try{return C.utils.parseKey(t)instanceof Error&&e(!0),e(!1)}catch(i){console.log("Error parsing privateKey"),r(new Error(`ssh.isPassphraseRequiredForKey: err ${i}`))}})}async uploadFile(t,e){return await this.withSftp(async r=>new Promise((i,o)=>{r.fastPut(t,e,s=>{if(s){const a=new Error(`ssh.uploadFile: err: ${s}, localPath: ${t}, remotePath: ${e}`);return o(a)}i(!0)})}))}async withSftp(t){return new Promise((e,r)=>{this.client.sftp((i,o)=>{if(i)return r(new Error(`ssh.withSftp: sftp err: ${i}`));t(o).then(e).catch(s=>{r(new Error(`ssh.withSftp.callback: err ${s}`))}).finally(()=>{o==null||o.end()})})})}async writeFileOnTheServer(t,e,r=432){return this.withSftp(async i=>this.writeFile(i,t,e,r))}async getForderStructure(t,e,r={files:[],directories:[]}){return new Promise((i,o)=>{t.readdir(e,async(s,a)=>{if(s)return o(s);for(const c of a){const l=`${e}/${c.filename}`;if(c.attrs.isDirectory()){r.directories.push(l);try{await this.getForderStructure(t,l,r)}catch(d){return o(d instanceof Error?d:new Error(String(d)))}}else r.files.push(l)}i(r)})})}rmdir(t,e){return new Promise((r,i)=>{t.rmdir(e,o=>o?i(o):r(!0))})}unlink(t,e){return new Promise((r,i)=>{t.unlink(e,o=>o?i(o):r(!0))})}async deleteFolder(t){return this.withSftp(async e=>{try{const r=await this.getForderStructure(e,t);this.logger.info("ssh.deleteFolder list of files and directories"),this.logger.info(`ssh.deleteFolder list of files: ${r.files}`),this.logger.info(`ssh.deleteFolder list of directories: ${r.directories}`);for(const i of r.files)this.logger.info(`ssh.deleteFolder unlink file ${i}`),await this.unlink(e,i);r.directories.sort((i,o)=>o.length-i.length);for(const i of r.directories)this.logger.info(`ssh.deleteFolder rmdir ${i}`),await this.rmdir(e,i);return await this.rmdir(e,t),!0}catch(r){this.logger.error(r);const i=r instanceof Error?r.message:"";throw new Error(`ssh.deleteFolder: path: ${t}, message: ${i}`)}})}async readFile(t){return this.withSftp(async e=>new Promise((r,i)=>{e.readFile(t,(o,s)=>{if(o)return i(new Error(`ssh.readFile: ${o}`));r(s.toString())})}))}async chmod(t,e){return this.withSftp(async r=>new Promise((i,o)=>{r.chmod(t,e,s=>s?o(new Error(`ssh.chmod: ${s}, path: ${t}, mode: ${e}`)):i(void 0))}))}async checkFileExists(t){return this.withSftp(async e=>new Promise((r,i)=>{e.stat(t,(o,s)=>{if(o)return(o==null?void 0:o.code)===2?r(!1):i(new Error(`ssh.checkFileExists: err ${o}`));r(s.isFile())})}))}async checkPathExists(t){return this.withSftp(async e=>new Promise((r,i)=>{e.stat(t,(o,s)=>{if(o)return o.code===2?r({exists:!1,isFile:!1,isDirectory:!1}):i(new Error(`ssh.checkPathExists: ${o}`));r({exists:!0,isFile:s.isFile(),isDirectory:s.isDirectory()})})}))}async writeFile(t,e,r,i=432){return new Promise((o,s)=>{t.writeFile(e,r,{mode:i},a=>{if(a)return s(new Error(`ssh.writeFile: err ${a}, remotePath: ${e}`));o(!0)})})}uploadFileUsingExistingSftp(t,e,r,i=432){return new Promise((o,s)=>{y.readFile(e).then(async a=>this.writeFile(t,r,a,i).then(()=>{o(void 0)}).catch(c=>{const l=`uploadFileUsingExistingSftp: ${c}`;this.logger.error(l),s(new Error(l))}))})}async __uploadDirectory(t,e,r,i=432){return new Promise((o,s)=>{x.readdir(e,async(a,c)=>{if(a)return s(new Error(`ssh.__uploadDir: err ${a}, localDir: ${e}, remoteDir: ${r}`));try{await this.__createRemoteDirectory(t,r);for(const l of c){const d=u.join(e,l),h=`${r}/${l}`;x.lstatSync(d).isDirectory()?await this.__uploadDirectory(t,d,h,i):await this.uploadFileUsingExistingSftp(t,d,h,i)}o()}catch(l){const d=`ssh.__uploadDir: catched err ${l}`;this.logger.error(d),s(new Error(d))}})})}async uploadDirectory(t,e,r=432){return new Promise((i,o)=>{this.withSftp(async s=>{try{await this.__uploadDirectory(s,t,e,r),i()}catch(a){o(new Error(`ssh.uploadDirectory: ${a}`))}})})}__createRemoteDirectory(t,e){return new Promise((r,i)=>{const o=e.split("/");let s="";const a=c=>{if(c>=o.length)return r();s+=`${o[c]}/`,t.stat(s,l=>{l?t.mkdir(s,d=>{if(d)return i(new Error(`ssh.__createRemDir: err ${d}, remotePath: ${e}`));a(c+1)}):a(c+1)})};a(0)})}ensureRemoteDirCreated(t,e=493){return this.withSftp(async r=>{const i=t.split("/");let o="";for(const s of i){o+=`${s}/`;try{await new Promise((a,c)=>{r.stat(o,l=>{if(!l)return a();r.mkdir(o,{mode:e},d=>{if(d)return c(new Error(`ssh.createRemoteDir: err ${d}, remotePath: ${t}`));a()})})})}catch(a){throw console.error(`Failed to create directory: ${o}`,a),a}}})}async downloadFile(t,e){return this.withSftp(async r=>new Promise((i,o)=>{r.fastGet(t,e,s=>{if(s)return o(new Error(`ssh.downloadFile: err ${s}, remotePath: ${t}, localPath: ${e}`));i(!0)})}))}close(){this.closeForwardedPorts(),this.client.end()}}async function _t(n,t,e,r){return new Promise((i,o)=>{n.on("ready",()=>{i(n)}),n.on("error",s=>{o(new Error(`ssh.connect: ${s}`))}),n.on("close",()=>{}),n.connect(t),n.setNoDelay(!0)})}async function Tt(n,t,e,r,i,o){return new Promise((s,a)=>{t.forwardOut(e,r,i,o,(c,l)=>c?(n.error(`forwardOut.error: ${c}`),a(c)):s(l))})}const jt="minio-2024-12-18T13-15-44Z",Mt="supervisord-0.7.3",Ht="supervisord_0.7.3_Linux_64-bit";function $(n){return u.join(n,".platforma_ssh")}function O(n){return u.join($(n),"binaries")}function qt(n,t){return u.join(O(n),`pl-${A()}-${S(t)}`)}function Z(n,t){return u.join(qt(n,t),"binaries")}function _(n,t){return u.join(Z(n,t),"platforma")}function Gt(n,t){return u.join(Z(n,t),"free-port")}function X(n,t){return u.join(O(n),`minio-2024-12-18T13-15-44Z-${S(t)}`)}function zt(n,t){return u.join(X(n,t),"minio")}function Jt(n,t){return u.join(O(n),`supervisord-0.7.3-${S(t)}`,Ht)}function Q(n,t){return u.join(Jt(n,t),"supervisord")}function tt(n){return u.join($(n),"supervisor.conf")}function T(n){return u.join($(n),"connection.txt")}async function Lt(n,t,e){const r=await B(n,t,e,"--daemon");if(r.stderr)throw new Error(`Can not run ssh Platforma ${r.stderr}`)}async function Vt(n,t,e){const r=await B(n,t,e,"ctl shutdown");if(r.stderr)throw new Error(`Can not stop ssh Platforma ${r.stderr}`)}function E(n,t){return t?n.platforma&&n.minio:n.platforma}function Wt(n){return n.execError===void 0}async function Kt(n,t,e,r){let i;try{i=await B(t,e,r,"ctl status")}catch(c){return{execError:String(c)}}if(i.stderr)return n.info(`supervisord ctl status: stderr occurred: ${i.stderr}, stdout: ${i.stdout}`),{rawResult:i};const o=j(i.stdout,"platforma"),s=j(i.stdout,"minio"),a={rawResult:i,platforma:o,minio:s};return a.minio||n.warn("Minio is not running on the server"),a.platforma||n.warn("Platforma is not running on the server"),a}function Yt(n,t,e,r){const i=b.randomBytes(16).toString("hex"),o=n;return`
7
+ Target dir: ${r}`),e){case"tgz":await wt.x({file:t,cwd:r,gzip:!0});break;case"zip":await pt(t,r);break;default:p.assertNever(e)}await y.writeFile(i,"ok"),n.info(" ... unpack done.")}const Ft={linux:"tgz",macos:"tgz",windows:"zip"};function A(){return"1.35.2"}function At(){return{type:"Download",version:A()}}async function Ot(n,t,e){switch(e.type){case"Download":const r=await Et(n,t,"pl",`pl-${e.version}`,P.arch(),P.platform());return u.join(r.baseName,"binaries",xt[_(P.platform())]);case"Local":return e.path;default:p.assertNever(e)}}const xt={linux:"platforma",macos:"platforma",windows:"platforma.exe"};function J(n){return u.join(n,"pl_pid")}async function Dt(n){if(!await p.fileExists(n))return;const t=await y.readFile(n);return Number(t.toString())}async function kt(n,t){await y.writeFile(n,JSON.stringify(t))}function _t(){return{}}function Rt(n,t,e){return n[t]=e,e}async function R(n,t){const e=_t();try{return await t((i,o)=>Rt(e,i,o),e)}catch(r){throw n.error(`error ${r} while doing traced operation, state: ${JSON.stringify(e)}`),r}}const V="config-local.yaml";class W{constructor(t,e,r,i,o,s,a,c){f(this,"instance");f(this,"pid");f(this,"nRuns",0);f(this,"lastRunHistory",{});f(this,"wasStopped",!1);this.logger=t,this.workingDir=e,this.startOptions=r,this.initialStartHistory=i,this.onClose=o,this.onError=s,this.onCloseAndError=a,this.onCloseAndErrorNoStop=c}async start(){await R(this.logger,async(t,e)=>{this.wasStopped=!1;const r=yt(this.logger,this.startOptions);r.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)}),r.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)}),t("started",!0);const i=t("pidFile",J(this.workingDir));t("pid",p.notEmpty(r.pid)),t("pidWritten",await kt(i,p.notEmpty(r.pid))),this.nRuns++,this.instance=r,this.pid=r.pid,this.lastRunHistory=e})}stop(){this.wasStopped=!0,G(p.notEmpty(this.pid))}async waitStopped(){await z(p.notEmpty(this.pid),15e3)}stopped(){return this.wasStopped}async isAlive(){return await k(p.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 Nt(n,t){const e=Math.max(mt.cpus().length-2,1),r=K(t,e);return await R(n,async(i,o)=>{i("startOptions",{...r,config:"too wordy"});const s=u.resolve(r.workingDir);r.closeOld&&i("closeOld",await Bt(n,s));const a=u.join(s,V);n.info(`writing configuration '${a}'...`),await y.writeFile(a,r.config);const c=u.join(s,"binaries"),l=await Ot(n,c,r.plBinary),d=i("binaryPath",u.join("binaries",l)),h=Y(d,a,r,s,process.env);i("processOpts",{cmd:h.cmd,args:h.args,cwd:h.opts.cwd});const m=new W(n,r.workingDir,h,o,r.onClose,r.onError,r.onCloseAndError,r.onCloseAndErrorNoStop);return await m.start(),m})}async function Bt(n,t){return await R(n,async(e,r)=>{const i=e("pidFilePath",J(t)),o=e("pid",await Dt(i)),s=e("wasAlive",await k(o));return o!==void 0&&s&&(e("stopped",G(o)),e("waitStopped",await z(o,1e4))),r})}function K(n,t){var i;const e={plBinary:At(),spawnOptions:{env:{GOMAXPROCS:String(t)}},closeOld:!0};if((i=n.spawnOptions)!=null&&i.env&&(e.spawnOptions.env={...e.spawnOptions.env,...n.spawnOptions.env}),n.spawnOptions){const o={...n.spawnOptions};delete o.env,e.spawnOptions={...e.spawnOptions,...o}}const r={...n};return delete r.spawnOptions,{...e,...r}}function Y(n,t,e,r,i){var a;const o={cmd:n,args:["--config",t],opts:{env:{...i},cwd:r,stdio:["pipe","ignore","inherit"],windowsHide:!0}};(a=e.spawnOptions)!=null&&a.env&&(o.opts.env={...o.opts.env,...e.spawnOptions.env});const s={...e.spawnOptions};return delete s.env,o.opts={...o.opts,...s},o}const It={keepaliveInterval:6e4,keepaliveCountMax:10};class O{constructor(t,e){f(this,"config");f(this,"homeDir");f(this,"forwardedServers",[]);this.logger=t,this.client=e}static async init(t,e){const r={...It,...e},i=new O(t,new C.Client);return await i.connect(r),i}getForwardedServers(){return this.forwardedServers}getFullHostName(){var t,e;return`${(t=this.config)==null?void 0:t.host}:${(e=this.config)==null?void 0:e.port}`}getUserName(){var t;return(t=this.config)==null?void 0:t.username}async connect(t){return this.config=t,await Ut(this.client,t)}async exec(t){return new Promise((e,r)=>{this.client.exec(t,(i,o)=>{if(i)return r(new Error(`ssh.exec: ${t}: ${i}`));let s="",a="";o.on("close",c=>{c===0?e({stdout:s,stderr:a}):r(new Error(`Command ${t} exited with code ${c}, stdout: ${s}, stderr: ${a}`))}).on("data",c=>{s+=c.toString()}).stderr.on("data",c=>{a+=c.toString()})})})}static async getAuthTypes(t,e){return new Promise(r=>{let i="";const o=new C.Client;o.on("ready",()=>{o.end();const s=this.extractAuthMethods(i);r(s.length===0?["publickey","password"]:s)}),o.on("error",()=>{o.end(),r(["publickey","password"])}),o.connect({host:t,port:e,username:new Date().getTime().toString(),debug:s=>{i+=`${s}
8
+ `}})})}static extractAuthMethods(t){const e=t.match(/Inbound: Received USERAUTH_FAILURE \((.+)\)/);return e&&e[1]?e[1].split(",").map(r=>r.trim()):[]}async forwardPort(t,e){const r=`ssh.forward:${t.localPort}:${t.remotePort}.id_${b.randomBytes(1).toString("hex")}`;e=e??this.config;const i=new p.RetryablePromise(o=>new Promise((s,a)=>{const c=new C.Client;c.on("ready",()=>{this.logger.info(`${r}.client.ready`),s(c)}),c.on("error",l=>{this.logger.info(`${r}.client.error: ${l}`),o.reset(),a(l)}),c.on("close",()=>{this.logger.info(`${r}.client.closed`),o.reset()}),c.connect(e)}));return await i.ensure(),new Promise((o,s)=>{const a=H.createServer({pauseOnConnect:!0},async c=>{const l=`${r}.sock_${b.randomBytes(1).toString("hex")}`;let d;try{d=await i.ensure()}catch(m){this.logger.info(`${l}.persistentClient.catch: ${m}`),c.end();return}d.setNoDelay(!0),c.setNoDelay(!0);let h;try{h=await Tt(this.logger,d,"127.0.0.1",0,"127.0.0.1",t.remotePort)}catch(m){this.logger.error(`${l}.forwardOut.err: ${m}`),c.end();return}c.pipe(h),h.pipe(c),c.resume(),h.on("error",m=>{this.logger.error(`${l}.stream.error: ${m}`),c.end(),h.end()}),h.on("close",()=>{c.end(),h.end()}),c.on("close",()=>{this.logger.info(`${l}.localSocket: closed`),c.end(),h.end()})});a.listen(t.localPort,"127.0.0.1",()=>{this.logger.info(`${r}.server: started listening`),this.forwardedServers.push(a),o({server:a})}),a.on("error",c=>{a.close(),s(new Error(`${r}.server: error: ${JSON.stringify(c)}`))}),a.on("close",()=>{this.logger.info(`${r}.server: closed ${JSON.stringify(t)}`),this.forwardedServers=this.forwardedServers.filter(c=>c!==a)})})}closeForwardedPorts(){this.logger.info("[SSH] Closing all forwarded ports..."),this.forwardedServers.forEach(t=>{const e=t.address();if(e&&typeof e!="string"){const r=e;this.logger.info(`[SSH] Closing port forward for server ${r.address}:${r.port}`)}t.close()}),this.forwardedServers=[]}static async checkHostAvailability(t){return new Promise(e=>{ft.lookup(t,r=>{e(!r)})})}static async isPassphraseRequiredForKey(t){return new Promise((e,r)=>{try{return C.utils.parseKey(t)instanceof Error&&e(!0),e(!1)}catch(i){console.log("Error parsing privateKey"),r(new Error(`ssh.isPassphraseRequiredForKey: err ${i}`))}})}async uploadFile(t,e){return await this.withSftp(async r=>new Promise((i,o)=>{r.fastPut(t,e,s=>{if(s){const a=new Error(`ssh.uploadFile: err: ${s}, localPath: ${t}, remotePath: ${e}`);return o(a)}i(!0)})}))}async withSftp(t){return new Promise((e,r)=>{this.client.sftp((i,o)=>{if(i)return r(new Error(`ssh.withSftp: sftp err: ${i}`));t(o).then(e).catch(s=>{r(new Error(`ssh.withSftp.callback: err ${s}`))}).finally(()=>{o==null||o.end()})})})}async writeFileOnTheServer(t,e,r=432){return this.withSftp(async i=>this.writeFile(i,t,e,r))}async getForderStructure(t,e,r={files:[],directories:[]}){return new Promise((i,o)=>{t.readdir(e,async(s,a)=>{if(s)return o(s);for(const c of a){const l=`${e}/${c.filename}`;if(c.attrs.isDirectory()){r.directories.push(l);try{await this.getForderStructure(t,l,r)}catch(d){return o(d instanceof Error?d:new Error(String(d)))}}else r.files.push(l)}i(r)})})}rmdir(t,e){return new Promise((r,i)=>{t.rmdir(e,o=>o?i(o):r(!0))})}unlink(t,e){return new Promise((r,i)=>{t.unlink(e,o=>o?i(o):r(!0))})}async deleteFolder(t){return this.withSftp(async e=>{try{const r=await this.getForderStructure(e,t);this.logger.info("ssh.deleteFolder list of files and directories"),this.logger.info(`ssh.deleteFolder list of files: ${r.files}`),this.logger.info(`ssh.deleteFolder list of directories: ${r.directories}`);for(const i of r.files)this.logger.info(`ssh.deleteFolder unlink file ${i}`),await this.unlink(e,i);r.directories.sort((i,o)=>o.length-i.length);for(const i of r.directories)this.logger.info(`ssh.deleteFolder rmdir ${i}`),await this.rmdir(e,i);return await this.rmdir(e,t),!0}catch(r){this.logger.error(r);const i=r instanceof Error?r.message:"";throw new Error(`ssh.deleteFolder: path: ${t}, message: ${i}`)}})}async readFile(t){return this.withSftp(async e=>new Promise((r,i)=>{e.readFile(t,(o,s)=>{if(o)return i(new Error(`ssh.readFile: ${o}`));r(s.toString())})}))}async chmod(t,e){return this.withSftp(async r=>new Promise((i,o)=>{r.chmod(t,e,s=>s?o(new Error(`ssh.chmod: ${s}, path: ${t}, mode: ${e}`)):i(void 0))}))}async checkFileExists(t){return this.withSftp(async e=>new Promise((r,i)=>{e.stat(t,(o,s)=>{if(o)return(o==null?void 0:o.code)===2?r(!1):i(new Error(`ssh.checkFileExists: err ${o}`));r(s.isFile())})}))}async checkPathExists(t){return this.withSftp(async e=>new Promise((r,i)=>{e.stat(t,(o,s)=>{if(o)return o.code===2?r({exists:!1,isFile:!1,isDirectory:!1}):i(new Error(`ssh.checkPathExists: ${o}`));r({exists:!0,isFile:s.isFile(),isDirectory:s.isDirectory()})})}))}async writeFile(t,e,r,i=432){return new Promise((o,s)=>{t.writeFile(e,r,{mode:i},a=>{if(a)return s(new Error(`ssh.writeFile: err ${a}, remotePath: ${e}`));o(!0)})})}uploadFileUsingExistingSftp(t,e,r,i=432){return new Promise((o,s)=>{y.readFile(e).then(async a=>this.writeFile(t,r,a,i).then(()=>{o(void 0)}).catch(c=>{const l=`uploadFileUsingExistingSftp: ${c}`;this.logger.error(l),s(new Error(l))}))})}async __uploadDirectory(t,e,r,i=432){return new Promise((o,s)=>{D.readdir(e,async(a,c)=>{if(a)return s(new Error(`ssh.__uploadDir: err ${a}, localDir: ${e}, remoteDir: ${r}`));try{await this.__createRemoteDirectory(t,r);for(const l of c){const d=u.join(e,l),h=`${r}/${l}`;D.lstatSync(d).isDirectory()?await this.__uploadDirectory(t,d,h,i):await this.uploadFileUsingExistingSftp(t,d,h,i)}o()}catch(l){const d=`ssh.__uploadDir: catched err ${l}`;this.logger.error(d),s(new Error(d))}})})}async uploadDirectory(t,e,r=432){return new Promise((i,o)=>{this.withSftp(async s=>{try{await this.__uploadDirectory(s,t,e,r),i()}catch(a){o(new Error(`ssh.uploadDirectory: ${a}`))}})})}__createRemoteDirectory(t,e){return new Promise((r,i)=>{const o=e.split("/");let s="";const a=c=>{if(c>=o.length)return r();s+=`${o[c]}/`,t.stat(s,l=>{l?t.mkdir(s,d=>{if(d)return i(new Error(`ssh.__createRemDir: err ${d}, remotePath: ${e}`));a(c+1)}):a(c+1)})};a(0)})}ensureRemoteDirCreated(t,e=493){return this.withSftp(async r=>{const i=t.split("/");let o="";for(const s of i){o+=`${s}/`;try{await new Promise((a,c)=>{r.stat(o,l=>{if(!l)return a();r.mkdir(o,{mode:e},d=>{if(d)return c(new Error(`ssh.createRemoteDir: err ${d}, remotePath: ${t}`));a()})})})}catch(a){throw console.error(`Failed to create directory: ${o}`,a),a}}})}async downloadFile(t,e){return this.withSftp(async r=>new Promise((i,o)=>{r.fastGet(t,e,s=>{if(s)return o(new Error(`ssh.downloadFile: err ${s}, remotePath: ${t}, localPath: ${e}`));i(!0)})}))}close(){this.closeForwardedPorts(),this.client.end()}}async function Ut(n,t,e,r){return new Promise((i,o)=>{n.on("ready",()=>{i(n)}),n.on("error",s=>{o(new Error(`ssh.connect: ${s}`))}),n.on("close",()=>{}),n.connect(t),n.setNoDelay(!0)})}async function Tt(n,t,e,r,i,o){return new Promise((s,a)=>{t.forwardOut(e,r,i,o,(c,l)=>c?(n.error(`forwardOut.error: ${c}`),a(c)):s(l))})}const jt="minio-2024-12-18T13-15-44Z",Mt="supervisord-0.7.3",Ht="supervisord_0.7.3_Linux_64-bit";function g(n){return u.join(n,".platforma_ssh")}function x(n){return u.join(g(n),"binaries")}function qt(n,t){return u.join(x(n),`pl-${A()}-${S(t)}`)}function Z(n,t){return u.join(qt(n,t),"binaries")}function U(n,t){return u.join(Z(n,t),"platforma")}function Gt(n,t){return u.join(Z(n,t),"free-port")}function X(n,t){return u.join(x(n),`minio-2024-12-18T13-15-44Z-${S(t)}`)}function zt(n,t){return u.join(X(n,t),"minio")}function Lt(n,t){return u.join(x(n),`supervisord-0.7.3-${S(t)}`,Ht)}function Q(n,t){return u.join(Lt(n,t),"supervisord")}function tt(n){return u.join(g(n),"supervisor.conf")}function T(n){return u.join(g(n),"connection.txt")}function Jt(n){return u.join(g(n),"platforma_cli_logs.log")}async function Vt(n,t,e){const r=await N(n,t,e,"--daemon");if(r.stderr)throw new Error(`Can not run ssh Platforma ${r.stderr}`)}async function Wt(n,t,e){const r=await N(n,t,e,"ctl shutdown");if(r.stderr)throw new Error(`Can not stop ssh Platforma ${r.stderr}`)}function E(n,t){return t?n.platforma&&n.minio:n.platforma}function Kt(n){return n.execError===void 0}async function Yt(n,t,e,r){let i;try{i=await N(t,e,r,"ctl status")}catch(c){return{execError:String(c)}}if(i.stderr)return n.info(`supervisord ctl status: stderr occurred: ${i.stderr}, stdout: ${i.stdout}`),{rawResult:i};const o=j(i.stdout,"platforma"),s=j(i.stdout,"minio"),a={rawResult:i,platforma:o,minio:s};return a.minio||n.warn("Minio is not running on the server"),a.platforma||n.warn("Platforma is not running on the server"),a}function Zt(n,t,e,r){const i=b.randomBytes(16).toString("hex"),o=n;return`
9
9
  [supervisord]
10
10
  logfile=${t}/supervisord.log
11
11
  loglevel=info
@@ -26,7 +26,11 @@ autostart=true
26
26
  command=${r} --config ${e}
27
27
  directory=${t}
28
28
  autorestart=true
29
- `}function Zt(n,t,e,r,i,o,s){const a=Object.entries(t).map(([d,h])=>`${d}="${h}"`).join(","),c=b.randomBytes(16).toString("hex"),l=e;return`
29
+ stdout_logfile=${t}/platforma_cli_logs.log
30
+ stdout_logfile_maxbytes=10000
31
+ stdout_logfile_backups=10
32
+ redirect_stderr=true
33
+ `}function Xt(n,t,e,r,i,o,s){const a=Object.entries(t).map(([d,h])=>`${d}="${h}"`).join(","),c=b.randomBytes(16).toString("hex"),l=e;return`
30
34
  [supervisord]
31
35
  logfile=${r}/supervisord.log
32
36
  loglevel=info
@@ -55,7 +59,7 @@ environment=${a}
55
59
  command=${o} server ${n}
56
60
  directory=${r}
57
61
  autorestart=true
58
- `}async function B(n,t,e,r){const i=Q(t,e),o=tt(t),s=`${i} --configuration ${o} ${r}`;return await n.exec(s)}function j(n,t){return(i=>i.replace(/\x1B\[[0-9;]*m/g,""))(n).split(`
59
- `).some(i=>{const[o,s]=i.trim().split(/\s{2,}/);return o===t&&s==="Running"})}const v=f.z.object({local:f.z.number(),remote:f.z.number()}),et=f.z.object({grpc:v,http:v.optional(),monitoring:v,debug:v,minioPort:v,minioConsolePort:v}),rt=f.z.object({plUser:f.z.string(),plPassword:f.z.string(),ports:et,useGlobalAccess:f.z.boolean().default(!1),plVersion:f.z.string().default("1.18.3"),minioIsUsed:f.z.boolean().default(!0)});function it(n,t,e,r,i,o){return{plUser:n,plPassword:t,ports:e,useGlobalAccess:r,plVersion:i,minioIsUsed:o}}function nt(n){return rt.parse(JSON.parse(n))}function ot(n){return JSON.stringify(n,void 0,2)}const M=2.28;class I{constructor(t,e,r){w(this,"initState",{step:"init"});this.logger=t,this.sshClient=e,this.username=r}info(){return{username:this.username,initState:this.initState}}static async init(t,e){try{const r=await D.init(t,e);return new I(t,r,p.notEmpty(e.username))}catch(r){throw t.error(`Connection error in SshClient.init: ${r}`),r}}cleanUp(){this.sshClient.close()}async isAlive(){const t=await this.getArch(),e=await this.getUserHomeDirectory();return await Kt(this.logger,this.sshClient,e,t.arch)}async start(t){const e=await this.getArch(),r=await this.getUserHomeDirectory();try{if(!E(await this.isAlive(),t))return await Lt(this.sshClient,r,e.arch),await this.checkIsAliveWithInterval(t)}catch(i){const o=`SshPl.start: ${i}`;throw this.logger.error(o),new Error(o)}}async stop(){const t=await this.getArch(),e=await this.getUserHomeDirectory();try{const r=await this.isAlive();if(Wt(r)){await Vt(this.sshClient,e,t.arch);const i=r.minio===!0;return await this.checkIsAliveWithInterval(i,1e3,15,!1)}}catch(r){const i=`PlSsh.stop: ${r}`;throw this.logger.error(i),new Error(i)}}async reset(){return await this.stopAndClean(),this.cleanUp(),!0}async stopAndClean(){const t=await this.getUserHomeDirectory();this.logger.info("pl.reset: Stop Platforma on the server"),await this.stop(),this.logger.info(`pl.reset: Deleting Platforma workDir ${$(t)} on the server`),await this.sshClient.deleteFolder($(t))}async platformaInit(t){const e={localWorkdir:t.localWorkdir,step:"init"},{onProgress:r}=t,i={...Xt,...t};e.plBinaryOps=i.plBinary;try{return await this.doStepDetectArch(e,r),await this.doStepDetectHome(e,r),await this.doStepReadExistedConfig(e,i,r)?(await this.doStepStopExistedPlatforma(e,r),await(r==null?void 0:r("Installation platforma...")),await this.doStepDownloadBinaries(e,r,i),await this.doStepFetchPorts(e),await this.doStepGenerateNewConfig(e,r,i),await this.doStepCreateFoldersAndSaveFiles(e,r),await this.doStepConfigureSupervisord(e,r),await this.doStepSaveNewConnectionInfo(e,r,i),await this.doStepStartPlatforma(e,r),e.connectionInfo):(await(r==null?void 0:r("Platforma is already running. Skipping initialization.")),e.existedSettings)}catch(o){const s=`SshPl.platformaInit: ${o}, state: ${JSON.stringify(this.removeSensitiveData(e))}`;throw this.logger.error(s),new Error(s)}}async doStepStopExistedPlatforma(t,e){t.step="stopExistedPlatforma",E(t.alive,t.shouldUseMinio??!1)&&(await(e==null?void 0:e("Stopping services...")),await this.stop())}removeSensitiveData(t){const e={...t};return e.generatedConfig={...e.generatedConfig,filesToCreate:{skipped:"sanitized"}},e}async doStepStartPlatforma(t,e){t.step="startPlatforma",await(e==null?void 0:e("Starting Platforma on the server...")),await this.start(t.shouldUseMinio??!1),t.started=!0,this.initState=t,await(e==null?void 0:e("Platforma has been started successfully."))}async doStepSaveNewConnectionInfo(t,e,r){t.step="saveNewConnectionInfo";const i=t.generatedConfig;await(e==null?void 0:e("Saving connection information...")),t.connectionInfo=it(i.plUser,i.plPassword,t.ports,p.notEmpty(r.useGlobalAccess),r.plBinary.version,t.shouldUseMinio??!1),await this.sshClient.writeFileOnTheServer(T(t.remoteHome),ot(t.connectionInfo)),await(e==null?void 0:e("Connection information saved."))}async doStepConfigureSupervisord(t,e){await(e==null?void 0:e("Writing supervisord configuration...")),t.step="configureSupervisord";const r=t.generatedConfig;let i;if(t.shouldUseMinio?i=Zt(r.minioConfig.storageDir,r.minioConfig.envs,await this.getFreePortForPlatformaOnServer(t.remoteHome,t.arch),r.workingDir,r.plConfig.configPath,t.binPaths.minioRelPath,t.binPaths.downloadedPl):i=Yt(await this.getFreePortForPlatformaOnServer(t.remoteHome,t.arch),r.workingDir,r.plConfig.configPath,t.binPaths.downloadedPl),!await this.sshClient.writeFileOnTheServer(tt(t.remoteHome),i))throw new Error(`Can not write supervisord config on the server ${$(t.remoteHome)}`);await(e==null?void 0:e("Supervisord configuration written."))}async doStepCreateFoldersAndSaveFiles(t,e){t.step="createFoldersAndSaveFiles";const r=t.generatedConfig;await(e==null?void 0:e("Generating folder structure..."));for(const[i,o]of Object.entries(r.filesToCreate))await this.sshClient.writeFileOnTheServer(i,o),this.logger.info(`Created file ${i}`);for(const i of r.dirsToCreate)await this.sshClient.ensureRemoteDirCreated(i),this.logger.info(`Created directory ${i}`);await(e==null?void 0:e("Folder structure created."))}async doStepGenerateNewConfig(t,e,r){t.step="generateNewConfig",await(e==null?void 0:e("Generating new config..."));const i=await g.generateSshPlConfigs({logger:this.logger,workingDir:$(t.remoteHome),portsMode:{type:"customWithMinio",ports:{debug:t.ports.debug.remote,grpc:t.ports.grpc.remote,http:t.ports.http.remote,minio:t.ports.minioPort.remote,minioConsole:t.ports.minioConsolePort.remote,monitoring:t.ports.monitoring.remote,httpLocal:t.ports.http.local,grpcLocal:t.ports.grpc.local,minioLocal:t.ports.minioPort.local}},licenseMode:r.license,useGlobalAccess:p.notEmpty(r.useGlobalAccess),plConfigPostprocessing:r.plConfigPostprocessing,useMinio:t.shouldUseMinio??!1});t.generatedConfig={...i},await(e==null?void 0:e("New config generated"))}async doStepFetchPorts(t){var e;if(t.step="fetchPorts",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||!((e=t.ports.http)!=null&&e.remote))throw new Error("SshPl.platformaInit: remote ports are not defined")}async doStepDownloadBinaries(t,e,r){t.step="downloadBinaries",await(e==null?void 0:e("Downloading and uploading required binaries..."));const i=await Qt(this.logger,this.sshClient);if(i<M)throw new Error(`glibc version ${i} is too old. Version ${M} or higher is required for Platforma.`);const o=await this.downloadBinariesAndUploadToTheServer(r.localWorkdir,r.plBinary,t.remoteHome,t.arch,t.shouldUseMinio??!1);await(e==null?void 0:e("All required binaries have been downloaded and uploaded.")),t.binPaths={...o,history:void 0},t.downloadedBinaries=o.history}async doStepDetectArch(t,e){t.step="detectArch",await(e==null?void 0:e("Detecting server architecture...")),t.arch=await this.getArch(),await(e==null?void 0:e("Server architecture detected."))}async doStepDetectHome(t,e){t.step="detectHome",await(e==null?void 0:e("Fetching user home directory...")),t.remoteHome=await this.getUserHomeDirectory(),await(e==null?void 0:e("User home directory retrieved."))}async doStepReadExistedConfig(t,e,r){var s;if(t.step="checkAlive",await(r==null?void 0:r("Checking platform status...")),t.alive=await this.isAlive(),!((s=t.alive)!=null&&s.platforma))return!0;if(await(r==null?void 0:r("All required services are running.")),t.existedSettings=await this.readExistedConfig(t.remoteHome),!t.existedSettings)throw new Error("SshPl.platformaInit: platforma is alive but existed settings are not found");const i=t.existedSettings.useGlobalAccess==e.useGlobalAccess,o=t.existedSettings.plVersion==e.plBinary.version;return t.needRestart=!(i&&o),this.logger.info(`SshPl.platformaInit: need restart? ${t.needRestart}`),t.shouldUseMinio=t.existedSettings.minioIsUsed,t.shouldUseMinio?this.logger.info("SshPl.platformaInit: minio is used"):this.logger.info("SshPl.platformaInit: minio is not used"),t.needRestart?(await(r==null?void 0:r("Stopping services...")),await this.stop(),!0):(await(r==null?void 0:r("Server setup completed.")),!1)}async downloadBinariesAndUploadToTheServer(t,e,r,i,o){const s=[];try{const a=await this.downloadAndUntar(t,r,i,"pl",`pl-${e.version}`);s.push(a);const c=await this.downloadAndUntar(t,r,i,"supervisord",Mt);s.push(c);const l=zt(r,i.arch);if(o){const d=await this.downloadAndUntar(t,r,i,"minio",jt);s.push(d),await this.sshClient.chmod(l,488)}return{history:s,minioRelPath:o?l:void 0,downloadedPl:_(r,i.arch)}}catch(a){const c=`SshPl.downloadBinariesAndUploadToServer: ${a}, state: ${JSON.stringify(s)}`;throw this.logger.error(c),a}}async downloadAndUntar(t,e,r,i,o){const s={};s.binBasePath=O(e),await this.sshClient.ensureRemoteDirCreated(s.binBasePath),s.binBasePathCreated=!0;let a=null;const c=5;for(let d=1;d<=c;d++)try{a=await Ct(this.logger,t,i,o,r.arch,r.platform);break}catch(h){if(await p.sleep(300),d==c)throw new Error(`downloadAndUntar: ${c} attempts, last error: ${h}`)}s.downloadResult=p.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.ensureRemoteDirCreated(s.remoteDir),await this.sshClient.uploadFile(s.localArchivePath,s.remoteArchivePath),s.uploadDone=!0;try{await this.sshClient.exec("hash tar")}catch{throw new Error("tar is not installed on the server. Please install it before running Platforma.")}const l=await this.sshClient.exec(`tar --warning=no-all -xvf ${s.remoteArchivePath} --directory=${s.remoteDir}`);if(l.stderr)throw new Error(`downloadAndUntar: untar: stderr occurred: ${l.stderr}, stdout: ${l.stdout}`);return s.untarDone=!0,s}async needDownload(t,e){const r=Q(t,e.arch),i=X(t,e.arch),o=_(t,e.arch);return!await this.sshClient.checkFileExists(o)||!await this.sshClient.checkFileExists(i)||!await this.sshClient.checkFileExists(r)}async checkIsAliveWithInterval(t,e=1e3,r=15,i=!0){const o=r*e;let s=0,a=await this.isAlive();for(;i?!E(a,t):E(a,t);){if(await p.sleep(e),s+=e,s>o)throw new Error(`isAliveWithInterval: The process did not ${i?"started":"stopped"} after ${o} ms. Live status: ${JSON.stringify(a)}`);a=await this.isAlive()}}async readExistedConfig(t){const e=await this.sshClient.readFile(T(t));return nt(e)}async fetchPorts(t,e){return{grpc:{local:await g.getFreePort(),remote:await this.getFreePortForPlatformaOnServer(t,e)},monitoring:{local:await g.getFreePort(),remote:await this.getFreePortForPlatformaOnServer(t,e)},debug:{local:await g.getFreePort(),remote:await this.getFreePortForPlatformaOnServer(t,e)},http:{local:await g.getFreePort(),remote:await this.getFreePortForPlatformaOnServer(t,e)},minioPort:{local:await g.getFreePort(),remote:await this.getFreePortForPlatformaOnServer(t,e)},minioConsolePort:{local:await g.getFreePort(),remote:await this.getFreePortForPlatformaOnServer(t,e)}}}async getLocalFreePort(){return new Promise(t=>{const e=H.createServer();e.listen(0,()=>{const r=e.address().port;e.close(i=>t(r))})})}async getFreePortForPlatformaOnServer(t,e){const r=Gt(t,e.arch),{stdout:i,stderr:o}=await this.sshClient.exec(`${r}`);if(o)throw new Error(`getFreePortForPlatformaOnServer: stderr is not empty: ${o}, stdout: ${i}`);return+i}async getArch(){const{stdout:t,stderr:e}=await this.sshClient.exec("uname -s && uname -m");if(e)throw new Error(`getArch: stderr is not empty: ${e}, stdout: ${t}`);const r=t.split(`
60
- `);return{platform:r[0],arch:r[1]}}async getUserHomeDirectory(){const{stdout:t,stderr:e}=await this.sshClient.exec("echo $HOME");if(e){const r=`/home/${this.username}`;return console.warn(`getUserHomeDirectory: stderr is not empty: ${e}, stdout: ${t}, will get a default home: ${r}`),r}return t.trim()}}const Xt={useGlobalAccess:!1,plBinary:{type:"Download",version:A()}};async function Qt(n,t){try{const{stdout:e,stderr:r}=await t.exec("ldd --version | head -n 1");if(r)throw new Error(`Failed to check glibc version: ${r}`);return st(e)}catch(e){throw n.error(`glibc version check failed: ${e}`),e}}function st(n){const t=n.match(/\d+\.\d+/);if(!t)throw new Error(`Could not parse glibc version from: ${n}`);return parseFloat(t[0])}exports.ConnectionInfo=rt;exports.LocalConfigYaml=V;exports.LocalPl=W;exports.PortPair=v;exports.SshClient=D;exports.SshPl=I;exports.SshPlPorts=et;exports.getDefaultPlVersion=A;exports.localPlatformaInit=Bt;exports.mergeDefaultOps=K;exports.newConnectionInfo=it;exports.parseConnectionInfo=nt;exports.parseGlibcVersion=st;exports.plProcessOps=Y;exports.stringifyConnectionInfo=ot;
62
+ `}async function N(n,t,e,r){const i=Q(t,e),o=tt(t),s=`${i} --configuration ${o} ${r}`;return await n.exec(s)}function j(n,t){return(i=>i.replace(/\x1B\[[0-9;]*m/g,""))(n).split(`
63
+ `).some(i=>{const[o,s]=i.trim().split(/\s{2,}/);return o===t&&s==="Running"})}const $=w.z.object({local:w.z.number(),remote:w.z.number()}),et=w.z.object({grpc:$,http:$.optional(),monitoring:$,debug:$,minioPort:$,minioConsolePort:$}),rt=w.z.object({plUser:w.z.string(),plPassword:w.z.string(),ports:et,useGlobalAccess:w.z.boolean().default(!1),plVersion:w.z.string().default("1.18.3"),minioIsUsed:w.z.boolean().default(!0)});function it(n,t,e,r,i,o){return{plUser:n,plPassword:t,ports:e,useGlobalAccess:r,plVersion:i,minioIsUsed:o}}function nt(n){return rt.parse(JSON.parse(n))}function ot(n){return JSON.stringify(n,void 0,2)}const M=2.28;class B{constructor(t,e,r){f(this,"initState",{step:"init"});this.logger=t,this.sshClient=e,this.username=r}info(){return{username:this.username,initState:this.initState}}static async init(t,e){try{const r=await O.init(t,e);return new B(t,r,p.notEmpty(e.username))}catch(r){throw t.error(`Connection error in SshClient.init: ${r}`),r}}cleanUp(){this.sshClient.close()}async isAlive(){const t=await this.getArch(),e=await this.getUserHomeDirectory();return await Yt(this.logger,this.sshClient,e,t.arch)}async start(t){const e=await this.getArch(),r=await this.getUserHomeDirectory();try{if(!E(await this.isAlive(),t))return await Vt(this.sshClient,r,e.arch),await this.checkIsAliveWithInterval(t)}catch(i){let o=`SshPl.start: ${i}`,s="";try{s=await this.sshClient.readFile(Jt(r)),o+=`, platforma cli logs: ${s}`}catch(a){o+=`, Can not read platforma cli logs: ${a}`}throw this.logger.error(o),new Error(o)}}async stop(){const t=await this.getArch(),e=await this.getUserHomeDirectory();try{const r=await this.isAlive();if(Kt(r)){await Wt(this.sshClient,e,t.arch);const i=r.minio===!0;return await this.checkIsAliveWithInterval(i,1e3,15,!1)}}catch(r){const i=`PlSsh.stop: ${r}`;throw this.logger.error(i),new Error(i)}}async reset(){return await this.stopAndClean(),this.cleanUp(),!0}async stopAndClean(){const t=await this.getUserHomeDirectory();this.logger.info("pl.reset: Stop Platforma on the server"),await this.stop(),this.logger.info(`pl.reset: Deleting Platforma workDir ${g(t)} on the server`),await this.sshClient.deleteFolder(g(t))}async platformaInit(t){const e={localWorkdir:t.localWorkdir,step:"init"},{onProgress:r}=t,i={...Qt,...t};e.plBinaryOps=i.plBinary;try{return await this.doStepDetectArch(e,r),await this.doStepDetectHome(e,r),await this.doStepReadExistedConfig(e,i,r)?(await this.doStepStopExistedPlatforma(e,r),await(r==null?void 0:r("Installation platforma...")),await this.doStepDownloadBinaries(e,r,i),await this.doStepFetchPorts(e),await this.doStepGenerateNewConfig(e,r,i),await this.doStepCreateFoldersAndSaveFiles(e,r),await this.doStepConfigureSupervisord(e,r),await this.doStepSaveNewConnectionInfo(e,r,i),await this.doStepStartPlatforma(e,r),e.connectionInfo):(await(r==null?void 0:r("Platforma is already running. Skipping initialization.")),e.existedSettings)}catch(o){const s=`SshPl.platformaInit: ${o}, state: ${JSON.stringify(this.removeSensitiveData(e))}`;throw this.logger.error(s),new Error(s)}}async doStepStopExistedPlatforma(t,e){t.step="stopExistedPlatforma",E(t.alive,t.shouldUseMinio??!1)&&(await(e==null?void 0:e("Stopping services...")),await this.stop())}removeSensitiveData(t){const e={...t};return e.generatedConfig={...e.generatedConfig,filesToCreate:{skipped:"sanitized"}},e}async doStepStartPlatforma(t,e){t.step="startPlatforma",await(e==null?void 0:e("Starting Platforma on the server...")),await this.start(t.shouldUseMinio??!1),t.started=!0,this.initState=t,await(e==null?void 0:e("Platforma has been started successfully."))}async doStepSaveNewConnectionInfo(t,e,r){t.step="saveNewConnectionInfo";const i=t.generatedConfig;await(e==null?void 0:e("Saving connection information...")),t.connectionInfo=it(i.plUser,i.plPassword,t.ports,p.notEmpty(r.useGlobalAccess),r.plBinary.version,t.shouldUseMinio??!1),await this.sshClient.writeFileOnTheServer(T(t.remoteHome),ot(t.connectionInfo)),await(e==null?void 0:e("Connection information saved."))}async doStepConfigureSupervisord(t,e){await(e==null?void 0:e("Writing supervisord configuration...")),t.step="configureSupervisord";const r=t.generatedConfig;let i;if(t.shouldUseMinio?i=Xt(r.minioConfig.storageDir,r.minioConfig.envs,await this.getFreePortForPlatformaOnServer(t.remoteHome,t.arch),r.workingDir,r.plConfig.configPath,t.binPaths.minioRelPath,t.binPaths.downloadedPl):i=Zt(await this.getFreePortForPlatformaOnServer(t.remoteHome,t.arch),r.workingDir,r.plConfig.configPath,t.binPaths.downloadedPl),!await this.sshClient.writeFileOnTheServer(tt(t.remoteHome),i))throw new Error(`Can not write supervisord config on the server ${g(t.remoteHome)}`);await(e==null?void 0:e("Supervisord configuration written."))}async doStepCreateFoldersAndSaveFiles(t,e){t.step="createFoldersAndSaveFiles";const r=t.generatedConfig;await(e==null?void 0:e("Generating folder structure..."));for(const[i,o]of Object.entries(r.filesToCreate))await this.sshClient.writeFileOnTheServer(i,o),this.logger.info(`Created file ${i}`);for(const i of r.dirsToCreate)await this.sshClient.ensureRemoteDirCreated(i),this.logger.info(`Created directory ${i}`);await(e==null?void 0:e("Folder structure created."))}async doStepGenerateNewConfig(t,e,r){t.step="generateNewConfig",await(e==null?void 0:e("Generating new config..."));const i=await v.generateSshPlConfigs({logger:this.logger,workingDir:g(t.remoteHome),portsMode:{type:"customWithMinio",ports:{debug:t.ports.debug.remote,grpc:t.ports.grpc.remote,http:t.ports.http.remote,minio:t.ports.minioPort.remote,minioConsole:t.ports.minioConsolePort.remote,monitoring:t.ports.monitoring.remote,httpLocal:t.ports.http.local,grpcLocal:t.ports.grpc.local,minioLocal:t.ports.minioPort.local}},licenseMode:r.license,useGlobalAccess:p.notEmpty(r.useGlobalAccess),plConfigPostprocessing:r.plConfigPostprocessing,useMinio:t.shouldUseMinio??!1});t.generatedConfig={...i},await(e==null?void 0:e("New config generated"))}async doStepFetchPorts(t){var e;if(t.step="fetchPorts",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||!((e=t.ports.http)!=null&&e.remote))throw new Error("SshPl.platformaInit: remote ports are not defined")}async doStepDownloadBinaries(t,e,r){t.step="downloadBinaries",await(e==null?void 0:e("Downloading and uploading required binaries..."));const i=await te(this.logger,this.sshClient);if(i<M)throw new Error(`glibc version ${i} is too old. Version ${M} or higher is required for Platforma.`);const o=await this.downloadBinariesAndUploadToTheServer(r.localWorkdir,r.plBinary,t.remoteHome,t.arch,t.shouldUseMinio??!1);await(e==null?void 0:e("All required binaries have been downloaded and uploaded.")),t.binPaths={...o,history:void 0},t.downloadedBinaries=o.history}async doStepDetectArch(t,e){t.step="detectArch",await(e==null?void 0:e("Detecting server architecture...")),t.arch=await this.getArch(),await(e==null?void 0:e("Server architecture detected."))}async doStepDetectHome(t,e){t.step="detectHome",await(e==null?void 0:e("Fetching user home directory...")),t.remoteHome=await this.getUserHomeDirectory(),await(e==null?void 0:e("User home directory retrieved."))}async doStepReadExistedConfig(t,e,r){var s;if(t.step="checkAlive",await(r==null?void 0:r("Checking platform status...")),t.alive=await this.isAlive(),!((s=t.alive)!=null&&s.platforma))return!0;if(await(r==null?void 0:r("All required services are running.")),t.existedSettings=await this.readExistedConfig(t.remoteHome),!t.existedSettings)throw new Error("SshPl.platformaInit: platforma is alive but existed settings are not found");const i=t.existedSettings.useGlobalAccess==e.useGlobalAccess,o=t.existedSettings.plVersion==e.plBinary.version;return t.needRestart=!(i&&o),this.logger.info(`SshPl.platformaInit: need restart? ${t.needRestart}`),t.shouldUseMinio=t.existedSettings.minioIsUsed,t.shouldUseMinio?this.logger.info("SshPl.platformaInit: minio is used"):this.logger.info("SshPl.platformaInit: minio is not used"),t.needRestart?(await(r==null?void 0:r("Stopping services...")),await this.stop(),!0):(await(r==null?void 0:r("Server setup completed.")),!1)}async downloadBinariesAndUploadToTheServer(t,e,r,i,o){const s=[];try{const a=await this.downloadAndUntar(t,r,i,"pl",`pl-${e.version}`);s.push(a);const c=await this.downloadAndUntar(t,r,i,"supervisord",Mt);s.push(c);const l=zt(r,i.arch);if(o){const d=await this.downloadAndUntar(t,r,i,"minio",jt);s.push(d),await this.sshClient.chmod(l,488)}return{history:s,minioRelPath:o?l:void 0,downloadedPl:U(r,i.arch)}}catch(a){const c=`SshPl.downloadBinariesAndUploadToServer: ${a}, state: ${JSON.stringify(s)}`;throw this.logger.error(c),a}}async downloadAndUntar(t,e,r,i,o){const s={};s.binBasePath=x(e),await this.sshClient.ensureRemoteDirCreated(s.binBasePath),s.binBasePathCreated=!0;let a=null;const c=5;for(let d=1;d<=c;d++)try{a=await Ct(this.logger,t,i,o,r.arch,r.platform);break}catch(h){if(await p.sleep(300),d==c)throw new Error(`downloadAndUntar: ${c} attempts, last error: ${h}`)}s.downloadResult=p.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.ensureRemoteDirCreated(s.remoteDir),await this.sshClient.uploadFile(s.localArchivePath,s.remoteArchivePath),s.uploadDone=!0;try{await this.sshClient.exec("hash tar")}catch{throw new Error("tar is not installed on the server. Please install it before running Platforma.")}const l=await this.sshClient.exec(`tar --warning=no-all -xvf ${s.remoteArchivePath} --directory=${s.remoteDir}`);if(l.stderr)throw new Error(`downloadAndUntar: untar: stderr occurred: ${l.stderr}, stdout: ${l.stdout}`);return s.untarDone=!0,s}async needDownload(t,e){const r=Q(t,e.arch),i=X(t,e.arch),o=U(t,e.arch);return!await this.sshClient.checkFileExists(o)||!await this.sshClient.checkFileExists(i)||!await this.sshClient.checkFileExists(r)}async checkIsAliveWithInterval(t,e=1e3,r=15,i=!0){const o=r*e;let s=0,a=await this.isAlive();for(;i?!E(a,t):E(a,t);){if(await p.sleep(e),s+=e,s>o)throw new Error(`isAliveWithInterval: The process did not ${i?"started":"stopped"} after ${o} ms. Live status: ${JSON.stringify(a)}`);a=await this.isAlive()}}async readExistedConfig(t){const e=await this.sshClient.readFile(T(t));return nt(e)}async fetchPorts(t,e){return{grpc:{local:await v.getFreePort(),remote:await this.getFreePortForPlatformaOnServer(t,e)},monitoring:{local:await v.getFreePort(),remote:await this.getFreePortForPlatformaOnServer(t,e)},debug:{local:await v.getFreePort(),remote:await this.getFreePortForPlatformaOnServer(t,e)},http:{local:await v.getFreePort(),remote:await this.getFreePortForPlatformaOnServer(t,e)},minioPort:{local:await v.getFreePort(),remote:await this.getFreePortForPlatformaOnServer(t,e)},minioConsolePort:{local:await v.getFreePort(),remote:await this.getFreePortForPlatformaOnServer(t,e)}}}async getLocalFreePort(){return new Promise(t=>{const e=H.createServer();e.listen(0,()=>{const r=e.address().port;e.close(i=>t(r))})})}async getFreePortForPlatformaOnServer(t,e){const r=Gt(t,e.arch),{stdout:i,stderr:o}=await this.sshClient.exec(`${r}`);if(o)throw new Error(`getFreePortForPlatformaOnServer: stderr is not empty: ${o}, stdout: ${i}`);return+i}async getArch(){const{stdout:t,stderr:e}=await this.sshClient.exec("uname -s && uname -m");if(e)throw new Error(`getArch: stderr is not empty: ${e}, stdout: ${t}`);const r=t.split(`
64
+ `);return{platform:r[0],arch:r[1]}}async getUserHomeDirectory(){const{stdout:t,stderr:e}=await this.sshClient.exec("echo $HOME");if(e){const r=`/home/${this.username}`;return console.warn(`getUserHomeDirectory: stderr is not empty: ${e}, stdout: ${t}, will get a default home: ${r}`),r}return t.trim()}}const Qt={useGlobalAccess:!1,plBinary:{type:"Download",version:A()}};async function te(n,t){try{const{stdout:e,stderr:r}=await t.exec("ldd --version | head -n 1");if(r)throw new Error(`Failed to check glibc version: ${r}`);return st(e)}catch(e){throw n.error(`glibc version check failed: ${e}`),e}}function st(n){const t=n.match(/\d+\.\d+/);if(!t)throw new Error(`Could not parse glibc version from: ${n}`);return parseFloat(t[0])}exports.ConnectionInfo=rt;exports.LocalConfigYaml=V;exports.LocalPl=W;exports.PortPair=$;exports.SshClient=O;exports.SshPl=B;exports.SshPlPorts=et;exports.getDefaultPlVersion=A;exports.localPlatformaInit=Nt;exports.mergeDefaultOps=K;exports.newConnectionInfo=it;exports.parseConnectionInfo=nt;exports.parseGlibcVersion=st;exports.plProcessOps=Y;exports.stringifyConnectionInfo=ot;
61
65
  //# sourceMappingURL=index.js.map