99 "os"
1010 "path"
1111 "runtime"
12+ "strings"
1213 "time"
1314
1415 upgradetypes "cosmossdk.io/x/upgrade/types"
@@ -23,7 +24,15 @@ import (
2324
2425const zetaclientdBinaryName = "zetaclientd"
2526
26- var defaultUpgradesDir = os .ExpandEnv ("$HOME/.zetaclientd/upgrades" )
27+ var (
28+ zetaclientDirectory = os .ExpandEnv ("$HOME/.zetaclientd" )
29+ defaultUpgradesDir = path .Join (zetaclientDirectory , "upgrades" )
30+ // defaultZetaclientdBinaryPath is the path where the zetaclientd binary is expected to be found,this is the path used for localnet e2e tests
31+ defaultZetaclientdBinaryPath = "/usr/local/bin/zetaclientd"
32+ // zetaclientUpgradeTriggerFile is a file watched by the supervisor to trigger a binary upgrade.This should be used when upgrading zetaclient only.
33+ // This is primarily used for testing on localnet e2e tests.
34+ zetaclientUpgradeTriggerFile = path .Join (zetaclientDirectory , "zetaclientd-upgrade-trigger" )
35+ )
2736
2837func getLogger (cfg config.Config , out io.Writer ) zerolog.Logger {
2938 var logger zerolog.Logger
@@ -44,12 +53,13 @@ func getLogger(cfg config.Config, out io.Writer) zerolog.Logger {
4453}
4554
4655type zetaclientdSupervisor struct {
47- zetacoredConn * grpc.ClientConn
48- reloadSignals chan bool
49- logger zerolog.Logger
50- upgradesDir string
51- upgradePlanName string
52- enableAutoDownload bool
56+ zetacoredConn * grpc.ClientConn
57+ reloadSignals chan bool
58+ logger zerolog.Logger
59+ upgradesDir string
60+ upgradePlanName string
61+ enableAutoDownload bool
62+ zetaclientdBinaryPath string
5363}
5464
5565func newZetaclientdSupervisor (
@@ -66,17 +76,19 @@ func newZetaclientdSupervisor(
6676 return nil , fmt .Errorf ("grpc dial: %w" , err )
6777 }
6878 return & zetaclientdSupervisor {
69- zetacoredConn : conn ,
70- logger : logger ,
71- reloadSignals : make (chan bool , 1 ),
72- upgradesDir : defaultUpgradesDir ,
73- enableAutoDownload : enableAutoDownload ,
79+ zetacoredConn : conn ,
80+ logger : logger ,
81+ reloadSignals : make (chan bool , 1 ),
82+ upgradesDir : defaultUpgradesDir ,
83+ enableAutoDownload : enableAutoDownload ,
84+ zetaclientdBinaryPath : defaultZetaclientdBinaryPath ,
7485 }, nil
7586}
7687
7788func (s * zetaclientdSupervisor ) Start (ctx context.Context ) {
7889 go s .watchForVersionChanges (ctx )
7990 go s .handleCoreUpgradePlan (ctx )
91+ go s .handleFileBasedUpgrade (ctx )
8092}
8193
8294func (s * zetaclientdSupervisor ) WaitForReloadSignal (ctx context.Context ) {
@@ -239,3 +251,77 @@ func (s *zetaclientdSupervisor) downloadZetaclientd(ctx context.Context, plan *u
239251 }
240252 return nil
241253}
254+
255+ // handleFileBasedUpgrade watches for the trigger file to be created
256+ // Once created the function updates the zetaclient binary using the URL in the file and triggers a restart
257+ // This is currently only used for local testing and the trigger file is created by the start-zetae2e.sh script
258+ func (s * zetaclientdSupervisor ) handleFileBasedUpgrade (ctx context.Context ) {
259+ for {
260+ select {
261+ case <- time .After (time .Second ):
262+ case <- ctx .Done ():
263+ return
264+ }
265+
266+ if _ , err := os .Stat (zetaclientUpgradeTriggerFile ); err != nil {
267+ continue
268+ }
269+
270+ s .logger .Info ().Msg ("detected file-based upgrade trigger" )
271+
272+ //#nosec G304 used for testing only
273+ binURLBytes , err := os .ReadFile (zetaclientUpgradeTriggerFile )
274+ if err != nil {
275+ panic (fmt .Sprintf ("read trigger file: %v" , err ))
276+ }
277+ binURL := strings .TrimSpace (string (binURLBytes ))
278+ if binURL == "" {
279+ panic ("empty download URL in trigger file" )
280+ }
281+
282+ tempDir := os .TempDir ()
283+ err = s .downloadZetaclientdToPath (ctx , tempDir , binURL )
284+ if err != nil {
285+ errRemove := os .Remove (tempDir )
286+ if errRemove != nil {
287+ s .logger .Error ().Err (errRemove ).Msg ("remove temp dir after failed download" )
288+ }
289+ panic (fmt .Sprintf ("download zetaclientd: %v" , err ))
290+ }
291+
292+ err = os .Rename (tempDir , s .zetaclientdBinaryPath )
293+ if err != nil {
294+ panic (fmt .Sprintf ("rename binary into place: %v" , err ))
295+ }
296+
297+ err = os .Remove (zetaclientUpgradeTriggerFile )
298+ if err != nil {
299+ panic (fmt .Sprintf ("remove trigger file: %v" , err ))
300+ }
301+
302+ s .reloadSignals <- true
303+ s .logger .Info ().Msg ("zetaclientd binary updated and restart triggered" )
304+ }
305+ }
306+
307+ // downloadZetaclientdToPath downloads the zetaclientd binary to the specified path
308+ func (s * zetaclientdSupervisor ) downloadZetaclientdToPath (ctx context.Context , targetPath string , binURL string ) error {
309+ s .logger .Info ().Msgf ("downloading zetaclientd to %s from %s" , targetPath , binURL )
310+
311+ err := getter .GetFile (targetPath , binURL , getter .WithContext (ctx ), getter .WithUmask (0o750 ))
312+ if err != nil {
313+ return fmt .Errorf ("get file %s: %w" , binURL , err )
314+ }
315+
316+ info , err := os .Stat (targetPath )
317+ if err != nil {
318+ return fmt .Errorf ("stat binary: %w" , err )
319+ }
320+ newMode := info .Mode ().Perm () | 0o111
321+ err = os .Chmod (targetPath , newMode )
322+ if err != nil {
323+ return fmt .Errorf ("chmod %s: %w" , targetPath , err )
324+ }
325+
326+ return nil
327+ }
0 commit comments