@@ -717,3 +717,113 @@ func replaceUnitMultiple(cmd string, n int) error {
717717
718718 return nil
719719}
720+
721+ // TestReplaceSerialization tests if the ExecStartPre of the new version
722+ // of the unit when it replaces the old one is excuted after
723+ // ExecStopPost of the old version.
724+ // This test is to make sure that two versions of the same unit will not
725+ // conflict with each other, that the directives are always serialized,
726+ // and it tries its best to avoid the following scenarios:
727+ // https://github.com/coreos/fleet/issues/1000
728+ // https://github.com/systemd/systemd/issues/518
729+ // Now we can't guarantee that that behaviour will not be triggered by
730+ // another external operation, but at least from the Unit replace
731+ // feature context we try to avoid it.
732+ func TestReplaceSerialization (t * testing.T ) {
733+ cluster , err := platform .NewNspawnCluster ("smoke" )
734+ if err != nil {
735+ t .Fatal (err )
736+ }
737+ defer cluster .Destroy ()
738+
739+ m , err := cluster .CreateMember ()
740+ if err != nil {
741+ t .Fatal (err )
742+ }
743+
744+ _ , err = cluster .WaitForNMachines (m , 1 )
745+ if err != nil {
746+ t .Fatal (err )
747+ }
748+
749+ tmpSyncFile := "/tmp/fleetSyncReplaceFile"
750+ syncOld := "echo 'sync'"
751+ syncNew := fmt .Sprintf ("test -f %s" , tmpSyncFile )
752+ tmpSyncService := "/tmp/replace-sync.service"
753+ syncService := "fixtures/units/replace-sync.service"
754+
755+ stdout , stderr , err := cluster .Fleetctl (m , "start" , syncService )
756+ if err != nil {
757+ t .Fatalf ("Unable to start unit: \n stdout: %s\n stderr: %s\n err: %v" , stdout , stderr , err )
758+ }
759+
760+ _ , err = cluster .WaitForNActiveUnits (m , 1 )
761+ if err != nil {
762+ t .Fatal (err )
763+ }
764+
765+ // replace the unit content, make sure that:
766+ // It shows up and it did 'test -f /tmp/fleetSyncReplaceFile' correctly
767+ err = util .GenNewFleetService (tmpSyncService , syncService , syncNew , syncOld )
768+ if err != nil {
769+ t .Fatalf ("Failed to generate a temp fleet service: %v" , err )
770+ }
771+
772+ stdout , stderr , err = cluster .Fleetctl (m , "start" , "--replace" , tmpSyncService )
773+ if err != nil {
774+ t .Fatalf ("Failed to replace unit: \n stdout: %s\n stderr: %s\n err: %v" , stdout , stderr , err )
775+ }
776+
777+ _ , err = cluster .WaitForNActiveUnits (m , 1 )
778+ if err != nil {
779+ t .Fatalf ("Did not find 1 unit in cluster, unit replace failed: %v" , err )
780+ }
781+
782+ // Wait for the sync file, if the sync file is not created then
783+ // the previous unit failed, if it's created we continue. Here
784+ // the new version of the unit is probably already running and
785+ // the ExecStartPre is running at the same time, if it failed
786+ // then we probably will catch it later when we check its status
787+ tmpService := path .Base (tmpSyncService )
788+ timeout , err := util .WaitForState (
789+ func () bool {
790+ _ , err = cluster .MemberCommand (m , syncNew )
791+ if err != nil {
792+ return false
793+ }
794+ return true
795+ },
796+ )
797+ if err != nil {
798+ t .Fatalf ("Failed to check if file %s exists within %v" , tmpSyncFile , timeout )
799+ }
800+
801+ timeout , err = util .WaitForState (
802+ func () bool {
803+ stdout , _ = cluster .MemberCommand (m , "systemctl" , "show" , "--property=ActiveState" , tmpService )
804+ if strings .TrimSpace (stdout ) != "ActiveState=active" {
805+ return false
806+ }
807+ return true
808+ },
809+ )
810+ if err != nil {
811+ t .Fatalf ("%s unit not reported as active within %v" , tmpService , timeout )
812+ }
813+
814+ timeout , err = util .WaitForState (
815+ func () bool {
816+ stdout , _ = cluster .MemberCommand (m , "systemctl" , "show" , "--property=Result" , tmpService )
817+ if strings .TrimSpace (stdout ) != "Result=success" {
818+ return false
819+ }
820+ return true
821+ },
822+ )
823+ if err != nil {
824+ t .Fatalf ("Result for %s unit not reported as success withing %v" , tmpService , timeout )
825+ }
826+
827+ os .Remove (tmpSyncFile )
828+ os .Remove (tmpSyncService )
829+ }
0 commit comments