WIP: implemented Ping, implemented Set and Shutdown in agent, and added umask

This commit is contained in:
2025-06-23 16:43:53 +10:00
parent cfdfcb6ed5
commit b22529be7b
10 changed files with 243 additions and 60 deletions

View File

@@ -19,9 +19,12 @@ limitations under the License.
import (
"context"
"fmt"
"golang.org/x/sys/unix"
"net"
"os"
"os/exec"
"sync/atomic"
"syscall"
"time"
pb "gitea.suyono.dev/suyono/go-agent/proto"
@@ -32,8 +35,12 @@ import (
type Option interface {
SocketPath() string
Expiry() string
StopGraceTime() time.Duration
Background() bool
ExecArgs() []string
ExecEnv() []string
ExecLogPath() string
Umask() int
}
type Storage interface {
@@ -42,6 +49,18 @@ type Storage interface {
Shutdown() error
}
type BgProcFlag int
const (
child BgProcFlag = iota
parent
)
const (
goAgentDaemonEnvFlag = "GO_AGENT_DAEMON"
goAgentDaemonLogPath = "GO_AGENT_DAEMON_LOG"
)
type server struct {
pb.UnimplementedAgentServer
stor Storage
@@ -77,6 +96,48 @@ func (s *server) Shutdown(context.Context, *emptypb.Empty) (*emptypb.Empty, erro
return &emptypb.Empty{}, nil
}
func GetDaemonLogPath() (string, error) {
// The child process of the main program should call this function and set up the logging infrastructure
envVal, ok := os.LookupEnv(goAgentDaemonLogPath)
if !ok {
return "", fmt.Errorf("programming issue: parent process did not set log path")
}
return envVal, nil
}
func ExecBackground(opt Option) (BgProcFlag, error) {
var (
cmd *exec.Cmd
ok bool
envVal string
)
args := opt.ExecArgs()
envVal, ok = os.LookupEnv(goAgentDaemonEnvFlag)
if !opt.Background() || len(args) == 0 || (envVal == "1" && ok) {
return child, nil
}
if len(args) > 1 {
cmd = exec.Command(args[0], args[1:]...)
} else {
cmd = exec.Command(args[0])
}
cmd.Env = append(os.Environ(), fmt.Sprintf("%s=1", goAgentDaemonEnvFlag))
if opt.ExecLogPath() != "" {
cmd.Env = append(cmd.Env, fmt.Sprintf("%s=%s", goAgentDaemonLogPath, opt.ExecLogPath()))
}
cmd.Env = append(cmd.Env, opt.ExecEnv()...)
cmd.SysProcAttr = &syscall.SysProcAttr{Setsid: true}
cmd.Stdin, cmd.Stdout, cmd.Stderr = nil, nil, nil
if err := cmd.Start(); err != nil {
return parent, err
}
return parent, nil
}
func Serve(ctx context.Context, opt Option) error {
var (
l net.Listener
@@ -85,18 +146,30 @@ func Serve(ctx context.Context, opt Option) error {
ok bool
sw *atomic.Bool
cancel context.CancelFunc
bgFlag BgProcFlag
)
socketPath := opt.SocketPath()
os.Remove(socketPath)
if l, err = net.Listen("unix", socketPath); err != nil {
return fmt.Errorf("failed to listen on unix socket: %w", err)
if bgFlag, err = ExecBackground(opt); err != nil {
return fmt.Errorf("could not start background process: %w", err)
}
if bgFlag == parent {
return nil
}
_ = os.Remove(opt.SocketPath())
oldUmask := unix.Umask(opt.Umask())
if l, err = net.Listen("unix", opt.SocketPath()); err != nil {
return fmt.Errorf("failed to listen on unix socket: %w", err)
}
unix.Umask(oldUmask)
grpcServer := grpc.NewServer()
pb.RegisterAgentServer(grpcServer, &server{stor: storage.NewInMap()})
errChan := make(chan error, 1)
ctx, cancel = context.WithCancel(ctx)
pb.RegisterAgentServer(grpcServer, &server{
stor: storage.NewInMap(cancel),
})
errChan := make(chan error, 1)
sw = new(atomic.Bool)
sw.Store(false)
@@ -137,3 +210,7 @@ fsl:
return err
}
func (s *server) Ping(ctx context.Context, req *emptypb.Empty) (*emptypb.Empty, error) {
return &emptypb.Empty{}, nil
}