Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -544,7 +544,7 @@ pscale maintenance windows <database> <schedule-id> --org <org> --format json
`pscale branch resize` queues a single asynchronous **change request** for a Postgres branch covering cluster size, replica count, and configuration parameters in any combination. Track it with `resize status`; cancel it with `resize cancel` while queued.

```bash
# Read the parameter catalog first (names, current/default values, restart/immutable flags)
# Read the parameter catalog first (names, current/default values, restart flags)
pscale branch parameters list <database> <branch> --org <org> --format json
pscale branch parameters list <database> <branch> --org <org> --format json --namespace pgconf

Expand Down Expand Up @@ -589,7 +589,7 @@ pscale branch resize cancel <database> <branch> --org <org> --format json
- At least one of `--cluster-size`, `--replicas`, or `--parameters` is required.
- Neki `--inherited-roles` may include `neki_viewer` (must also include `pg_read_all_data`) and `neki_operator` (must also include `postgres`). The API rejects those pairings if the required role is missing.
- `--replica`, `--dedicated-read-replica`, and `--bouncer` are mutually exclusive. `--dedicated-read-replica` and `--bouncer` are Postgres-only and cannot combine with `--router` or `--shard`. The deprecated `--read-only-replica` flag is a compatibility alias for `--dedicated-read-replica`. On Neki, `--replica`, `--shard`, and `--router` can be combined. `--router` rewrites `username` to `user|<name>`. `--replica` and `--shard` set `options` (`-c __neki.target=REPLICA`, `-c __neki.shard=…`) and add them to `database_url`. List names with `pscale branch router list` and `pscale branch shard list` (use the shard name, not the API id).
- `--parameters` values are validated against the catalog before submission; unknown or immutable parameters fail fast. Parameters with `"restart": true` in the catalog restart the database when applied — surface this to the user before changing them.
- `--parameters` values are validated against the changeable parameters in the catalog before submission; parameters that don't exist or can't be changed fail fast. Parameters with `"restart": true` in the catalog restart the database when applied — surface this to the user before changing them.
- Change request `state` is one of `queued`, `pending`, `resizing`, `completed`, `canceled`. Only `completed` and `canceled` are terminal. Without `--wait`, poll `resize status` instead of assuming completion.
- A no-op (branch already matches the requested configuration) prints `{"result": "no_change", "branch": "<branch>"}` in JSON mode instead of a change request.
- `resize cancel` prints `{"result": "canceled", "branch": "<branch>"}` in JSON mode.
Expand Down
4 changes: 1 addition & 3 deletions internal/cmd/branch/parameters.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ To change parameters, use 'pscale branch resize <database> <branch> --parameters
registerFlags := func(cmd *cobra.Command) {
cmd.Flags().StringVar(&flags.namespace, "namespace", "", "Only show parameters in this namespace (e.g. pgconf, pgbouncer, patroni).")
cmd.Flags().BoolVar(&flags.extension, "extension", false, "Only show parameters that configure an extension (--extension=false hides them).")
cmd.Flags().BoolVar(&flags.internal, "internal", false, "Only show internal (immutable) parameters (--internal=false hides them).")
cmd.Flags().BoolVar(&flags.internal, "internal", false, "Only show internal parameters, which cannot be changed (--internal=false hides them).")
}

// The bare 'parameters <database> <branch>' invocation is an alias for
Expand Down Expand Up @@ -111,7 +111,6 @@ type postgresParameter struct {
Default string `header:"default" json:"default_value"`
Type string `header:"type" json:"parameter_type"`
Restart bool `header:"restart" json:"restart"`
Immutable bool `header:"immutable" json:"immutable"`

orig *ps.PostgresParameter
}
Expand All @@ -126,7 +125,6 @@ func toPostgresParameters(parameters []*ps.PostgresParameter) []*postgresParamet
Default: formatParameterValue(param.DefaultValue),
Type: param.ParameterType,
Restart: param.Restart,
Immutable: param.Immutable,
orig: param,
})
}
Expand Down
7 changes: 3 additions & 4 deletions internal/cmd/branch/resize.go
Original file line number Diff line number Diff line change
Expand Up @@ -193,10 +193,12 @@ func preflightParameters(ctx context.Context, client *ps.Client, organization, d
return nil, nil
}

internal := false
catalog, err := client.PostgresBranches.ListParameters(ctx, &ps.ListPostgresParametersRequest{
Organization: organization,
Database: database,
Branch: branch,
Internal: &internal,
})
if err != nil {
return nil, nil
Expand All @@ -221,10 +223,7 @@ func preflightParameters(ctx context.Context, client *ps.Client, organization, d
for _, key := range keys {
param, ok := known[key]
if !ok {
return nil, fmt.Errorf("unknown parameter %s. Run 'pscale branch parameters list %s %s' to see available parameters", printer.BoldBlue(key), database, branch)
}
if param.Immutable {
return nil, fmt.Errorf("parameter %s cannot be changed", printer.BoldBlue(key))
return nil, fmt.Errorf("parameter %s does not exist or cannot be changed. Run 'pscale branch parameters list %s %s --org %s --internal=false' to see the parameters you can change", printer.BoldBlue(key), database, branch, organization)
}
if param.Restart {
restartParams = append(restartParams, key)
Expand Down
42 changes: 5 additions & 37 deletions internal/cmd/branch/resize_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,9 @@ func TestBranch_ResizeCmd_WithParameters(t *testing.T) {

pgSvc := &mock.PostgresBranchesService{
ListParametersFn: func(ctx context.Context, req *ps.ListPostgresParametersRequest) ([]*ps.PostgresParameter, error) {
c.Assert(req.Internal, qt.IsNotNil)
c.Assert(*req.Internal, qt.IsFalse)

return []*ps.PostgresParameter{
{Namespace: "pgconf", Name: "max_connections", ParameterType: "integer", Restart: true},
}, nil
Expand Down Expand Up @@ -116,43 +119,8 @@ func TestBranch_ResizeCmd_UnknownParameter(t *testing.T) {
err := cmd.Execute()

c.Assert(err, qt.IsNotNil)
c.Assert(err.Error(), qt.Contains, "unknown parameter")
c.Assert(pgSvc.ResizeFnInvoked, qt.IsFalse)
}

func TestBranch_ResizeCmd_ImmutableParameter(t *testing.T) {
c := qt.New(t)

var buf bytes.Buffer
format := printer.JSON
p := printer.NewPrinter(&format)
p.SetResourceOutput(&buf)

dbSvc := &mock.DatabaseService{
GetFn: func(ctx context.Context, req *ps.GetDatabaseRequest) (*ps.Database, error) {
return &ps.Database{Name: "postgres-db", Kind: "postgresql"}, nil
},
}

pgSvc := &mock.PostgresBranchesService{
ListParametersFn: func(ctx context.Context, req *ps.ListPostgresParametersRequest) ([]*ps.PostgresParameter, error) {
return []*ps.PostgresParameter{
{Namespace: "pgconf", Name: "wal_level", Immutable: true},
}, nil
},
ResizeFn: func(ctx context.Context, req *ps.ResizePostgresBranchRequest) (*ps.PostgresBranchClusterResizeRequest, error) {
return nil, nil
},
}

ch := testResizeHelper(p, "planetscale", dbSvc, pgSvc)

cmd := ResizeCmd(ch)
cmd.SetArgs([]string{"postgres-db", "main", "--parameters", "pgconf.wal_level=logical"})
err := cmd.Execute()

c.Assert(err, qt.IsNotNil)
c.Assert(err.Error(), qt.Contains, "cannot be changed")
c.Assert(err.Error(), qt.Contains, "does not exist or cannot be changed")
c.Assert(err.Error(), qt.Contains, "--org planetscale")
c.Assert(pgSvc.ResizeFnInvoked, qt.IsFalse)
}

Expand Down
1 change: 0 additions & 1 deletion internal/planetscale/postgres_bouncers.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@ type PostgresBouncerParameter struct {
DisplayName string `json:"display_name"`
Category string `json:"category"`
Description string `json:"description"`
Immutable bool `json:"immutable"`
ParameterType string `json:"parameter_type"`
DefaultValue string `json:"default_value"`
Value string `json:"value"`
Expand Down
2 changes: 1 addition & 1 deletion internal/planetscale/postgres_bouncers_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ func TestPostgresBouncers_Get(t *testing.T) {
"deleted_at":null,
"actor":{"id":"user-1","display_name":"Alice","avatar_url":"https://example.com/a.png"},
"branch":{"id":"branch-1","name":"main","created_at":"2021-01-01T00:00:00.000Z","updated_at":"2021-01-01T00:00:00.000Z","deleted_at":null},
"parameters":[{"id":"p1","namespace":"pgbouncer","name":"default_pool_size","display_name":"Default pool size","category":"","description":"","immutable":false,"parameter_type":"integer","default_value":"20","value":"50","required":false,"restart":false,"created_at":"2021-01-14T10:19:23.000Z","updated_at":"2021-01-14T10:19:23.000Z"}]
"parameters":[{"id":"p1","namespace":"pgbouncer","name":"default_pool_size","display_name":"Default pool size","category":"","description":"","parameter_type":"integer","default_value":"20","value":"50","required":false,"restart":false,"created_at":"2021-01-14T10:19:23.000Z","updated_at":"2021-01-14T10:19:23.000Z"}]
}`
_, err := w.Write([]byte(out))
c.Assert(err, qt.IsNil)
Expand Down
4 changes: 1 addition & 3 deletions internal/planetscale/postgres_branches.go
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,7 @@ type ListPostgresParametersRequest struct {
// Extension filters parameters by whether they configure an extension.
// Nil returns both.
Extension *bool
// Internal filters parameters by whether they are internal (immutable).
// Internal filters parameters by whether they are internal and cannot be changed.
// Nil returns both.
Internal *bool
}
Expand All @@ -209,8 +209,6 @@ type PostgresParameter struct {
Namespace string `json:"namespace"`
Category string `json:"category"`
Description string `json:"description"`
Extension bool `json:"extension"`
Immutable bool `json:"immutable"`
ParameterType string `json:"parameter_type"`
DefaultValue any `json:"default_value"`
Value any `json:"value"`
Expand Down
2 changes: 1 addition & 1 deletion internal/planetscale/postgres_branches_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -564,7 +564,7 @@ func TestPostgresBranches_ListParameters(t *testing.T) {

w.WriteHeader(200)
// The parameters endpoint returns a bare array, not a {"data": [...]} envelope.
out := `[{"id":"param-1","name":"max_connections","display_name":"Max connections","namespace":"pgconf","parameter_type":"integer","default_value":"100","value":"200","restart":true,"immutable":false,"min":25,"max":5000}]`
out := `[{"id":"param-1","name":"max_connections","display_name":"Max connections","namespace":"pgconf","parameter_type":"integer","default_value":"100","value":"200","restart":true,"min":25,"max":5000}]`
_, err := w.Write([]byte(out))
c.Assert(err, qt.IsNil)
}))
Expand Down
Loading