Send notification when compose fails to start

This is tricky as this early in the process we don't know the compose
ID. The new message gives the full command line that was called.

Relates: #439
Signed-off-by: Lubomír Sedlář <lsedlar@redhat.com>
This commit is contained in:
Lubomír Sedlář 2016-10-20 09:23:10 +02:00
parent 6e55cc6419
commit 74aa41f8bd
3 changed files with 38 additions and 18 deletions

View File

@ -121,32 +121,43 @@ def main():
)
opts, args = parser.parse_args()
import pungi.notifier
notifier = pungi.notifier.PungiNotifier(opts.notification_script)
def fail_to_start(msg, **kwargs):
notifier.send('fail-to-start', workdir=opts.target_dir,
command=sys.argv, target_dir=opts.target_dir,
config=opts.config, detail=msg, **kwargs)
def abort(msg):
fail_to_start(msg)
parser.error(msg)
if opts.version:
print("pungi %s" % get_full_version())
sys.exit(0)
if opts.target_dir and opts.compose_dir:
parser.error("cannot specify --target-dir and --compose-dir at once")
abort("cannot specify --target-dir and --compose-dir at once")
if not opts.target_dir and not opts.compose_dir:
parser.error("please specify a target directory")
abort("please specify a target directory")
if opts.target_dir and not opts.compose_dir:
opts.target_dir = os.path.abspath(opts.target_dir)
if not os.path.isdir(opts.target_dir):
parser.error("The target directory does not exist or is not a directory: %s" % opts.target_dir)
abort("The target directory does not exist or is not a directory: %s" % opts.target_dir)
else:
opts.compose_dir = os.path.abspath(opts.compose_dir)
if not os.path.isdir(opts.compose_dir):
parser.error("The compose directory does not exist or is not a directory: %s" % opts.compose_dir)
abort("The compose directory does not exist or is not a directory: %s" % opts.compose_dir)
compose_type = opts.compose_type or "production"
if compose_type == "production" and not opts.label and not opts.no_label:
parser.error("must specify label for a production compose")
abort("must specify label for a production compose")
if not opts.config:
parser.error("please specify a config")
abort("please specify a config")
opts.config = os.path.abspath(opts.config)
import kobo.conf
@ -157,10 +168,9 @@ def main():
try:
productmd.composeinfo.verify_label(opts.label)
except ValueError as ex:
parser.error(str(ex))
abort(str(ex))
from pungi.compose import Compose
import pungi.notifier
logger = logging.Logger("Pungi")
kobo.log.add_stderr_logger(logger)
@ -177,6 +187,7 @@ def main():
if errors:
for error in errors:
print >>sys.stderr, error
fail_to_start('Config validation failed', errors=errors)
sys.exit(1)
if opts.target_dir:
@ -184,8 +195,6 @@ def main():
else:
compose_dir = opts.compose_dir
notifier = pungi.notifier.PungiNotifier(opts.notification_script)
compose = Compose(conf,
topdir=compose_dir,
debug=opts.debug_mode,

View File

@ -12,6 +12,9 @@ happened. A JSON-encoded object will be passed to standard input to provide
more information about the event. At the very least, the object will contain a
``compose_id`` key.
The script is invoked in compose directory and can read other information
there.
Currently these messages are sent:
* ``status-change`` -- when composing starts, finishes or fails; a ``status``
@ -21,12 +24,12 @@ Currently these messages are sent:
* ``createiso-targets`` -- with a list of images to be created
* ``createiso-imagedone`` -- when any single image is finished
* ``createiso-imagefail`` -- when any single image fails to create
* ``fail-to-start`` -- when there are incorrect CLI options or errors in
configuration file; this message does not contain ``compose_id`` nor is it
started in the compose directory (which does not exist yet)
For phase related messages ``phase_name`` key is provided as well.
The script is invoked in compose directory and can read other information
there.
A ``pungi-fedmsg-notification`` script is provided and understands this
interface.

View File

@ -30,9 +30,12 @@ class PungiNotifier(object):
def __init__(self, cmd):
self.cmd = cmd
self.lock = threading.Lock()
self.compose = None
def _update_args(self, data):
"""Add compose related information to the data."""
if not self.compose:
return
data.setdefault('compose_id', self.compose.compose_id)
# Publish where in the world this compose will end up living
@ -40,7 +43,7 @@ class PungiNotifier(object):
self.compose, self.compose.paths.compose.topdir())
data.setdefault('location', location)
def send(self, msg, **kwargs):
def send(self, msg, workdir=None, **kwargs):
"""Send a message.
The actual meaning of ``msg`` depends on what the notification script
@ -55,13 +58,18 @@ class PungiNotifier(object):
self._update_args(kwargs)
if self.compose:
workdir = self.compose.paths.compose.topdir()
with self.lock:
self.compose.log_debug("Notification: %r %r, %r" % (
self.cmd, msg, kwargs))
if self.compose:
self.compose.log_debug("Notification: %r %r, %r" % (
self.cmd, msg, kwargs))
ret, _ = shortcuts.run((self.cmd, msg),
stdin_data=json.dumps(kwargs),
can_fail=True,
workdir=self.compose.paths.compose.topdir(),
workdir=workdir,
return_stdout=False)
if ret != 0:
self.compose.log_warning('Failed to invoke notification script.')
if self.compose:
self.compose.log_warning('Failed to invoke notification script.')