@@ -529,6 +529,109 @@ func (cl *Client) CalculateStats(jsonStats *types.StatsJSON) *models.Stats {
529
529
return stats
530
530
}
531
531
532
+ func (cl * Client ) ContainerReplace (containerID string , image string , tag string ) error {
533
+
534
+ originalContainer , err := cl .ContainerGet (containerID )
535
+ if err != nil {
536
+ if cl .log != nil {
537
+ cl .log .Error ("failed to get container with id" , containerID , err )
538
+ }
539
+ return err
540
+ }
541
+
542
+ originalContainerName := originalContainer .Name
543
+ tempContainerName := originalContainerName + "_temp"
544
+ rErr := cl .ContainerRename (originalContainer .ID , tempContainerName )
545
+ if rErr != nil {
546
+ return rErr
547
+ }
548
+
549
+ originalConf := originalContainer .Config
550
+ // replace image with the new image
551
+ originalConf .Image = image + ":" + tag
552
+
553
+ newlyCreatedContainer , ccErr := cl .ContainerCreate (originalContainerName , originalConf , originalContainer .HostConfig , nil )
554
+ if ccErr != nil {
555
+ // revert renaming back the old container
556
+ rbErr := cl .ContainerRename (containerID , originalContainerName )
557
+ if rbErr != nil {
558
+ return rbErr
559
+ }
560
+ if cl .log != nil {
561
+ cl .log .Error ("failed to create a new container with original name" , originalContainerName , ccErr )
562
+ }
563
+ return ccErr
564
+ }
565
+
566
+ sErr := cl .ContainerStart (newlyCreatedContainer .ID )
567
+ if sErr != nil {
568
+ if cl .log != nil {
569
+ cl .log .Error ("failed to start newly created container" , originalContainerName , newlyCreatedContainer .ID , sErr )
570
+ }
571
+ // undo previous changes to origial container and remove newly created container
572
+ cerr := cl .ContainerRename (containerID , originalContainerName )
573
+ cerr = cl .ContainerRemove (newlyCreatedContainer .ID )
574
+ if cerr != nil {
575
+ return cerr
576
+ }
577
+
578
+ return sErr
579
+ }
580
+
581
+ // removing old container
582
+ killAfter := time .Second * 5
583
+ stopErr := cl .ContainerStop (containerID , & killAfter )
584
+ if stopErr != nil {
585
+ if cl .log != nil {
586
+ cl .log .Error ("failed to stop old container" , containerID , stopErr )
587
+ }
588
+ return stopErr
589
+ }
590
+
591
+ _ , remErr := cl .ContainersPrune (filters .NewArgs ())
592
+ if remErr != nil {
593
+ if cl .log != nil {
594
+ cl .log .Error ("failed to remove old container" , containerID , remErr )
595
+ }
596
+ return remErr
597
+ }
598
+
599
+ return nil
600
+ }
601
+
602
+ // ContainerRemove - removing the container. timeout in 10 seconds, force removing all
603
+ func (cl * Client ) ContainerRemove (containerID string ) error {
604
+
605
+ ctx , cancel := context .WithTimeout (context .Background (), time .Second * 10 )
606
+ defer cancel ()
607
+
608
+ remErr := cl .client .ContainerRemove (ctx , containerID , types.ContainerRemoveOptions {Force : true , RemoveVolumes : true , RemoveLinks : true })
609
+ if remErr != nil {
610
+ if cl .log != nil {
611
+ cl .log .Error ("failed to remove old container" , containerID , remErr )
612
+ }
613
+ return remErr
614
+ }
615
+ return nil
616
+ }
617
+
618
+ // replaceRevert reverts the phases done by ContainerReplace function in case of errors
619
+ func (cl * Client ) ContainerRename (containerID string , newContainerName string ) error {
620
+ ctx , cancel := context .WithTimeout (context .Background (), time .Second * 10 )
621
+ defer cancel ()
622
+
623
+ // revert renaming back
624
+ rbErr := cl .client .ContainerRename (ctx , containerID , newContainerName )
625
+ if rbErr != nil {
626
+ if cl .log != nil {
627
+ cl .log .Error ("failed to rename old container back" , newContainerName , rbErr )
628
+ }
629
+ return rbErr
630
+ }
631
+
632
+ return nil
633
+ }
634
+
532
635
func calculateBlockIO (blkio types.BlkioStats ) (blkRead uint64 , blkWrite uint64 ) {
533
636
for _ , bioEntry := range blkio .IoServiceBytesRecursive {
534
637
switch strings .ToLower (bioEntry .Op ) {
0 commit comments