Sfoglia il codice sorgente

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
James Read 3 anni fa
parent
commit
f05de1c726

+ 1 - 0
OliveTin.proto

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

+ 7 - 1
cmd/OliveTin/main.go

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

+ 9 - 8
internal/config/config.go

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

+ 4 - 0
internal/executor/executor.go

@@ -17,6 +17,7 @@ import (
 type ExecutionRequest struct {
 	ActionName         string
 	Arguments          map[string]string
+	Tags               []string
 	action             *config.Action
 	Cfg                *config.Config
 	AuthenticatedUser  *acl.AuthenticatedUser
@@ -33,6 +34,7 @@ type InternalLogEntry struct {
 	Stderr   string
 	TimedOut bool
 	ExitCode int32
+	Tags     []string
 
 	/*
 		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.Tags = req.Tags
+
 	return true
 }

+ 9 - 6
internal/grpcapi/grpcApi.go

@@ -15,11 +15,12 @@ import (
 
 var (
 	cfg *config.Config
-	ex  = executor.DefaultExecutor()
 )
 
 type oliveTinAPI struct {
 	pb.UnimplementedOliveTinApiServer
+
+	executor *executor.Executor
 }
 
 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,
 	}
 
-	return ex.ExecRequest(&execReq), nil
+	return api.executor.ExecRequest(&execReq), nil
 }
 
 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.
 
-	for _, logEntry := range ex.Logs {
+	for _, logEntry := range api.executor.Logs {
 		ret.Logs = append(ret.Logs, &pb.LogEntry{
 			ActionTitle: logEntry.ActionTitle,
 			ActionIcon:  logEntry.ActionIcon,
@@ -69,6 +70,7 @@ func (api *oliveTinAPI) GetLogs(ctx ctx.Context, req *pb.GetLogsRequest) (*pb.Ge
 			Stderr:      logEntry.Stderr,
 			TimedOut:    logEntry.TimedOut,
 			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.
-func Start(globalConfig *config.Config) {
+func Start(globalConfig *config.Config, ex *executor.Executor) {
 	cfg = globalConfig
 
 	lis, err := net.Listen("tcp", cfg.ListenAddressGrpcActions)
@@ -117,7 +119,7 @@ func Start(globalConfig *config.Config) {
 	}
 
 	grpcServer := grpc.NewServer()
-	pb.RegisterOliveTinApiServer(grpcServer, newServer())
+	pb.RegisterOliveTinApiServer(grpcServer, newServer(ex))
 
 	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.executor = ex
 	return &server
 }

+ 4 - 1
internal/grpcapi/grpcApi_test.go

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

+ 32 - 0
internal/onstartup/startup.go

@@ -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)
+		}
+	}
+}

+ 2 - 1
webui/index.html

@@ -102,7 +102,7 @@
 				<td>
 					<span class = "icon" role = "icon"></span>
 					<span class = "content">?</span>
-				
+	
 					<details>
 						<summary>stdout</summary>
 						<pre class = "stdout">
@@ -117,6 +117,7 @@
 						</pre>
 					</details>
 
+					<div class = "tags"></div>
 				</td>
 				<td class = "exit-code">?</td>
 			</tr>

+ 8 - 0
webui/js/marshaller.js

@@ -57,6 +57,14 @@ export function marshalLogsJsonToHtml (json) {
     row.querySelector('pre.stderr').innerText = logEntry.stderr
     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)
   }
 }

+ 6 - 0
webui/style.css

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