guix-commits
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[no subject]


From: Mathieu Othacehe
Date: Wed, 21 Apr 2021 03:53:59 -0400 (EDT)

branch: master
commit 166aa9a11a446267713c9f00d0557e71e67adf68
Author: Mathieu Othacehe <othacehe@gnu.org>
AuthorDate: Wed Apr 21 09:49:42 2021 +0200

    Add a dashboard registration API.
---
 doc/cuirass.texi         | 51 ++++++++++++++++++++++++++++++++++++++++++++++++
 src/cuirass/database.scm | 25 ++++++++++++++++++++++++
 src/cuirass/http.scm     | 37 ++++++++++++++++++++++++++++++++++-
 src/cuirass/remote.scm   | 26 +-----------------------
 src/cuirass/utils.scm    | 28 +++++++++++++++++++++++++-
 src/schema.sql           |  7 +++++++
 src/sql/upgrade-8.sql    | 10 ++++++++++
 tests/database.scm       |  5 +++++
 8 files changed, 162 insertions(+), 27 deletions(-)

diff --git a/doc/cuirass.texi b/doc/cuirass.texi
index 89eed92..966076a 100644
--- a/doc/cuirass.texi
+++ b/doc/cuirass.texi
@@ -975,6 +975,40 @@ The jobs list for this evaluation, as a JSON array.
 
 @end table
 
+@subsection Dashboard registration
+
+The user can register a dashboard using the "/api/dashboard/register"
+API.  This request accepts two mandatory parameters.
+
+@table @code
+@item specification
+The specification name. This parameter is @emph{mandatory}.
+
+@item names
+The dashboard jobs names, where names is a comma separated list of job
+names.  This parameter is @emph{mandatory}.
+
+@end table
+
+For example, to register a dashboard for the @code{emacs.x86_64-linux}
+and @code{emacs-minimal.x86_64-linux} jobs of the @code{master}
+specification:
+
+@example
+$ curl 
"http://localhost:8080/api/dashboard/register?spec=master&names=emacs.x86_64-linux,emacs-minimal.x86_64-linux";
+@end example
+
+The nominal output is a JSON object which contains a unique field:
+
+@table @code
+@item id
+The registered dashboard id.
+
+@end table
+
+The dashboard is then accessible at the following address:
+@code{http://localhost:8080/dashboard/<id>}.
+
 @subsection Latest builds
 
 The list of latest builds can be obtained with the API
@@ -1364,6 +1398,23 @@ the worker.
 
 @end table
 
+@section Dashboards
+@cindex dashboards, database
+
+This table contains the user registered Dashboards.
+
+@table @code
+@item id
+This is an automatically incrementing numeric identifier.
+
+@item specification
+This field holds the @code{name} of a specification from the
+@code{Specifications} table.
+
+@item jobs
+This text field holds a list of comma separated job names.
+
+@end table
 @c *********************************************************************
 
 @node Contributing
diff --git a/src/cuirass/database.scm b/src/cuirass/database.scm
index b773c4e..afbca36 100644
--- a/src/cuirass/database.scm
+++ b/src/cuirass/database.scm
@@ -104,6 +104,8 @@
             db-get-build-product-path
             db-push-notification
             db-pop-notification
+            db-register-dashboard
+            db-get-dashboard
             db-add-or-update-worker
             db-get-worker
             db-get-workers
@@ -1608,6 +1610,29 @@ DELETE FROM Notifications WHERE id =" id ";")
              (db-get-build (string->number build))))
       (else #f))))
 
+(define (db-register-dashboard specification jobs)
+  "Insert a new dashboard for SPECIFICATION and JOBS into Dashboards table."
+  (let ((id (random-string 16)))
+    (with-db-worker-thread db
+      (match (expect-one-row
+              (exec-query/bind db "\
+INSERT INTO Dashboards (id, specification, jobs)
+VALUES (" id ", " specification "," jobs ")
+RETURNING id;"))
+        ((id) id)
+        (else #f)))))
+
+(define (db-get-dashboard id)
+  "Return the dashboard specification and jobs with the given ID."
+  (with-db-worker-thread db
+    (match (expect-one-row
+            (exec-query/bind db "
+SELECT specification, jobs from Dashboards WHERE id = " id ";"))
+      ((specification jobs)
+       `((#:specification . ,specification)
+         (#:jobs . ,jobs)))
+      (else #f))))
+
 (define (db-add-or-update-worker worker)
   "Insert WORKER into Worker table."
   (with-db-worker-thread db
diff --git a/src/cuirass/http.scm b/src/cuirass/http.scm
index 5bd78d6..31b7a22 100644
--- a/src/cuirass/http.scm
+++ b/src/cuirass/http.scm
@@ -738,6 +738,22 @@ into a specification record and return it."
                                     #:limit limit))))
            (lambda _
              (respond-json-with-error 500 "Invalid body")))))))
+    (('GET "api" "dashboard" "register")
+     (let* ((params (request-parameters request))
+            (spec (assq-ref params 'spec))
+            (names (assq-ref params 'names)))
+       (cond
+        ((not (and names spec))
+         (respond-json-with-error 500 "Parameter not defined"))
+        (else
+         (let ((id (db-register-dashboard spec names)))
+           (if id
+               (respond-json
+                (object->json-string
+                 `((#:id . ,id))))
+               (respond-json-with-error
+                500
+                "Failed to register the dashboard")))))))
     (('GET "api" "evaluation")
      (let* ((params (request-parameters request))
             (id (assq-ref params 'id)))
@@ -805,7 +821,26 @@ into a specification record and return it."
                                `((#:id . ,(assq-ref e #:evaluation))))
                              evals))))
                     '())))
-
+    (('GET "dashboard" id)
+     (let ((dashboard (db-get-dashboard id)))
+       (if dashboard
+           (let* ((spec (assq-ref dashboard #:specification))
+                  (jobs (assq-ref dashboard #:jobs))
+                  (evaluations (db-get-latest-evaluations))
+                  (evaluation
+                   (any (lambda (eval)
+                          (and (string=? (assq-ref eval #:specification)
+                                         spec)
+                               (assq-ref eval #:evaluation)))
+                        evaluations))
+                  (uri
+                   (string->uri-reference
+                    (format #f "/eval/~a/dashboard?names=~a"
+                            evaluation jobs))))
+             (respond (build-response #:code 302
+                                      #:headers `((location . ,uri)))
+                      #:body ""))
+           (respond-html-eval-not-found id))))
     (('GET "jobset" name)
      (respond-html
       (let* ((evaluation-id-max (db-get-evaluations-id-max name))
diff --git a/src/cuirass/remote.scm b/src/cuirass/remote.scm
index f79a145..9386612 100644
--- a/src/cuirass/remote.scm
+++ b/src/cuirass/remote.scm
@@ -18,6 +18,7 @@
 
 (define-module (cuirass remote)
   #:use-module (cuirass logging)
+  #:use-module (cuirass utils)
   #:use-module (guix avahi)
   #:use-module (guix config)
   #:use-module (guix derivations)
@@ -136,31 +137,6 @@
       (systems systems)
       (last-seen last-seen)))))
 
-(define %seed
-  (seed->random-state
-   (logxor (getpid) (car (gettimeofday)))))
-
-(define (integer->alphanumeric-char n)
-  "Map N, an integer in the [0..62] range, to an alphanumeric character."
-  (cond ((< n 10)
-         (integer->char (+ (char->integer #\0) n)))
-        ((< n 36)
-         (integer->char (+ (char->integer #\A) (- n 10))))
-        ((< n 62)
-         (integer->char (+ (char->integer #\a) (- n 36))))
-        (else
-         (error "integer out of bounds" n))))
-
-(define (random-string len)
-  "Compute a random string of size LEN where each character is alphanumeric."
-  (let loop ((chars '())
-             (len len))
-    (if (zero? len)
-        (list->string chars)
-        (let ((n (random 62 %seed)))
-          (loop (cons (integer->alphanumeric-char n) chars)
-                (- len 1))))))
-
 (define (generate-worker-name)
   "Return the service name of the server."
   (random-string 8))
diff --git a/src/cuirass/utils.scm b/src/cuirass/utils.scm
index dfc5dd9..f64d318 100644
--- a/src/cuirass/utils.scm
+++ b/src/cuirass/utils.scm
@@ -55,7 +55,8 @@
             essential-task
             bytevector-range
 
-            date->rfc822-str))
+            date->rfc822-str
+            random-string))
 
 (define (alist? obj)
   "Return #t if OBJ is an alist."
@@ -323,3 +324,28 @@ die silently while the rest of the program keeps going."
 
 (define (date->rfc822-str date)
   (date->string date "~a, ~d ~b ~Y ~T ~z"))
+
+(define %seed
+  (seed->random-state
+   (logxor (getpid) (car (gettimeofday)))))
+
+(define (integer->alphanumeric-char n)
+  "Map N, an integer in the [0..62] range, to an alphanumeric character."
+  (cond ((< n 10)
+         (integer->char (+ (char->integer #\0) n)))
+        ((< n 36)
+         (integer->char (+ (char->integer #\A) (- n 10))))
+        ((< n 62)
+         (integer->char (+ (char->integer #\a) (- n 36))))
+        (else
+         (error "integer out of bounds" n))))
+
+(define (random-string len)
+  "Compute a random string of size LEN where each character is alphanumeric."
+  (let loop ((chars '())
+             (len len))
+    (if (zero? len)
+        (list->string chars)
+        (let ((n (random 62 %seed)))
+          (loop (cons (integer->alphanumeric-char n) chars)
+                (- len 1))))))
diff --git a/src/schema.sql b/src/schema.sql
index bd20327..84740a6 100644
--- a/src/schema.sql
+++ b/src/schema.sql
@@ -111,6 +111,13 @@ CREATE TABLE Workers (
   last_seen   INTEGER NOT NULL
 );
 
+CREATE TABLE Dashboards (
+  id              TEXT NOT NULL PRIMARY KEY,
+  specification   TEXT NOT NULL,
+  jobs            TEXT NOT NULL,
+  FOREIGN KEY (specification) REFERENCES Specifications(name) ON DELETE CASCADE
+);
+
 -- XXX: All queries targeting Builds and Outputs tables *must* be covered by
 -- an index.  It is also preferable for the other tables.
 CREATE INDEX Builds_status_index ON Builds (status);
diff --git a/src/sql/upgrade-8.sql b/src/sql/upgrade-8.sql
new file mode 100644
index 0000000..c28de76
--- /dev/null
+++ b/src/sql/upgrade-8.sql
@@ -0,0 +1,10 @@
+BEGIN TRANSACTION;
+
+CREATE TABLE Dashboards (
+  id              TEXT NOT NULL PRIMARY KEY,
+  specification   TEXT NOT NULL,
+  jobs            TEXT NOT NULL,
+  FOREIGN KEY (specification) REFERENCES Specifications(name) ON DELETE CASCADE
+);
+
+COMMIT;
diff --git a/tests/database.scm b/tests/database.scm
index 1229ac6..3f32130 100644
--- a/tests/database.scm
+++ b/tests/database.scm
@@ -674,6 +674,11 @@ timestamp, checkouttime, evaltime) VALUES ('guix', 0, 0, 
0, 0);")
            (eq? (assq-ref (db-get-build drv-2) #:id)
                 (assq-ref build #:id)))))))
 
+  (test-equal "db-register-dashboard"
+    "guix"
+    (let ((id (db-register-dashboard "guix" "emacs")))
+      (assq-ref (db-get-dashboard id) #:specification)))
+
   (test-assert "db-close"
     (begin
       (false-if-exception (delete-file tmp-mail))



reply via email to

[Prev in Thread] Current Thread [Next in Thread]