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

tasks: Drop cockpit-tasks as main entry point, move tasks secrets from /secrets to /run/secrets/tasks, drop setup-tasks, add local mock PR test #585

Merged
merged 10 commits into from
Mar 5, 2024
Merged
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ tasks-shell:
$(DOCKER) run -ti --rm \
--shm-size=1024m \
--volume=$(CURDIR)/tasks:/usr/local/bin \
--volume=$(TASK_SECRETS):/secrets:ro \
--volume=$(TASK_SECRETS):/run/secrets/tasks/:ro \
Copy link
Member

Choose a reason for hiding this comment

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

...(drive by) this entire chunk seems pretty DRY-unfriendly vs. install-service...

Copy link
Member Author

Choose a reason for hiding this comment

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

Yeah, I know :/

--volume=$(WEBHOOK_SECRETS):/run/secrets/webhook/:ro \
--volume=$(TASK_CACHE):/cache:rw \
--entrypoint=/bin/bash \
Expand Down
14 changes: 13 additions & 1 deletion ansible/roles/tasks-systemd/tasks/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,22 @@
semodule -i /tmp/cockpituous.pp
when: selinux_policy.changed

# This only applies to RH VPN; make that optional if we ever deploy to public infrastructure
- name: Create npm configuration
copy:
dest: /etc/npmrc
mode: 0644
content: |
registry=https://repository.engineering.redhat.com/nexus/repository/registry.npmjs.org/
fetch-retries=6
fetch-timeout=600000
fetch-retry-mintimeout=60000
maxsockets=3
cafile=/run/secrets/tasks/npm-registry.crt

- name: Set up systemd service for cockpit/tasks
shell: |
export INSTANCES={{ instances | default(4) }}
export NPM_REGISTRY=https://repository.engineering.redhat.com/nexus/repository/registry.npmjs.org/
export TEST_NOTIFICATION_MX={{ notification_mx | default('') }}
export TEST_NOTIFICATION_TO={{ notification_to | default('') }}
/run/install-service
9 changes: 3 additions & 6 deletions tasks/Containerfile
Original file line number Diff line number Diff line change
Expand Up @@ -64,17 +64,15 @@ RUN dnf -y update && \
dnf clean all && \
pip install ruff

COPY setup-tasks cockpit-tasks install-service webhook github_handler.py /usr/local/bin/
COPY cockpit-tasks install-service webhook github_handler.py /usr/local/bin/

RUN groupadd -g 1111 -r user && useradd -r -g user -u 1111 user --home-dir /work && \
groupadd -g 1001 -r github && useradd -r --no-create-home -g github -u 1001 github && \
mkdir -p /usr/local/bin /secrets /cache/images /cache/github && \
mkdir -p /usr/local/bin /cache/images /cache/github && \
mkdir -p /work/.config /work/.config/cockpit-dev /work/.ssh /work/.cache /work/.rhel && \
printf '[user]\n\t\nemail = cockpituous@cockpit-project.org\n\tname = Cockpituous\n[cockpit "bots"]\n\timages-data-dir = /cache/images\n' >/work/.gitconfig && \
ln -snf /secrets/s3-keys /work/.config/cockpit-dev/s3-keys && \
ln -snf /run/secrets/webhook/.config--github-token /work/.config/github-token && \
chmod g=u /etc/passwd && \
chmod -R ugo+w /cache /secrets /cache /work && \
chmod -R ugo+w /cache /work && \
chown -R user:user /cache /work && \
printf '[libdefaults]\ndefault_ccache_name = FILE:/tmp/krb5.ccache\n' > /etc/krb5.conf.d/0_file_ccache && \
echo 'user ALL=NOPASSWD: /usr/bin/chmod 666 /dev/kvm' > /etc/sudoers.d/user-fix-kvm
Expand All @@ -86,4 +84,3 @@ VOLUME /cache/images

USER user
WORKDIR /work
CMD ["/usr/local/bin/cockpit-tasks", "--verbose"]
14 changes: 8 additions & 6 deletions tasks/build-secrets
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,10 @@ metadata:
data:
EOF
cd "$BASE/tasks"
for f in $(find -type f -o -type l); do
printf ' %s: %s\n' "$(echo $f | sed 's!^./!!; s!/!--!g')" "$(base64 --wrap=0 $f)"
# This intentionally does not capture subdirs like tasks/s3-keys/. As OpenShift secret volumes don't have subdirectories,
# these need to be created as a separate volume if and when we ever need that.
for f in $(find -maxdepth 1 -type f -o -type l); do
printf ' %s: %s\n' "${f#./}" "$(base64 --wrap=0 $f)"
Copy link
Member

Choose a reason for hiding this comment

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

I was going to suggest "that thing you can do with shell parameter expansion that drops prefixes" as another option, but I was too lazy to look it up ;)

done

# webhook secrets
Expand All @@ -31,8 +33,8 @@ metadata:
data:
EOF
cd "$BASE/webhook"
for f in $(find -type f -o -type l); do
printf ' %s: %s\n' "$(echo $f | sed 's!^./!!; s!/!--!g')" "$(base64 --wrap=0 $f)"
for f in $(find -maxdepth 1 -type f -o -type l); do
printf ' %s: %s\n' "${f#./}" "$(base64 --wrap=0 $f)"
done

# metrics secrets
Expand All @@ -46,6 +48,6 @@ metadata:
data:
EOF
cd "$BASE/metrics"
for f in $(find -type f -o -type l); do
printf ' %s: %s\n' "$(echo -e $f | sed 's!^./!!; s!/!--!g')" "$(tr -d '\n' < $f | base64 --wrap=0)"
for f in $(find -maxdepth 1 -type f -o -type l); do
printf ' %s: %s\n' "${f#./}" "$(tr -d '\n' < $f | base64 --wrap=0)"
done
2 changes: 0 additions & 2 deletions tasks/cockpit-tasks
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@

set -eux

setup-tasks

COCKPIT_BOTS_REPO=${COCKPIT_BOTS_REPO:-https://github.com/cockpit-project/bots}
COCKPIT_BOTS_BRANCH=${COCKPIT_BOTS_BRANCH:-main}

Expand Down
5 changes: 4 additions & 1 deletion tasks/cockpit-tasks-centosci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,11 @@ spec:
env:
- name: RUN_STATISTICS_QUEUE
value: '1'
- name: COCKPIT_GITHUB_TOKEN_FILE
value: /run/secrets/webhook/.config--github-token
volumeMounts:
- name: secrets
mountPath: "/secrets"
mountPath: /run/secrets/tasks
readOnly: true
- name: webhook-secrets
mountPath: /run/secrets/webhook
Expand All @@ -31,6 +33,7 @@ spec:
mountPath: "/cache"
- name: prometheus-data
mountPath: "/cache/images"
command: [ "cockpit-tasks" ]
resources:
limits:
memory: 1Gi
Expand Down
5 changes: 5 additions & 0 deletions tasks/cockpit-tasks-webhook.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,11 @@ spec:
- name: webhook-secrets
mountPath: /run/secrets/webhook
readOnly: true
env:
- name: COCKPIT_GITHUB_TOKEN_FILE
value: /run/secrets/webhook/.config--github-token
- name: COCKPIT_GITHUB_WEBHOOK_TOKEN_FILE
value: /run/secrets/webhook/.config--github-webhook-token
resources:
limits:
memory: 1G
Expand Down
2 changes: 1 addition & 1 deletion tasks/github_handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ def check_sig(self, request):
See https://developer.github.com/webhooks/securing/
'''
# load key
keyfile = os.path.expanduser('~/.config/github-webhook-token')
keyfile = os.getenv("COCKPIT_GITHUB_WEBHOOK_TOKEN_FILE", os.path.expanduser('~/.config/github-webhook-token'))
try:
with open(keyfile, 'rb') as f:
key = f.read().strip()
Expand Down
14 changes: 5 additions & 9 deletions tasks/install-service
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,6 @@ mkdir -p $SECRETS/tasks $SECRETS/webhook $CACHE
chown -R 1111:1111 $SECRETS $CACHE
chcon -R -t container_file_t $SECRETS $CACHE

if [ -e "${SECRETS}/tasks/npm-registry.crt" ]; then
NODE_EXTRA_CA_CERTS=/secrets/npm-registry.crt
fi

if [ $INSTANCES -eq 1 ]; then
# just use the hostname without prefix
CONTAINER_HOSTNAME="%l"
Expand All @@ -47,7 +43,6 @@ Environment="TEST_CACHE=$CACHE"
Environment="TEST_SECRETS=$SECRETS"
Environment="TEST_NOTIFICATION_MX=${TEST_NOTIFICATION_MX:-}"
Environment="TEST_NOTIFICATION_TO=${TEST_NOTIFICATION_TO:-}"
Environment="NPM_REGISTRY=${NPM_REGISTRY:-}"
Restart=always
RestartSec=60
# give image pull enough time
Expand All @@ -62,15 +57,16 @@ ExecStart=/usr/bin/podman run --name=cockpit-tasks-%i --hostname=${CONTAINER_HOS
--device=/dev/kvm --network=cockpit-tasks-%i \
--memory=24g --pids-limit=16384 --shm-size=1024m ${TMPVOL:-} \
--volume=\${TEST_CACHE}/images:/cache/images:rw \
--volume=\${TEST_SECRETS}/tasks:/secrets:ro \
--volume=\${TEST_SECRETS}/tasks:/run/secrets/tasks:ro \
Copy link
Member

Choose a reason for hiding this comment

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

I wonder if we could think a step ahead here and:

  • add /run/secrets/github-token as the 'authoritative' location for the token file
  • add /run/secrets/s3-keys as the location for the s3-keys directory

...and adjust the symlinks to point to those things. That's where we'll want to have those two things inside of containers spawned by job-runner, under control of the "secrets" attribute in the job definition.

Of course, we'd also continue to have the volume mount for secrets/webhook and secrets/tasks since we still use those at present. We might want to start thinking about what to do more generally with "external config" such as the npm-registry certificate, though... it's not really a secret.

Copy link
Member Author

Choose a reason for hiding this comment

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

No objection to the two extra volumes (and doing the same in run-local.sh). Do you want to do that in this PR?

I'm not sure if we can commit the npm registry internal RH mirror cert to a public place -- it's not really secret, but it applies to RH internal infrastructure only. TBH I wouldn't change that right now without at least some more checking.

Copy link
Member

Choose a reason for hiding this comment

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

I'd like to see the github-token and s3-keys bit in this PR. No time like the present!

The npm registry cert is a bit more interesting and it dovetails into the question about what to do with the npm config bits that current live in setup-tasks (which needs to die, I'm increasingly convinced)...

Copy link
Member Author

Choose a reason for hiding this comment

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

I didn't yet do this, instead used the env variables. Let's stabilize this version first, then I can take another look.

Copy link
Member

Choose a reason for hiding this comment

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

Sure. With the envvars, I care a lot less.

--volume=\${TEST_SECRETS}/webhook:/run/secrets/webhook:ro \
--volume=${IMAGE_STORES}:/work/.config/cockpit-dev/image-stores:ro \
--env=NPM_REGISTRY=\${NPM_REGISTRY} \
--env=NODE_EXTRA_CA_CERTS=${NODE_EXTRA_CA_CERTS:-} \
--volume=/etc/npmrc:/etc/npmrc:ro \
--env=COCKPIT_GITHUB_TOKEN_FILE=/run/secrets/webhook/.config--github-token \
--env=COCKPIT_S3_KEY_DIR=/run/secrets/tasks/s3-keys \
--env=TEST_JOBS=\${TEST_JOBS} \
--env=TEST_NOTIFICATION_MX=\${TEST_NOTIFICATION_MX} \
--env=TEST_NOTIFICATION_TO=\${TEST_NOTIFICATION_TO} \
quay.io/cockpit/tasks
quay.io/cockpit/tasks cockpit-tasks --verbose
ExecStop=/usr/bin/podman rm -f cockpit-tasks-%i
ExecStop=/usr/bin/podman network rm cockpit-tasks-%i

Expand Down
86 changes: 86 additions & 0 deletions tasks/mock-github-pr
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
#!/usr/bin/env python3
# Mock GitHub API server for testing an opened PR
# You can run this manually in `tasks/run-local.sh -i` with `podman cp` and running
# cd bots
# PYTHONPATH=. ./mock-github-pr cockpit-project/bots $(git rev-parse HEAD) &
# export GITHUB_API=http://127.0.0.7:8443
# PYTHONPATH=. ./mock-github-pr --print-event cockpit-project/bots $(git rev-parse HEAD) | \
# ./publish-queue --amqp localhost:5671 --queue webhook
#
# and then two `./run-queue --amqp localhost:5671`
# first to process webhook → tests-scan → public, second to actually run it

import argparse
import json
import os
import tempfile

from task.test_mock_server import MockHandler, MockServer

repo = None
sha = None


class Handler(MockHandler):
def do_GET(self):
if self.path in self.server.data:
self.replyJson(self.server.data[self.path])
elif self.path.startswith(f'/repos/{repo}/pulls?'):
self.replyJson([self.server.data[f'/repos/{repo}/pulls/1']])
elif self.path == f'/{repo}/{sha}/.cockpit-ci/container':
self.replyData('quay.io/cockpit/tasks')
else:
self.send_error(404, 'Mock Not Found: ' + self.path)

def do_POST(self):
if self.path.startswith(f'/repos/{repo}/statuses/{sha}'):
self.replyJson({})
else:
self.send_error(405, 'Method not allowed: ' + self.path)


argparser = argparse.ArgumentParser()
argparser.add_argument('--port', type=int, default=8443, help="Port to listen on (default: %(default)s)")
argparser.add_argument('--print-event', action='store_true', help="Print GitHub webhook pull_request event and exit")
argparser.add_argument('repo', metavar='USER/PROJECT', help="GitHub user/org and project name")
argparser.add_argument('sha', help="SHA to test in repo for the mock PR")
args = argparser.parse_args()
repo = args.repo
sha = args.sha

ADDRESS = ('127.0.0.7', args.port)

GITHUB_DATA = {
f'/repos/{repo}/pulls/1': {
'title': 'mock PR',
'number': 1,
'state': 'open',
'body': "This is the body",
'base': {'repo': {'full_name': repo}, 'ref': 'main'},
'head': {'sha': args.sha, 'user': {'login': repo.split('/')[0]}},
'labels': [],
'updated_at': 0,
},
f'/repos/{repo}/commits/{args.sha}/status?page=1&per_page=100': {
'state': 'pending',
'statuses': [],
'sha': sha,
},
}

if args.print_event:
print(json.dumps({
'event': 'pull_request',
'request': {
'action': 'opened',
'pull_request': GITHUB_DATA[f'/repos/{repo}/pulls/1']
}
}, indent=4))
exit(0)

temp = tempfile.TemporaryDirectory()
cache_dir = os.path.join(temp.name, 'cache')
os.environ['XDG_CACHE_HOME'] = cache_dir
server = MockServer(ADDRESS, Handler, GITHUB_DATA)
server.start()
print(f'export GITHUB_API=http://{ADDRESS[0]}:{ADDRESS[1]}')
Loading
Loading