From: Michael Tremer Date: Wed, 1 Nov 2023 09:14:28 +0000 (+0000) Subject: buildservice: Add function to signal finished build jobs X-Git-Tag: 0.9.30~1361 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=36835ffcd6adb0fd6c6b4b2dcb18e79c8fbe3bb1;p=pakfire.git buildservice: Add function to signal finished build jobs Signed-off-by: Michael Tremer --- diff --git a/src/_pakfire/buildservice.c b/src/_pakfire/buildservice.c index 9a1263206..67a401be0 100644 --- a/src/_pakfire/buildservice.c +++ b/src/_pakfire/buildservice.c @@ -69,6 +69,106 @@ static PyObject* BuildService_get_url(BuildServiceObject* self) { return PyUnicode_FromString(url); } +static int convert_packages(PyObject* object, void* data) { + char*** packages = data; + + // Called for cleanup + if (!object) + goto ERROR; + + // Nothing to do when object is None + if (object == Py_None) + return Py_CLEANUP_SUPPORTED; + + if (!PySequence_Check(object)) { + PyErr_SetString(PyExc_ValueError, "packages must be a sequence"); + goto ERROR; + } + + const unsigned int length = PySequence_Length(object); + if (!length) + return Py_CLEANUP_SUPPORTED; + + // Allocate array + *packages = calloc(length + 1, sizeof(*packages)); + if (!*packages) { + PyErr_SetFromErrno(PyExc_OSError); + goto ERROR; + } + + for (unsigned int i = 0; i < length; i++) { + PyObject* item = PySequence_GetItem(object, i); + + // Check if input is a string + if (!PyUnicode_Check(item)) { + Py_DECREF(item); + + PyErr_SetString(PyExc_AttributeError, "Expected a string"); + goto ERROR; + } + + // Fetch string + const char* package = PyUnicode_AsUTF8(item); + if (!package) { + Py_DECREF(item); + goto ERROR; + } + + // Add package to array + (*packages)[i] = strdup(package); + if (!(*packages)[i]) { + Py_DECREF(item); + goto ERROR; + } + + Py_DECREF(item); + } + + // Success + return Py_CLEANUP_SUPPORTED; + +ERROR: + if (*packages) { + for (char** package = *packages; *package; package++) + free(*package); + free(*packages); + } + + return 0; +} + +static PyObject* BuildService_job_finished(BuildServiceObject* self, PyObject* args, PyObject* kwargs) { + char* kwlist[] = { "uuid", "success", "logfile", "packages", NULL }; + const char* uuid = NULL; + int success = 0; + const char* logfile = NULL; + char** packages = NULL; + int r; + + // Parse arguments + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "sp|zO&", kwlist, &uuid, &success, + &logfile, convert_packages, &packages)) + return NULL; + + // Send request + r = pakfire_buildservice_job_finished(self->service, uuid, success, + logfile, (const char**)packages); + if (r) + goto ERROR; + +ERROR: + if (packages) { + for (char** package = packages; *package; package++) + free(*package); + free(packages); + } + + if (r) + return NULL; + + Py_RETURN_NONE; +} + static PyObject* BuildService_submit_stats(BuildServiceObject* self) { int r; @@ -116,6 +216,12 @@ ERROR: } static struct PyMethodDef BuildService_methods[] = { + { + "job_finished", + (PyCFunction)BuildService_job_finished, + METH_VARARGS|METH_KEYWORDS, + NULL, + }, { "submit_stats", (PyCFunction)BuildService_submit_stats, diff --git a/src/libpakfire/buildservice.c b/src/libpakfire/buildservice.c index 66d9816af..1634e7a72 100644 --- a/src/libpakfire/buildservice.c +++ b/src/libpakfire/buildservice.c @@ -1216,3 +1216,81 @@ ERROR: return r; } + +PAKFIRE_EXPORT int pakfire_buildservice_job_finished(struct pakfire_buildservice* service, + const char* uuid, int success, const char* logfile, const char** packages) { + struct pakfire_xfer* xfer = NULL; + char url[PATH_MAX]; + char* buffer = NULL; + size_t length = 0; + int r; + + struct json_object* response = NULL; + + unsigned int num_packages = 0; + + // Count packages + for (const char** package = packages; *package; packages++) + num_packages++; + + // Compose the URL + r = pakfire_string_format(url, "/api/v1/jobs/%s", uuid); + if (r) + goto ERROR; + + // Create a new xfer + r = pakfire_buildservice_create_xfer(&xfer, service, url); + if (r) + goto ERROR; + + // Enable authentication + r = pakfire_xfer_auth(xfer); + if (r) + goto ERROR; + + // Has the job been successful? + r = pakfire_xfer_add_param(xfer, "success", "%s", (success) ? "true" : "false"); + if (r) + goto ERROR; + + // Logfile + if (logfile) { + r = pakfire_xfer_add_param(xfer, "logfile", "%s", logfile); + if (r) + goto ERROR; + } + + // Packages + for (const char** package = packages; *package; package++) { + r = pakfire_xfer_add_param(xfer, "package", "%s", *package); + if (r) + goto ERROR; + } + + // Write the response to the buffer + r = pakfire_xfer_set_output_buffer(xfer, &buffer, &length); + if (r) + goto ERROR; + + // Run the xfer + r = pakfire_xfer_run(xfer, PAKFIRE_XFER_NO_PROGRESS); + if (r) + goto ERROR; + + // Parse the response + r = pakfire_buildservice_parse_response(service, xfer, buffer, length, &response); + if (r) { + CTX_ERROR(service->ctx, "Could not parse the response: %s\n", strerror(-r)); + goto ERROR; + } + +ERROR: + if (xfer) + pakfire_xfer_unref(xfer); + if (response) + json_object_put(response); + if (buffer) + free(buffer); + + return r; +} diff --git a/src/libpakfire/include/pakfire/buildservice.h b/src/libpakfire/include/pakfire/buildservice.h index d705aad18..af11bc6b3 100644 --- a/src/libpakfire/include/pakfire/buildservice.h +++ b/src/libpakfire/include/pakfire/buildservice.h @@ -67,4 +67,9 @@ int pakfire_buildservice_delete_repo(struct pakfire_buildservice* service, int pakfire_buildservice_submit_stats(struct pakfire_buildservice* service); +// Jobs + +int pakfire_buildservice_job_finished(struct pakfire_buildservice* service, + const char* uuid, int success, const char* logfile, const char** packages); + #endif /* PAKFIRE_BUILDSERVICE_H */ diff --git a/src/libpakfire/libpakfire.sym b/src/libpakfire/libpakfire.sym index fd416cd10..73fb3968d 100644 --- a/src/libpakfire/libpakfire.sym +++ b/src/libpakfire/libpakfire.sym @@ -98,6 +98,7 @@ global: pakfire_buildservice_delete_repo; pakfire_buildservice_get_url; pakfire_buildservice_submit_stats; + pakfire_buildservice_job_finished; # dependencies pakfire_static_version_compare; diff --git a/src/pakfire/buildservice.py b/src/pakfire/buildservice.py index f05acfd6b..08f9d5f87 100644 --- a/src/pakfire/buildservice.py +++ b/src/pakfire/buildservice.py @@ -23,6 +23,7 @@ import json import kerberos import logging import os + import subprocess import tempfile import tornado.httpclient @@ -429,22 +430,8 @@ class JobControlConnection(Connection): for package in packages: await self.service.upload(package) - while True: - try: - # Send the request - response = await self.service._request("POST", "/api/v1/jobs/%s/finished" % self.id, - success="1" if success else "0", logfile=logfile, packages=packages, - ) - - # Try again after a short moment on connection errors - except TemporaryConnectionError as e: - await asyncio.sleep(5) - - else: - break - - # Handle the response - # XXX TODO + # Send request + self.service.job_finished(self.id, success=success, logfile=logfile, packages=packages) async def log(self, timestamp, level, message): """