Add option to remove persistent remote_services (#18)

This commit is contained in:
Tobias Gesellchen
2026-02-08 00:04:20 +01:00
committed by GitHub
parent 1281af7f6f
commit 059498b16e
5 changed files with 108 additions and 1 deletions
+1
View File
@@ -165,6 +165,7 @@ func main() {
r.Get("/summary/{deviceIP}", server.HandleGetMigrationSummary)
r.Post("/migrate/{deviceIP}", server.HandleMigrateDevice)
r.Post("/ensure-remote-services/{deviceIP}", server.HandleEnsureRemoteServices)
r.Post("/remove-remote-services/{deviceIP}", server.HandleRemoveRemoteServices)
r.Post("/backup/{deviceIP}", server.HandleBackupConfig)
r.Get("/proxy-settings", server.HandleGetProxySettings)
r.Post("/proxy-settings", server.HandleUpdateProxySettings)
+35
View File
@@ -190,6 +190,41 @@ func (s *Server) HandleEnsureRemoteServices(w http.ResponseWriter, r *http.Reque
}
}
// HandleRemoveRemoteServices removes remote services configuration from a device.
func (s *Server) HandleRemoveRemoteServices(w http.ResponseWriter, r *http.Request) {
deviceIP := chi.URLParam(r, "deviceIP")
if deviceIP == "" {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusBadRequest)
if err := json.NewEncoder(w).Encode(map[string]interface{}{"ok": false, "message": "Device IP is required"}); err != nil {
http.Error(w, "Failed to encode response", http.StatusInternalServerError)
return
}
return
}
if err := s.sm.RemoveRemoteServices(deviceIP); err != nil {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusInternalServerError)
if encodeErr := json.NewEncoder(w).Encode(map[string]interface{}{"ok": false, "message": err.Error()}); encodeErr != nil {
http.Error(w, "Failed to encode response", http.StatusInternalServerError)
return
}
return
}
w.Header().Set("Content-Type", "application/json")
if err := json.NewEncoder(w).Encode(map[string]interface{}{"ok": true, "message": "Remote services removed"}); err != nil {
http.Error(w, "Failed to encode response", http.StatusInternalServerError)
return
}
}
// HandleBackupConfig creates a backup of the device configuration.
func (s *Server) HandleBackupConfig(w http.ResponseWriter, r *http.Request) {
deviceIP := chi.URLParam(r, "deviceIP")
+38 -1
View File
@@ -119,7 +119,8 @@
</div>
<div style="margin-top: 15px;">
<button id="confirm-migrate-btn" style="background-color: #4CAF50; color: white; border: none; padding: 10px 20px;">Confirm Migration & Reboot</button>
<button id="ensure-remote-btn" style="background-color: #2196F3; color: white; border: none; padding: 10px 20px;">Ensure Persistent Remote Services</button>
<button id="ensure-remote-btn" style="background-color: #2196F3; color: white; border: none; padding: 10px 20px;">Enable Persistent Remote Services</button>
<button id="remove-remote-btn" style="background-color: #f44336; color: white; border: none; padding: 10px 20px;">Remove Persistent Remote Services</button>
<button onclick="document.getElementById('migration-summary').style.display='none'" style="padding: 10px 20px;">Cancel</button>
</div>
</div>
@@ -346,6 +347,10 @@
remoteBtn.onclick = () => ensureRemoteServices(ip);
remoteBtn.disabled = !summary.ssh_success;
const removeRemoteBtn = document.getElementById('remove-remote-btn');
removeRemoteBtn.onclick = () => removeRemoteServices(ip);
removeRemoteBtn.disabled = !summary.ssh_success || !summary.remote_services_enabled;
const backupBtn = document.getElementById('backup-config-btn');
backupBtn.onclick = () => backupConfig(ip);
backupBtn.disabled = !summary.ssh_success || !!summary.original_config;
@@ -438,6 +443,38 @@
}
}
async function removeRemoteServices(ip) {
if (!ip) {
alert('Please enter a valid IP address.');
return;
}
if (!confirm('Are you sure you want to remove remote services from ' + ip + '?')) {
return;
}
const summaryDiv = document.getElementById('migration-summary');
summaryDiv.style.display = 'none';
const statusDiv = document.getElementById('status');
statusDiv.style.display = 'block';
statusDiv.style.backgroundColor = '#ffffcc';
statusDiv.innerHTML = 'Removing remote services for ' + ip + '...';
try {
const response = await fetch('/setup/remove-remote-services/' + ip, { method: 'POST' });
const result = await response.json();
if (result.ok) {
statusDiv.style.backgroundColor = '#ccffcc';
statusDiv.innerHTML = 'Successfully removed remote services from ' + ip + '.';
} else {
statusDiv.style.backgroundColor = '#ffcccc';
statusDiv.innerHTML = 'Failed to remove remote services for ' + ip + ': ' + (result.message || 'Unknown error');
}
} catch (error) {
statusDiv.style.backgroundColor = '#ffcccc';
statusDiv.innerHTML = 'Error removing remote services for ' + ip + ': ' + error;
}
}
async function backupConfig(ip) {
if (!ip) {
alert('Please enter a valid IP address.');
+2
View File
@@ -48,6 +48,8 @@ func setupRouter(targetURL string, ds *datastore.DataStore) (*chi.Mux, *Server)
r.Route("/setup", func(r chi.Router) {
r.Get("/proxy-settings", server.HandleGetProxySettings)
r.Post("/proxy-settings", server.HandleUpdateProxySettings)
r.Post("/ensure-remote-services/{deviceIP}", server.HandleEnsureRemoteServices)
r.Post("/remove-remote-services/{deviceIP}", server.HandleRemoveRemoteServices)
})
r.NotFound(func(w http.ResponseWriter, r *http.Request) {
+32
View File
@@ -449,3 +449,35 @@ func (m *Manager) EnsureRemoteServices(deviceIP string) error {
return fmt.Errorf("failed to enable remote services in any of the locations: %v", locations)
}
// RemoveRemoteServices removes remote services from the device by deleting the known remote_services files.
func (m *Manager) RemoveRemoteServices(deviceIP string) error {
client := ssh.NewClient(deviceIP)
rwCmd := "(rw || mount -o remount,rw /)"
locations := []string{
"/etc/remote_services",
"/mnt/nv/remote_services",
"/tmp/remote_services",
}
var errors []error
for _, loc := range locations {
// Try to make filesystem writable and remove the file
_, err := client.Run(fmt.Sprintf("%s && rm -f %s", rwCmd, loc))
if err != nil {
// If rw && rm failed, try just rm (e.g. for /tmp)
_, err = client.Run(fmt.Sprintf("rm -f %s", loc))
if err != nil {
errors = append(errors, fmt.Errorf("failed to remove %s: %w", loc, err))
}
}
}
if len(errors) == len(locations) {
return fmt.Errorf("failed to remove remote services from any location: %v", errors)
}
return nil
}