github.com/hernad/nomad@v1.6.112/drivers/shared/executor/grpc_server.go (about) 1 // Copyright (c) HashiCorp, Inc. 2 // SPDX-License-Identifier: MPL-2.0 3 4 package executor 5 6 import ( 7 "context" 8 "fmt" 9 "syscall" 10 "time" 11 12 "github.com/golang/protobuf/ptypes" 13 "google.golang.org/grpc/codes" 14 "google.golang.org/grpc/status" 15 16 "github.com/hernad/nomad/drivers/shared/executor/proto" 17 "github.com/hernad/nomad/nomad/structs" 18 "github.com/hernad/nomad/plugins/drivers" 19 sproto "github.com/hernad/nomad/plugins/shared/structs/proto" 20 ) 21 22 type grpcExecutorServer struct { 23 impl Executor 24 } 25 26 func (s *grpcExecutorServer) Launch(ctx context.Context, req *proto.LaunchRequest) (*proto.LaunchResponse, error) { 27 ps, err := s.impl.Launch(&ExecCommand{ 28 Cmd: req.Cmd, 29 Args: req.Args, 30 Resources: drivers.ResourcesFromProto(req.Resources), 31 StdoutPath: req.StdoutPath, 32 StderrPath: req.StderrPath, 33 Env: req.Env, 34 User: req.User, 35 TaskDir: req.TaskDir, 36 ResourceLimits: req.ResourceLimits, 37 BasicProcessCgroup: req.BasicProcessCgroup, 38 NoPivotRoot: req.NoPivotRoot, 39 Mounts: drivers.MountsFromProto(req.Mounts), 40 Devices: drivers.DevicesFromProto(req.Devices), 41 NetworkIsolation: drivers.NetworkIsolationSpecFromProto(req.NetworkIsolation), 42 ModePID: req.DefaultPidMode, 43 ModeIPC: req.DefaultIpcMode, 44 Capabilities: req.Capabilities, 45 }) 46 47 if err != nil { 48 return nil, err 49 } 50 51 process, err := processStateToProto(ps) 52 if err != nil { 53 return nil, err 54 } 55 56 return &proto.LaunchResponse{ 57 Process: process, 58 }, nil 59 } 60 61 func (s *grpcExecutorServer) Wait(ctx context.Context, req *proto.WaitRequest) (*proto.WaitResponse, error) { 62 ps, err := s.impl.Wait(ctx) 63 if err != nil { 64 return nil, err 65 } 66 67 process, err := processStateToProto(ps) 68 if err != nil { 69 return nil, err 70 } 71 72 return &proto.WaitResponse{ 73 Process: process, 74 }, nil 75 } 76 77 func (s *grpcExecutorServer) Shutdown(ctx context.Context, req *proto.ShutdownRequest) (*proto.ShutdownResponse, error) { 78 if err := s.impl.Shutdown(req.Signal, time.Duration(req.GracePeriod)); err != nil { 79 return nil, err 80 } 81 82 return &proto.ShutdownResponse{}, nil 83 } 84 85 func (s *grpcExecutorServer) UpdateResources(ctx context.Context, req *proto.UpdateResourcesRequest) (*proto.UpdateResourcesResponse, error) { 86 if err := s.impl.UpdateResources(drivers.ResourcesFromProto(req.Resources)); err != nil { 87 return nil, err 88 } 89 90 return &proto.UpdateResourcesResponse{}, nil 91 } 92 93 func (s *grpcExecutorServer) Version(context.Context, *proto.VersionRequest) (*proto.VersionResponse, error) { 94 v, err := s.impl.Version() 95 if err != nil { 96 return nil, err 97 } 98 99 return &proto.VersionResponse{ 100 Version: v.Version, 101 }, nil 102 } 103 104 func (s *grpcExecutorServer) Stats(req *proto.StatsRequest, stream proto.Executor_StatsServer) error { 105 interval := time.Duration(req.Interval) 106 if interval == 0 { 107 interval = time.Second 108 } 109 110 outCh, err := s.impl.Stats(stream.Context(), interval) 111 if err != nil { 112 if rec, ok := err.(structs.Recoverable); ok { 113 st := status.New(codes.FailedPrecondition, rec.Error()) 114 st, err := st.WithDetails(&sproto.RecoverableError{Recoverable: rec.IsRecoverable()}) 115 if err != nil { 116 // If this error, it will always error 117 panic(err) 118 } 119 return st.Err() 120 } 121 return err 122 } 123 124 for resp := range outCh { 125 pbStats, err := drivers.TaskStatsToProto(resp) 126 if err != nil { 127 return err 128 } 129 130 presp := &proto.StatsResponse{ 131 Stats: pbStats, 132 } 133 134 // Send the stats 135 if err := stream.Send(presp); err != nil { 136 return err 137 } 138 } 139 140 return nil 141 } 142 143 func (s *grpcExecutorServer) Signal(ctx context.Context, req *proto.SignalRequest) (*proto.SignalResponse, error) { 144 sig := syscall.Signal(req.Signal) 145 if err := s.impl.Signal(sig); err != nil { 146 return nil, err 147 } 148 return &proto.SignalResponse{}, nil 149 } 150 151 func (s *grpcExecutorServer) Exec(ctx context.Context, req *proto.ExecRequest) (*proto.ExecResponse, error) { 152 deadline, err := ptypes.Timestamp(req.Deadline) 153 if err != nil { 154 return nil, err 155 } 156 157 out, exit, err := s.impl.Exec(deadline, req.Cmd, req.Args) 158 if err != nil { 159 return nil, err 160 } 161 162 return &proto.ExecResponse{ 163 Output: out, 164 ExitCode: int32(exit), 165 }, nil 166 } 167 168 func (s *grpcExecutorServer) ExecStreaming(server proto.Executor_ExecStreamingServer) error { 169 msg, err := server.Recv() 170 if err != nil { 171 return fmt.Errorf("failed to receive initial message: %v", err) 172 } 173 174 if msg.Setup == nil { 175 return fmt.Errorf("first message should always be setup") 176 } 177 178 return s.impl.ExecStreaming(server.Context(), 179 msg.Setup.Command, msg.Setup.Tty, 180 server) 181 }