Skip to content
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: push completed image #11

Merged
merged 3 commits into from
Nov 6, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 44 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,12 @@ concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

env:
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository }}

jobs:
# see https://docs.docker.com/build/ci/github-actions/test-before-push/
test-proposals:
runs-on: ubuntu-latest
timeout-minutes: 60
Expand All @@ -29,12 +34,49 @@ jobs:
sudo rm -rf "$AGENT_TOOLSDIRECTORY"
echo "=== After cleanup:"
df -h
- uses: actions/checkout@v3

- name: Checkout repository
uses: actions/checkout@v4

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3

- name: Log in to the Container registry
uses: docker/login-action@v3
# see https://docs.github.com/en/actions/publishing-packages/publishing-docker-images
with:
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
registry: ${{ env.REGISTRY }}

- name: Extract metadata (tags, labels) for Docker
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}

# The .ts scripts depend upon this
- run: yarn global add tsx

- name: build test images
run: ./buildTestImages.ts
run: |
docker info
./buildTestImages.ts
- name: run test images
run: ./runTestImages.ts

# XXX this should be instant because all the stages were already built in the steps above
# but it's re-building the last stage. This is deemed good enough for now.
# see https://github.com/moby/moby/issues/34715
- name: Build and push complete image
uses: docker/build-push-action@v5
with:
context: .
# push to registry on every repo push. A PR #2 will push with tag `pr-2` and `main` will have tag `main`.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When should I expect :latest to get updated? Is :latest a thing at all in this workflow?

In ci logs, I see

#73 pushing manifest for ghcr.io/agoric/agoric-3-proposals:pr-11@sha256:0f8745ce487cf505d545e5fcc98266583928baba42dac7336e43ade30c801144 2.0s done

I tried docker pull ghcr.io/agoric/agoric-3-proposals:latest... I got something, but it doesn't match:

latest: Pulling from agoric/agoric-3-proposals
Digest: sha256:af7b4c7936c836e63e03ea797923513d81d48279de09397659976e4927f1e27c
Status: Image is up to date for ghcr.io/agoric/agoric-3-proposals:latest
ghcr.io/agoric/agoric-3-proposals:latest

I then tried docker pull ghcr.io/agoric/agoric-3-proposals:pr-11 and it matched, after downloading a bunch of stuff:

pulling agoric-3-proposals:pr-11
pr-11: Pulling from agoric/agoric-3-proposals
6a70103cc499: Already exists 
ccb4221e2c63: Already exists 
9fe6e67e69c8: Already exists 
ea30286b46fb: Already exists 
f75d822ab76b: Already exists 
2a87910e6b0c: Already exists 
ab305ba4cb89: Already exists 
88cbdb8927c8: Already exists 
834c64460156: Already exists 
4f4fb700ef54: Pulling fs layer 
7e8324770d8b: Already exists 
e192c61a6def: Already exists 
c1d4948858f7: Already exists 
5a814c9274ba: Already exists 
346b2a71a005: Already exists 
ab4ff57efef0: Already exists 
a03ddbfe4d35: Already exists 
10adcfe6c382: Already exists 
4f4fb700ef54: Pull complete 
d09e22f9ea6a: Already exists 
12b856665564: Already exists 
e9b5f3e6f97d: Already exists 
facabfcce2e2: Pull complete 
e4439afb5d15: Pull complete 
56d24d137f12: Pull complete 
8fe61e7e41f7: Pull complete 
7f80f1216b96: Pull complete 
ae78e7f4d96c: Pull complete 
98c37641cd3b: Pull complete 
2f4b49cbabcf: Pull complete 
455ff1e7f43e: Pull complete 
a0cd10d7f86b: Pull complete 
381fe0cf8d26: Pull complete 
fe815550ea19: Pull complete 
Digest: sha256:0f8745ce487cf505d545e5fcc98266583928baba42dac7336e43ade30c801144
Status: Downloaded newer image for ghcr.io/agoric/agoric-3-proposals:pr-11
ghcr.io/agoric/agoric-3-proposals:pr-11

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

latest was a thing in an earlier revision of this PR. I took it out because the term is generally used for "latest release" and there's no release. The defaults of this step are to use the default branch name (main) which I think is clearer. I'll document in README.

# See https://github.com/docker/metadata-action?tab=readme-ov-file#basic.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yay for breadcrumbs!

push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
- name: notify on failure
if: failure() && github.event_name != 'pull_request'
uses: ./.github/actions/notify-status
Expand Down
10 changes: 5 additions & 5 deletions buildTestImages.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
#!/usr/bin/env tsx
// @ts-check

import { parseArgs } from 'node:util';
import { execSync } from 'node:child_process';
Expand All @@ -11,7 +10,7 @@ refreshDockerfile();
const options = {
match: { short: 'm', type: 'string' },
dry: { type: 'boolean' },
};
} as const;
const { values } = parseArgs({ options });

const { match, dry } = values;
Expand All @@ -27,10 +26,11 @@ for (const proposal of proposals) {
console.log(`\nBuilding test image for proposal ${proposal.proposalName}`);
}
const { name, target } = imageNameForProposalTest(proposal);
const cmd = `docker build --tag ${name} --target ${target} .`;
// 'load' to ensure the images are output to the Docker client. Seems to be necessary
// for the CI docker/build-push-action to re-use the cached stages.
const cmd = `docker buildx build --load --tag ${name} --target ${target} .`;
console.log(cmd);
if (!dry) {
// TODO stream the output
execSync(cmd);
execSync(cmd, { stdio: 'inherit' });
}
}
17 changes: 16 additions & 1 deletion makeDockerfile.ts
Original file line number Diff line number Diff line change
Expand Up @@ -135,10 +135,22 @@ RUN ./run_use.sh ${proposalIdentifier}:${proposalName}
# TEST ${proposalName}
FROM use-${proposalName} as test-${proposalName}

# XXX the test files were already copied in the "use" stage
WORKDIR /usr/src/upgrade-test-scripts
SHELL ["/bin/bash", "-c"]
ENTRYPOINT ./run_test.sh ${proposalIdentifier}:${proposalName}
`;
},
/**
* The last target in the file, for untargeted `docker build`
*/
DEFAULT(lastProposal: ProposalInfo) {
return `
# DEFAULT
FROM use-${lastProposal.proposalName}

WORKDIR /usr/src/upgrade-test-scripts
SHELL ["/bin/bash", "-c"]
ENTRYPOINT ./start_agd.sh
`;
},
};
Expand Down Expand Up @@ -166,10 +178,13 @@ for (const proposal of readProposals()) {
blocks.push(stage.EXECUTE(proposal));
}

// The stages must be output in dependency order because if the builder finds a FROM
// that it hasn't built yet, it will search for it in the registry. But it won't be there!
blocks.push(stage.USE(proposal));
blocks.push(stage.TEST(proposal));
previousProposal = proposal;
}
blocks.push(stage.DEFAULT(previousProposal!));

export function refreshDockerfile() {
const contents = blocks.join('\n');
Expand Down
6 changes: 2 additions & 4 deletions runTestImages.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
#!/usr/bin/env tsx
// @ts-check

import { parseArgs } from 'node:util';
import { execSync } from 'node:child_process';
import { imageNameForProposalTest, readProposals } from './common';

const options = {
match: { short: 'm', type: 'string' },
};
} as const;
const { values } = parseArgs({ options });

const { match } = values;
Expand All @@ -23,6 +22,5 @@ for (const proposal of proposals) {
const { name } = imageNameForProposalTest(proposal);
// 'rm' to remove the container when it exits
const cmd = `docker run --rm ${name}`;
// TODO stream the output
execSync(cmd);
execSync(cmd, { stdio: 'inherit' });
}
11 changes: 11 additions & 0 deletions upgrade-test-scripts/start_agd.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#!/bin/bash
# Start and leave agd running

grep -qF 'env_setup.sh' /root/.bashrc || echo "source /usr/src/upgrade-test-scripts/env_setup.sh" >>/root/.bashrc
grep -qF 'printKeys' /root/.bashrc || echo "printKeys" >>/root/.bashrc

source ./env_setup.sh

export SLOGFILE=slog.slog

startAgd
83 changes: 39 additions & 44 deletions upgrade-test-scripts/start_to_to.sh
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#!/bin/bash
# Prepare or execute an upgrade

grep -qF 'env_setup.sh' /root/.bashrc || echo "source /usr/src/upgrade-test-scripts/env_setup.sh" >>/root/.bashrc
grep -qF 'printKeys' /root/.bashrc || echo "printKeys" >>/root/.bashrc
Expand All @@ -9,52 +10,46 @@ export SLOGFILE=slog.slog

startAgd

if [[ "$DEST" != "1" ]]; then
#Destined for an upgrade
if [[ -z "${UPGRADE_TO}" ]]; then
echo "no upgrade set. running for a few blocks and exiting"
waitForBlock 5
exit 0
fi
if [[ -z "${UPGRADE_TO}" ]]; then
echo "no upgrade set. running for a few blocks and exiting"
waitForBlock 5
exit 0
fi

voting_period_s=10
latest_height=$(agd status | jq -r .SyncInfo.latest_block_height)
height=$((latest_height + voting_period_s + 10))
info=${UPGRADE_INFO-"{}"}
if echo "$info" | jq .; then
echo "upgrade-info: $info"
else
status=$?
echo "Upgrade info is not valid JSON: $info"
exit $status
fi
agd tx gov submit-proposal software-upgrade "$UPGRADE_TO" \
--upgrade-height="$height" --upgrade-info="$info" \
--title="Upgrade to ${UPGRADE_TO}" --description="upgrades" \
--from=validator --chain-id="$CHAINID" \
--yes --keyring-backend=test
waitForBlock

voting_period_s=10
voteLatestProposalAndWait

echo "Chain in to-be-upgraded state for $UPGRADE_TO"

while true; do
latest_height=$(agd status | jq -r .SyncInfo.latest_block_height)
height=$((latest_height + voting_period_s + 10))
info=${UPGRADE_INFO-"{}"}
if echo "$info" | jq .; then
echo "upgrade-info: $info"
if [ "$latest_height" != "$height" ]; then
echo "Waiting for upgrade height for $UPGRADE_TO to be reached (need $height, have $latest_height)"
sleep 1
else
status=$?
echo "Upgrade info is not valid JSON: $info"
exit $status
echo "Upgrade height for $UPGRADE_TO reached. Killing agd"
echo "(CONSENSUS FAILURE above for height $height is expected)"
break
fi
agd tx gov submit-proposal software-upgrade "$UPGRADE_TO" \
--upgrade-height="$height" --upgrade-info="$info" \
--title="Upgrade to ${UPGRADE_TO}" --description="upgrades" \
--from=validator --chain-id="$CHAINID" \
--yes --keyring-backend=test
waitForBlock

voteLatestProposalAndWait

echo "Chain in to-be-upgraded state for $UPGRADE_TO"

while true; do
latest_height=$(agd status | jq -r .SyncInfo.latest_block_height)
if [ "$latest_height" != "$height" ]; then
echo "Waiting for upgrade height for $UPGRADE_TO to be reached (need $height, have $latest_height)"
sleep 1
else
echo "Upgrade height for $UPGRADE_TO reached. Killing agd"
echo "(CONSENSUS FAILURE above for height $height is expected)"
break
fi
done

sleep 2
killAgd
echo "state directory $HOME/.agoric ready for upgrade to $UPGRADE_TO"
else
done

waitAgd
fi
sleep 2
killAgd
echo "state directory $HOME/.agoric ready for upgrade to $UPGRADE_TO"