-
Notifications
You must be signed in to change notification settings - Fork 7
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: proposal pre/post test steps #210
Changes from 25 commits
2660fec
8e3f3e4
df80864
0554920
5d4e465
2c94fef
a689ecc
61371f5
9f24947
3d6780c
5b4c029
608e2da
0ee2a77
7ad7d92
f55ef1f
8b22861
b89fe4f
6d5c227
f121f67
679a083
f983826
36a2a20
5d54940
ef3d10b
963e59f
1a137a4
12c5042
ac2c07b
b34bdb6
73a9c4b
9d67bc1
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
@@ -1,7 +1,29 @@ | ||||||
import { execSync } from 'node:child_process'; | ||||||
import { realpathSync } from 'node:fs'; | ||||||
import { spawnSync } from 'node:child_process'; | ||||||
import { existsSync, realpathSync } from 'node:fs'; | ||||||
import { basename, resolve as resolvePath } from 'node:path'; | ||||||
import { fileSync as createTempFile } from 'tmp'; | ||||||
import { ProposalInfo, imageNameForProposal } from './proposals.js'; | ||||||
|
||||||
const createMessageFile = (proposal: ProposalInfo) => | ||||||
createTempFile({ prefix: proposal.proposalName }); | ||||||
|
||||||
const executeHostScriptIfPresent = ( | ||||||
extraEnv: typeof process.env, | ||||||
proposal: ProposalInfo, | ||||||
scriptName: string, | ||||||
) => { | ||||||
const scriptPath = `${resolvePath('.')}/proposals/${proposal.path}/host/${scriptName}`; | ||||||
if (existsSync(scriptPath)) { | ||||||
console.log( | ||||||
`Running script ${scriptName} for proposal ${proposal.proposalName}`, | ||||||
); | ||||||
spawnSync(scriptPath, { | ||||||
env: { ...process.env, ...extraEnv }, | ||||||
stdio: 'inherit', | ||||||
}); | ||||||
} | ||||||
}; | ||||||
|
||||||
/** | ||||||
* Used to propagate a SLOGFILE environment variable into Docker containers. | ||||||
* Any file identified by such a variable will be created if it does not already | ||||||
|
@@ -14,40 +36,101 @@ const propagateSlogfile = env => { | |||||
const { SLOGFILE } = env; | ||||||
if (!SLOGFILE) return []; | ||||||
|
||||||
execSync('touch "$SLOGFILE"'); | ||||||
return ['-e', 'SLOGFILE', '-v', `"$SLOGFILE:${realpathSync(SLOGFILE)}"`]; | ||||||
spawnSync('touch', [SLOGFILE]); | ||||||
|
||||||
return [ | ||||||
'--env', | ||||||
`SLOGFILE=${SLOGFILE}`, | ||||||
'--volume', | ||||||
`${SLOGFILE}:${realpathSync(SLOGFILE)}`, | ||||||
]; | ||||||
}; | ||||||
|
||||||
export const runTestImage = (proposal: ProposalInfo) => { | ||||||
console.log(`Running test image for proposal ${proposal.proposalName}`); | ||||||
const { name } = imageNameForProposal(proposal, 'test'); | ||||||
const slogOpts = propagateSlogfile(process.env); | ||||||
// 'rm' to remove the container when it exits | ||||||
const cmd = `docker run ${slogOpts.join(' ')} --rm ${name}`; | ||||||
execSync(cmd, { stdio: 'inherit' }); | ||||||
export const runTestImage = ({ | ||||||
extraDockerArgs = [], | ||||||
proposal, | ||||||
removeContainerOnExit = true, | ||||||
}: { | ||||||
extraDockerArgs?: Array<string>; | ||||||
proposal: ProposalInfo; | ||||||
removeContainerOnExit?: boolean; | ||||||
}) => { | ||||||
const { name: messageFilePath, removeCallback: removeTempFileCallback } = | ||||||
createMessageFile(proposal); | ||||||
const messageFileName = basename(messageFilePath); | ||||||
|
||||||
const containerFilePath = `/root/${messageFileName}`; | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I thought we would have the message file in the container use a static name (not even related to the proposal name) to avoid having to plumb an extra env. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Container file doesn't necessarily need to use the proposal name in it's path, but we still need to pass the host file path to the host start script so that the follower can mount that file in it's container There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Right but the code above will make the container file name dynamic, without any way for the container script to figure out what that name is. Or am I missing something? |
||||||
|
||||||
try { | ||||||
executeHostScriptIfPresent( | ||||||
{ | ||||||
MESSAGE_FILE_PATH: messageFilePath, | ||||||
}, | ||||||
proposal, | ||||||
'before-test-run.sh', | ||||||
); | ||||||
|
||||||
console.log(`Running test image for proposal ${proposal.proposalName}`); | ||||||
const { name } = imageNameForProposal(proposal, 'test'); | ||||||
spawnSync( | ||||||
'docker', | ||||||
[ | ||||||
'run', | ||||||
'--env', | ||||||
`MESSAGE_FILE_PATH=${containerFilePath}`, | ||||||
'--mount', | ||||||
`source=${messageFilePath},target=${containerFilePath},type=bind`, | ||||||
'--network', | ||||||
'host', | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm pretty sure this is a bad idea. Why do we need to hook onto the host network interfaces? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If we don't use There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't understand. How is different IPs different than different ports? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I never submitted this last week, but for future reference:
|
||||||
removeContainerOnExit && '--rm', | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. To avoid the
Suggested change
|
||||||
...propagateSlogfile(process.env), | ||||||
...extraDockerArgs, | ||||||
name, | ||||||
] | ||||||
.filter(Boolean) | ||||||
.map(String), | ||||||
{ stdio: 'inherit' }, | ||||||
); | ||||||
|
||||||
executeHostScriptIfPresent( | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. So at this point our tests are being executed inside container, right? |
||||||
{ | ||||||
MESSAGE_FILE_PATH: messageFilePath, | ||||||
}, | ||||||
proposal, | ||||||
'after-test-run.sh', | ||||||
); | ||||||
} catch (err) { | ||||||
removeTempFileCallback(); | ||||||
throw err; | ||||||
} | ||||||
mhofman marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||
}; | ||||||
|
||||||
export const debugTestImage = (proposal: ProposalInfo) => { | ||||||
const { name } = imageNameForProposal(proposal, 'test'); | ||||||
console.log( | ||||||
` | ||||||
Starting chain of test image for proposal ${proposal.proposalName} | ||||||
|
||||||
To get an interactive shell in the container, use an IDE feature like "Attach Shell" or this command:' | ||||||
|
||||||
docker exec -ti $(docker ps -q -f ancestor=${name}) bash | ||||||
|
||||||
And within that shell: | ||||||
cd /usr/src/proposals/${proposal.path} && ./test.sh | ||||||
|
||||||
To edit files you can use terminal tools like vim, or mount the container in your IDE. | ||||||
In VS Code the command is: | ||||||
Dev Containers: Attach to Running Container... | ||||||
`, | ||||||
); | ||||||
|
||||||
const slogOpts = propagateSlogfile(process.env); | ||||||
// start the chain with ports mapped | ||||||
const cmd = `docker run ${slogOpts.join(' ')} --publish 26657:26657 --publish 1317:1317 --publish 9090:9090 --interactive --tty --entrypoint /usr/src/upgrade-test-scripts/start_agd.sh ${name}`; | ||||||
execSync(cmd, { stdio: 'inherit' }); | ||||||
return runTestImage({ | ||||||
extraDockerArgs: [ | ||||||
'--entrypoint', | ||||||
'/usr/src/upgrade-test-scripts/start_agd.sh', | ||||||
'--interactive', | ||||||
'--tty', | ||||||
], | ||||||
proposal, | ||||||
removeContainerOnExit: false, | ||||||
}); | ||||||
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's be more explicit about what the
host
folder is for. There has been some confusion: Agoric/agoric-sdk#10947 (comment)While you're at it a change like this would help,
This is not blocking feedback. If something is delayed by this PR the docs improvements can come later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added