-
Notifications
You must be signed in to change notification settings - Fork 247
/
Copy pathshow_machines.go
122 lines (107 loc) · 3 KB
/
show_machines.go
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
109
110
111
112
113
114
115
116
117
118
119
120
121
122
package scale
import (
"context"
"encoding/json"
"fmt"
"slices"
"strings"
"github.com/samber/lo"
"github.com/superfly/flyctl/api"
"github.com/superfly/flyctl/flaps"
"github.com/superfly/flyctl/internal/appconfig"
"github.com/superfly/flyctl/internal/flag"
"github.com/superfly/flyctl/internal/render"
"github.com/superfly/flyctl/iostreams"
)
func runMachinesScaleShow(ctx context.Context) error {
io := iostreams.FromContext(ctx)
appName := appconfig.NameFromContext(ctx)
flapsClient, err := flaps.NewFromAppName(ctx, appName)
if err != nil {
return err
}
ctx = flaps.NewContext(ctx, flapsClient)
machines, _, err := flapsClient.ListFlyAppsMachines(ctx)
if err != nil {
return err
}
machineGroups := lo.GroupBy(machines, func(m *api.Machine) string {
return m.ProcessGroup()
})
// Deterministic output sorted by group name
groupNames := lo.Keys(machineGroups)
slices.Sort(groupNames)
// TODO: Each machine can technically have a different Guest configuration.
// It's impractical to show the guest for each machine, but arbitrarily
// picking the first one is not ideal either.
representativeGuests := lo.MapValues(machineGroups, func(machines []*api.Machine, _ string) *api.MachineGuest {
if len(machines) == 0 {
return nil
}
return machines[0].Config.Guest
})
if flag.GetBool(ctx, "json") {
type groupData struct {
Process string
Count int
CPUKind string
CPUs int
Memory int
Regions map[string]int
}
groups := lo.FilterMap(groupNames, func(name string, _ int) (res groupData, ok bool) {
machines := machineGroups[name]
guest := representativeGuests[name]
if guest == nil {
return res, false
}
return groupData{
Process: name,
Count: len(machines),
CPUKind: guest.CPUKind,
CPUs: guest.CPUs,
Memory: guest.MemoryMB,
Regions: lo.CountValues(lo.Map(machines, func(m *api.Machine, _ int) string {
return m.Region
})),
}, true
})
prettyJSON, _ := json.MarshalIndent(groups, "", " ")
fmt.Fprintln(io.Out, string(prettyJSON))
return nil
}
rows := make([][]string, 0, len(machineGroups))
for _, groupName := range groupNames {
machines := machineGroups[groupName]
guest := representativeGuests[groupName]
if guest == nil {
continue
}
rows = append(rows, []string{
groupName,
fmt.Sprintf("%d", len(machines)),
guest.CPUKind,
fmt.Sprintf("%d", guest.CPUs),
fmt.Sprintf("%d MB", guest.MemoryMB),
formatRegions(machines),
})
}
fmt.Fprintf(io.Out, "VM Resources for app: %s\n\n", appName)
render.Table(io.Out, "Groups", rows, "Name", "Count", "Kind", "CPUs", "Memory", "Regions")
return nil
}
func formatRegions(machines []*api.Machine) string {
regions := lo.Map(
lo.Entries(lo.CountValues(lo.Map(machines, func(m *api.Machine, _ int) string {
return m.Region
}))),
func(e lo.Entry[string, int], _ int) string {
if e.Value > 1 {
return fmt.Sprintf("%s(%d)", e.Key, e.Value)
}
return e.Key
},
)
slices.Sort(regions)
return strings.Join(regions, ",")
}