Files

146 lines
3.9 KiB
Go

package main
import (
"context"
"fmt"
"strings"
"time"
"github.com/UpCloudLtd/upcloud-go-api/v8/upcloud/request"
"github.com/spf13/cobra"
)
var statusCmd = &cobra.Command{
Use: "status",
Short: "Show infrastructure state and health",
Args: cobra.NoArgs,
RunE: func(cmd *cobra.Command, args []string) error {
token, _ := cmd.Root().PersistentFlags().GetString("token")
return cmdStatus(token)
},
}
func init() {
rootCmd.AddCommand(statusCmd)
}
func cmdStatus(token string) error {
state, err := loadState()
if err != nil {
return err
}
naming := state.Naming()
svc, err := newService(token)
if err != nil {
return err
}
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
fmt.Printf("Zone: %s\n\n", state.Zone)
// Server status
for _, s := range []struct {
name string
ss ServerState
serviceName string
healthURL string
}{
{"Appview", state.Appview, naming.Appview(), "http://localhost:5000/health"},
{"Hold", state.Hold, naming.Hold(), "http://localhost:8080/xrpc/_health"},
} {
fmt.Printf("%-8s UUID: %s\n", s.name, s.ss.UUID)
fmt.Printf(" Public: %s\n", s.ss.PublicIP)
fmt.Printf(" Private: %s\n", s.ss.PrivateIP)
if s.ss.UUID != "" {
details, err := svc.GetServerDetails(ctx, &request.GetServerDetailsRequest{
UUID: s.ss.UUID,
})
if err != nil {
fmt.Printf(" State: error (%v)\n", err)
} else {
fmt.Printf(" State: %s\n", details.State)
}
}
// SSH health check
if s.ss.PublicIP != "" {
output, err := runSSH(s.ss.PublicIP, fmt.Sprintf(
"systemctl is-active %s 2>/dev/null || echo 'inactive'; curl -sf %s > /dev/null 2>&1 && echo 'health:ok' || echo 'health:fail'",
s.serviceName, s.healthURL,
), false)
if err != nil {
fmt.Printf(" Service: unreachable\n")
} else {
lines := strings.Split(strings.TrimSpace(output), "\n")
for _, line := range lines {
line = strings.TrimSpace(line)
if line == "active" || line == "inactive" {
fmt.Printf(" Service: %s\n", line)
} else if strings.HasPrefix(line, "health:") {
fmt.Printf(" Health: %s\n", strings.TrimPrefix(line, "health:"))
}
}
}
}
fmt.Println()
}
// Scanner status (runs on hold server)
if state.ScannerEnabled {
fmt.Printf("Scanner (on hold server)\n")
if state.Hold.PublicIP != "" {
output, err := runSSH(state.Hold.PublicIP, fmt.Sprintf(
"systemctl is-active %s 2>/dev/null || echo 'inactive'; curl -sf http://localhost:9090/healthz > /dev/null 2>&1 && echo 'health:ok' || echo 'health:fail'",
naming.Scanner(),
), false)
if err != nil {
fmt.Printf(" Service: unreachable\n")
} else {
lines := strings.Split(strings.TrimSpace(output), "\n")
for _, line := range lines {
line = strings.TrimSpace(line)
if line == "active" || line == "inactive" {
fmt.Printf(" Service: %s\n", line)
} else if strings.HasPrefix(line, "health:") {
fmt.Printf(" Health: %s\n", strings.TrimPrefix(line, "health:"))
}
}
}
}
fmt.Println()
}
// LB status
if state.LB.UUID != "" {
fmt.Printf("Load Balancer: %s\n", state.LB.UUID)
lb, err := svc.GetLoadBalancer(ctx, &request.GetLoadBalancerRequest{
UUID: state.LB.UUID,
})
if err != nil {
fmt.Printf(" State: error (%v)\n", err)
} else {
fmt.Printf(" State: %s\n", lb.OperationalState)
for _, n := range lb.Networks {
fmt.Printf(" Network (%s): %s\n", n.Type, n.DNSName)
}
}
}
fmt.Printf("\nNetwork: %s\n", state.Network.UUID)
if state.ObjectStorage.UUID != "" {
fmt.Printf("\nObject Storage: %s\n", state.ObjectStorage.UUID)
fmt.Printf(" Endpoint: %s\n", state.ObjectStorage.Endpoint)
fmt.Printf(" Region: %s\n", state.ObjectStorage.Region)
fmt.Printf(" Bucket: %s\n", state.ObjectStorage.Bucket)
fmt.Printf(" Access Key: %s\n", state.ObjectStorage.AccessKeyID)
}
return nil
}