@@ -596,6 +596,75 @@ func (c *LocalCluster) StopZero(id int) error {
596596 return c .stopContainer (c .zeros [id ])
597597}
598598
599+ // GetZeroContainerName returns the Docker container name for the specified Zero,
600+ // which also serves as a DNS alias on the cluster network.
601+ func (c * LocalCluster ) GetZeroContainerName (id int ) (string , error ) {
602+ if id >= c .conf .numZeros {
603+ return "" , fmt .Errorf ("invalid id of zero: %v" , id )
604+ }
605+ return c .zeros [id ].containerName , nil
606+ }
607+
608+ // SetZeroMyAddr overrides the --my flag for the specified Zero node. The next
609+ // time the container is recreated (via RecreateZero), this address will be
610+ // used instead of the default container alias.
611+ func (c * LocalCluster ) SetZeroMyAddr (id int , addr string ) error {
612+ if id >= c .conf .numZeros {
613+ return fmt .Errorf ("invalid id of zero: %v" , id )
614+ }
615+ c .zeros [id ].myAddrOverride = addr
616+ return nil
617+ }
618+
619+ // RecreateZero destroys the Zero container and creates a new one with the
620+ // current command-line flags (e.g. a different --my address). The Zero's data
621+ // directory is preserved across the recreation by extracting it from the old
622+ // (stopped) container and injecting it into the new one. This simulates a
623+ // process restart with persistent storage — the exact scenario where stale WAL
624+ // addresses surface.
625+ func (c * LocalCluster ) RecreateZero (id int ) error {
626+ if id >= c .conf .numZeros {
627+ return fmt .Errorf ("invalid id of zero: %v" , id )
628+ }
629+ z := c .zeros [id ]
630+
631+ ctx , cancel := context .WithTimeout (context .Background (), requestTimeout )
632+ defer cancel ()
633+
634+ // Extract the data directory from the stopped container so the WAL survives.
635+ dataReader , _ , err := c .dcli .CopyFromContainer (ctx , z .cid (), zeroWorkingDir )
636+ if err != nil {
637+ return errors .Wrapf (err , "error copying data from zero container [%v]" , z .cname ())
638+ }
639+ defer dataReader .Close ()
640+
641+ // Read the tar into memory (Zero WAL is small).
642+ dataTar , err := io .ReadAll (dataReader )
643+ if err != nil {
644+ return errors .Wrap (err , "error reading zero data tar" )
645+ }
646+
647+ ro := container.RemoveOptions {RemoveVolumes : true , Force : true }
648+ if err := c .dcli .ContainerRemove (ctx , z .cid (), ro ); err != nil {
649+ return errors .Wrapf (err , "error removing zero container [%v]" , z .cname ())
650+ }
651+
652+ cid , err := c .createContainer (z )
653+ if err != nil {
654+ return errors .Wrapf (err , "error recreating zero container [%v]" , z .cname ())
655+ }
656+ z .containerID = cid
657+
658+ // Inject the data directory into the new container. CopyToContainer expects
659+ // a tar archive rooted at the parent of the target path.
660+ if err := c .dcli .CopyToContainer (ctx , cid , "/data" , bytes .NewReader (dataTar ),
661+ container.CopyToContainerOptions {}); err != nil {
662+ return errors .Wrapf (err , "error restoring data to zero container [%v]" , z .cname ())
663+ }
664+
665+ return nil
666+ }
667+
599668func (c * LocalCluster ) StopAlpha (id int ) error {
600669 if id >= c .conf .numAlphas {
601670 return fmt .Errorf ("invalid id of alpha: %v" , id )
@@ -1006,6 +1075,19 @@ func (c *LocalCluster) GetAlphaHttpClient(alphaID int) (*dgraphapi.HTTPClient, e
10061075 return dgraphapi .GetHttpClient (url , "" )
10071076}
10081077
1078+ // GetZeroStateURL returns the full HTTP URL for the /state endpoint of the
1079+ // specified Zero node.
1080+ func (c * LocalCluster ) GetZeroStateURL (id int ) (string , error ) {
1081+ if id >= c .conf .numZeros {
1082+ return "" , fmt .Errorf ("invalid id of zero: %v" , id )
1083+ }
1084+ pubPort , err := publicPort (c .dcli , c .zeros [id ], zeroHttpPort )
1085+ if err != nil {
1086+ return "" , err
1087+ }
1088+ return "http://0.0.0.0:" + pubPort + "/state" , nil
1089+ }
1090+
10091091// serverURL returns url to the 'server' 'endpoint'
10101092func (c * LocalCluster ) serverURL (server , endpoint string ) (string , error ) {
10111093 pubPort , err := publicPort (c .dcli , c .alphas [0 ], alphaHttpPort )
0 commit comments