aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKaren Arutyunov <karen@codesynthesis.com>2024-05-26 13:46:55 +0300
committerKaren Arutyunov <karen@codesynthesis.com>2024-05-28 13:58:46 +0300
commita7ae434c48c14bfde46a871455a3aa2ac0b81376 (patch)
tree2d4f66a2e153842e166becfcbb2a820036faffcb
parent5e631e5f63fdc8528d5d178d6a66dfb32a2c0f8b (diff)
Add CI cancel handler
-rw-r--r--brep/handler/ci/ci-load.in20
-rw-r--r--mod/ci-common.cxx36
-rw-r--r--mod/ci-common.hxx30
-rw-r--r--mod/mod-build-configs.cxx2
-rw-r--r--mod/mod-build-force.cxx2
-rw-r--r--mod/mod-build-log.cxx2
-rw-r--r--mod/mod-build-result.cxx2
-rw-r--r--mod/mod-builds.cxx2
-rw-r--r--mod/mod-ci.cxx64
-rw-r--r--mod/mod-ci.hxx31
-rw-r--r--mod/mod-package-details.cxx2
-rw-r--r--mod/mod-repository-details.cxx2
-rw-r--r--mod/mod-repository-root.cxx14
-rw-r--r--mod/mod-repository-root.hxx2
-rw-r--r--mod/module.cli26
15 files changed, 197 insertions, 40 deletions
diff --git a/brep/handler/ci/ci-load.in b/brep/handler/ci/ci-load.in
index b3c05f0..6f65777 100644
--- a/brep/handler/ci/ci-load.in
+++ b/brep/handler/ci/ci-load.in
@@ -10,6 +10,11 @@
# brep tenant id to this value and include the resulting URL in the response
# message.
#
+# --cancel-url <url>
+# CI task canceling URL base for the response. If specified, the handler will
+# append the brep tenant id to this value and include the resulting URL in
+# the response message.
+#
# <loader-path>
# Loader program (normally brep-load(1)).
#
@@ -36,6 +41,7 @@ shopt -s nullglob # Expand no-match globs to nothing rather than themselves.
# The handler's own options.
#
result_url=
+cancel_url=
while [[ "$#" -gt 0 ]]; do
case $1 in
--result-url)
@@ -43,6 +49,11 @@ while [[ "$#" -gt 0 ]]; do
result_url="${1%/}"
shift
;;
+ --cancel-url)
+ shift
+ cancel_url="${1%/}"
+ shift
+ ;;
*)
break
;;
@@ -355,4 +366,11 @@ run "$loader" "${loader_options[@]}" "$loadtab"
run rm -r "$data_dir"
trace "CI request for '$spec' is queued$message_suffix"
-exit_with_manifest 200 "CI request is queued$message_suffix"
+
+msg="CI request is queued$message_suffix"
+
+if [[ -n "$cancel_url" ]]; then
+ msg="$msg"$'\n'"to cancel CI request: $cancel_url=$reference&reason="
+fi
+
+exit_with_manifest 200 "$msg"
diff --git a/mod/ci-common.cxx b/mod/ci-common.cxx
index 7c41a7b..c0ef89f 100644
--- a/mod/ci-common.cxx
+++ b/mod/ci-common.cxx
@@ -720,4 +720,40 @@ namespace brep
return r;
}
+
+ bool ci_start::
+ cancel (const basic_mark&,
+ const basic_mark&,
+ const basic_mark* trace,
+ const string& reason,
+ odb::core::database& db,
+ const string& tid) const
+ {
+ using namespace odb::core;
+
+ assert (!transaction::has_current ());
+
+ transaction tr (db.begin ());
+
+ shared_ptr<build_tenant> t (db.find<build_tenant> (tid));
+
+ if (t == nullptr)
+ return false;
+
+ if (!t->archived)
+ {
+ t->archived = true;
+ db.update (t);
+ }
+
+ tr.commit ();
+
+ if (trace != nullptr)
+ *trace << "CI request " << tid << " is canceled: "
+ << (reason.size () < 50
+ ? reason
+ : string (reason, 0, 50) + "...");
+
+ return true;
+ }
}
diff --git a/mod/ci-common.hxx b/mod/ci-common.hxx
index 8efeb26..848bca1 100644
--- a/mod/ci-common.hxx
+++ b/mod/ci-common.hxx
@@ -111,6 +111,20 @@ namespace brep
const string& type,
const string& id) const;
+ // Cancel previously created or started CI request. Return false if there
+ // is no tenant for the specified tenant id. Note that the reason argument
+ // is only used for tracing.
+ //
+ // Note: should be called out of the database transaction.
+ //
+ bool
+ cancel (const basic_mark& error,
+ const basic_mark& warn,
+ const basic_mark* trace,
+ const string& reason,
+ odb::core::database&,
+ const string& tenant_id) const;
+
// Helpers.
//
@@ -122,22 +136,6 @@ namespace brep
private:
shared_ptr<options::ci_start> options_;
};
-
- class ci_cancel
- {
- public:
- void
- init (shared_ptr<options::ci_cancel>, shared_ptr<odb::core::database>);
-
- // @@ TODO Archive the tenant.
- //
- void
- cancel (/*...*/);
-
- private:
- shared_ptr<options::ci_cancel> options_;
- shared_ptr<odb::core::database> build_db_;
- };
}
#endif // MOD_CI_COMMON_HXX
diff --git a/mod/mod-build-configs.cxx b/mod/mod-build-configs.cxx
index 9282544..0ac4615 100644
--- a/mod/mod-build-configs.cxx
+++ b/mod/mod-build-configs.cxx
@@ -30,8 +30,6 @@ build_configs (const build_configs& r)
void brep::build_configs::
init (scanner& s)
{
- HANDLER_DIAG;
-
options_ = make_shared<options::build_configs> (
s, unknown_mode::fail, unknown_mode::fail);
diff --git a/mod/mod-build-force.cxx b/mod/mod-build-force.cxx
index 168a835..ea921e9 100644
--- a/mod/mod-build-force.cxx
+++ b/mod/mod-build-force.cxx
@@ -42,8 +42,6 @@ build_force (const build_force& r, const tenant_service_map& tsm)
void brep::build_force::
init (scanner& s)
{
- HANDLER_DIAG;
-
options_ = make_shared<options::build_force> (
s, unknown_mode::fail, unknown_mode::fail);
diff --git a/mod/mod-build-log.cxx b/mod/mod-build-log.cxx
index c8e803b..5487f6e 100644
--- a/mod/mod-build-log.cxx
+++ b/mod/mod-build-log.cxx
@@ -34,8 +34,6 @@ build_log (const build_log& r)
void brep::build_log::
init (scanner& s)
{
- HANDLER_DIAG;
-
options_ = make_shared<options::build_log> (
s, unknown_mode::fail, unknown_mode::fail);
diff --git a/mod/mod-build-result.cxx b/mod/mod-build-result.cxx
index 64503aa..3ba18e1 100644
--- a/mod/mod-build-result.cxx
+++ b/mod/mod-build-result.cxx
@@ -49,8 +49,6 @@ build_result (const build_result& r, const tenant_service_map& tsm)
void brep::build_result::
init (scanner& s)
{
- HANDLER_DIAG;
-
options_ = make_shared<options::build_result> (
s, unknown_mode::fail, unknown_mode::fail);
diff --git a/mod/mod-builds.cxx b/mod/mod-builds.cxx
index 30562f3..81d4649 100644
--- a/mod/mod-builds.cxx
+++ b/mod/mod-builds.cxx
@@ -50,8 +50,6 @@ builds (const builds& r)
void brep::builds::
init (scanner& s)
{
- HANDLER_DIAG;
-
options_ = make_shared<options::builds> (
s, unknown_mode::fail, unknown_mode::fail);
diff --git a/mod/mod-ci.cxx b/mod/mod-ci.cxx
index 0045002..8c47bc4 100644
--- a/mod/mod-ci.cxx
+++ b/mod/mod-ci.cxx
@@ -22,6 +22,8 @@ using namespace butl;
using namespace web;
using namespace brep::cli;
+// ci
+//
#ifdef BREP_CI_TENANT_SERVICE
brep::ci::
ci (tenant_service_map& tsm)
@@ -536,3 +538,65 @@ build_unloaded (tenant_service&& ts,
}
#endif
#endif
+
+// ci_cancel
+//
+brep::ci_cancel::
+ci_cancel (const ci_cancel& r)
+ : database_module (r),
+ options_ (r.initialized_ ? r.options_ : nullptr)
+{
+}
+
+void brep::ci_cancel::
+init (scanner& s)
+{
+ options_ = make_shared<options::ci_cancel> (
+ s, unknown_mode::fail, unknown_mode::fail);
+
+ if (options_->build_config_specified ())
+ database_module::init (*options_, options_->build_db_retry ());
+}
+
+bool brep::ci_cancel::
+handle (request& rq, response& rs)
+{
+ HANDLER_DIAG;
+
+ if (build_db_ == nullptr)
+ throw invalid_request (501, "not implemented");
+
+ params::ci_cancel params;
+
+ try
+ {
+ name_value_scanner s (rq.parameters (1024));
+ params = params::ci_cancel (s, unknown_mode::fail, unknown_mode::fail);
+ }
+ catch (const cli::exception& e)
+ {
+ throw invalid_request (400, e.what ());
+ }
+
+ const string& reason (params.reason ());
+
+ if (reason.empty ())
+ throw invalid_request (400, "missing CI request cancellation reason");
+
+ // Verify the tenant id.
+ //
+ const string tid (params.id ());
+
+ if (tid.empty ())
+ throw invalid_request (400, "invalid CI request id");
+
+ if (!cancel (error, warn, verb_ ? &trace : nullptr, reason, *build_db_, tid))
+ throw invalid_request (400, "unknown CI request id");
+
+ // We have all the data, so don't buffer the response content.
+ //
+ ostream& os (rs.content (200, "text/plain;charset=utf-8", false));
+ os << "CI request " << tid << " has been canceled";
+
+ return true;
+}
diff --git a/mod/mod-ci.hxx b/mod/mod-ci.hxx
index a83b9d3..bd91e99 100644
--- a/mod/mod-ci.hxx
+++ b/mod/mod-ci.hxx
@@ -16,6 +16,7 @@
#include <mod/module-options.hxx>
#include <mod/ci-common.hxx>
+#include <mod/database-module.hxx>
#if defined(BREP_CI_TENANT_SERVICE_UNLOADED) && !defined(BREP_CI_TENANT_SERVICE)
# error BREP_CI_TENANT_SERVICE must be defined if BREP_CI_TENANT_SERVICE_UNLOADED is defined
@@ -23,10 +24,6 @@
#ifdef BREP_CI_TENANT_SERVICE
# include <mod/tenant-service.hxx>
-
-#ifdef BREP_CI_TENANT_SERVICE_UNLOADED
-# include <mod/database-module.hxx>
-#endif
#endif
namespace brep
@@ -110,6 +107,32 @@ namespace brep
tenant_service_map& tenant_service_map_;
#endif
};
+
+ class ci_cancel: public database_module,
+ private ci_start
+ {
+ public:
+ ci_cancel () = default;
+
+ // Create a shallow copy (handling instance) if initialized and a deep
+ // copy (context exemplar) otherwise.
+ //
+ explicit
+ ci_cancel (const ci_cancel&);
+
+ virtual bool
+ handle (request&, response&) override;
+
+ virtual const cli::options&
+ cli_options () const override {return options::ci_cancel::description ();}
+
+ private:
+ virtual void
+ init (cli::scanner&) override;
+
+ private:
+ shared_ptr<options::ci_cancel> options_;
+ };
}
#endif // MOD_MOD_CI_HXX
diff --git a/mod/mod-package-details.cxx b/mod/mod-package-details.cxx
index fcd50da..1fb51da 100644
--- a/mod/mod-package-details.cxx
+++ b/mod/mod-package-details.cxx
@@ -37,8 +37,6 @@ package_details (const package_details& r)
void brep::package_details::
init (scanner& s)
{
- HANDLER_DIAG;
-
options_ = make_shared<options::package_details> (
s, unknown_mode::fail, unknown_mode::fail);
diff --git a/mod/mod-repository-details.cxx b/mod/mod-repository-details.cxx
index 082903b..93b6c9e 100644
--- a/mod/mod-repository-details.cxx
+++ b/mod/mod-repository-details.cxx
@@ -39,8 +39,6 @@ repository_details (const repository_details& r)
void brep::repository_details::
init (scanner& s)
{
- HANDLER_DIAG;
-
options_ = make_shared<options::repository_details> (
s, unknown_mode::fail, unknown_mode::fail);
diff --git a/mod/mod-repository-root.cxx b/mod/mod-repository-root.cxx
index 34b4007..bc861a8 100644
--- a/mod/mod-repository-root.cxx
+++ b/mod/mod-repository-root.cxx
@@ -133,6 +133,7 @@ namespace brep
#else
ci_ (make_shared<ci> ()),
#endif
+ ci_cancel_ (make_shared<ci_cancel> ()),
upload_ (make_shared<upload> ())
{
}
@@ -201,6 +202,10 @@ namespace brep
#else
: make_shared<ci> (*r.ci_)),
#endif
+ ci_cancel_ (
+ r.initialized_
+ ? r.ci_cancel_
+ : make_shared<ci_cancel> (*r.ci_cancel_)),
upload_ (
r.initialized_
? r.upload_
@@ -231,6 +236,7 @@ namespace brep
append (r, build_configs_->options ());
append (r, submit_->options ());
append (r, ci_->options ());
+ append (r, ci_cancel_->options ());
append (r, upload_->options ());
return r;
}
@@ -277,6 +283,7 @@ namespace brep
sub_init (*build_configs_, "build_configs");
sub_init (*submit_, "submit");
sub_init (*ci_, "ci");
+ sub_init (*ci_cancel_, "ci-cancel");
sub_init (*upload_, "upload");
// Parse own configuration options.
@@ -473,6 +480,13 @@ namespace brep
return handle ("ci", param);
}
+ else if (func == "ci-cancel")
+ {
+ if (handler_ == nullptr)
+ handler_.reset (new ci_cancel (*ci_cancel_));
+
+ return handle ("ci-cancel", param);
+ }
else if (func == "upload")
{
if (handler_ == nullptr)
diff --git a/mod/mod-repository-root.hxx b/mod/mod-repository-root.hxx
index aa60fda..990587e 100644
--- a/mod/mod-repository-root.hxx
+++ b/mod/mod-repository-root.hxx
@@ -25,6 +25,7 @@ namespace brep
class build_configs;
class submit;
class ci;
+ class ci_cancel;
class upload;
class repository_root: public handler
@@ -74,6 +75,7 @@ namespace brep
shared_ptr<build_configs> build_configs_;
shared_ptr<submit> submit_;
shared_ptr<ci> ci_;
+ shared_ptr<ci_cancel> ci_cancel_;
shared_ptr<upload> upload_;
shared_ptr<options::repository_root> options_;
diff --git a/mod/module.cli b/mod/module.cli
index 5f63930..5133935 100644
--- a/mod/module.cli
+++ b/mod/module.cli
@@ -796,10 +796,6 @@ namespace brep
}
};
- class ci_cancel
- {
- };
-
class ci: ci_start, build, build_db, page, repository_url, handler
{
// Classic CI-specific options.
@@ -815,7 +811,11 @@ namespace brep
}
};
- class ci_github: ci_start, ci_cancel, build, build_db, handler
+ class ci_cancel: build, build_db, handler
+ {
+ };
+
+ class ci_github: ci_start, build, build_db, handler
{
// GitHub CI-specific options (e.g., request timeout when invoking
// GitHub APIs).
@@ -1099,6 +1099,22 @@ namespace brep
string simulate;
};
+ // All parameters are non-optional.
+ //
+ class ci_cancel
+ {
+ // CI task tenant id.
+ //
+ // Note that the ci-cancel parameter is renamed to '_' by the root
+ // handler (see the request_proxy class for details).
+ //
+ string id | _;
+
+ // CI task canceling reason. Must not be empty.
+ //
+ string reason;
+ };
+
// Parameters other than challenge must be all present.
//
// Note also that besides these parameters there can be others. We don't