-
Notifications
You must be signed in to change notification settings - Fork 207
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(swingset): add controller.terminateVat(vatID, reason) (#9253)
This new API allows the host application to terminate any vat for which is knows the VatID (which must be gleaned manually from logs or the database). This might be useful if the normal vat code is unable or unwilling to terminate the vat, or if you need to trigger termination at some specific point in time. closes #8687
- Loading branch information
Showing
5 changed files
with
172 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
27 changes: 27 additions & 0 deletions
27
packages/SwingSet/test/external-termination/bootstrap-external-termination.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
import { Far, E } from '@endo/far'; | ||
|
||
export function buildRootObject() { | ||
let vatAdmin; | ||
let bcap; | ||
let root; | ||
let adminNode; | ||
let exitval; | ||
|
||
return Far('root', { | ||
bootstrap: async (vats, devices) => { | ||
vatAdmin = await E(vats.vatAdmin).createVatAdminService(devices.vatAdmin); | ||
bcap = await E(vatAdmin).getNamedBundleCap('doomed'); | ||
const res = await E(vatAdmin).createVat(bcap); | ||
root = res.root; | ||
adminNode = res.adminNode; | ||
E(adminNode) | ||
.done() | ||
.then( | ||
happy => (exitval = ['fulfill', happy]), | ||
sad => (exitval = ['reject', sad]), | ||
); | ||
}, | ||
ping: async count => E(root).ping(count), | ||
getExitVal: () => exitval, | ||
}); | ||
} |
80 changes: 80 additions & 0 deletions
80
packages/SwingSet/test/external-termination/external-termination.test.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
// eslint-disable-next-line import/order | ||
import { test } from '../../tools/prepare-test-env-ava.js'; | ||
|
||
import { initSwingStore } from '@agoric/swing-store'; | ||
import { kser, kunser } from '@agoric/kmarshal'; | ||
import { initializeSwingset, makeSwingsetController } from '../../src/index.js'; | ||
|
||
const bfile = name => new URL(name, import.meta.url).pathname; | ||
|
||
const testExternalTermination = async (t, defaultManagerType) => { | ||
/** @type {SwingSetConfig} */ | ||
const config = { | ||
defaultManagerType, | ||
bootstrap: 'bootstrap', | ||
vats: { | ||
bootstrap: { sourceSpec: bfile('./bootstrap-external-termination.js') }, | ||
}, | ||
bundles: { | ||
doomed: { sourceSpec: bfile('./vat-doomed.js') }, | ||
}, | ||
}; | ||
|
||
const kernelStorage = initSwingStore().kernelStorage; | ||
await initializeSwingset(config, [], kernelStorage); | ||
const c = await makeSwingsetController(kernelStorage); | ||
t.teardown(c.shutdown); | ||
c.pinVatRoot('bootstrap'); | ||
await c.run(); | ||
|
||
const getVatIDs = () => c.dump().vatTables.map(vt => vt.vatID); | ||
|
||
// vat-doomed should now be running. We casually assume the new vat | ||
// has the last ID | ||
const vatIDs = getVatIDs(); | ||
const vatID = vatIDs[vatIDs.length - 1]; | ||
|
||
{ | ||
const kpid = c.queueToVatRoot('bootstrap', 'ping', [1]); | ||
await c.run(); | ||
t.is(kunser(c.kpResolution(kpid)), 1); | ||
} | ||
{ | ||
const kpid = c.queueToVatRoot('bootstrap', 'getExitVal'); | ||
await c.run(); | ||
t.is(kunser(c.kpResolution(kpid)), undefined); | ||
} | ||
|
||
// The "vat has been terminated" flags are set synchronously during | ||
// c.terminateVat(), as well as all the vat's promises being | ||
// rejected. The deletion of state happens during the first cleanup | ||
// crank, which (since we aren't limiting it with a runPolicy) | ||
// cleans to completion during this c.run() | ||
|
||
c.terminateVat(vatID, kser('doom!')); | ||
await c.run(); | ||
|
||
t.false(getVatIDs().includes(vatID)); | ||
|
||
{ | ||
// this provokes noise: liveslots logs one RemoteError | ||
const kpid = c.queueToVatRoot('bootstrap', 'ping', [1]); | ||
await c.run(); | ||
t.is(c.kpStatus(kpid), 'rejected'); | ||
t.deepEqual(kunser(c.kpResolution(kpid)), Error('vat terminated')); | ||
} | ||
|
||
{ | ||
const kpid = c.queueToVatRoot('bootstrap', 'getExitVal'); | ||
await c.run(); | ||
t.deepEqual(kunser(c.kpResolution(kpid)), ['reject', 'doom!']); | ||
} | ||
}; | ||
|
||
test('external termination: local worker', async t => { | ||
await testExternalTermination(t, 'local'); | ||
}); | ||
|
||
test('external termination: xsnap worker', async t => { | ||
await testExternalTermination(t, 'xsnap'); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
import { Far } from '@endo/far'; | ||
|
||
export function buildRootObject() { | ||
return Far('doomed', { | ||
ping: count => count, | ||
}); | ||
} |