Skip to content

Commit c2eb787

Browse files
authored
Merge pull request canopy-network#339 from canopy-network/auto-update-changes-for-graduator
feat: change auto update when off to start local binary and make auto update repo check configurable
2 parents 3b840d3 + 129c9fe commit c2eb787

4 files changed

Lines changed: 53 additions & 15 deletions

File tree

cmd/auto-update/coordinator.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -276,6 +276,9 @@ func (c *Coordinator) UpdateLoop(cancelSignal chan os.Signal) error {
276276
return err
277277
// periodic check for updates
278278
case <-timer.C:
279+
if !c.updater.Enabled {
280+
continue
281+
}
279282
// wrap it on a goroutine so it doesn't block the main loop
280283
go func() {
281284
c.log.Infof("checking for updates")

cmd/auto-update/main.go

Lines changed: 43 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55
"os"
66
"os/exec"
77
"os/signal"
8+
"path/filepath"
89
"syscall"
910
"time"
1011

@@ -91,32 +92,32 @@ func main() {
9192
"This message appears because the program was started directly instead of using 'start'.")
9293
return
9394
}
94-
// do not run the auto-update process if its disabled
95-
if !configs.Coordinator.Canopy.AutoUpdate {
96-
logger.Info("auto-update disabled, starting CLI directly")
97-
cli.Start()
98-
return
95+
// ensure the binary exists before proceeding
96+
if !isExecutable(configs.Coordinator.BinPath) {
97+
logger.Fatalf("canopy binary not found or not executable: %s", configs.Coordinator.BinPath)
98+
}
99+
if configs.Coordinator.Canopy.AutoUpdate {
100+
logger.Infof("auto-update enabled, starting coordinator on version %s", rpc.SoftwareVersion)
101+
} else {
102+
logger.Infof("auto-update disabled, starting binary: %s", configs.Coordinator.BinPath)
99103
}
100-
logger.Infof("auto-update enabled, starting coordinator on version %s", rpc.SoftwareVersion)
101104
// handle external shutdown signals
102105
sigChan := make(chan os.Signal, 1)
103106
signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT)
104107
// setup the dependencies
105-
updater := NewReleaseManager(configs.Updater, rpc.SoftwareVersion)
108+
updater := NewReleaseManager(configs.Updater, rpc.SoftwareVersion, configs.Coordinator.Canopy.AutoUpdate)
106109
snapshot := NewSnapshotManager(configs.Snapshot)
107-
108110
// setup plugin updater and config if configured
109111
var pluginUpdater *ReleaseManager
110112
var pluginConfig *PluginReleaseConfig
111113
if configs.PluginUpdater != nil {
112-
pluginUpdater = NewReleaseManager(configs.PluginUpdater, "v0.0.0")
114+
pluginUpdater = NewReleaseManager(configs.PluginUpdater, "v0.0.0", true)
113115
pluginConfig = configs.PluginUpdater.PluginConfig
114116
logger.Infof("plugin auto-update enabled from %s/%s",
115117
configs.PluginUpdater.RepoOwner,
116118
configs.PluginUpdater.RepoName)
117119
}
118120
supervisor := NewSupervisor(logger, pluginConfig)
119-
120121
coordinator := NewCoordinator(configs.Coordinator, updater, pluginUpdater, supervisor, snapshot, logger)
121122
// start the update loop
122123
err := coordinator.UpdateLoop(sigChan)
@@ -155,10 +156,20 @@ func getConfigs() (*Configs, lib.LoggerI) {
155156
binPath := envOrDefault("BIN_PATH", defaultBinPath)
156157
githubToken := envOrDefault("CANOPY_GITHUB_API_TOKEN", "")
157158

159+
// core auto-update repo: config.json or defaults
160+
repoOwner := canopyConfig.AutoUpdateRepoOwner
161+
if repoOwner == "" {
162+
repoOwner = defaultRepoOwner
163+
}
164+
repoName := canopyConfig.AutoUpdateRepoName
165+
if repoName == "" {
166+
repoName = defaultRepoName
167+
}
168+
158169
updater := &ReleaseManagerConfig{
159170
Type: ReleaseTypeCLI,
160-
RepoName: envOrDefault("REPO_NAME", defaultRepoName),
161-
RepoOwner: envOrDefault("REPO_OWNER", defaultRepoOwner),
171+
RepoName: repoName,
172+
RepoOwner: repoOwner,
162173
GithubApiToken: githubToken,
163174
BinPath: binPath,
164175
SnapshotKey: snapshotMetadataKey,
@@ -213,6 +224,26 @@ func getConfigs() (*Configs, lib.LoggerI) {
213224
}, l
214225
}
215226

227+
// isExecutable returns true if path exists, is a regular file, and has execute permission.
228+
func isExecutable(path string) bool {
229+
// resolve to absolute path to avoid relative path ambiguity
230+
absPath, err := filepath.Abs(path)
231+
if err != nil {
232+
return false
233+
}
234+
// check if the file exists and is accessible
235+
info, err := os.Stat(absPath)
236+
if err != nil {
237+
return false
238+
}
239+
// directories are not executable binaries
240+
if info.IsDir() {
241+
return false
242+
}
243+
// check for any execute bit (owner, group, or other)
244+
return info.Mode()&0111 != 0
245+
}
246+
216247
// envOrDefault returns the value of the environment variable with the given key,
217248
// or the default value if the variable is not set.
218249
func envOrDefault(key, defaultValue string) string {

cmd/auto-update/releaser.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,14 +75,16 @@ type ReleaseManager struct {
7575
config *ReleaseManagerConfig
7676
httpClient *http.Client
7777
Version string // current version
78+
Enabled bool // whether this updater should actively check for updates
7879
}
7980

8081
// NewReleaseManager creates a new ReleaseManager instance
81-
func NewReleaseManager(config *ReleaseManagerConfig, version string) *ReleaseManager {
82+
func NewReleaseManager(config *ReleaseManagerConfig, version string, enabled bool) *ReleaseManager {
8283
return &ReleaseManager{
8384
config: config,
8485
httpClient: &http.Client{Timeout: httpReleaseClientTimeout},
8586
Version: version,
87+
Enabled: enabled,
8688
}
8789
}
8890

lib/config.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -66,8 +66,10 @@ type MainConfig struct {
6666
RootChain []RootChain `json:"rootChain"` // a list of the root chain(s) a node could connect to as dictated by the governance parameter 'RootChainId'
6767
RunVDF bool `json:"runVDF"` // whether the node should run a Verifiable Delay Function to help secure the network against Long-Range-Attacks
6868
Headless bool `json:"headless"` // turn off the web wallet and block explorer 'web' front ends
69-
AutoUpdate bool `json:"autoUpdate"` // check for new versions of software each X time
70-
Plugin string `json:"plugin"` // the configured plugin to use
69+
AutoUpdate bool `json:"autoUpdate"` // check for new versions of software each X time
70+
AutoUpdateRepoOwner string `json:"autoUpdateRepoOwner"` // GitHub repo owner for core auto-updates (e.g., "canopy-network")
71+
AutoUpdateRepoName string `json:"autoUpdateRepoName"` // GitHub repo name for core auto-updates (e.g., "canopy")
72+
Plugin string `json:"plugin"` // the configured plugin to use
7173
PluginTimeoutMS int `json:"pluginTimeoutMS"` // plugin request timeout in milliseconds
7274
PluginAutoUpdate PluginAutoUpdateConfig `json:"pluginAutoUpdate"` // plugin auto-update configuration
7375
}

0 commit comments

Comments
 (0)