diff --git a/dev/vbrowser.sh b/dev/vbrowser.sh index af06cb3c8f..b2236b0718 100644 --- a/dev/vbrowser.sh +++ b/dev/vbrowser.sh @@ -18,8 +18,11 @@ echo ' #!/bin/bash iptables -t nat -A PREROUTING -p tcp --dport 80 -j REDIRECT --to-port 5000 -# create random password -# uuidgen > ~/password +# do if password does not exist +# if [ ! -f ~/password ] +# then +# hostname > ~/password +# fi # PASSWORD=$(cat ~/password) PASSWORD=$(hostname) #RESOLUTION=$(if [ "$(nproc)" -le "2" ]; then echo "1280x720@30"; else echo "1920x1080@30"; fi) diff --git a/package.json b/package.json index c746dedd8e..fec3c4beb1 100644 --- a/package.json +++ b/package.json @@ -61,6 +61,7 @@ "ncu": "ncu --semverLevel major -u", "updateSnapshot": "curl -X POST http://localhost:3100/updateSnapshot -H 'Content-Type: application/json' -d '{\"provider\":\"Hetzner\",\"region\":\"US\"}'", "testvBrowser": "docker run -d --rm --name=vbrowser --log-opt max-size=1g --net=host --shm-size=1g --cap-add=\"SYS_ADMIN\" -e DISPLAY=\":99.0\" -e NEKO_PASSWORD=user -e NEKO_PASSWORD_ADMIN=admin -e NEKO_BIND=\":5100\" -e NEKO_EPR=\":59000-59100\" -e NEKO_H264=\"1\" howardc93/vbrowser", + "testvlc": "docker run -d --rm --name=vlc --log-opt max-size=1g --net=host -e VLC_MEDIA=\"https://github.com/ietf-wg-cellar/matroska-test-files/raw/master/test_files/test1.mkv\" -e NEKO_PASSWORD=user -e NEKO_PASSWORD_ADMIN=admin -e NEKO_BIND=\":5100\" -e NEKO_EPR=\":59000-59100\" -e NEKO_H264=\"1\" m1k1o/neko:vlc", "analyze": "source-map-explorer 'build/static/js/*.js' --html result.html" }, "husky": { diff --git a/server/vm/base.ts b/server/vm/base.ts index 225b3e5350..3a09ef73b0 100644 --- a/server/vm/base.ts +++ b/server/vm/base.ts @@ -201,16 +201,20 @@ export abstract class VMManager { // Since most user sessions are less than an hour // Otherwise if it's per-second or Docker, it's easier to just terminate it on reboot if (this.reuseVMs) { - // To reset without API calls: - // Update vbrowser image to generate password and save to file - // vbrowser uses file content as password - // ssh to vbrowser and sudo reboot - // Image serves file content at secret endpoint - // on vmWorker, checkvmready checks secret endpoint for password and updates DB + // To reset without API calls/reimaging (logic can be reused on any cloud provider): + // Update vbrowser image to create default password file with hostname + // vbrowser image should use file content as password instead of hostname + // generate a new password on vmWorker + // ssh to vbrowser, then: + // save generated password to file (~/password) + // sudo reboot + // update DB with generated password + // getVM needs to lookup password from db rather than reading server name from API + // listvm only needs ID, so avoid doing DB password lookup // add option to force reimage VM (in case of chrome updates) await this.rebootVM(vmid); // we could crash here and then row will remain in used state - // Once the heartbeat becomes stale cleanup will reset it + // Once the heartbeat becomes stale cleanup will reset it again const result = await postgres.query( ` INSERT INTO vbrowser(pool, vmid, "creationTime", state) @@ -305,12 +309,8 @@ export abstract class VMManager { // filter to only VMs eligible for deletion // they must be up for long enough // keep the oldest min pool size number of VMs - // Hetzner/DO rounds up to nearest hour + // Hetzner/DO/Scaleway rounds up to nearest hour let modulo = 3600; - if (this.id === 'Scaleway') { - // Scaleway just charges by the minute with a min of 60 min so don't modulo - modulo = 2147483647; - } const { rows } = await postgres.query( ` DELETE FROM vbrowser @@ -558,7 +558,7 @@ export abstract class VMManager { protected abstract rebootVM: (id: string) => Promise; protected abstract terminateVM: (id: string) => Promise; public abstract getVM: (id: string) => Promise; - protected abstract listVMs: (filter?: string) => Promise; + protected abstract listVMs: (filter: string) => Promise; protected abstract powerOn: (id: string) => Promise; protected abstract attachToNetwork: (id: string) => Promise; protected abstract mapServerObject: (server: any) => VM; @@ -601,11 +601,7 @@ export interface VM { id: string; pass: string; host: string; - state: string; - tags: string[]; - creation_date: string; provider: string; - originalName?: string; large: boolean; region: string; } diff --git a/server/vm/digitalocean.ts b/server/vm/digitalocean.ts index c0b4e3a0b6..82c2c8cdda 100644 --- a/server/vm/digitalocean.ts +++ b/server/vm/digitalocean.ts @@ -125,7 +125,7 @@ export class DigitalOcean extends VMManager { return server; }; - listVMs = async (filter?: string) => { + listVMs = async (filter: string) => { // console.log(filter, tags); const response = await axios({ method: 'GET', @@ -140,9 +140,7 @@ export class DigitalOcean extends VMManager { tag_name: filter, }, }); - return response.data.droplets - .map(this.mapServerObject) - .filter((server: VM) => server.tags.includes(this.getTag())); + return response.data.droplets.map(this.mapServerObject); }; powerOn = async (_id: string) => {}; @@ -165,9 +163,6 @@ export class DigitalOcean extends VMManager { pass: server.name, // The gateway handles SSL termination and proxies to the private IP host: ip ? `${gatewayHost}/?ip=${ip}` : '', - state: server.status, - tags: server.tags, - creation_date: server.created_at, provider: this.id, large: this.isLarge, region: this.region, diff --git a/server/vm/docker.ts b/server/vm/docker.ts index 7181cf2ff0..f96231e380 100644 --- a/server/vm/docker.ts +++ b/server/vm/docker.ts @@ -88,7 +88,7 @@ export class Docker extends VMManager { return server; }; - listVMs = async (filter?: string) => { + listVMs = async (filter: string) => { const conn = await this.getSSH(); const listCmd = `docker inspect $(docker ps --filter label=${filter} --quiet --no-trunc)`; const { stdout } = await conn.execCommand(listCmd); @@ -117,9 +117,6 @@ export class Docker extends VMManager { id: server.Id, pass: server.Name?.slice(1), host: `${this.hostname}:${5000 + Number(server.Config?.Labels?.index)}`, - state: server.State?.Status, - tags: server.Config?.Labels, - creation_date: server.State?.StartedAt, provider: this.id, large: this.isLarge, region: this.region, diff --git a/server/vm/hetzner.ts b/server/vm/hetzner.ts index 155505d47b..98bd4ee2ac 100644 --- a/server/vm/hetzner.ts +++ b/server/vm/hetzner.ts @@ -45,7 +45,6 @@ export class Hetzner extends VMManager { // user_data: `replace with vbrowser.sh startup script if we want to boot vbrowser on instance creation (won't trigger on rebuild/restart)` labels: { [this.getTag()]: '1', - originalName: name, }, location: this.getRandomDatacenter(), }; @@ -126,7 +125,7 @@ export class Hetzner extends VMManager { return server; }; - listVMs = async (filter?: string) => { + listVMs = async (filter: string) => { const limit = this.getLimitSize(); const pageCount = Math.ceil((limit || 1) / 50); const pages = Array.from(Array(pageCount).keys()).map((i) => i + 1); @@ -148,9 +147,7 @@ export class Hetzner extends VMManager { ), ); const responsesMapped = responses.map((response) => - response.data.servers - .map(this.mapServerObject) - .filter((server: VM) => server.tags.includes(this.getTag())), + response.data.servers.map(this.mapServerObject), ); return responsesMapped.flat(); }; @@ -252,10 +249,6 @@ export class Hetzner extends VMManager { pass: server.name, // The gateway handles SSL termination and proxies to the private IP host: ip ? `${this.gateway}/?ip=${ip}` : '', - state: server.status, - tags: Object.keys(server.labels), - creation_date: server.created, - originalName: server.labels.originalName, provider: this.id, large: this.isLarge, region: this.region, diff --git a/server/vm/scaleway.ts b/server/vm/scaleway.ts index 464d93ac9c..726e9c87c2 100644 --- a/server/vm/scaleway.ts +++ b/server/vm/scaleway.ts @@ -120,7 +120,7 @@ export class Scaleway extends VMManager { return server; }; - listVMs = async (filter?: string) => { + listVMs = async (filter: string) => { const limit = this.getLimitSize(); const pageCount = Math.ceil((limit || 1) / 100); const pages = Array.from(Array(pageCount).keys()).map((i) => i + 1); @@ -142,9 +142,7 @@ export class Scaleway extends VMManager { ), ); const responsesMapped = responses.map((response) => - response.data.servers - .map(this.mapServerObject) - .filter((server: VM) => server.tags.includes(this.getTag())), + response.data.servers.map(this.mapServerObject), ); return responsesMapped.flat(); }; @@ -165,9 +163,6 @@ export class Scaleway extends VMManager { pass: server.name, // The gateway handles SSL termination and proxies to the private IP host: ip ? `${gatewayHost}/?ip=${ip}` : '', - state: server.state, - tags: server.tags, - creation_date: server.creation_date, provider: this.id, large: this.isLarge, region: this.region,