@@ -32,6 +32,7 @@ import (
32
32
// secure randomness
33
33
"math/rand" // #nosec
34
34
35
+ "github.com/containerd/containerd/cio"
35
36
"github.com/containerd/containerd/errdefs"
36
37
"github.com/containerd/containerd/events/exchange"
37
38
"github.com/containerd/containerd/log"
@@ -88,6 +89,10 @@ const (
88
89
89
90
// StopEventName is the topic published to when a VM stops
90
91
StopEventName = "/firecracker-vm/stop"
92
+
93
+ // taskExecID is a special exec ID that is pointing its task itself.
94
+ // While the constant is defined here, the convention is coming from containerd.
95
+ taskExecID = ""
91
96
)
92
97
93
98
var (
@@ -146,6 +151,10 @@ type service struct {
146
151
machineConfig * firecracker.Config
147
152
vsockIOPortCount uint32
148
153
vsockPortMu sync.Mutex
154
+
155
+ // fifos have stdio FIFOs containerd passed to the shim. The key is [taskID][execID].
156
+ fifos map [string ]map [string ]cio.Config
157
+ fifosMu sync.Mutex
149
158
}
150
159
151
160
func shimOpts (shimCtx context.Context ) (* shim.Opts , error ) {
@@ -210,6 +219,7 @@ func NewService(shimCtx context.Context, id string, remotePublisher shim.Publish
210
219
211
220
vmReady : make (chan struct {}),
212
221
jailer : newNoopJailer (shimCtx , logger , shimDir ),
222
+ fifos : make (map [string ]map [string ]cio.Config ),
213
223
}
214
224
215
225
s .startEventForwarders (remotePublisher )
@@ -891,6 +901,39 @@ func (s *service) newIOProxy(logger *logrus.Entry, stdin, stdout, stderr string,
891
901
return ioConnectorSet , nil
892
902
}
893
903
904
+ func (s * service ) addFIFOs (taskID , execID string , config cio.Config ) error {
905
+ s .fifosMu .Lock ()
906
+ defer s .fifosMu .Unlock ()
907
+
908
+ _ , exists := s .fifos [taskID ]
909
+ if ! exists {
910
+ s .fifos [taskID ] = make (map [string ]cio.Config )
911
+ }
912
+
913
+ value , exists := s.fifos [taskID ][execID ]
914
+ if exists {
915
+ return fmt .Errorf ("failed to add FIFO files for task %q (exec=%q). There was %+v already" , taskID , execID , value )
916
+ }
917
+ s.fifos [taskID ][execID ] = config
918
+ return nil
919
+ }
920
+
921
+ func (s * service ) deleteFIFOs (taskID , execID string ) error {
922
+ s .fifosMu .Lock ()
923
+ defer s .fifosMu .Unlock ()
924
+
925
+ _ , exists := s.fifos [taskID ][execID ]
926
+ if ! exists {
927
+ return fmt .Errorf ("task %q (exec=%q) doesn't have corresponding FIFOs to delete" , taskID , execID )
928
+ }
929
+ delete (s .fifos [taskID ], execID )
930
+
931
+ if execID == taskExecID {
932
+ delete (s .fifos , taskID )
933
+ }
934
+ return nil
935
+ }
936
+
894
937
func (s * service ) Create (requestCtx context.Context , request * taskAPI.CreateTaskRequest ) (* taskAPI.CreateTaskResponse , error ) {
895
938
logger := s .logger .WithField ("task_id" , request .ID )
896
939
defer logPanicAndDie (logger )
@@ -982,6 +1025,15 @@ func (s *service) Create(requestCtx context.Context, request *taskAPI.CreateTask
982
1025
return nil , err
983
1026
}
984
1027
1028
+ err = s .addFIFOs (request .ID , taskExecID , cio.Config {
1029
+ Stdin : request .Stdin ,
1030
+ Stdout : request .Stdout ,
1031
+ Stderr : request .Stderr ,
1032
+ })
1033
+ if err != nil {
1034
+ return nil , err
1035
+ }
1036
+
985
1037
return resp , nil
986
1038
}
987
1039
@@ -1008,6 +1060,11 @@ func (s *service) Delete(requestCtx context.Context, req *taskAPI.DeleteRequest)
1008
1060
return nil , err
1009
1061
}
1010
1062
1063
+ err = s .deleteFIFOs (req .ID , req .ExecID )
1064
+ if err != nil {
1065
+ return nil , err
1066
+ }
1067
+
1011
1068
// Only delete a process as like runc when there is ExecID
1012
1069
// https://github.com/containerd/containerd/blob/f3e148b1ccf268450c87427b5dbb6187db3d22f1/runtime/v2/runc/container.go#L320
1013
1070
if req .ExecID != "" {
@@ -1069,6 +1126,16 @@ func (s *service) Exec(requestCtx context.Context, req *taskAPI.ExecProcessReque
1069
1126
return nil , err
1070
1127
}
1071
1128
1129
+ err = s .addFIFOs (req .ID , req .ExecID , cio.Config {
1130
+ Terminal : req .Terminal ,
1131
+ Stdin : req .Stdin ,
1132
+ Stdout : req .Stdout ,
1133
+ Stderr : req .Stderr ,
1134
+ })
1135
+ if err != nil {
1136
+ return nil , err
1137
+ }
1138
+
1072
1139
return resp , nil
1073
1140
}
1074
1141
@@ -1095,6 +1162,14 @@ func (s *service) State(requestCtx context.Context, req *taskAPI.StateRequest) (
1095
1162
return nil , err
1096
1163
}
1097
1164
1165
+ // These fields are pointing files inside the VM.
1166
+ // Replace them with the corresponding files on the host, so clients can access.
1167
+ s .fifosMu .Lock ()
1168
+ defer s .fifosMu .Unlock ()
1169
+ resp .Stdin = s.fifos [req.ID ][req.ExecID ].Stdin
1170
+ resp .Stdout = s.fifos [req.ID ][req.ExecID ].Stdout
1171
+ resp .Stderr = s.fifos [req.ID ][req.ExecID ].Stderr
1172
+
1098
1173
return resp , nil
1099
1174
}
1100
1175
0 commit comments