completed basic gui functionalities linking to run and start
This commit is contained in:
parent
1e60140a6c
commit
fe944519ac
|
@ -56,6 +56,7 @@ table.sortable thead {
|
|||
table.sortable td {
|
||||
font-size: .8em;
|
||||
font-family: "arial"
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.input-form {
|
||||
|
|
|
@ -48,16 +48,19 @@
|
|||
(defroutes
|
||||
app-routes
|
||||
|
||||
(GET "/" request (web/render "Hello World!")) ;; web/readme))
|
||||
(GET "/" request (web/render "Hello there!")) ;; web/readme))
|
||||
|
||||
;; NEW ROUTES HERE
|
||||
(GET "/upload" request
|
||||
(->> (fn [req conf acct]
|
||||
(web/render acct views/dockerfile-upload-form))
|
||||
(web/render acct [:div
|
||||
views/dockerfile-upload-form
|
||||
(views/list-jobs acct)]))
|
||||
(s/check request)))
|
||||
|
||||
(POST "/dockerfile" request
|
||||
(->> views/dockerfile-upload-post
|
||||
(->> (fn [req conf acct]
|
||||
(web/render acct (views/dockerfile-upload-post req conf acct)))
|
||||
(s/check request)))
|
||||
|
||||
(GET "/edit" request
|
||||
|
@ -66,7 +69,30 @@
|
|||
(s/check request)))
|
||||
|
||||
(GET "/list" request
|
||||
(->> views/list-jobs
|
||||
(->> (fn [req conf acct]
|
||||
(web/render acct (views/list-jobs acct)))
|
||||
(s/check request)))
|
||||
|
||||
(POST "/remove" request
|
||||
(->> (fn [req conf acct]
|
||||
(web/render acct (views/remove-job req conf acct)))
|
||||
(s/check request)))
|
||||
|
||||
(POST "/start" request
|
||||
(->> (fn [req conf acct]
|
||||
(web/render acct (views/start-job req conf acct)))
|
||||
(s/check request)))
|
||||
|
||||
(POST "/view" request
|
||||
(->> (fn [req conf acct]
|
||||
(web/render acct (views/view-job req conf acct)))
|
||||
(s/check request)))
|
||||
|
||||
(GET "/error" request
|
||||
(->> (fn [req conf acct]
|
||||
(web/render acct [:div
|
||||
(web/render-error "Generic Error Page")
|
||||
(views/list-jobs acct)]))
|
||||
(s/check request)))
|
||||
|
||||
;; JUST-AUTH ROUTES
|
||||
|
@ -90,7 +116,7 @@
|
|||
(let [session {:session {:config config
|
||||
:auth logged}}]
|
||||
(conj session
|
||||
(views/list-jobs request config logged)))
|
||||
(web/render logged (views/list-jobs logged))))
|
||||
;; (web/render
|
||||
;; logged
|
||||
;; [:div
|
||||
|
|
|
@ -46,26 +46,35 @@
|
|||
r_mkdir (ssh "-i" (q config [:jenkins :key])
|
||||
(ssh-host config) "mkdir" "-p" jobdir)
|
||||
r_scp (scp "-i" (q config [:jenkins :key])
|
||||
path (str (ssh-host config) ":" jobdir))
|
||||
r_job (log/spy (sync_jobs config "-a" jobname))
|
||||
r_store (log/spy (db/store!
|
||||
@jobs :jobid
|
||||
(log/spy {:jobid jobname
|
||||
:email (:email account)
|
||||
:account (dissoc account :password :activation-link)
|
||||
:lint (if (.contains r_lint "is OK") true false)
|
||||
:timestamp tstamp
|
||||
:type "vm_amd64"})))]
|
||||
path (str (ssh-host config) ":" jobdir "/Dockerfile"))
|
||||
r_job (sync_jobs config "-a" jobname)
|
||||
r_store (db/store! @jobs :jobid
|
||||
{:jobid jobname
|
||||
:email (:email account)
|
||||
:account (dissoc account :password :activation-link)
|
||||
:lint (if (.contains r_lint "is OK") true false)
|
||||
:timestamp tstamp
|
||||
:type "vm_amd64"
|
||||
:dockerfile (slurp path)})]
|
||||
{:lint r_lint
|
||||
:job r_job}
|
||||
(f/when-failed [e]
|
||||
(web/render-error-page
|
||||
(web/render-error
|
||||
(str "Job add failure: " (f/message e))))))))
|
||||
|
||||
(defn trash [jobid config]
|
||||
(f/attempt-all [r_sync (sync_jobs config "-d" jobid)]
|
||||
jobid
|
||||
(f/when-failed [e]
|
||||
(web/render-error
|
||||
(str "Job remove failure: " (f/message e))))))
|
||||
|
||||
(defn start [jobid config]
|
||||
(f/attempt-all [r_sync (sync_jobs config "-r" jobid)]
|
||||
jobid
|
||||
(f/when-failed [e]
|
||||
(web/render-error
|
||||
(str "Job start failure: " (f/message e))))))
|
||||
|
||||
(defn listall [config account]
|
||||
(sync_jobs config "-l" (:email account))
|
||||
;;(db/query @jobs {:email (:email account)})
|
||||
)
|
||||
|
||||
|
||||
|
|
|
@ -1,113 +1,148 @@
|
|||
(ns toaster.views
|
||||
(:require
|
||||
[clojure.java.io :as io]
|
||||
[clojure.string :as str]
|
||||
[clojure.contrib.humanize :as humanize :refer [datetime]]
|
||||
;; [clojure.data.json :as json :refer [read-str]]
|
||||
[toaster.webpage :as web]
|
||||
[toaster.session :as s]
|
||||
[toaster.ring :as ring]
|
||||
[toaster.jobs :as job]
|
||||
[failjure.core :as f]
|
||||
[auxiliary.string :refer [strcasecmp]]
|
||||
[toaster.config :as conf]
|
||||
[taoensso.timbre :as log :refer [debug]]
|
||||
[me.raynes.conch :as sh :refer [with-programs]]
|
||||
[clj-time.core :as time]
|
||||
[clj-time.coerce :as tc]
|
||||
[clj-time.local :as tl]
|
||||
[hiccup.form :as hf]))
|
||||
(:require
|
||||
[clojure.java.io :as io]
|
||||
[clojure.string :as str]
|
||||
[clojure.contrib.humanize :as humanize :refer [datetime]]
|
||||
;; [clojure.data.json :as json :refer [read-str]]
|
||||
[toaster.webpage :as web]
|
||||
[toaster.session :as s]
|
||||
[toaster.ring :as ring]
|
||||
[toaster.jobs :as job]
|
||||
[failjure.core :as f]
|
||||
[auxiliary.string :refer [strcasecmp]]
|
||||
[toaster.config :as conf]
|
||||
[taoensso.timbre :as log :refer [debug]]
|
||||
[me.raynes.conch :as sh :refer [with-programs]]
|
||||
[clj-time.core :as time]
|
||||
[clj-time.coerce :as tc]
|
||||
[clj-time.local :as tl]
|
||||
[clj-storage.core :as db]
|
||||
[hiccup.form :as hf]))
|
||||
|
||||
(def dockerfile-upload-form
|
||||
[:div {:class "container-fluid"}
|
||||
[:h1 "Upload a Dockerfile to toast"]
|
||||
[:p " Choose the file in your computer and click 'Submit' to
|
||||
[:div {:class "container-fluid"}
|
||||
[:h1 "Upload a Dockerfile to toast"]
|
||||
[:p " Choose the file in your computer and click 'Submit' to
|
||||
proceed to validation."]
|
||||
[:div {:class "form-group"}
|
||||
[:form {:action "dockerfile" :method "post"
|
||||
:class "form-shell"
|
||||
:enctype "multipart/form-data"}
|
||||
[:fieldset {:class "fieldset btn btn-default btn-file btn-lg"}
|
||||
[:input {:name "file" :type "file"}]]
|
||||
;; [:fieldset {:class "fieldset-submit"}
|
||||
[:input {:class "btn btn-primary btn-lg"
|
||||
:id "field-submit" :type "submit"
|
||||
:name "submit" :value "submit"}]]]])
|
||||
[:div {:class "form-group"}
|
||||
[:form {:action "dockerfile" :method "post"
|
||||
:class "form-shell"
|
||||
:enctype "multipart/form-data"}
|
||||
[:fieldset {:class "fieldset btn btn-default btn-file btn-lg"}
|
||||
[:input {:name "file" :type "file"}]]
|
||||
;; [:fieldset {:class "fieldset-submit"}
|
||||
[:input {:class "btn btn-primary btn-lg"
|
||||
:id "field-submit" :type "submit"
|
||||
:name "submit" :value "submit"}]]]])
|
||||
|
||||
(def dockerfile-edit-form
|
||||
[:div {:class "container-fluid"}
|
||||
[:h1 "Edit your Dockerfile to toast"]
|
||||
[:div {:class "form-group"}
|
||||
[:form {:action "dockerfile" :method "post"
|
||||
:class "form-shell"
|
||||
:enctype "multipart/form-data"}
|
||||
[:fieldset {:class "fieldset btn btn-default btn-file btn-lg"}
|
||||
[:textarea {:name "editor" :id "editor"
|
||||
:rows 30 :cols 72 } "FROM: dyne/devuan:ascii"]
|
||||
[:input {:class "btn btn-primary btn-lg"
|
||||
:id "field-submit" :type "submit"
|
||||
:name "submit" :value "submit"}]]]]
|
||||
[:script "var editor = ace.edit(\"editor\");
|
||||
editor.setTheme(\"ace/theme/monokai\");
|
||||
editor.session.setMode(\"ace/mode/dockerfile\");"]])
|
||||
[:div {:class "container-fluid"}
|
||||
[:h1 "Edit your Dockerfile to toast"]
|
||||
[:div {:class "form-group"}
|
||||
[:form {:action "dockerfile" :method "post"
|
||||
:class "form-shell"
|
||||
:enctype "multipart/form-data"}
|
||||
[:fieldset {:class "fieldset btn btn-default btn-file btn-lg"}
|
||||
[:textarea {:name "editor" :id "editor"
|
||||
:rows 30 :cols 72} "FROM: dyne/devuan:ascii"]
|
||||
[:input {:class "btn btn-primary btn-lg"
|
||||
:id "field-submit" :type "submit"
|
||||
:name "submit" :value "submit"}]]]]
|
||||
[:script "var editor = ace.edit(\"editor\");
|
||||
editor.setTheme(\"ace/theme/monokai\");
|
||||
editor.session.setMode(\"ace/mode/dockerfile\");"]])
|
||||
|
||||
|
||||
|
||||
(def welcome-menu
|
||||
[:div {:class "container-fluid"}
|
||||
[:div {:class "row-fluid"}
|
||||
[:div {:class "row"} [:a {:href "/list"} "List all your toaster jobs"]]
|
||||
[:div {:class "row"} [:a {:href "/upload"} "Upload a new toaster job"]]]])
|
||||
[:div {:class "container-fluid"}
|
||||
[:div {:class "row-fluid"}
|
||||
[:div {:class "row"} [:a {:href "/list"} "List all your toaster jobs"]]
|
||||
[:div {:class "row"} [:a {:href "/upload"} "Upload a new toaster job"]]]])
|
||||
|
||||
(defn dockerfile-upload-post [request config account]
|
||||
(web/render
|
||||
account
|
||||
(let
|
||||
[tempfile (get-in request [:params :file :tempfile])
|
||||
filename (get-in request [:params :file :filename])
|
||||
params (:params request)]
|
||||
(cond
|
||||
(> (get-in params [:file :size]) 64000)
|
||||
;; max upload size in bytes
|
||||
;; TODO: put in config
|
||||
(web/render-error-page params "File too big in upload (64KB limit).")
|
||||
:else
|
||||
(let [file (io/copy tempfile (io/file "/tmp" filename))
|
||||
path (str "/tmp/" filename)]
|
||||
(io/delete-file tempfile)
|
||||
(if (not (.exists (io/file path)))
|
||||
(web/render-error-page
|
||||
(log/spy :error
|
||||
[:h1 (str "Uploaded file not found: " filename)]))
|
||||
;; file is now in 'tmp' var
|
||||
[:div {:class "container-fluid"}
|
||||
[:h1 "Job uploaded and added"]
|
||||
[:p "Log messages:"]
|
||||
(web/render-yaml (job/add path config account))]))))))
|
||||
(let
|
||||
[tempfile (get-in request [:params :file :tempfile])
|
||||
filename (get-in request [:params :file :filename])
|
||||
params (:params request)]
|
||||
(cond
|
||||
(> (get-in params [:file :size]) 64000)
|
||||
;; max upload size in bytes
|
||||
;; TODO: put in config
|
||||
(web/render-error params "File too big in upload (64KB limit).")
|
||||
:else
|
||||
(let [file (io/copy tempfile (io/file "/tmp" filename))
|
||||
path (str "/tmp/" filename)]
|
||||
(io/delete-file tempfile)
|
||||
(if (not (.exists (io/file path)))
|
||||
(web/render-error
|
||||
(log/spy :error
|
||||
[:h1 (str "Uploaded file not found: " filename)]))
|
||||
;; file is now in 'tmp' var
|
||||
[:div {:class "container-fluid"}
|
||||
[:h1 "Job uploaded and added"]
|
||||
[:p "Log messages:"]
|
||||
(web/render-yaml (job/add path config account))])))))
|
||||
|
||||
(defn list-jobs [request config account]
|
||||
(defn list-jobs [account]
|
||||
(f/attempt-all
|
||||
[joblist (db/query @ring/jobs {:email (:email account)})]
|
||||
[:div {:class "container-fluid"}
|
||||
[:h1 (str "List all toaster jobs for " (:name account))]
|
||||
[:table {:class "sortable table"}
|
||||
[:thead nil
|
||||
[:tr nil [:th nil "Date"] [:th nil "Type"] [:th nil "Status"] [:th nil "Actions"]]]
|
||||
[:tbody nil
|
||||
(for [j joblist]
|
||||
(let [type (:type j) ;; (-> j (str/split #"-") second)
|
||||
tstamp (:timestamp j) ;; (-> j (str/split #"-") last)
|
||||
jobid (:jobid j)
|
||||
joburl (str/replace jobid #"@" "AT")]
|
||||
[:tr nil
|
||||
[:td {:class "date"} (-> tstamp Long/valueOf tc/from-long humanize/datetime)]
|
||||
[:td {:class "job"} [:a {:href (str "https://sdk.dyne.org:4443/view/web-sdk-builds/job/" joburl)} type]]
|
||||
[:td {:class "status"} [:a {:href (str "https://sdk.dyne.org:4443/job/" joburl "/lastBuild/console")}
|
||||
[:img {:src (str "https://sdk.dyne.org:4443/job/" joburl "/badge/icon")}]]]
|
||||
[:td {:class "actions"}
|
||||
[:div {:class "btn-toolbar" :role "toolbar" :arial-label "Actions"}
|
||||
(web/button "/view" "\uD83D\uDC41" (hf/hidden-field "jobid" jobid))
|
||||
(web/button "/start" "▶" (hf/hidden-field "jobid" jobid))
|
||||
(web/button "/remove" "\uD83D\uDDD1" (hf/hidden-field "jobid" jobid))]]]
|
||||
))]]]
|
||||
(f/when-failed [e]
|
||||
(web/render-error
|
||||
(str "Job list failure: " (f/message e))))))
|
||||
|
||||
|
||||
(defn remove-job [request config account]
|
||||
(f/attempt-all
|
||||
[joblist (job/listall config account)]
|
||||
(web/render
|
||||
account
|
||||
[:div {:class "container-fluid"}
|
||||
[:h1 (str "List all toaster jobs for " (:name account))]
|
||||
[:table {:class "sortable table"}
|
||||
[:thead nil
|
||||
[:tr nil [:th nil "Date"] [:th nil "Type"] [:th nil "Actions"]]]
|
||||
[:tbody nil
|
||||
(for [j joblist]
|
||||
(let [type (-> j (str/split #"-") second)
|
||||
tstamp (-> j (str/split #"-") last)]
|
||||
[:tr nil
|
||||
[:td {:class "date"} (-> tstamp Long/valueOf tc/from-long tl/to-local-date-time
|
||||
humanize/datetime)]
|
||||
[:td {:class "job"} [:a {:href (str "https://sdk.dyne.org:4443/view/web-sdk-builds/job/"
|
||||
(str/replace j #"@" "AT"))} type]]
|
||||
[:td {:class "start-job"} (web/button "/start" "Start" (hf/hidden-field "job" j))
|
||||
(web/button "/remove" "Remove" (hf/hidden-field "job" j))]]
|
||||
))]]])
|
||||
[jobid (s/param request :jobid)
|
||||
jobfound (db/query @ring/jobs {:jobid jobid})
|
||||
r_rmjob (db/delete! @ring/jobs jobid)
|
||||
r_sync (job/trash jobid config)]
|
||||
[:h1 (str "Job removed: " jobid)]
|
||||
(f/when-failed [e]
|
||||
(web/render-error-page
|
||||
(str "Job list failure: " (f/message e))))
|
||||
))
|
||||
(web/render-error (str "Failure removing job: " (f/message e))))))
|
||||
|
||||
(defn start-job [request config account]
|
||||
(f/attempt-all
|
||||
[jobid (s/param request :jobid)
|
||||
jobfound (db/query @ring/jobs {:jobid jobid})
|
||||
r_sync (job/start jobid config)]
|
||||
[:div {:class "container-fluid"}
|
||||
[:h1 (str "Job started: " jobid)]
|
||||
[:p [:a {:href (str "https://sdk.dyne.org:4443/view/web-sdk-builds/job/"
|
||||
(str/replace jobid #"@" "AT"))}]]]
|
||||
(f/when-failed [e]
|
||||
(web/render-error (str "Failure starting job: " (f/message e))))))
|
||||
|
||||
(defn view-job [request config account]
|
||||
(f/attempt-all
|
||||
[jobid (s/param request :jobid)
|
||||
jobfound (db/fetch @ring/jobs jobid)
|
||||
dockerfile (log/spy (-> jobfound :dockerfile))]
|
||||
(web/render account [:div
|
||||
[:h1 (str "Viewing job: " jobid)]
|
||||
[:pre dockerfile]])
|
||||
(f/when-failed [e]
|
||||
(web/render-error (str "Failure viewing job: " (f/message e))))))
|
||||
|
|
|
@ -98,6 +98,14 @@
|
|||
[:div {:class "container-fluid"} body]
|
||||
(render-footer)])}))
|
||||
|
||||
(defn render-success
|
||||
"render a successful message without ending the page"
|
||||
[succ]
|
||||
[:div {:class "alert alert-success" :role "alert"}
|
||||
[:span {:class "far fa-check-circle"
|
||||
:aria-hidden "true" :style "padding: .5em"}]
|
||||
[:span {:class "sr-only"} "Success:" ]
|
||||
succ])
|
||||
|
||||
(defn render-error
|
||||
"render an error message without ending the page"
|
||||
|
|
Loading…
Reference in New Issue