feature: Kill support in the UI (#297)
* feature: Kill command API (wip) * feature: Kill support in the UI
This commit is contained in:
parent
a783fc8cd4
commit
dc6f6c2896
|
|
@ -189,6 +189,17 @@ message EventExecutionFinished {
|
||||||
LogEntry log_entry = 1;
|
LogEntry log_entry = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
message KillActionRequest {
|
||||||
|
string execution_tracking_id = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message KillActionResponse {
|
||||||
|
string execution_tracking_id = 1;
|
||||||
|
bool killed = 2;
|
||||||
|
bool already_completed = 3;
|
||||||
|
bool found = 4;
|
||||||
|
}
|
||||||
|
|
||||||
service OliveTinApiService {
|
service OliveTinApiService {
|
||||||
rpc GetDashboardComponents(GetDashboardComponentsRequest) returns (GetDashboardComponentsResponse) {
|
rpc GetDashboardComponents(GetDashboardComponentsRequest) returns (GetDashboardComponentsResponse) {
|
||||||
option (google.api.http) = {
|
option (google.api.http) = {
|
||||||
|
|
@ -222,6 +233,13 @@ service OliveTinApiService {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rpc KillAction(KillActionRequest) returns (KillActionResponse) {
|
||||||
|
option (google.api.http) = {
|
||||||
|
post: "/api/KillAction"
|
||||||
|
body: "*"
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
rpc ExecutionStatus(ExecutionStatusRequest) returns (ExecutionStatusResponse) {
|
rpc ExecutionStatus(ExecutionStatusRequest) returns (ExecutionStatusResponse) {
|
||||||
option (google.api.http) = {
|
option (google.api.http) = {
|
||||||
post: "/api/ExecutionStatus"
|
post: "/api/ExecutionStatus"
|
||||||
|
|
|
||||||
|
|
@ -74,6 +74,7 @@ type InternalLogEntry struct {
|
||||||
ExecutionStarted bool
|
ExecutionStarted bool
|
||||||
ExecutionFinished bool
|
ExecutionFinished bool
|
||||||
ExecutionTrackingID string
|
ExecutionTrackingID string
|
||||||
|
Process *os.Process
|
||||||
|
|
||||||
/*
|
/*
|
||||||
The following 3 properties are obviously on Action normally, but it's useful
|
The following 3 properties are obviously on Action normally, but it's useful
|
||||||
|
|
@ -382,6 +383,8 @@ func stepExec(req *ExecutionRequest) bool {
|
||||||
|
|
||||||
runerr := cmd.Start()
|
runerr := cmd.Start()
|
||||||
|
|
||||||
|
req.logEntry.Process = cmd.Process
|
||||||
|
|
||||||
waiterr := cmd.Wait()
|
waiterr := cmd.Wait()
|
||||||
|
|
||||||
req.logEntry.ExitCode = int32(cmd.ProcessState.ExitCode())
|
req.logEntry.ExitCode = int32(cmd.ProcessState.ExitCode())
|
||||||
|
|
|
||||||
|
|
@ -30,6 +30,28 @@ type oliveTinAPI struct {
|
||||||
executor *executor.Executor
|
executor *executor.Executor
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (api *oliveTinAPI) KillAction(ctx ctx.Context, req *pb.KillActionRequest) (*pb.KillActionResponse, error) {
|
||||||
|
ret := &pb.KillActionResponse{
|
||||||
|
ExecutionTrackingId: req.ExecutionTrackingId,
|
||||||
|
}
|
||||||
|
|
||||||
|
execReq, found := api.executor.Logs[req.ExecutionTrackingId]
|
||||||
|
|
||||||
|
ret.Found = found
|
||||||
|
|
||||||
|
if found {
|
||||||
|
err := execReq.Process.Kill()
|
||||||
|
|
||||||
|
if err == nil {
|
||||||
|
ret.AlreadyCompleted = true
|
||||||
|
} else {
|
||||||
|
ret.Killed = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (api *oliveTinAPI) StartAction(ctx ctx.Context, req *pb.StartActionRequest) (*pb.StartActionResponse, error) {
|
func (api *oliveTinAPI) StartAction(ctx ctx.Context, req *pb.StartActionRequest) (*pb.StartActionResponse, error) {
|
||||||
args := make(map[string]string)
|
args := make(map[string]string)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -125,11 +125,13 @@
|
||||||
</details>
|
</details>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<form method = "dialog">
|
<div class = "buttons">
|
||||||
<div class = "buttons">
|
<button name = "kill" title = "Kill" id = "execution-dialog-kill-action">Kill</button>
|
||||||
|
|
||||||
|
<form method = "dialog">
|
||||||
<button name = "Cancel" title = "Close">Close</button>
|
<button name = "Cancel" title = "Close">Close</button>
|
||||||
</div>
|
</form>
|
||||||
</form>
|
</div>
|
||||||
</dialog>
|
</dialog>
|
||||||
|
|
||||||
<template id = "tplArgumentForm">
|
<template id = "tplArgumentForm">
|
||||||
|
|
|
||||||
|
|
@ -146,6 +146,7 @@ class ActionButton extends ExecutionFeedbackButton {
|
||||||
window.executionDialog.hideEverythingApartFromOutput()
|
window.executionDialog.hideEverythingApartFromOutput()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
window.executionDialog.executionTrackingId = executionTrackingId
|
||||||
window.executionDialog.show(this)
|
window.executionDialog.show(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,8 @@ export class ExecutionDialog {
|
||||||
this.toggleSize()
|
this.toggleSize()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.domBtnKill = document.getElementById('execution-dialog-kill-action')
|
||||||
|
|
||||||
this.domDatetimeStarted = document.getElementById('execution-dialog-datetime-started')
|
this.domDatetimeStarted = document.getElementById('execution-dialog-datetime-started')
|
||||||
this.domDatetimeFinished = document.getElementById('execution-dialog-datetime-finished')
|
this.domDatetimeFinished = document.getElementById('execution-dialog-datetime-finished')
|
||||||
this.domExitCode = document.getElementById('execution-dialog-exit-code')
|
this.domExitCode = document.getElementById('execution-dialog-exit-code')
|
||||||
|
|
@ -36,6 +38,7 @@ export class ExecutionDialog {
|
||||||
|
|
||||||
reset () {
|
reset () {
|
||||||
this.executionSeconds = 0
|
this.executionSeconds = 0
|
||||||
|
this.executionTrackingId = 'notset'
|
||||||
|
|
||||||
this.dlg.classList.remove('big')
|
this.dlg.classList.remove('big')
|
||||||
this.dlg.style.maxWidth = 'calc(100vw - 2em)'
|
this.dlg.style.maxWidth = 'calc(100vw - 2em)'
|
||||||
|
|
@ -54,6 +57,9 @@ export class ExecutionDialog {
|
||||||
this.domStdout.innerText = ''
|
this.domStdout.innerText = ''
|
||||||
this.domStderr.innerText = ''
|
this.domStderr.innerText = ''
|
||||||
|
|
||||||
|
this.domBtnKill.disabled = true
|
||||||
|
this.domBtnKill.onclick = () => {}
|
||||||
|
|
||||||
this.hideDetailsOnResult = false
|
this.hideDetailsOnResult = false
|
||||||
this.domExecutionBasics.hidden = false
|
this.domExecutionBasics.hidden = false
|
||||||
|
|
||||||
|
|
@ -68,6 +74,11 @@ export class ExecutionDialog {
|
||||||
this.domIcon.innerText = actionButton.domIcon.innerText
|
this.domIcon.innerText = actionButton.domIcon.innerText
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.domBtnKill.disabled = false
|
||||||
|
this.domBtnKill.onclick = () => {
|
||||||
|
this.killAction()
|
||||||
|
}
|
||||||
|
|
||||||
clearInterval(window.executionDialogTicker)
|
clearInterval(window.executionDialogTicker)
|
||||||
this.executionSeconds = 0
|
this.executionSeconds = 0
|
||||||
this.executionTick()
|
this.executionTick()
|
||||||
|
|
@ -82,6 +93,24 @@ export class ExecutionDialog {
|
||||||
this.dlg.showModal()
|
this.dlg.showModal()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
killAction () {
|
||||||
|
const killActionArgs = {
|
||||||
|
executionTrackingId: this.executionTrackingId
|
||||||
|
}
|
||||||
|
|
||||||
|
window.fetch(window.restBaseUrl + 'KillAction', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
},
|
||||||
|
body: JSON.stringify(killActionArgs)
|
||||||
|
}).then((res) => {
|
||||||
|
console.log(res)
|
||||||
|
}).catch(err => {
|
||||||
|
throw err
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
executionTick () {
|
executionTick () {
|
||||||
this.executionSeconds++
|
this.executionSeconds++
|
||||||
|
|
||||||
|
|
@ -93,8 +122,8 @@ export class ExecutionDialog {
|
||||||
this.domExecutionBasics.hidden = true
|
this.domExecutionBasics.hidden = true
|
||||||
}
|
}
|
||||||
|
|
||||||
fetchExecutionResult (uuid) {
|
fetchExecutionResult (executionTrackingId) {
|
||||||
this.executionTrackingId = uuid
|
this.executionTrackingId = executionTrackingId
|
||||||
|
|
||||||
const executionStatusArgs = {
|
const executionStatusArgs = {
|
||||||
executionTrackingId: this.executionTrackingId
|
executionTrackingId: this.executionTrackingId
|
||||||
|
|
@ -133,6 +162,8 @@ export class ExecutionDialog {
|
||||||
|
|
||||||
this.executionTrackingId = res.logEntry.executionTrackingId
|
this.executionTrackingId = res.logEntry.executionTrackingId
|
||||||
|
|
||||||
|
this.domBtnKill.disabled = res.logEntry.executionFinished
|
||||||
|
|
||||||
if (res.logEntry.executionFinished) {
|
if (res.logEntry.executionFinished) {
|
||||||
this.domStatus.innerText = 'Completed'
|
this.domStatus.innerText = 'Completed'
|
||||||
this.domStatus.classList.add('action-success')
|
this.domStatus.classList.add('action-success')
|
||||||
|
|
|
||||||
|
|
@ -424,8 +424,10 @@ p.argument-wrapper {
|
||||||
display: flex;
|
display: flex;
|
||||||
}
|
}
|
||||||
|
|
||||||
form div.buttons {
|
div.buttons {
|
||||||
text-align: right;
|
display: flex;
|
||||||
|
justify-content: end;
|
||||||
|
gap: 1em;
|
||||||
}
|
}
|
||||||
|
|
||||||
pre {
|
pre {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue