Skip to content

Commit da2ab02

Browse files
andystimeclaude
andcommitted
fix: allow re-registration when local config is stale or --force is set
After uninstalling ggo on Linux, ~/.gpugo/config/config.json persists, causing 'ggo agent register' to always fail with "already registered". Fix: before blocking, verify the agent still exists on the server. - If the server returns an error (agent deleted/missing), treat the local config as stale, clean it up automatically, and proceed with registration. - If the agent is still live on the server, keep blocking but improve the error message to mention 'ggo agent unregister' or --force. - Add --force flag to explicitly replace an existing registration: deletes the old agent from the server and clears local config before re-registering. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent c68f725 commit da2ab02

1 file changed

Lines changed: 41 additions & 4 deletions

File tree

cmd/ggo/agent/agent.go

Lines changed: 41 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,7 @@ func stopHypervisorManager() {
129129

130130
func newRegisterCmd() *cobra.Command {
131131
var token string
132+
var force bool
132133

133134
cmd := &cobra.Command{
134135
Use: "register",
@@ -156,11 +157,46 @@ func newRegisterCmd() *cobra.Command {
156157
return err
157158
}
158159
if registered {
159-
cmd.SilenceUsage = true
160-
if !out.IsJSON() {
161-
out.Error("Agent already registered on this machine. Please run the uninstall command and register again.")
160+
cfg, _ := configMgr.LoadConfig()
161+
162+
if !force {
163+
// Verify whether the agent still exists on the server.
164+
// If it is gone (e.g. deleted via dashboard or a prior uninstall),
165+
// the local config is stale and we can safely clean it up and
166+
// proceed. If the agent is still live, block as before.
167+
agentClient := api.NewClient(
168+
api.WithBaseURL(serverURL),
169+
api.WithAgentSecret(cfg.AgentSecret),
170+
)
171+
_, serverErr := agentClient.GetAgentConfig(context.Background(), cfg.AgentID)
172+
if serverErr == nil {
173+
// Agent is alive on the server – require explicit action.
174+
cmd.SilenceUsage = true
175+
if !out.IsJSON() {
176+
out.Error("Agent already registered on this machine. Run 'ggo agent unregister' first, or use --force to replace the existing registration.")
177+
}
178+
return agent.ErrAlreadyRegistered
179+
}
180+
// Agent not found on server → stale local config.
181+
if !out.IsJSON() {
182+
out.Warning(fmt.Sprintf("Stale local registration found (agent %s no longer on server). Clearing config and re-registering...", cfg.AgentID))
183+
}
184+
} else {
185+
// --force: attempt to delete the old agent from the server so it
186+
// does not linger as an orphan record.
187+
agentClient := api.NewClient(
188+
api.WithBaseURL(serverURL),
189+
api.WithAgentSecret(cfg.AgentSecret),
190+
)
191+
if deleteErr := agentClient.SelfDeleteAgent(context.Background(), cfg.AgentID); deleteErr != nil {
192+
klog.Warningf("Failed to delete old agent from server (continuing): agent_id=%s error=%v", cfg.AgentID, deleteErr)
193+
}
194+
}
195+
196+
// Remove the stale / replaced local config before re-registering.
197+
if removeErr := configMgr.RemoveConfig(); removeErr != nil {
198+
klog.Warningf("Failed to remove local config (continuing): %v", removeErr)
162199
}
163-
return agent.ErrAlreadyRegistered
164200
}
165201

166202
// Sync deps manifest before registration
@@ -203,6 +239,7 @@ func newRegisterCmd() *cobra.Command {
203239
}
204240

205241
cmd.Flags().StringVarP(&token, "token", "t", "", "Temporary installation token")
242+
cmd.Flags().BoolVar(&force, "force", false, "Force re-registration, replacing any existing registration on this machine")
206243

207244
return cmd
208245
}

0 commit comments

Comments
 (0)