openvibers/openvibe.host Commits
List the OpenRe WHIP worker and correct the stale Bot note (#18)
Changes
@@@ -2113,7 +2113,7 @@}},"bot": {-- "_note": "Not deployed yet. Bot owns openvibe.bot.conf: deploy bot installs its proxy vhost after Sites skips that filename. Before the first deploy, provision bot.env, the database and the existing TLS certificate; use ovhost deploy bot --restart if the checkout is already current so it installs and enables the service unit. Keep Sites on its ovhost deploy path (its legacy fallback still installs every vhost).",++ "_note": "Deployed; migrations 0001 and 0002 applied. Bot owns openvibe.bot.conf: deploy bot installs its proxy vhost after Sites skips that filename. BOT_WHIP_BASE (in /etc/openvibe/bot.env) is the switch that points Bot's video at https://ingest.openre.stream/whip. Use ovhost deploy bot --restart if the checkout is already current so it installs and enables the service unit. Keep Sites on its ovhost deploy path (its legacy fallback still installs every vhost).","repo": "/opt/openvibe.bot","installUnits": true,"enableUnits": true,@@@ -2178,7 +2178,7 @@}},"openre": {-- "_note": "Release layout: /opt/openre.stream/repo is the git clone, releases/<sha12> the releases (npm ci into each, chowned to ubuntu), `current` the link the API and the coordinator run from (deploy.sh release + api as ovhost deploy openre; ovhost rollback openre). units are the API and the session coordinator. workerUnits are the transport workers: one instance per release (openre-rtmp-ingest@<release>, openre-jsmpeg@<release>), started by deploy.sh workers (still the repository's script), drained by the coordinator when a newer generation is ready, and exiting on their own. ovhost lists them in status/validate, never starts, stops or restarts them (the inventory refuses a worker unit in units), and never prunes a release a worker instance runs from.",++ "_note": "Release layout: /opt/openre.stream/repo is the git clone, releases/<sha12> the releases (npm ci into each, chowned to ubuntu), `current` the link the API and the coordinator run from (deploy.sh release + api as ovhost deploy openre; ovhost rollback openre). units are the API and the session coordinator. workerUnits are the transport workers: one instance per release (openre-rtmp-ingest@<release>, openre-jsmpeg@<release>, openre-webrtc@<release>), started by deploy.sh workers (still the repository's script), drained by the coordinator when a newer generation is ready, and exiting on their own. ovhost lists them in status/validate, never starts, stops or restarts them (the inventory refuses a worker unit in units), and never prunes a release a worker instance runs from. deploy.sh workers starts openre-webrtc@<release> once the WHIP vhost (ingest.openre.stream) and MEDIASOUP_ANNOUNCED_IP are set.","repo": "/opt/openre.stream","strategy": "release-layout","owner": "root",@@@ -2197,7 +2197,8 @@"workerUnits": [-- "[email protected]"++ "[email protected]",++ "[email protected]"],"envFile": "/etc/openvibe/openre.env","env": {@@@ -15,7 +15,12 @@ const { normalise } = require('../lib/inventory');const EXAMPLE = JSON.parse(fs.readFileSync(path.join(__dirname, '..', 'host.example.json'), 'utf8'));const RELEASE = '655b98a10aaa';const OLD = '0123456789ab';--const WORKERS = [`openre-rtmp-ingest@${RELEASE}.service`, `openre-restream-worker@${RELEASE}.service`, `openre-jsmpeg@${RELEASE}.service`];++const WORKERS = [++ `openre-rtmp-ingest@${RELEASE}.service`,++ `openre-restream-worker@${RELEASE}.service`,++ `openre-jsmpeg@${RELEASE}.service`,++ `openre-webrtc@${RELEASE}.service`,++];/** The standard fake host plus OpenRe as on openvibe-ovh: release layout, two units, worker instances. */async function openreHost({ workersRunning = true } = {}) {@@@ -49,6 +54,7 @@ async function openreHost({ workersRunning = true } = {}) {host.addUnit(`openre-rtmp-ingest@${RELEASE}.service`, { mainPid: 3102, ...(workersRunning ? {} : { active: 'inactive', sub: 'dead' }) });host.addUnit(`openre-restream-worker@${RELEASE}.service`, { mainPid: 3103, ...(workersRunning ? {} : { active: 'inactive', sub: 'dead' }) });host.addUnit(`openre-jsmpeg@${RELEASE}.service`, { mainPid: 3104, ...(workersRunning ? {} : { active: 'inactive', sub: 'dead' }) });++ host.addUnit(`openre-webrtc@${RELEASE}.service`, { mainPid: 3105, ...(workersRunning ? {} : { active: 'inactive', sub: 'dead' }) });host.addUnit(`openre-rtmp-ingest@${OLD}.service`, { active: 'inactive', sub: 'dead', mainPid: 0 });host.addUnit(`openre-jsmpeg@${OLD}.service`, { active: 'inactive', sub: 'dead', mainPid: 0 });// openre is PostgreSQL: the production database and a healthy pgBackRest stanza so that@@@ -89,7 +95,7 @@ runTests([const inv = normalise(EXAMPLE);const o = inv.services.openre;assert.deepStrictEqual(o.units, ['openre-api.service', 'openre-session-coordinator.service']);-- assert.deepStrictEqual(o.workerUnits, ['[email protected]', '[email protected]', '[email protected]']);++ assert.deepStrictEqual(o.workerUnits, ['[email protected]', '[email protected]', '[email protected]', '[email protected]']);assert.strictEqual(o.layout, 'release');assert.strictEqual(o.strategy, 'release-layout');assert.strictEqual(o.managed, true, 'ovhost deploy openre: release + api (WS-N task 11)');@@@ -119,9 +125,9 @@ runTests([const host = await openreHost();const r = await host.cli('status', 'openre');assert.strictEqual(r.code, 0, r.out);-- assert.match(r.out, new RegExp(`openre\\s+${RELEASE}\\s+ready\\s+openre-api=active openre-session-coordinator=active workers\\[openre-rtmp-ingest@${RELEASE}=active openre-rtmp-ingest@${OLD}=inactive openre-restream-worker@${RELEASE}=active openre-jsmpeg@${RELEASE}=active openre-jsmpeg@${OLD}=inactive\\] ingest sessions=0$`, 'm'));++ assert.match(r.out, new RegExp(`openre\\s+${RELEASE}\\s+ready\\s+openre-api=active openre-session-coordinator=active workers\\[openre-rtmp-ingest@${RELEASE}=active openre-rtmp-ingest@${OLD}=inactive openre-restream-worker@${RELEASE}=active openre-jsmpeg@${RELEASE}=active openre-jsmpeg@${OLD}=inactive openre-webrtc@${RELEASE}=active\\] ingest sessions=0$`, 'm'));const json = JSON.parse((await host.cli('status', 'openre', '--json')).out);-- assert.deepStrictEqual(json[0].workers.map((w) => [w.unit, w.active]), [[`openre-rtmp-ingest@${RELEASE}.service`, 'active'], [`openre-rtmp-ingest@${OLD}.service`, 'inactive'], [`openre-restream-worker@${RELEASE}.service`, 'active'], [`openre-jsmpeg@${RELEASE}.service`, 'active'], [`openre-jsmpeg@${OLD}.service`, 'inactive']]);++ assert.deepStrictEqual(json[0].workers.map((w) => [w.unit, w.active]), [[`openre-rtmp-ingest@${RELEASE}.service`, 'active'], [`openre-rtmp-ingest@${OLD}.service`, 'inactive'], [`openre-restream-worker@${RELEASE}.service`, 'active'], [`openre-jsmpeg@${RELEASE}.service`, 'active'], [`openre-jsmpeg@${OLD}.service`, 'inactive'], [`openre-webrtc@${RELEASE}.service`, 'active']]);const lists = host.calls.filter((c) => c.cmd === 'systemctl' && c.args[0] === 'list-units');assert.deepStrictEqual(lists[0].args, ['list-units', '--all', '--plain', '--no-legend', '--no-pager', 'openre-rtmp-ingest@*.service']);assert.ok(lists.every((c) => !c.privileged), 'listing needs no privileges');@@@ -132,7 +138,7 @@ runTests([let host = await openreHost();let res = JSON.parse((await host.cli('validate', 'openre', '--json')).out);const workers = res.findings.filter((f) => f.area === 'units' && /^worker /.test(f.message));-- assert.deepStrictEqual(workers.map((f) => f.level), ['info', 'info', 'info', 'info', 'info']);++ assert.deepStrictEqual(workers.map((f) => f.level), ['info', 'info', 'info', 'info', 'info', 'info']);assert.match(workers[0].message, /never starts, stops or restarts it/);assert.ok(!res.findings.some((f) => /no running instance/.test(f.message)));assert.deepStrictEqual(stateChanges(host), []);@@@ -142,6 +148,7 @@ runTests([['warn', 'no running instance of worker unit [email protected]'],['warn', 'no running instance of worker unit [email protected]'],['warn', 'no running instance of worker unit [email protected]'],++ ['warn', 'no running instance of worker unit [email protected]'],]);assert.deepStrictEqual(stateChanges(host), []);assert.ok(!JSON.stringify(res).includes(SECRET));
@@ -2113,7 +2113,7 @@
@@ -2113,7 +2113,7 @@
}
}
},
},
"bot": {
"bot": {
- "_note": "Not deployed yet. Bot owns openvibe.bot.conf: deploy bot installs its proxy vhost after Sites skips that filename. Before the first deploy, provision bot.env, the database and the existing TLS certificate; use ovhost deploy bot --restart if the checkout is already current so it installs and enables the service unit. Keep Sites on its ovhost deploy path (its legacy fallback still installs every vhost).",
+ "_note": "Deployed; migrations 0001 and 0002 applied. Bot owns openvibe.bot.conf: deploy bot installs its proxy vhost after Sites skips that filename. BOT_WHIP_BASE (in /etc/openvibe/bot.env) is the switch that points Bot's video at https://ingest.openre.stream/whip. Use ovhost deploy bot --restart if the checkout is already current so it installs and enables the service unit. Keep Sites on its ovhost deploy path (its legacy fallback still installs every vhost).",
"repo": "/opt/openvibe.bot",
"repo": "/opt/openvibe.bot",
"installUnits": true,
"installUnits": true,
"enableUnits": true,
"enableUnits": true,
@@ -2178,7 +2178,7 @@
@@ -2178,7 +2178,7 @@
}
}
},
},
"openre": {
"openre": {
- "_note": "Release layout: /opt/openre.stream/repo is the git clone, releases/<sha12> the releases (npm ci into each, chowned to ubuntu), `current` the link the API and the coordinator run from (deploy.sh release + api as ovhost deploy openre; ovhost rollback openre). units are the API and the session coordinator. workerUnits are the transport workers: one instance per release (openre-rtmp-ingest@<release>, openre-jsmpeg@<release>), started by deploy.sh workers (still the repository's script), drained by the coordinator when a newer generation is ready, and exiting on their own. ovhost lists them in status/validate, never starts, stops or restarts them (the inventory refuses a worker unit in units), and never prunes a release a worker instance runs from.",
+ "_note": "Release layout: /opt/openre.stream/repo is the git clone, releases/<sha12> the releases (npm ci into each, chowned to ubuntu), `current` the link the API and the coordinator run from (deploy.sh release + api as ovhost deploy openre; ovhost rollback openre). units are the API and the session coordinator. workerUnits are the transport workers: one instance per release (openre-rtmp-ingest@<release>, openre-jsmpeg@<release>, openre-webrtc@<release>), started by deploy.sh workers (still the repository's script), drained by the coordinator when a newer generation is ready, and exiting on their own. ovhost lists them in status/validate, never starts, stops or restarts them (the inventory refuses a worker unit in units), and never prunes a release a worker instance runs from. deploy.sh workers starts openre-webrtc@<release> once the WHIP vhost (ingest.openre.stream) and MEDIASOUP_ANNOUNCED_IP are set.",
"repo": "/opt/openre.stream",
"repo": "/opt/openre.stream",
"strategy": "release-layout",
"strategy": "release-layout",
"owner": "root",
"owner": "root",
@@ -2197,7 +2197,8 @@
@@ -2197,7 +2197,8 @@
"workerUnits": [
"workerUnits": [
+ "[email protected]",
],
],
"envFile": "/etc/openvibe/openre.env",
"envFile": "/etc/openvibe/openre.env",
"env": {
"env": {
@@ -15,7 +15,12 @@ const { normalise } = require('../lib/inventory');
@@ -15,7 +15,12 @@ const { normalise } = require('../lib/inventory');
const EXAMPLE = JSON.parse(fs.readFileSync(path.join(__dirname, '..', 'host.example.json'), 'utf8'));
const EXAMPLE = JSON.parse(fs.readFileSync(path.join(__dirname, '..', 'host.example.json'), 'utf8'));
const RELEASE = '655b98a10aaa';
const RELEASE = '655b98a10aaa';
const OLD = '0123456789ab';
const OLD = '0123456789ab';
-const WORKERS = [`openre-rtmp-ingest@${RELEASE}.service`, `openre-restream-worker@${RELEASE}.service`, `openre-jsmpeg@${RELEASE}.service`];
+const WORKERS = [
+ `openre-rtmp-ingest@${RELEASE}.service`,
+ `openre-restream-worker@${RELEASE}.service`,
+ `openre-jsmpeg@${RELEASE}.service`,
+ `openre-webrtc@${RELEASE}.service`,
+];
/** The standard fake host plus OpenRe as on openvibe-ovh: release layout, two units, worker instances. */
/** The standard fake host plus OpenRe as on openvibe-ovh: release layout, two units, worker instances. */
async function openreHost({ workersRunning = true } = {}) {
async function openreHost({ workersRunning = true } = {}) {
@@ -49,6 +54,7 @@ async function openreHost({ workersRunning = true } = {}) {
@@ -49,6 +54,7 @@ async function openreHost({ workersRunning = true } = {}) {
host.addUnit(`openre-rtmp-ingest@${RELEASE}.service`, { mainPid: 3102, ...(workersRunning ? {} : { active: 'inactive', sub: 'dead' }) });
host.addUnit(`openre-rtmp-ingest@${RELEASE}.service`, { mainPid: 3102, ...(workersRunning ? {} : { active: 'inactive', sub: 'dead' }) });
host.addUnit(`openre-restream-worker@${RELEASE}.service`, { mainPid: 3103, ...(workersRunning ? {} : { active: 'inactive', sub: 'dead' }) });
host.addUnit(`openre-restream-worker@${RELEASE}.service`, { mainPid: 3103, ...(workersRunning ? {} : { active: 'inactive', sub: 'dead' }) });
host.addUnit(`openre-jsmpeg@${RELEASE}.service`, { mainPid: 3104, ...(workersRunning ? {} : { active: 'inactive', sub: 'dead' }) });
host.addUnit(`openre-jsmpeg@${RELEASE}.service`, { mainPid: 3104, ...(workersRunning ? {} : { active: 'inactive', sub: 'dead' }) });
+ host.addUnit(`openre-webrtc@${RELEASE}.service`, { mainPid: 3105, ...(workersRunning ? {} : { active: 'inactive', sub: 'dead' }) });
host.addUnit(`openre-rtmp-ingest@${OLD}.service`, { active: 'inactive', sub: 'dead', mainPid: 0 });
host.addUnit(`openre-rtmp-ingest@${OLD}.service`, { active: 'inactive', sub: 'dead', mainPid: 0 });
host.addUnit(`openre-jsmpeg@${OLD}.service`, { active: 'inactive', sub: 'dead', mainPid: 0 });
host.addUnit(`openre-jsmpeg@${OLD}.service`, { active: 'inactive', sub: 'dead', mainPid: 0 });
// openre is PostgreSQL: the production database and a healthy pgBackRest stanza so that
// openre is PostgreSQL: the production database and a healthy pgBackRest stanza so that
@@ -89,7 +95,7 @@ runTests([
@@ -89,7 +95,7 @@ runTests([
const inv = normalise(EXAMPLE);
const inv = normalise(EXAMPLE);
const o = inv.services.openre;
const o = inv.services.openre;
assert.deepStrictEqual(o.units, ['openre-api.service', 'openre-session-coordinator.service']);
assert.deepStrictEqual(o.units, ['openre-api.service', 'openre-session-coordinator.service']);
- assert.deepStrictEqual(o.workerUnits, ['[email protected]', '[email protected]', '[email protected]']);
+ assert.deepStrictEqual(o.workerUnits, ['[email protected]', '[email protected]', '[email protected]', '[email protected]']);
assert.strictEqual(o.layout, 'release');
assert.strictEqual(o.layout, 'release');
assert.strictEqual(o.strategy, 'release-layout');
assert.strictEqual(o.strategy, 'release-layout');
assert.strictEqual(o.managed, true, 'ovhost deploy openre: release + api (WS-N task 11)');
assert.strictEqual(o.managed, true, 'ovhost deploy openre: release + api (WS-N task 11)');
@@ -119,9 +125,9 @@ runTests([
@@ -119,9 +125,9 @@ runTests([
const host = await openreHost();
const host = await openreHost();
const r = await host.cli('status', 'openre');
const r = await host.cli('status', 'openre');
assert.strictEqual(r.code, 0, r.out);
assert.strictEqual(r.code, 0, r.out);
- assert.match(r.out, new RegExp(`openre\\s+${RELEASE}\\s+ready\\s+openre-api=active openre-session-coordinator=active workers\\[openre-rtmp-ingest@${RELEASE}=active openre-rtmp-ingest@${OLD}=inactive openre-restream-worker@${RELEASE}=active openre-jsmpeg@${RELEASE}=active openre-jsmpeg@${OLD}=inactive\\] ingest sessions=0$`, 'm'));
+ assert.match(r.out, new RegExp(`openre\\s+${RELEASE}\\s+ready\\s+openre-api=active openre-session-coordinator=active workers\\[openre-rtmp-ingest@${RELEASE}=active openre-rtmp-ingest@${OLD}=inactive openre-restream-worker@${RELEASE}=active openre-jsmpeg@${RELEASE}=active openre-jsmpeg@${OLD}=inactive openre-webrtc@${RELEASE}=active\\] ingest sessions=0$`, 'm'));
const json = JSON.parse((await host.cli('status', 'openre', '--json')).out);
const json = JSON.parse((await host.cli('status', 'openre', '--json')).out);
- assert.deepStrictEqual(json[0].workers.map((w) => [w.unit, w.active]), [[`openre-rtmp-ingest@${RELEASE}.service`, 'active'], [`openre-rtmp-ingest@${OLD}.service`, 'inactive'], [`openre-restream-worker@${RELEASE}.service`, 'active'], [`openre-jsmpeg@${RELEASE}.service`, 'active'], [`openre-jsmpeg@${OLD}.service`, 'inactive']]);
+ assert.deepStrictEqual(json[0].workers.map((w) => [w.unit, w.active]), [[`openre-rtmp-ingest@${RELEASE}.service`, 'active'], [`openre-rtmp-ingest@${OLD}.service`, 'inactive'], [`openre-restream-worker@${RELEASE}.service`, 'active'], [`openre-jsmpeg@${RELEASE}.service`, 'active'], [`openre-jsmpeg@${OLD}.service`, 'inactive'], [`openre-webrtc@${RELEASE}.service`, 'active']]);
const lists = host.calls.filter((c) => c.cmd === 'systemctl' && c.args[0] === 'list-units');
const lists = host.calls.filter((c) => c.cmd === 'systemctl' && c.args[0] === 'list-units');
assert.deepStrictEqual(lists[0].args, ['list-units', '--all', '--plain', '--no-legend', '--no-pager', 'openre-rtmp-ingest@*.service']);
assert.deepStrictEqual(lists[0].args, ['list-units', '--all', '--plain', '--no-legend', '--no-pager', 'openre-rtmp-ingest@*.service']);
assert.ok(lists.every((c) => !c.privileged), 'listing needs no privileges');
assert.ok(lists.every((c) => !c.privileged), 'listing needs no privileges');
@@ -132,7 +138,7 @@ runTests([
@@ -132,7 +138,7 @@ runTests([
let host = await openreHost();
let host = await openreHost();
let res = JSON.parse((await host.cli('validate', 'openre', '--json')).out);
let res = JSON.parse((await host.cli('validate', 'openre', '--json')).out);
const workers = res.findings.filter((f) => f.area === 'units' && /^worker /.test(f.message));
const workers = res.findings.filter((f) => f.area === 'units' && /^worker /.test(f.message));
- assert.deepStrictEqual(workers.map((f) => f.level), ['info', 'info', 'info', 'info', 'info']);
+ assert.deepStrictEqual(workers.map((f) => f.level), ['info', 'info', 'info', 'info', 'info', 'info']);
assert.match(workers[0].message, /never starts, stops or restarts it/);
assert.match(workers[0].message, /never starts, stops or restarts it/);
assert.ok(!res.findings.some((f) => /no running instance/.test(f.message)));
assert.ok(!res.findings.some((f) => /no running instance/.test(f.message)));
assert.deepStrictEqual(stateChanges(host), []);
assert.deepStrictEqual(stateChanges(host), []);
@@ -142,6 +148,7 @@ runTests([
@@ -142,6 +148,7 @@ runTests([
['warn', 'no running instance of worker unit [email protected]'],
['warn', 'no running instance of worker unit [email protected]'],
['warn', 'no running instance of worker unit [email protected]'],
['warn', 'no running instance of worker unit [email protected]'],
['warn', 'no running instance of worker unit [email protected]'],
['warn', 'no running instance of worker unit [email protected]'],
+ ['warn', 'no running instance of worker unit [email protected]'],
]);
]);
assert.deepStrictEqual(stateChanges(host), []);
assert.deepStrictEqual(stateChanges(host), []);
assert.ok(!JSON.stringify(res).includes(SECRET));
assert.ok(!JSON.stringify(res).includes(SECRET));