remote: auto-upgrade ollie-remote on each tool call
Before each CallTool, check if the local ollie-remote binary hash differs from what was deployed. If so, close the SSH connection, re-dial (triggering bootstrap to upload the new binary), and swap the connection transparently. Emits info events when upgrade is detected and when it completes.
This commit is contained in:
parent
249b9f80f9
commit
0c75d06c59
|
|
@ -48,6 +48,11 @@ type RemoteServer struct {
|
|||
dec *json.Decoder
|
||||
nextID atomic.Int64
|
||||
Info HostInfo
|
||||
|
||||
// For auto-upgrade on hash mismatch.
|
||||
cfg RemoteConfig
|
||||
ctx context.Context
|
||||
deployedHash string
|
||||
}
|
||||
|
||||
// Config holds the parameters for connecting to a remote host.
|
||||
|
|
@ -198,11 +203,14 @@ func RemoteDial(ctx context.Context, cfg RemoteConfig) (*RemoteServer, error) {
|
|||
|
||||
// Bootstrap complete — stdin/stdout are now JSON-RPC.
|
||||
s := &RemoteServer{
|
||||
stdin: stdin,
|
||||
stdout: stdout,
|
||||
cmd: cmd,
|
||||
enc: json.NewEncoder(stdin),
|
||||
dec: json.NewDecoder(bufio.NewReader(stdout)),
|
||||
stdin: stdin,
|
||||
stdout: stdout,
|
||||
cmd: cmd,
|
||||
enc: json.NewEncoder(stdin),
|
||||
dec: json.NewDecoder(bufio.NewReader(stdout)),
|
||||
cfg: cfg,
|
||||
ctx: ctx,
|
||||
deployedHash: hashStr,
|
||||
}
|
||||
|
||||
// Verify connectivity with a ping.
|
||||
|
|
@ -277,6 +285,50 @@ func (s *RemoteServer) Close() error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// checkUpgrade compares the local ollie-remote binary hash to the deployed
|
||||
// hash. If they differ, it closes the current connection and re-dials,
|
||||
// which triggers the bootstrap to upload the new binary.
|
||||
func (s *RemoteServer) checkUpgrade() error {
|
||||
localBin, err := findLocalBinary()
|
||||
if err != nil {
|
||||
return nil // can't find binary, skip check
|
||||
}
|
||||
binData, err := os.ReadFile(localBin)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
hash := sha256.Sum256(binData)
|
||||
hashStr := hex.EncodeToString(hash[:])
|
||||
|
||||
if hashStr == s.deployedHash {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Hash changed — reconnect.
|
||||
StreamOutput(s.ctx, "[info] ollie-remote binary changed, upgrading remote...\n")
|
||||
|
||||
s.Close()
|
||||
|
||||
fresh, err := RemoteDial(s.ctx, s.cfg)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Swap internals from the fresh connection.
|
||||
s.mu.Lock()
|
||||
s.stdin = fresh.stdin
|
||||
s.stdout = fresh.stdout
|
||||
s.cmd = fresh.cmd
|
||||
s.enc = fresh.enc
|
||||
s.dec = fresh.dec
|
||||
s.deployedHash = fresh.deployedHash
|
||||
s.Info = fresh.Info
|
||||
s.mu.Unlock()
|
||||
|
||||
StreamOutput(s.ctx, "[info] remote binary upgraded successfully\n")
|
||||
return nil
|
||||
}
|
||||
|
||||
// --- Server interface ---
|
||||
|
||||
func (s *RemoteServer) ListTools() ([]ToolInfo, error) {
|
||||
|
|
@ -311,6 +363,11 @@ func (s *RemoteServer) ListTools() ([]ToolInfo, error) {
|
|||
}
|
||||
|
||||
func (s *RemoteServer) CallTool(ctx context.Context, tool string, args json.RawMessage) (json.RawMessage, error) {
|
||||
// Check if local binary has been updated; reconnect if so.
|
||||
if err := s.checkUpgrade(); err != nil {
|
||||
StreamOutput(ctx, "[info] remote upgrade failed: "+err.Error()+"\n")
|
||||
}
|
||||
|
||||
// Forward the call with the tool name as the RPC method.
|
||||
id := s.nextID.Add(1)
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue