@@ -20,20 +20,20 @@ import (
2020)
2121
2222const (
23- compKey string = "name"
24- ddComponentKey string = "component"
25- ddComponentAll string = "all"
26- ddLogLvlKey string = "level"
27- ddLogLvlAlert string = "alert"
28- ddLogLvlCritical string = "critical"
29- ddLogLvlAll string = "all"
30- ddLogLvlSuf string = "-info"
31- ddFileSegSize int = 4096
32- artifactSleepTime time.Duration = 5 * time .Second
23+ compKey string = "name"
24+ ddComponentKey string = "component"
25+ ddComponentAll string = "all"
26+ ddLogLvlKey string = "level"
27+ ddLogLvlAlert string = "alert"
28+ ddLogLvlCritical string = "critical"
29+ ddLogLvlAll string = "all"
30+ ddLogLvlSuf string = "-info"
31+ ddFileSegSize int = 4096
3332)
3433
3534var (
3635 artifactColTimeout time.Duration = 5 * time .Minute
36+ artifactSleepTime time.Duration = 5 * time .Second
3737)
3838
3939func isDebugData (p * types.Path ) bool {
@@ -207,6 +207,117 @@ func (srv *HealthzServer) Get(ctx context.Context, req *healthz.GetRequest) (*he
207207 return nil , status .Errorf (codes .Unimplemented , "Healthz.Get is unimplemented for component: [%s]." , path .GetElem ())
208208}
209209
210+ func (srv * HealthzServer ) Artifact (req * healthz.ArtifactRequest , stream healthz.Healthz_ArtifactServer ) error {
211+ log .V (1 ).Infof ("Artifact RPC Get request ID: %+v" , req .GetId ())
212+ file := req .GetId ()
213+ allowedDir := "/tmp/dump"
214+ cleanPath := filepath .Clean (file )
215+ if ! strings .HasPrefix (cleanPath , allowedDir ) {
216+ return status .Errorf (codes .InvalidArgument , "Invalid artifact path" )
217+ }
218+ file_path := filepath .Join ("/mnt/host" , cleanPath )
219+
220+ f , err := os .Open (file_path )
221+ if err != nil {
222+ if os .IsNotExist (err ) {
223+ return status .Errorf (codes .NotFound , "File not found: %v" , err )
224+ }
225+ return status .Errorf (codes .Internal , "Failed to open file: %v" , err )
226+ }
227+ defer f .Close ()
228+
229+ hasher := sha256 .New ()
230+ size , err := io .Copy (hasher , f ) // Streams through hasher, constant memory
231+ if err != nil {
232+ return status .Errorf (codes .Internal , "Error hashing: [%v]" , err )
233+ }
234+ hashSum := hasher .Sum (nil )
235+
236+ // Reset file pointer to start for streaming chunks
237+ if _ , err := f .Seek (0 , io .SeekStart ); err != nil {
238+ return status .Errorf (codes .Internal , "Failed to reset file pointer: %v" , err )
239+ }
240+
241+ header := & healthz.ArtifactResponse {
242+ Contents : & healthz.ArtifactResponse_Header {
243+ Header : & healthz.ArtifactHeader {
244+ Id : file ,
245+ ArtifactType : & healthz.ArtifactHeader_File {
246+ File : & healthz.FileArtifactType {
247+ Name : file ,
248+ Size : size ,
249+ Hash : & types.HashType {
250+ Method : types .HashType_SHA256 ,
251+ Hash : hashSum [:],
252+ },
253+ },
254+ },
255+ },
256+ },
257+ }
258+ if err := stream .Send (header ); err != nil {
259+ log .Errorf ("failed to send header: %v" , err )
260+ return err
261+ }
262+
263+ buf := make ([]byte , ddFileSegSize )
264+
265+ for {
266+ n , err := f .Read (buf )
267+ if err == io .EOF {
268+ break
269+ }
270+ if err != nil {
271+ log .Errorf ("failed to send trailer: %v" , err )
272+ return status .Errorf (codes .Internal , "File read error: %v" , err )
273+ }
274+ content := & healthz.ArtifactResponse {
275+ Contents : & healthz.ArtifactResponse_Bytes {
276+ Bytes : buf [:n ],
277+ },
278+ }
279+ if err := stream .Send (content ); err != nil {
280+ log .Errorf ("failed to send Artifact data: %v" , err )
281+ return err
282+ }
283+ }
284+
285+ trailer := & healthz.ArtifactResponse {
286+ Contents : & healthz.ArtifactResponse_Trailer {
287+ Trailer : & healthz.ArtifactTrailer {},
288+ },
289+ }
290+ if err := stream .Send (trailer ); err != nil {
291+ log .Errorf ("failed to send trailer: %v" , err )
292+ return err
293+ }
294+ log .Infof ("Successfully streamed artifact: %s (size=%d bytes)" , file_path , size )
295+ return nil
296+ }
297+
298+ // Acknowledge implements the corresponding RPC.
299+ func (srv * HealthzServer ) Acknowledge (ctx context.Context , req * healthz.AcknowledgeRequest ) (* healthz.AcknowledgeResponse , error ) {
300+ log .V (1 ).Infof ("Acknowledge RPC Get request ID: %+v" , req .GetId ())
301+ ctx , err := authenticate (srv .config , ctx , "gnoi" , false )
302+ if err != nil {
303+ log .Errorf ("Healthz.Acknowledge authentication failed: %v" , err )
304+ return nil , err
305+ }
306+ sc , err := ssc .NewDbusClient ()
307+ if err != nil {
308+ log .Errorf ("NewDbusClient error: %v\n " , err )
309+ return nil , err
310+ }
311+ defer sc .Close ()
312+ _ , err = sc .HealthzAck (req .GetId ())
313+ if err != nil {
314+ log .Errorf ("HealthzAck() Dbus failed: %v" , err )
315+ return nil , status .Errorf (codes .Internal , "Host service error: %v" , err )
316+ }
317+
318+ return & healthz.AcknowledgeResponse {}, nil
319+ }
320+
210321func (srv * HealthzServer ) List (ctx context.Context , req * healthz.ListRequest ) (* healthz.ListResponse , error ) {
211322 return nil , status .Errorf (codes .Unimplemented , "gNOI Healthz List not implemented" )
212323}
0 commit comments