Skip to content

Commit e922d22

Browse files
author
asib
authored
Add status and list MPG subcommands (#4332)
1 parent 353255a commit e922d22

5 files changed

Lines changed: 174 additions & 1 deletion

File tree

internal/command/mpg/list.go

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
package mpg
2+
3+
import (
4+
"context"
5+
"fmt"
6+
7+
"github.com/spf13/cobra"
8+
9+
"github.com/superfly/flyctl/gql"
10+
"github.com/superfly/flyctl/iostreams"
11+
12+
"github.com/superfly/flyctl/internal/command"
13+
"github.com/superfly/flyctl/internal/command/orgs"
14+
"github.com/superfly/flyctl/internal/config"
15+
"github.com/superfly/flyctl/internal/flag"
16+
"github.com/superfly/flyctl/internal/flyutil"
17+
"github.com/superfly/flyctl/internal/render"
18+
"github.com/superfly/flyctl/internal/uiexutil"
19+
)
20+
21+
func newList() *cobra.Command {
22+
const (
23+
long = `List MPG clusters owned by the specified organization.
24+
If no organization is specified, the user's personal organization is used.`
25+
short = "List MPG clusters."
26+
usage = "list"
27+
)
28+
29+
cmd := command.New(usage, short, long, runList,
30+
command.RequireSession,
31+
command.RequireUiex,
32+
)
33+
34+
cmd.Aliases = []string{"ls"}
35+
36+
flag.Add(cmd, flag.JSONOutput())
37+
flag.Add(cmd, flag.Org())
38+
39+
return cmd
40+
}
41+
42+
func runList(ctx context.Context) error {
43+
cfg := config.FromContext(ctx)
44+
out := iostreams.FromContext(ctx).Out
45+
46+
org, err := orgs.OrgFromFlagOrSelect(ctx)
47+
if err != nil {
48+
return err
49+
}
50+
51+
uiexClient := uiexutil.ClientFromContext(ctx)
52+
genqClient := flyutil.ClientFromContext(ctx).GenqClient()
53+
54+
// For ui-ex request we need the real org slug
55+
var fullOrg *gql.GetOrganizationResponse
56+
if fullOrg, err = gql.GetOrganization(ctx, genqClient, org.Slug); err != nil {
57+
err = fmt.Errorf("failed fetching org: %w", err)
58+
return err
59+
}
60+
61+
clusters, err := uiexClient.ListManagedClusters(ctx, fullOrg.Organization.RawSlug)
62+
if err != nil {
63+
return fmt.Errorf("failed to list managed clusters for organization %s: %w", org.Slug, err)
64+
}
65+
66+
if len(clusters.Data) == 0 {
67+
fmt.Fprintf(out, "No managed postgres clusters found in organization %s\n", org.Slug)
68+
return nil
69+
}
70+
71+
if cfg.JSONOutput {
72+
return render.JSON(out, clusters.Data)
73+
}
74+
75+
rows := make([][]string, 0, len(clusters.Data))
76+
for _, cluster := range clusters.Data {
77+
rows = append(rows, []string{
78+
cluster.Id,
79+
cluster.Name,
80+
cluster.Organization.Slug,
81+
cluster.Region,
82+
cluster.Status,
83+
cluster.Plan,
84+
})
85+
}
86+
87+
return render.Table(out, "", rows, "ID", "Name", "Org", "Region", "Status", "Plan")
88+
}

internal/command/mpg/mpg.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ func New() *cobra.Command {
3131
newProxy(),
3232
newConnect(),
3333
newAttach(),
34+
newStatus(),
35+
newList(),
3436
newCreate(),
3537
)
3638

internal/command/mpg/proxy.go

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,6 @@ func newProxy() (cmd *cobra.Command) {
3737
}
3838

3939
func runProxy(ctx context.Context) (err error) {
40-
4140
localProxyPort := "16380"
4241
cluster, params, password, err := getMpgProxyParams(ctx, localProxyPort)
4342
if err != nil {

internal/command/mpg/status.go

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
package mpg
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"strconv"
7+
8+
"github.com/spf13/cobra"
9+
"github.com/superfly/flyctl/iostreams"
10+
11+
"github.com/superfly/flyctl/internal/command"
12+
"github.com/superfly/flyctl/internal/config"
13+
"github.com/superfly/flyctl/internal/flag"
14+
"github.com/superfly/flyctl/internal/render"
15+
"github.com/superfly/flyctl/internal/uiexutil"
16+
)
17+
18+
func newStatus() *cobra.Command {
19+
const (
20+
long = `Show status and details of a specific Managed Postgres cluster using its ID.`
21+
short = "Show MPG cluster status."
22+
usage = "status [CLUSTER_ID]"
23+
)
24+
25+
cmd := command.New(usage, short, long, runStatus,
26+
command.RequireSession,
27+
command.RequireUiex,
28+
)
29+
30+
cmd.Args = cobra.ExactArgs(1)
31+
32+
flag.Add(cmd, flag.JSONOutput())
33+
34+
return cmd
35+
}
36+
37+
func runStatus(ctx context.Context) error {
38+
cfg := config.FromContext(ctx)
39+
out := iostreams.FromContext(ctx).Out
40+
uiexClient := uiexutil.ClientFromContext(ctx)
41+
42+
clusterID := flag.FirstArg(ctx)
43+
if clusterID == "" {
44+
// Should not happen due to cobra.ExactArgs(1), but good practice
45+
return fmt.Errorf("cluster ID argument is required")
46+
}
47+
48+
// Fetch detailed cluster information by ID
49+
clusterDetails, err := uiexClient.GetManagedClusterById(ctx, clusterID)
50+
if err != nil {
51+
return fmt.Errorf("failed retrieving details for cluster %s: %w", clusterID, err)
52+
}
53+
54+
if cfg.JSONOutput {
55+
return render.JSON(out, clusterDetails)
56+
}
57+
58+
rows := [][]string{{
59+
clusterDetails.Data.Id,
60+
clusterDetails.Data.Name,
61+
clusterDetails.Data.Organization.Slug,
62+
clusterDetails.Data.Region,
63+
clusterDetails.Data.Status,
64+
strconv.Itoa(clusterDetails.Data.Disk),
65+
strconv.Itoa(clusterDetails.Data.Replicas),
66+
clusterDetails.Data.IpAssignments.Direct,
67+
}}
68+
69+
cols := []string{
70+
"ID",
71+
"Name",
72+
"Organization",
73+
"Region",
74+
"Status",
75+
"Allocated Disk (GB)",
76+
"Replicas",
77+
"Direct IP",
78+
}
79+
80+
return render.VerticalTable(out, "Cluster Status", rows, cols...)
81+
}

internal/uiex/managed_postgres.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,15 @@ import (
1515
type ManagedClusterIpAssignments struct {
1616
Direct string `json:"direct"`
1717
}
18+
1819
type ManagedCluster struct {
1920
Id string `json:"id"`
2021
Name string `json:"name"`
2122
Region string `json:"region"`
2223
Status string `json:"status"`
2324
Plan string `json:"plan"`
25+
Disk int `json:"disk"`
26+
Replicas int `json:"replicas"`
2427
Organization fly.Organization `json:"organization"`
2528
IpAssignments ManagedClusterIpAssignments `json:"ip_assignments"`
2629
}

0 commit comments

Comments
 (0)