Add shutdown machine feature with configurable command
Backend:
- New migration: add shutdown_command TEXT column to machines table
- Machine model updated with ShutdownCommand field (Create/GetAll/GetByID/Update)
- MachineRequest/MachineResponse DTOs updated with shutdown_command field
- New ShutdownResponse DTO
- New POST /api/machines/{id}/shutdown handler via SSH
- Refactor sshmanager/testconn.go: extract dialSSH() helper shared with shutdown.go
- New sshmanager/shutdown.go: RunRemoteCommand with 15s timeout
Frontend:
- New shutdownMachine() API helper and ShutdownResponse type in client.ts
- New shutdown_command field in MachineForm
- Power button (amber) in machines table actions
- Shutdown confirmation modal with WoL warning notice
- shutdown_command input field in machine edit/create form
- Machine interface updated with shutdown_command and last_seen_at fields
This commit is contained in:
@@ -22,6 +22,7 @@ type Machine struct {
|
||||
Status string `db:"status" json:"status"`
|
||||
LastSeenAt *time.Time `db:"last_seen_at" json:"last_seen_at"`
|
||||
CreatedAt time.Time `db:"created_at" json:"created_at"`
|
||||
ShutdownCommand string `db:"shutdown_command" json:"shutdown_command"`
|
||||
}
|
||||
|
||||
type MachineRepository struct {
|
||||
@@ -36,11 +37,12 @@ func (r *MachineRepository) Create(m *Machine) (int64, error) {
|
||||
res, err := r.db.Exec(`
|
||||
INSERT INTO machines (name, host, port, ssh_user, ssh_key_id, mac_address,
|
||||
wol_enabled, broadcast_addr, wake_timeout_seconds, wake_check_interval_seconds,
|
||||
fingerprint_confirmed, host_key_fingerprint, status)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
||||
fingerprint_confirmed, host_key_fingerprint, status, shutdown_command)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
||||
m.Name, m.Host, m.Port, m.SSHUser, m.SSHKeyID, m.MACAddress,
|
||||
boolToInt(m.WoLEnabled), m.BroadcastAddr, m.WakeTimeoutSeconds,
|
||||
m.WakeCheckIntervalSeconds, boolToInt(m.FingerprintConfirmed), m.HostKeyFingerprint, m.Status,
|
||||
m.ShutdownCommand,
|
||||
)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
@@ -52,7 +54,7 @@ func (r *MachineRepository) GetAll() ([]Machine, error) {
|
||||
rows, err := r.db.Query(`
|
||||
SELECT id, name, host, port, ssh_user, ssh_key_id, mac_address,
|
||||
wol_enabled, broadcast_addr, wake_timeout_seconds, wake_check_interval_seconds,
|
||||
fingerprint_confirmed, host_key_fingerprint, status, last_seen_at, created_at
|
||||
fingerprint_confirmed, host_key_fingerprint, status, last_seen_at, created_at, shutdown_command
|
||||
FROM machines ORDER BY name`)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -69,7 +71,7 @@ func (r *MachineRepository) GetAll() ([]Machine, error) {
|
||||
err := rows.Scan(&m.ID, &m.Name, &m.Host, &m.Port, &m.SSHUser, &keyID,
|
||||
&mac, &m.WoLEnabled, &bcast, &m.WakeTimeoutSeconds,
|
||||
&m.WakeCheckIntervalSeconds, &m.FingerprintConfirmed,
|
||||
&hostKeyFP, &m.Status, &lastSeen, &m.CreatedAt)
|
||||
&hostKeyFP, &m.Status, &lastSeen, &m.CreatedAt, &m.ShutdownCommand)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -103,12 +105,12 @@ func (r *MachineRepository) GetByID(id int64) (*Machine, error) {
|
||||
err := r.db.QueryRow(`
|
||||
SELECT id, name, host, port, ssh_user, ssh_key_id, mac_address,
|
||||
wol_enabled, broadcast_addr, wake_timeout_seconds, wake_check_interval_seconds,
|
||||
fingerprint_confirmed, host_key_fingerprint, status, last_seen_at, created_at
|
||||
fingerprint_confirmed, host_key_fingerprint, status, last_seen_at, created_at, shutdown_command
|
||||
FROM machines WHERE id = ?`, id).Scan(
|
||||
&m.ID, &m.Name, &m.Host, &m.Port, &m.SSHUser, &keyID,
|
||||
&mac, &m.WoLEnabled, &bcast, &m.WakeTimeoutSeconds,
|
||||
&m.WakeCheckIntervalSeconds, &m.FingerprintConfirmed,
|
||||
&hostKeyFP, &m.Status, &lastSeen, &m.CreatedAt)
|
||||
&hostKeyFP, &m.Status, &lastSeen, &m.CreatedAt, &m.ShutdownCommand)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -135,12 +137,13 @@ func (r *MachineRepository) Update(m *Machine) error {
|
||||
_, err := r.db.Exec(`
|
||||
UPDATE machines SET name=?, host=?, port=?, ssh_user=?, ssh_key_id=?,
|
||||
mac_address=?, wol_enabled=?, broadcast_addr=?, wake_timeout_seconds=?,
|
||||
wake_check_interval_seconds=?, fingerprint_confirmed=?, host_key_fingerprint=?, status=?, last_seen_at=?
|
||||
wake_check_interval_seconds=?, fingerprint_confirmed=?, host_key_fingerprint=?, status=?, last_seen_at=?,
|
||||
shutdown_command=?
|
||||
WHERE id=?`,
|
||||
m.Name, m.Host, m.Port, m.SSHUser, m.SSHKeyID, m.MACAddress,
|
||||
boolToInt(m.WoLEnabled), m.BroadcastAddr, m.WakeTimeoutSeconds,
|
||||
m.WakeCheckIntervalSeconds, boolToInt(m.FingerprintConfirmed), m.HostKeyFingerprint,
|
||||
m.Status, m.LastSeenAt, m.ID,
|
||||
m.Status, m.LastSeenAt, m.ShutdownCommand, m.ID,
|
||||
)
|
||||
return err
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user