summaryrefslogtreecommitdiffstats
path: root/cmd/ship/host/status.go
blob: eb2de5330e4a58943498d14dfa591b5eeeed18c4 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
package host

import (
	"fmt"

	"github.com/bdw/ship/internal/ssh"
	"github.com/bdw/ship/internal/state"
	"github.com/spf13/cobra"
)

var statusCmd = &cobra.Command{
	Use:   "status",
	Short: "Show VPS health (uptime, disk, memory)",
	RunE:  runStatus,
}

func runStatus(cmd *cobra.Command, args []string) error {
	st, err := state.Load()
	if err != nil {
		return fmt.Errorf("error loading state: %w", err)
	}

	host, _ := cmd.Flags().GetString("host")
	if host == "" {
		host = st.GetDefaultHost()
	}

	if host == "" {
		return fmt.Errorf("--host is required (no default host set)")
	}

	fmt.Printf("Connecting to %s...\n\n", host)

	client, err := ssh.Connect(host)
	if err != nil {
		return fmt.Errorf("error connecting to VPS: %w", err)
	}
	defer client.Close()

	fmt.Println("UPTIME")
	if output, err := client.Run("uptime -p"); err == nil {
		fmt.Printf("  %s", output)
	}
	if output, err := client.Run("uptime -s"); err == nil {
		fmt.Printf("  Since: %s", output)
	}
	fmt.Println()

	fmt.Println("LOAD")
	if output, err := client.Run("cat /proc/loadavg | awk '{print $1, $2, $3}'"); err == nil {
		fmt.Printf("  1m, 5m, 15m: %s", output)
	}
	fmt.Println()

	fmt.Println("MEMORY")
	if output, err := client.Run("free -h | awk 'NR==2 {print \"  Used: \" $3 \" / \" $2}'"); err == nil {
		fmt.Print(output)
	}
	if output, err := client.Run("free -h | awk 'NR==2 {printf \"  Available: %s\\n\", $7}'"); err == nil {
		fmt.Print(output)
	}
	fmt.Println()

	fmt.Println("DISK")
	if output, err := client.Run("df -h / | awk 'NR==2 {print \"  Used: \" $3 \" / \" $2 \" (\" $5 \")\"}'"); err == nil {
		fmt.Print(output)
	}
	if output, err := client.Run("df -h / | awk 'NR==2 {print \"  Available: \" $4}'"); err == nil {
		fmt.Print(output)
	}
	fmt.Println()

	fmt.Println("UPDATES")
	if output, err := client.Run("[ -f /var/lib/update-notifier/updates-available ] && cat /var/lib/update-notifier/updates-available | head -2 || echo '  (update info not available)'"); err == nil {
		fmt.Print(output)
	}
	fmt.Println()

	fmt.Println("SERVICES")
	if output, err := client.Run("systemctl is-active caddy 2>/dev/null && echo '  Caddy: active' || echo '  Caddy: inactive'"); err == nil {
		if output == "active\n" {
			fmt.Println("  Caddy: active")
		} else {
			fmt.Println("  Caddy: inactive")
		}
	}

	hostState := st.GetHost(host)
	if hostState != nil && len(hostState.Apps) > 0 {
		activeCount := 0
		for name, app := range hostState.Apps {
			if app.Type == "app" {
				if output, err := client.Run(fmt.Sprintf("systemctl is-active %s 2>/dev/null", name)); err == nil && output == "active\n" {
					activeCount++
				}
			}
		}
		appCount := 0
		for _, app := range hostState.Apps {
			if app.Type == "app" {
				appCount++
			}
		}
		fmt.Printf("  Deployed apps: %d/%d active\n", activeCount, appCount)
	}

	return nil
}