feature: Execute actions on startup. Externalize the executor and add… (#101)

* feature: Execute actions on startup. Externalize the executor and add tags to logs.

* fmt: Codestyle fixes
This commit is contained in:
James Read 2023-02-02 09:35:18 +00:00 committed by GitHub
parent b6196a4b3f
commit f05de1c726
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 82 additions and 17 deletions

View File

@ -70,6 +70,7 @@ message LogEntry {
string user = 7; string user = 7;
string userClass = 8; string userClass = 8;
string actionIcon = 9; string actionIcon = 9;
repeated string tags = 10;
} }
message GetLogsResponse { message GetLogsResponse {

View File

@ -5,7 +5,9 @@ import (
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
"github.com/OliveTin/OliveTin/internal/executor"
grpcapi "github.com/OliveTin/OliveTin/internal/grpcapi" grpcapi "github.com/OliveTin/OliveTin/internal/grpcapi"
"github.com/OliveTin/OliveTin/internal/onstartup"
updatecheck "github.com/OliveTin/OliveTin/internal/updatecheck" updatecheck "github.com/OliveTin/OliveTin/internal/updatecheck"
"github.com/OliveTin/OliveTin/internal/httpservers" "github.com/OliveTin/OliveTin/internal/httpservers"
@ -100,9 +102,13 @@ func main() {
log.Debugf("Config: %+v", cfg) log.Debugf("Config: %+v", cfg)
executor := executor.DefaultExecutor()
go onstartup.Execute(cfg, executor)
go updatecheck.StartUpdateChecker(version, commit, cfg, configDir) go updatecheck.StartUpdateChecker(version, commit, cfg, configDir)
go grpcapi.Start(cfg) go grpcapi.Start(cfg, executor)
httpservers.StartServers(cfg) httpservers.StartServers(cfg)
} }

View File

@ -3,14 +3,15 @@ package config
// Action represents the core functionality of OliveTin - commands that show up // Action represents the core functionality of OliveTin - commands that show up
// as buttons in the UI. // as buttons in the UI.
type Action struct { type Action struct {
ID string ID string
Title string Title string
Icon string Icon string
Shell string Shell string
CSS map[string]string `mapstructure:"omitempty"` CSS map[string]string `mapstructure:"omitempty"`
Timeout int Timeout int
Acls []string Acls []string
Arguments []ActionArgument ExecOnStartup bool
Arguments []ActionArgument
} }
// ActionArgument objects appear on Actions. // ActionArgument objects appear on Actions.

View File

@ -17,6 +17,7 @@ import (
type ExecutionRequest struct { type ExecutionRequest struct {
ActionName string ActionName string
Arguments map[string]string Arguments map[string]string
Tags []string
action *config.Action action *config.Action
Cfg *config.Config Cfg *config.Config
AuthenticatedUser *acl.AuthenticatedUser AuthenticatedUser *acl.AuthenticatedUser
@ -33,6 +34,7 @@ type InternalLogEntry struct {
Stderr string Stderr string
TimedOut bool TimedOut bool
ExitCode int32 ExitCode int32
Tags []string
/* /*
The following two properties are obviously on Action normally, but it's useful The following two properties are obviously on Action normally, but it's useful
@ -185,5 +187,7 @@ func stepExec(req *ExecutionRequest) bool {
req.logEntry.TimedOut = true req.logEntry.TimedOut = true
} }
req.logEntry.Tags = req.Tags
return true return true
} }

View File

@ -15,11 +15,12 @@ import (
var ( var (
cfg *config.Config cfg *config.Config
ex = executor.DefaultExecutor()
) )
type oliveTinAPI struct { type oliveTinAPI struct {
pb.UnimplementedOliveTinApiServer pb.UnimplementedOliveTinApiServer
executor *executor.Executor
} }
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) {
@ -38,7 +39,7 @@ func (api *oliveTinAPI) StartAction(ctx ctx.Context, req *pb.StartActionRequest)
Cfg: cfg, Cfg: cfg,
} }
return ex.ExecRequest(&execReq), nil return api.executor.ExecRequest(&execReq), nil
} }
func (api *oliveTinAPI) GetDashboardComponents(ctx ctx.Context, req *pb.GetDashboardComponentsRequest) (*pb.GetDashboardComponentsResponse, error) { func (api *oliveTinAPI) GetDashboardComponents(ctx ctx.Context, req *pb.GetDashboardComponentsRequest) (*pb.GetDashboardComponentsResponse, error) {
@ -60,7 +61,7 @@ func (api *oliveTinAPI) GetLogs(ctx ctx.Context, req *pb.GetLogsRequest) (*pb.Ge
// TODO Limit to 10 entries or something to prevent browser lag. // TODO Limit to 10 entries or something to prevent browser lag.
for _, logEntry := range ex.Logs { for _, logEntry := range api.executor.Logs {
ret.Logs = append(ret.Logs, &pb.LogEntry{ ret.Logs = append(ret.Logs, &pb.LogEntry{
ActionTitle: logEntry.ActionTitle, ActionTitle: logEntry.ActionTitle,
ActionIcon: logEntry.ActionIcon, ActionIcon: logEntry.ActionIcon,
@ -69,6 +70,7 @@ func (api *oliveTinAPI) GetLogs(ctx ctx.Context, req *pb.GetLogsRequest) (*pb.Ge
Stderr: logEntry.Stderr, Stderr: logEntry.Stderr,
TimedOut: logEntry.TimedOut, TimedOut: logEntry.TimedOut,
ExitCode: logEntry.ExitCode, ExitCode: logEntry.ExitCode,
Tags: logEntry.Tags,
}) })
} }
@ -107,7 +109,7 @@ func (api *oliveTinAPI) WhoAmI(ctx ctx.Context, req *pb.WhoAmIRequest) (*pb.WhoA
} }
// Start will start the GRPC API. // Start will start the GRPC API.
func Start(globalConfig *config.Config) { func Start(globalConfig *config.Config, ex *executor.Executor) {
cfg = globalConfig cfg = globalConfig
lis, err := net.Listen("tcp", cfg.ListenAddressGrpcActions) lis, err := net.Listen("tcp", cfg.ListenAddressGrpcActions)
@ -117,7 +119,7 @@ func Start(globalConfig *config.Config) {
} }
grpcServer := grpc.NewServer() grpcServer := grpc.NewServer()
pb.RegisterOliveTinApiServer(grpcServer, newServer()) pb.RegisterOliveTinApiServer(grpcServer, newServer(ex))
err = grpcServer.Serve(lis) err = grpcServer.Serve(lis)
@ -126,7 +128,8 @@ func Start(globalConfig *config.Config) {
} }
} }
func newServer() *oliveTinAPI { func newServer(ex *executor.Executor) *oliveTinAPI {
server := oliveTinAPI{} server := oliveTinAPI{}
server.executor = ex
return &server return &server
} }

View File

@ -14,6 +14,7 @@ import (
pb "github.com/OliveTin/OliveTin/gen/grpc" pb "github.com/OliveTin/OliveTin/gen/grpc"
config "github.com/OliveTin/OliveTin/internal/config" config "github.com/OliveTin/OliveTin/internal/config"
"github.com/OliveTin/OliveTin/internal/executor"
) )
const bufSize = 1024 * 1024 const bufSize = 1024 * 1024
@ -21,9 +22,11 @@ const bufSize = 1024 * 1024
var lis *bufconn.Listener var lis *bufconn.Listener
func init() { func init() {
ex := executor.DefaultExecutor()
lis = bufconn.Listen(bufSize) lis = bufconn.Listen(bufSize)
s := grpc.NewServer() s := grpc.NewServer()
pb.RegisterOliveTinApiServer(s, newServer()) pb.RegisterOliveTinApiServer(s, newServer(ex))
go func() { go func() {
if err := s.Serve(lis); err != nil { if err := s.Serve(lis); err != nil {

View File

@ -0,0 +1,32 @@
package onstartup
import (
"github.com/OliveTin/OliveTin/internal/acl"
config "github.com/OliveTin/OliveTin/internal/config"
"github.com/OliveTin/OliveTin/internal/executor"
log "github.com/sirupsen/logrus"
)
func Execute(cfg *config.Config, ex *executor.Executor) {
user := &acl.AuthenticatedUser{
Username: "startup-user",
}
for _, action := range cfg.Actions {
if action.ExecOnStartup {
log.WithFields(log.Fields{
"action": action.Title,
}).Infof("Startup action")
req := &executor.ExecutionRequest{
ActionName: action.Title,
Arguments: nil,
Cfg: cfg,
Tags: []string{"startup"},
AuthenticatedUser: user,
}
ex.ExecRequest(req)
}
}
}

View File

@ -117,6 +117,7 @@
</pre> </pre>
</details> </details>
<div class = "tags"></div>
</td> </td>
<td class = "exit-code">?</td> <td class = "exit-code">?</td>
</tr> </tr>

View File

@ -57,6 +57,14 @@ export function marshalLogsJsonToHtml (json) {
row.querySelector('pre.stderr').innerText = logEntry.stderr row.querySelector('pre.stderr').innerText = logEntry.stderr
row.querySelector('.exit-code').innerText = logTableExitCode row.querySelector('.exit-code').innerText = logTableExitCode
for (const tag of logEntry.tags) {
const domTag = document.createElement('span')
domTag.classList.add('tag')
domTag.innerText = tag
row.querySelector('.tags').append(domTag)
}
document.querySelector('#logTableBody').prepend(row) document.querySelector('#logTableBody').prepend(row)
} }
} }

View File

@ -387,6 +387,12 @@ input.invalid {
border-radius: 1em; border-radius: 1em;
} }
span.tag {
background-color: lightgray;
border-radius: 0.6em;
padding: 0.2em;
}
@media (prefers-color-scheme: dark) { @media (prefers-color-scheme: dark) {
body { body {
background-color: #333; background-color: #333;