@@ -437,9 +437,11 @@ func (w *executor) runAndWaitContainers(ctx context.Context, containers ...model
437437}
438438
439439const (
440- startProbeCheckInterval = 5 * time .Second
441- defaultCheckTimeout = 3 * time .Second
442- defaultProbeTimeout = 2 * time .Minute
440+ startProbeCheckInterval = 5 * time .Second
441+ defaultCheckTimeout = 3 * time .Second
442+ defaultProbeTimeout = 2 * time .Minute
443+ defaultHookExecTimeout = 10 * time .Second
444+ defaultHookRetriesInterval = time .Second
443445)
444446
445447func (w * executor ) waitContainersReady (ctx context.Context , containers ... model.ContainerDefinition ) error {
@@ -509,6 +511,9 @@ func (w *executor) runContainers(ctx context.Context, containers ...model.Contai
509511 }
510512 fallthrough
511513 case model .UpdatePolicyModeRestart :
514+ if err := w .doContainerPreRestart (ctx , c ); err != nil {
515+ return fmt .Errorf ("pre-restart container %s: %w" , c .Name , err )
516+ }
512517 if _ , err := w .runtime .GetContainer (ctx , c .Name ); err == nil || ! errdefs .IsNotFound (err ) {
513518 w .Infof ("remove container %s from containerd" , c .Name )
514519 _ = w .runtime .RemoveContainer (ctx , c .Name )
@@ -626,6 +631,47 @@ func (w *executor) doUpdateOperationMetadata(ctx context.Context, pluginHash, ti
626631 return errdefs .FromGRPC (lo .T2 (c .Update (ctx , & req )).B )
627632}
628633
634+ func (w * executor ) doContainerPreRestart (ctx context.Context , c model.ContainerDefinition ) error {
635+ if c .UpdatePolicy == nil || c .UpdatePolicy .PreRestartHook == nil {
636+ return nil
637+ }
638+ return w .doContainerExecHook (ctx , c .Name , "pre-restart" , c .UpdatePolicy .PreRestartHook )
639+ }
640+
641+ func (w * executor ) doContainerExecHook (ctx context.Context , name , hookName string , hook * model.Hook ) error {
642+ interval := defaultHookRetriesInterval
643+ if hook .RetriesInterval != nil {
644+ interval = time .Duration (* hook .RetriesInterval ) * time .Second
645+ }
646+ timeout := defaultHookExecTimeout
647+ if hook .ExecTimeout != nil {
648+ timeout = time .Duration (* hook .ExecTimeout ) * time .Second
649+ }
650+
651+ var herr error
652+ ctx , cancel := context .WithTimeout (ctx , timeout )
653+ defer cancel ()
654+
655+ for retries := hook .MaxRetries ; retries >= 0 ; retries -- {
656+ w .Infof ("exec %s hook in container %s" , hookName , name )
657+ result , err := w .runtime .ExecCommand (ctx , name , hook .ExecCommand )
658+ herr = client .HandleTaskResult (result , err )
659+ if herr == nil {
660+ break
661+ }
662+ w .Warningf ("exec %s hook in container %s: %s" , hookName , name , herr )
663+ if retries > 0 {
664+ time .Sleep (interval )
665+ }
666+ }
667+
668+ if herr != nil && hook .IgnoreFailed {
669+ w .Warningf ("exec %s hook in container %s: failed after %d retries" , hookName , name , hook .MaxRetries + 1 )
670+ return nil
671+ }
672+ return herr
673+ }
674+
629675func (w * executor ) setupLogging (ctx context.Context ) error {
630676 if w .logging == nil {
631677 return nil
0 commit comments