pungi/pungi/scripts/wait_for_signed_ostree_hand...

111 lines
3.2 KiB
Python

# -*- coding: utf-8 -*-
"""
Messaging hook to block compose progress until an ostree commit is signed.
The signing is implemented by robosignatory, which listens on the message bus
and reacts to messages about new commits. It will create a signature and then
update the ref in the repo to point to the new commit.
This script should not be used if Pungi is updating the reference on its own
(since that does not leave time for the signature).
"""
from __future__ import print_function
import argparse
import datetime
import json
import os
import sys
import time
import fedora_messaging.api
import fedora_messaging.exceptions
RESEND_INTERVAL = 300 # In seconds
SLEEP_TIME = 5
def is_ref_updated(ref_file, commit):
"""The ref is updated when the file points to the correct commit."""
try:
with open(ref_file) as f:
return f.read().strip() == commit
except IOError:
# Failed to open the file, probably it does not exist, so let's just
# wait more.
return False
def ts_log(msg):
print("%s: %s" % (datetime.datetime.utcnow(), msg))
def send(cmd, data):
topic = "compose.%s" % cmd.replace("-", ".").lower()
try:
msg = fedora_messaging.api.Message(topic="pungi.{}".format(topic), body=data)
fedora_messaging.api.publish(msg)
except fedora_messaging.exceptions.PublishReturned as e:
print("Fedora Messaging broker rejected message %s: %s" % (msg.id, e))
sys.exit(1)
except fedora_messaging.exceptions.ConnectionException as e:
print("Error sending message %s: %s" % (msg.id, e))
sys.exit(1)
except Exception as e:
print("Error sending fedora-messaging message: %s" % e)
sys.exit(1)
def main():
parser = argparse.ArgumentParser()
parser.add_argument("cmd")
parser.add_argument(
"--config",
dest="config",
help="fedora-messaging configuration file to use. "
"This allows overriding the default "
"/etc/fedora-messaging/config.toml.",
)
opts = parser.parse_args()
if opts.cmd != "ostree":
# Not an announcement of new ostree commit, nothing to do.
sys.exit()
if opts.config:
fedora_messaging.config.conf.load_config(opts.config)
try:
data = json.load(sys.stdin)
except ValueError:
print("Failed to decode data", file=sys.stderr)
sys.exit(1)
repo = data["local_repo_path"]
commit = data["commitid"]
if not commit:
print("No new commit was created, nothing will get signed.")
sys.exit(0)
path = "%s/objects/%s/%s.commitmeta" % (repo, commit[:2], commit[2:])
def wait_for(msg, test, *args):
time_slept = 0
while not test(*args):
ts_log(msg)
time_slept += SLEEP_TIME
if time_slept >= RESEND_INTERVAL:
ts_log("Repeating notification")
send(opts.cmd, data)
time_slept = 0
time.sleep(SLEEP_TIME)
wait_for("Commit not signed yet", os.path.exists, path)
ts_log("Found signature, waiting for ref to be updated.")
ref_file = os.path.join(repo, "refs/heads", data["ref"])
wait_for("Ref is not yet up-to-date", is_ref_updated, ref_file, commit)
ts_log("Ref is up-to-date. All done!")