Skip to content

Commit 42f26bd

Browse files
authored
Merge a975408 into 641eb1c
2 parents 641eb1c + a975408 commit 42f26bd

File tree

10 files changed

+895
-1
lines changed

10 files changed

+895
-1
lines changed

internal/command/launch/plan/postgres_test.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,14 @@ func (m *mockUIEXClient) RestoreManagedClusterBackup(ctx context.Context, cluste
111111
return uiex.RestoreManagedClusterBackupResponse{}, nil
112112
}
113113

114+
func (m *mockUIEXClient) CreateAttachment(ctx context.Context, clusterId string, input uiex.CreateAttachmentInput) (uiex.CreateAttachmentResponse, error) {
115+
return uiex.CreateAttachmentResponse{}, nil
116+
}
117+
118+
func (m *mockUIEXClient) DeleteAttachment(ctx context.Context, clusterId string, appName string) (uiex.DeleteAttachmentResponse, error) {
119+
return uiex.DeleteAttachmentResponse{}, nil
120+
}
121+
114122
func (m *mockUIEXClient) CreateBuild(ctx context.Context, in uiex.CreateBuildRequest) (*uiex.BuildResponse, error) {
115123
return &uiex.BuildResponse{}, nil
116124
}

internal/command/mpg/attach.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -281,6 +281,15 @@ func runAttach(ctx context.Context) error {
281281
return err
282282
}
283283

284+
// Create attachment record to track the cluster-app relationship
285+
attachInput := uiex.CreateAttachmentInput{
286+
AppName: appName,
287+
}
288+
if _, err := uiexClient.CreateAttachment(ctx, cluster.Id, attachInput); err != nil {
289+
// Log warning but don't fail - the secret was set successfully
290+
fmt.Fprintf(io.ErrOut, "Warning: failed to create attachment record: %v\n", err)
291+
}
292+
284293
fmt.Fprintf(io.Out, "\nPostgres cluster %s is being attached to %s\n", cluster.Id, appName)
285294
fmt.Fprintf(io.Out, "The following secret was added to %s:\n %s=%s\n", appName, variableName, connectionUri)
286295

internal/command/mpg/detach.go

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
package mpg
2+
3+
import (
4+
"context"
5+
"fmt"
6+
7+
"github.com/spf13/cobra"
8+
"github.com/superfly/flyctl/internal/appconfig"
9+
"github.com/superfly/flyctl/internal/command"
10+
"github.com/superfly/flyctl/internal/flag"
11+
"github.com/superfly/flyctl/internal/flyutil"
12+
"github.com/superfly/flyctl/internal/uiexutil"
13+
"github.com/superfly/flyctl/iostreams"
14+
)
15+
16+
func newDetach() *cobra.Command {
17+
const (
18+
short = "Detach a managed Postgres cluster from an app"
19+
long = short + ". " +
20+
`This command will remove the attachment record linking the app to the cluster.
21+
Note: This does NOT remove any secrets from the app. Use 'fly secrets unset' to remove secrets.`
22+
usage = "detach <CLUSTER ID>"
23+
)
24+
25+
cmd := command.New(usage, short, long, runDetach,
26+
command.RequireSession,
27+
command.RequireAppName,
28+
)
29+
cmd.Args = cobra.MaximumNArgs(1)
30+
31+
flag.Add(cmd,
32+
flag.App(),
33+
flag.AppConfig(),
34+
)
35+
36+
return cmd
37+
}
38+
39+
func runDetach(ctx context.Context) error {
40+
// Check token compatibility early
41+
if err := validateMPGTokenCompatibility(ctx); err != nil {
42+
return err
43+
}
44+
45+
var (
46+
clusterId = flag.FirstArg(ctx)
47+
appName = appconfig.NameFromContext(ctx)
48+
client = flyutil.ClientFromContext(ctx)
49+
io = iostreams.FromContext(ctx)
50+
)
51+
52+
// Get app details to determine which org it belongs to
53+
app, err := client.GetAppBasic(ctx, appName)
54+
if err != nil {
55+
return fmt.Errorf("failed retrieving app %s: %w", appName, err)
56+
}
57+
58+
appOrgSlug := app.Organization.RawSlug
59+
if appOrgSlug != "" && clusterId == "" {
60+
fmt.Fprintf(io.Out, "Listing clusters in organization %s\n", appOrgSlug)
61+
}
62+
63+
// Get cluster details
64+
cluster, _, err := ClusterFromArgOrSelect(ctx, clusterId, appOrgSlug)
65+
if err != nil {
66+
return fmt.Errorf("failed retrieving cluster %s: %w", clusterId, err)
67+
}
68+
69+
clusterOrgSlug := cluster.Organization.Slug
70+
71+
// Verify that the app and cluster are in the same organization
72+
if appOrgSlug != clusterOrgSlug {
73+
return fmt.Errorf("app %s is in organization %s, but cluster %s is in organization %s. They must be in the same organization",
74+
appName, appOrgSlug, cluster.Id, clusterOrgSlug)
75+
}
76+
77+
uiexClient := uiexutil.ClientFromContext(ctx)
78+
79+
// Delete the attachment record
80+
_, err = uiexClient.DeleteAttachment(ctx, cluster.Id, appName)
81+
if err != nil {
82+
return fmt.Errorf("failed to detach: %w", err)
83+
}
84+
85+
fmt.Fprintf(io.Out, "\nPostgres cluster %s has been detached from %s\n", cluster.Id, appName)
86+
fmt.Fprintf(io.Out, "Note: This only removes the attachment record. Any secrets (like DATABASE_URL) are still set on the app.\n")
87+
fmt.Fprintf(io.Out, "Use 'fly secrets unset DATABASE_URL -a %s' to remove the connection string.\n", appName)
88+
89+
return nil
90+
}

internal/command/mpg/list.go

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,12 @@ package mpg
33
import (
44
"context"
55
"fmt"
6+
"strings"
67

78
"github.com/spf13/cobra"
89

910
"github.com/superfly/flyctl/gql"
11+
"github.com/superfly/flyctl/internal/uiex"
1012
"github.com/superfly/flyctl/iostreams"
1113

1214
"github.com/superfly/flyctl/internal/command"
@@ -95,8 +97,22 @@ func runList(ctx context.Context) error {
9597
cluster.Region,
9698
cluster.Status,
9799
cluster.Plan,
100+
formatAttachedApps(cluster.AttachedApps),
98101
})
99102
}
100103

101-
return render.Table(out, "", rows, "ID", "Name", "Org", "Region", "Status", "Plan")
104+
return render.Table(out, "", rows, "ID", "Name", "Org", "Region", "Status", "Plan", "Attached Apps")
105+
}
106+
107+
// formatAttachedApps formats the list of attached apps for display
108+
func formatAttachedApps(apps []uiex.AttachedApp) string {
109+
if len(apps) == 0 {
110+
return "<no attached apps>"
111+
}
112+
113+
names := make([]string, len(apps))
114+
for i, app := range apps {
115+
names[i] = app.Name
116+
}
117+
return strings.Join(names, ", ")
102118
}

internal/command/mpg/mpg.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ func New() *cobra.Command {
7676
newProxy(),
7777
newConnect(),
7878
newAttach(),
79+
newDetach(),
7980
newStatus(),
8081
newList(),
8182
newCreate(),

0 commit comments

Comments
 (0)