Added automatical hook scheduling
This commit is contained in:
parent
e0628bc480
commit
463d2805b3
6 changed files with 124 additions and 28 deletions
3
node.go
3
node.go
|
|
@ -94,7 +94,8 @@ func GetNode(nodeID int) (node Node, err error) { // {{{
|
|||
h.id,
|
||||
to_jsonb(s) AS script,
|
||||
ssh,
|
||||
env
|
||||
env,
|
||||
schedule_on_child_update AS ScheduleOnChildUpdate
|
||||
FROM hook h
|
||||
INNER JOIN public.script s ON h.script_id = s.id
|
||||
WHERE
|
||||
|
|
|
|||
110
script.go
110
script.go
|
|
@ -23,11 +23,12 @@ type Script struct {
|
|||
}
|
||||
|
||||
type Hook struct {
|
||||
ID int
|
||||
Node Node
|
||||
Script Script
|
||||
SSH string
|
||||
Env map[string]string
|
||||
ID int
|
||||
Node Node
|
||||
Script Script
|
||||
SSH string
|
||||
Env map[string]string
|
||||
ScheduleOnChildUpdate bool `db:"schedule_on_child_update"`
|
||||
}
|
||||
|
||||
func GetScript(scriptID int) (script Script, err error) { // {{{
|
||||
|
|
@ -135,13 +136,20 @@ func SearchScripts(search string) (scripts []Script, err error) { // {{{
|
|||
|
||||
row := db.QueryRow(`
|
||||
SELECT
|
||||
json_agg(script) AS scripts
|
||||
FROM public.script
|
||||
WHERE
|
||||
name ILIKE $1
|
||||
ORDER BY
|
||||
"group" ASC,
|
||||
name ASC
|
||||
COALESCE(
|
||||
json_agg(scripts),
|
||||
'[]'::json
|
||||
) AS scripts
|
||||
FROM (
|
||||
SELECT
|
||||
to_json(script) AS scripts
|
||||
FROM public.script
|
||||
WHERE
|
||||
name ILIKE $1
|
||||
ORDER BY
|
||||
"group" ASC,
|
||||
name ASC
|
||||
) scripts
|
||||
`,
|
||||
search,
|
||||
)
|
||||
|
|
@ -172,11 +180,12 @@ func GetHook(hookID int) (hook Hook, err error) { // {{{
|
|||
to_json(res)
|
||||
FROM (
|
||||
SELECT
|
||||
h.id,
|
||||
h.ssh,
|
||||
h.env,
|
||||
(SELECT to_json(node) FROM node WHERE id = h.node_id) AS node,
|
||||
(SELECT to_json(script) FROM script WHERE id = h.script_id) AS script
|
||||
h.id,
|
||||
h.ssh,
|
||||
h.env,
|
||||
h.schedule_on_child_update,
|
||||
(SELECT to_json(node) FROM node WHERE id = h.node_id) AS node,
|
||||
(SELECT to_json(script) FROM script WHERE id = h.script_id) AS script
|
||||
FROM hook h
|
||||
WHERE
|
||||
h.id = $1
|
||||
|
|
@ -198,7 +207,20 @@ func GetHook(hookID int) (hook Hook, err error) { // {{{
|
|||
} // }}}
|
||||
func UpdateHook(hook Hook) (err error) { // {{{
|
||||
j, _ := json.Marshal(hook.Env)
|
||||
_, err = db.Exec(`UPDATE hook SET ssh=$2, env=$3 WHERE id=$1`, hook.ID, strings.TrimSpace(hook.SSH), j)
|
||||
_, err = db.Exec(`
|
||||
UPDATE hook
|
||||
SET
|
||||
ssh=$2,
|
||||
env=$3,
|
||||
schedule_on_child_update=$4
|
||||
WHERE
|
||||
id=$1
|
||||
`,
|
||||
hook.ID,
|
||||
strings.TrimSpace(hook.SSH),
|
||||
j,
|
||||
hook.ScheduleOnChildUpdate,
|
||||
)
|
||||
if err != nil {
|
||||
err = werr.Wrap(err)
|
||||
return
|
||||
|
|
@ -259,6 +281,58 @@ func ScheduleHook(hookID int) (err error) { // {{{
|
|||
|
||||
return
|
||||
} // }}}
|
||||
func ScheduleHookRecursivelyUpwards(nodeID int) (err error) { // {{{
|
||||
var rows *sql.Rows
|
||||
rows, err = db.Query(`
|
||||
WITH RECURSIVE rec AS (
|
||||
SELECT
|
||||
id,
|
||||
parent_id
|
||||
FROM public.node
|
||||
WHERE
|
||||
id = $1
|
||||
|
||||
UNION ALL
|
||||
|
||||
SELECT
|
||||
n.id,
|
||||
n.parent_id
|
||||
FROM node n
|
||||
INNER JOIN rec ON n.id = rec.parent_id
|
||||
)
|
||||
|
||||
SELECT
|
||||
hook.id
|
||||
FROM rec
|
||||
INNER JOIN hook ON
|
||||
hook.node_id = rec.id AND
|
||||
hook.schedule_on_child_update
|
||||
`,
|
||||
nodeID,
|
||||
)
|
||||
if err != nil {
|
||||
err = werr.Wrap(err)
|
||||
return
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
for rows.Next() {
|
||||
var hookID int
|
||||
err = rows.Scan(&hookID)
|
||||
if err != nil {
|
||||
err = werr.Wrap(err)
|
||||
return
|
||||
}
|
||||
|
||||
err = ScheduleHook(hookID)
|
||||
if err != nil {
|
||||
err = werr.Wrap(err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
} // }}}
|
||||
|
||||
func ScriptPreservedID(name, source string) (id int, err error) { // {{{
|
||||
sum := md5.Sum([]byte(source))
|
||||
|
|
|
|||
1
sql/0018.sql
Normal file
1
sql/0018.sql
Normal file
|
|
@ -0,0 +1 @@
|
|||
ALTER TABLE public.hook DROP CONSTRAINT hook_unique;
|
||||
1
sql/0019.sql
Normal file
1
sql/0019.sql
Normal file
|
|
@ -0,0 +1 @@
|
|||
ALTER TABLE public.hook ADD schedule_on_child_update bool DEFAULT false NOT NULL;
|
||||
|
|
@ -1464,6 +1464,7 @@ class ScriptHookDialog extends Component {
|
|||
|
||||
this.env = null
|
||||
this.ssh = null
|
||||
this.schedule_on_child_update = null
|
||||
}// }}}
|
||||
renderComponent() {// {{{
|
||||
const div = document.createElement('div')
|
||||
|
|
@ -1472,9 +1473,16 @@ class ScriptHookDialog extends Component {
|
|||
<div class="header"></div>
|
||||
<img src="/images/${_VERSION}/node_modules/@mdi/svg/svg/trash-can.svg">
|
||||
</div>
|
||||
|
||||
<div class="label">SSH</div>
|
||||
<div><input type="text" class="ssh" style="width: 100%" /></div>
|
||||
|
||||
<div class="label">Schedule automatically</div>
|
||||
<div>
|
||||
<input type="checkbox" class="schedule-on-child" id="schedule-on-child" />
|
||||
<label for="schedule-on-child">on child update</label>
|
||||
</div>
|
||||
|
||||
<div class="label">
|
||||
Environment
|
||||
</div>
|
||||
|
|
@ -1499,6 +1507,9 @@ class ScriptHookDialog extends Component {
|
|||
this.env = div.querySelector('.env')
|
||||
this.env.value = JSON.stringify(this.hook.Env, null, " ")
|
||||
|
||||
this.schedule_on_child_update = div.querySelector('.schedule-on-child')
|
||||
this.schedule_on_child_update.checked = this.hook.ScheduleOnChildUpdate
|
||||
|
||||
const button = div.querySelector('button')
|
||||
this.env.addEventListener('keydown', event => {
|
||||
if (event.ctrlKey && event.key == 's') {
|
||||
|
|
@ -1527,6 +1538,7 @@ class ScriptHookDialog extends Component {
|
|||
try {
|
||||
this.hook.Env = JSON.parse(this.env.value)
|
||||
this.hook.SSH = this.ssh.value.trim()
|
||||
this.hook.ScheduleOnChildUpdate = this.schedule_on_child_update.checked
|
||||
window._app.query('/hooks/update', this.hook)
|
||||
.then(() => {
|
||||
this.callback()
|
||||
|
|
@ -1659,7 +1671,7 @@ class ScriptExecutionValueDialog extends Component {
|
|||
|
||||
this.value = null
|
||||
}// }}}
|
||||
getValue(execution) {
|
||||
getValue(execution) {// {{{
|
||||
switch (this.valueName) {
|
||||
case 'Source':
|
||||
return execution.Source
|
||||
|
|
@ -1677,7 +1689,7 @@ class ScriptExecutionValueDialog extends Component {
|
|||
case 'OutputStderr':
|
||||
return execution[this.valueName]?.String
|
||||
}
|
||||
}
|
||||
}// }}}
|
||||
renderComponent() {// {{{
|
||||
const div = document.createElement('div')
|
||||
div.innerHTML = `
|
||||
|
|
@ -1710,5 +1722,4 @@ class ScriptExecutionValueDialog extends Component {
|
|||
}// }}}
|
||||
}
|
||||
|
||||
|
||||
// vim: foldmethod=marker
|
||||
|
|
|
|||
20
webserver.go
20
webserver.go
|
|
@ -51,7 +51,7 @@ func initWebserver() (err error) {
|
|||
http.HandleFunc("/scripts/", actionScripts)
|
||||
http.HandleFunc("/scripts/update/{scriptID}", actionScriptUpdate)
|
||||
http.HandleFunc("/scripts/delete/{scriptID}", actionScriptDelete)
|
||||
http.HandleFunc("/hooks/search", actionScriptsSearch)
|
||||
http.HandleFunc("/scripts/search", actionScriptsSearch)
|
||||
http.HandleFunc("/hooks/update", actionHookUpdate)
|
||||
http.HandleFunc("/hooks/delete/{hookID}", actionHookDelete)
|
||||
http.HandleFunc("/hooks/schedule/{hookID}", actionHookSchedule)
|
||||
|
|
@ -173,6 +173,14 @@ func actionNodeUpdate(w http.ResponseWriter, r *http.Request) { // {{{
|
|||
return
|
||||
}
|
||||
|
||||
// Recursively schedule hooks with automatic trigger.
|
||||
err = ScheduleHookRecursivelyUpwards(nodeID)
|
||||
if err != nil {
|
||||
err = werr.Wrap(err)
|
||||
httpError(w, err)
|
||||
return
|
||||
}
|
||||
|
||||
out := struct {
|
||||
OK bool
|
||||
}{
|
||||
|
|
@ -605,7 +613,7 @@ func actionScripts(w http.ResponseWriter, r *http.Request) { // {{{
|
|||
}
|
||||
|
||||
out := struct {
|
||||
OK bool
|
||||
OK bool
|
||||
Scripts []Script
|
||||
}{
|
||||
true,
|
||||
|
|
@ -629,7 +637,7 @@ func actionScriptUpdate(w http.ResponseWriter, r *http.Request) { // {{{
|
|||
}
|
||||
|
||||
out := struct {
|
||||
OK bool
|
||||
OK bool
|
||||
Script Script
|
||||
}{
|
||||
true,
|
||||
|
|
@ -678,7 +686,7 @@ func actionScriptsSearch(w http.ResponseWriter, r *http.Request) { // {{{
|
|||
}
|
||||
|
||||
out := struct {
|
||||
OK bool
|
||||
OK bool
|
||||
Scripts []Script
|
||||
}{
|
||||
true,
|
||||
|
|
@ -763,7 +771,7 @@ func actionScriptExecutions(w http.ResponseWriter, r *http.Request) { // {{{
|
|||
}
|
||||
|
||||
out := struct {
|
||||
OK bool
|
||||
OK bool
|
||||
ScriptExecutions []ScriptExecutionBrief
|
||||
}{
|
||||
true,
|
||||
|
|
@ -785,7 +793,7 @@ func actionScriptExecutionGet(w http.ResponseWriter, r *http.Request) { // {{{
|
|||
}
|
||||
|
||||
out := struct {
|
||||
OK bool
|
||||
OK bool
|
||||
ScriptExecution ScriptExecution
|
||||
}{
|
||||
true,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue