@@ -105,10 +105,25 @@ reboot
105105 autopkgtestRebootPrepareScript = `#!/bin/bash
106106set -euo pipefail
107107exec /usr/local/bin/kolet reboot-request "$1"
108+ `
109+
110+ // Soft-reboot support
111+ autopkgTestSoftRebootPath = "/tmp/autopkgtest-soft-reboot"
112+ autopkgtestSoftRebootScript = `#!/bin/bash
113+ set -xeuo pipefail
114+ /usr/local/bin/kolet soft-reboot-request "$1"
115+ systemctl soft-reboot
116+ `
117+ autopkgTestSoftRebootPreparePath = "/tmp/autopkgtest-soft-reboot-prepare"
118+
119+ autopkgtestSoftRebootPrepareScript = `#!/bin/bash
120+ set -euo pipefail
121+ exec /usr/local/bin/kolet soft-reboot-request "$1"
108122`
109123
110124 // File used to communicate between the script and the kolet runner internally
111- rebootRequestFifo = "/run/kolet-reboot"
125+ rebootRequestFifo = "/run/kolet-reboot"
126+ softRebootRequestFifo = "/run/kolet-soft-reboot"
112127)
113128
114129var (
@@ -140,6 +155,13 @@ var (
140155 SilenceUsage : true ,
141156 }
142157
158+ cmdSoftReboot = & cobra.Command {
159+ Use : "soft-reboot-request MARK" ,
160+ Short : "Request a soft reboot" ,
161+ RunE : runSoftReboot ,
162+ SilenceUsage : true ,
163+ }
164+
143165 cmdHttpd = & cobra.Command {
144166 Use : "httpd" ,
145167 Short : "Start an HTTP server to serve the contents of the file system" ,
@@ -259,7 +281,11 @@ func initiateReboot(mark string) error {
259281 return nil
260282}
261283
284+ // / Create a FIFO in an idempotent fashion
262285func mkfifo (path string ) error {
286+ if _ , err := os .Stat (path ); err == nil {
287+ return nil
288+ }
263289 c := exec .Command ("mkfifo" , path )
264290 c .Stderr = os .Stderr
265291 err := c .Run ()
@@ -269,6 +295,20 @@ func mkfifo(path string) error {
269295 return nil
270296}
271297
298+ func initiateSoftReboot (mark string ) error {
299+ systemdjournal .Print (systemdjournal .PriInfo , "Processing soft-reboot request" )
300+ res := kola.KoletResult {
301+ SoftReboot : string (mark ),
302+ }
303+ buf , err := json .Marshal (& res )
304+ if err != nil {
305+ return errors .Wrapf (err , "serializing KoletResult" )
306+ }
307+ fmt .Println (string (buf ))
308+ systemdjournal .Print (systemdjournal .PriInfo , "Acknowledged soft-reboot request with mark: %s" , buf )
309+ return nil
310+ }
311+
272312func runExtUnit (cmd * cobra.Command , args []string ) error {
273313 rebootOff , _ := cmd .Flags ().GetBool ("deny-reboots" )
274314 // Write the autopkgtest wrappers
@@ -278,10 +318,18 @@ func runExtUnit(cmd *cobra.Command, args []string) error {
278318 if err := os .WriteFile (autopkgTestRebootPreparePath , []byte (autopkgtestRebootPrepareScript ), 0755 ); err != nil {
279319 return err
280320 }
321+ // Write the soft-reboot autopkgtest wrappers
322+ if err := os .WriteFile (autopkgTestSoftRebootPath , []byte (autopkgtestSoftRebootScript ), 0755 ); err != nil {
323+ return err
324+ }
325+ if err := os .WriteFile (autopkgTestSoftRebootPreparePath , []byte (autopkgtestSoftRebootPrepareScript ), 0755 ); err != nil {
326+ return err
327+ }
281328
282329 // Create the reboot cmdline -> login FIFO for the reboot mark and
283330 // proxy it into a channel
284331 rebootChan := make (chan string )
332+ softRebootChan := make (chan string )
285333 errChan := make (chan error )
286334
287335 // We want to prevent certain tests (like non-exclusive tests) from rebooting
@@ -303,6 +351,25 @@ func runExtUnit(cmd *cobra.Command, args []string) error {
303351 }
304352 rebootChan <- string (buf )
305353 }()
354+
355+ // Create soft-reboot FIFO and channel
356+ err = mkfifo (softRebootRequestFifo )
357+ if err != nil {
358+ return err
359+ }
360+ go func () {
361+ softRebootReader , err := os .Open (softRebootRequestFifo )
362+ if err != nil {
363+ errChan <- err
364+ return
365+ }
366+ defer softRebootReader .Close ()
367+ buf , err := io .ReadAll (softRebootReader )
368+ if err != nil {
369+ errChan <- err
370+ }
371+ softRebootChan <- string (buf )
372+ }()
306373 }
307374
308375 ctx := context .Background ()
@@ -344,6 +411,8 @@ func runExtUnit(cmd *cobra.Command, args []string) error {
344411 return err
345412 case reboot := <- rebootChan :
346413 return initiateReboot (reboot )
414+ case softReboot := <- softRebootChan :
415+ return initiateSoftReboot (softReboot )
347416 case m := <- unitevents :
348417 for n := range m {
349418 if n == unitname {
@@ -397,6 +466,35 @@ func runReboot(cmd *cobra.Command, args []string) error {
397466 return nil
398467}
399468
469+ // runSoftReboot handles soft-reboot requests similar to runReboot but for systemctl soft-reboot
470+ func runSoftReboot (cmd * cobra.Command , args []string ) error {
471+ if _ , err := os .Stat (softRebootRequestFifo ); os .IsNotExist (err ) {
472+ return errors .New ("Soft-reboots are not supported for this test, softRebootRequestFifo does not exist." )
473+ }
474+
475+ mark := args [0 ]
476+ systemdjournal .Print (systemdjournal .PriInfo , "Requesting soft-reboot with mark: %s" , mark )
477+ err := mkfifo (kola .KoletRebootAckFifo )
478+ if err != nil {
479+ return err
480+ }
481+ err = os .WriteFile (softRebootRequestFifo , []byte (mark ), 0644 )
482+ if err != nil {
483+ return err
484+ }
485+ f , err := os .Open (kola .KoletRebootAckFifo )
486+ if err != nil {
487+ return err
488+ }
489+ buf := make ([]byte , 1 )
490+ _ , err = f .Read (buf )
491+ if err != nil {
492+ return err
493+ }
494+ systemdjournal .Print (systemdjournal .PriInfo , "Soft-reboot request acknowledged" )
495+ return nil
496+ }
497+
400498func runHttpd (cmd * cobra.Command , args []string ) error {
401499 port , _ := cmd .Flags ().GetString ("port" )
402500 path , _ := cmd .Flags ().GetString ("path" )
@@ -413,6 +511,8 @@ func main() {
413511 root .AddCommand (cmdRunExtUnit )
414512 cmdReboot .Args = cobra .ExactArgs (1 )
415513 root .AddCommand (cmdReboot )
514+ cmdSoftReboot .Args = cobra .ExactArgs (1 )
515+ root .AddCommand (cmdSoftReboot )
416516 cmdHttpd .Flags ().StringP ("port" , "" , "80" , "port" )
417517 cmdHttpd .Flags ().StringP ("path" , "" , "./" , "path to filesystem contents to serve" )
418518 cmdHttpd .Args = cobra .ExactArgs (0 )
0 commit comments