Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Updated readme; minor fixes #18

Merged
merged 2 commits into from
Nov 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 56 additions & 1 deletion readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@ A web service for validating Eduhub OOAPI endpoints

## API

`GET /endpoints/{endpointId}/config`
### Check endpoint.

Perform basic checks on whether the endpoint is up.

Calls the endpoint with `endpointId` through the Eduhub gateway and
reports if a successful response is received.
Expand All @@ -13,6 +15,47 @@ On success, responds with a `200 OK` status

On error, responds with a `502 Bad Gateway` status.

`GET /endpoints/{endpointId}/config`

### Validate endpoint

Use the validator to validate the endpoint and generate a report.

`GET /endpoints/{endpointId}/paths`

### Fetch Status

Load the current status as json. Fields include job-status (pending, finished or failed), endpoint-id, profile,
pending-at and finished-at, with ISO-8601 timestamp format.

`GET /status/{uuid}`

# HTML Endpoints

## View status

View the status in the browser. If the status is finished, the report can be viewed, downloaded or deleted from this page.

`GET /view/status/{uuid}`

## View report

View the validation report in the browser.

`GET /view/report/{uuid}`

## Download Report

Download report as a HTML file.

`GET /download/report/{uuid}`

# Delete report

Delete the report and the associated status data from the Redis database.

`POST /delete/report/{uuid}`

## Configuring

The service is configured using environment variables:
Expand All @@ -31,6 +74,7 @@ SERVER_PORT Starts the app server on this port
REDIS_URI URI to redis
JOB_STATUS_EXPIRY_SECONDS Number of seconds before job status in Redis expires
SPIDER_TIMEOUT_MILLIS Maximum number of milliseconds before spider timeout.
VALIDATOR_SERVICE_ROOT_URL The root url of the web endpoint, used to generate a url to a status view. This url is included in the json output after starting a validation job as "web-url".
```

## Build
Expand All @@ -50,6 +94,17 @@ make docker-build
docker compose up
# To test:
curl -v 'http://localhost:3002/endpoints/demo04.test.surfeduhub.nl/config'
curl -v 'http://localhost:3002/endpoints/demo04.test.surfeduhub.nl/paths'
```

## Run locally

```bash
make
java -jar target/eduhub-validator-service.jar
# Extract ACCESS_TOKEN
curl -s -X POST https://connect.test.surfconext.nl/oidc/token -u client01.registry.validator.dev.surfeduhub.nl:$SURF_CONEXT_PASSWORD -d "grant_type=client_credentials"
curl -v -X POST 'http://localhost:3002/endpoints/demo04.test.surfeduhub.nl/paths?profile=rio' -H "Authorization: Bearer $ACCESS_TOKEN"
```

## Notes
Expand Down
1 change: 1 addition & 0 deletions resources/public/javascript/status.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
// Define the endpoint and polling interval (in milliseconds)
const rootUrl = `${window.location.protocol}//${window.location.host}`;
const endpoint = `${rootUrl}/status/${validationUuid}`; // Replace with your actual endpoint
const pollInterval = 2000; // Poll every 5 seconds

Expand Down
15 changes: 2 additions & 13 deletions src/nl/surf/eduhub/validator/service/api.clj
Original file line number Diff line number Diff line change
Expand Up @@ -30,17 +30,6 @@
[ring.middleware.json :refer [wrap-json-response]]
[ring.middleware.resource :refer [wrap-resource]]))

;; Many response handlers have the same structure - with this function they can be written inline.
;; `activate-handler?` is a function that takes a request and returns a boolean which determines if
;; the current handler should be activated (or skipped).
;; `response-handler` takes an intermediate response and processes it into the next step.
(defn wrap-response-handler [app action response-handler config]
(fn [req]
(let [resp (app req)]
(if (= action (:action resp))
(response-handler (dissoc resp :action) config)
resp))))

;; Turn the contents of a job status (stored in redis) into an http response.
(defn- job-status-handler [uuid {:keys [redis-conn] :as _config}]
(let [job-status (status/load-status redis-conn uuid)]
Expand All @@ -58,10 +47,10 @@
(status/delete-status redis-conn uuid)
{:status http-status/see-other :headers {"Location" (str "/view/status/" uuid)}})

(defn- view-status-handler [uuid {:keys [redis-conn] :as config}]
(defn- view-status-handler [uuid {:keys [redis-conn] :as _config}]
(let [validation (status/load-status redis-conn uuid)]
(if validation
{:status http-status/ok :body (views.status/render (assoc validation :uuid uuid) config)}
{:status http-status/ok :body (views.status/render (assoc validation :uuid uuid))}
{:status http-status/not-found :body (views.status/render-not-found)})))

(defn wrap-html-response [app]
Expand Down
4 changes: 2 additions & 2 deletions src/nl/surf/eduhub/validator/service/jobs/client.clj
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@

;; Enqueue the validate-endpoint call in the worker queue.
(defn enqueue-validation
[endpoint-id profile {:keys [redis-conn gateway-basic-auth gateway-url ooapi-version max-total-requests] :as _config}]
[endpoint-id profile {:keys [redis-conn gateway-basic-auth gateway-url ooapi-version max-total-requests root-url] :as _config}]
(let [uuid (str (UUID/randomUUID))
prof (or profile "rio")
opts {:basic-auth gateway-basic-auth
Expand All @@ -26,4 +26,4 @@
:profile prof}]
(status/set-status-fields redis-conn uuid "pending" {:endpoint-id endpoint-id, :profile prof} nil)
(c/perform-async client-opts `worker/validate-endpoint endpoint-id uuid opts)
{:status 200 :body {:job-status "pending" :uuid uuid, :web-url (str "http://localhost:3002/view/status/" uuid)}}))
{:status 200 :body {:job-status "pending" :uuid uuid, :web-url (str root-url "/view/status/" uuid)}}))
1 change: 0 additions & 1 deletion src/nl/surf/eduhub/validator/service/main.clj
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@
;; Starts a Jetty server on given port.
(defn start-server [routes {:keys [server-port] :as _config}]
(let [server (-> routes

(run-jetty {:port server-port :join? false}))
handler ^Runnable (fn [] (.stop server))]
;; Add a shutdown hook to stop Jetty on JVM exit (Ctrl+C)
Expand Down
10 changes: 5 additions & 5 deletions src/nl/surf/eduhub/validator/service/views/status.clj
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
h2/html
str))

(defn render [{:keys [endpoint-id job-status profile uuid]} {:keys [root-url] :as _config}]
(defn render [{:keys [endpoint-id job-status profile uuid]}]
{:pre [job-status profile uuid endpoint-id]}
(let [display (if (= "finished" job-status) "block" "none")]
(->
Expand All @@ -27,7 +27,7 @@
[:meta {:name "viewport" :content "width=device-width, initial-scale=1.0"}]
[:title "Status Report"]
[:link {:href "/stylesheets/all.css" :rel "stylesheet"}]
[:script (h2/raw (str "var rootUrl = '" root-url "'; var validationUuid = '" uuid "';"))]
[:script (h2/raw (str "var validationUuid = '" uuid "';"))]
[:script {:src "/javascript/status.js"}]
;; Start polling for the status to change to "finished" or "failed"
[:script (when (= job-status "pending") (h2/raw (str "const polling = setInterval(pollJobStatus, pollInterval);")))]]
Expand All @@ -37,9 +37,9 @@
[:p.status {:id "job-status" :class job-status} (str "Status: " job-status)]
[:p (str "Profile Name: " profile)]
[:div {:style (str "margin-left: 100px; display: " display)}
[:a.button.report-button {:href (str root-url "/view/report/" uuid)} "View Report"]
[:a.button.report-button {:href (str root-url "/download/report/" uuid)} "Download Report"]
[:form {:action (str root-url "/delete/report/" uuid) :method "POST"}
[:a.button.report-button {:href (str "/view/report/" uuid)} "View Report"]
[:a.button.report-button {:href (str "/download/report/" uuid)} "Download Report"]
[:form {:action (str "/delete/report/" uuid) :method "POST"}
[:button.delete-button.button {:type "submit"} "Delete Report"]]]]]]
h2/html
str)))