balena-supervisor/test/lib/dbus/systemd.ts

174 lines
3.7 KiB
TypeScript
Raw Normal View History

import * as DBus from 'dbus';
import { createSystemInterface } from './utils';
const systemdService = DBus.registerService(
'system',
'org.freedesktop.systemd1',
);
// Create the systemd
const systemd = createSystemInterface(
systemdService,
'/org/freedesktop/systemd1',
'org.freedesktop.systemd1.Manager',
);
type Unit = {
running: boolean;
path: string;
partOf?: string;
};
// Maintain the state of created units in memory
const units: { [key: string]: Unit } = {};
function createUnit(name: string, path: string, partOf?: string) {
// Each unit needs an object and a properties interface
const obj = systemdService.createObject(path);
const iface = obj.createInterface('org.freedesktop.DBus.Properties');
units[name] = { running: false, path, partOf };
// org.freedesktop.DBus.Properties needs a Get method to get the
// unit properties
iface.addMethod(
'Get',
{
in: [
{ type: 's', name: 'interface_name' },
{ type: 's', name: 'property_name' },
],
out: { type: 'v' },
} as any,
function (interfaceName, propertyName, callback: any) {
if (interfaceName !== 'org.freedesktop.systemd1.Unit') {
callback(`Unkown interface: ${interfaceName}`);
}
switch (propertyName) {
case 'ActiveState':
callback(null, units[name].running ? 'active' : 'inactive');
break;
case 'PartOf':
callback(partOf ?? 'none');
break;
default:
callback(`Unknown property: ${propertyName}`);
}
},
);
iface.update();
}
systemd.addMethod(
'StopUnit',
{
in: [
{ type: 's', name: 'unit_name' },
{ type: 's', name: 'mode' },
],
out: { type: 'o' },
} as any,
function (unitName, _mode, callback: any) {
if (!units[unitName]) {
callback(`Unit not found: ${unitName}`);
return;
}
// Wait a bit before changing the runtime state
setTimeout(() => {
units[unitName] = { ...units[unitName], running: false };
}, 500);
callback(
null,
`/org/freedesktop/systemd1/job/${String(
Math.floor(Math.random() * 10000),
)}`,
);
},
);
systemd.addMethod(
'StartUnit',
{
in: [
{ type: 's', name: 'unit_name' },
{ type: 's', name: 'mode' },
],
out: { type: 'o' },
} as any,
function (unitName, _mode, callback: any) {
if (!units[unitName]) {
callback(`Unit not found: ${unitName}`);
return;
}
// Wait a bit before changing the runtime state
setTimeout(() => {
units[unitName] = { ...units[unitName], running: true };
}, 500);
callback(
null,
// Make up a job number
`/org/freedesktop/systemd1/job/${String(
Math.floor(Math.random() * 10000),
)}`,
);
},
);
systemd.addMethod(
'RestartUnit',
{
in: [
{ type: 's', name: 'unit_name' },
{ type: 's', name: 'mode' },
],
out: { type: 'o' },
} as any,
function (unitName, _mode, callback: any) {
if (!units[unitName]) {
callback(`Unit not found: ${unitName}`);
return;
}
// Wait a bit before changing the runtime state
setTimeout(() => {
units[unitName] = { ...units[unitName], running: false };
}, 500);
setTimeout(() => {
units[unitName] = { ...units[unitName], running: true };
}, 1000);
callback(
null,
`/org/freedesktop/systemd1/job/${String(
Math.floor(Math.random() * 10000),
)}`,
);
},
);
systemd.addMethod(
'GetUnit',
{ in: [{ type: 's', name: 'unit_name' }], out: { type: 'o' } } as any,
function (unitName, callback) {
if (!units[unitName]) {
callback(`Unit not found: ${unitName}`);
return;
}
const { path } = units[unitName];
callback(null, path);
},
);
// Simulate OS units
createUnit('openvpn.service', '/org/freedesktop/systemd1/unit/openvpn');
createUnit('avahi.socket', '/org/freedesktop/systemd1/unit/avahi');
systemd.update();