Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Add frontend rules to the coordinator's config #1081

Merged
merged 7 commits into from
Mar 18, 2025
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
2 changes: 2 additions & 0 deletions .github/actions/spelling/expect.txt
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ datname
dbe
dbi
dbpool
dbr
dbtpcc
dcd
ddl
Expand Down Expand Up @@ -140,6 +141,7 @@ FQRN
frmp
frrule
frsm
frules
gcflags
getconn
gettime
Expand Down
28 changes: 18 additions & 10 deletions coordinator/provider/coordinator.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import (
"github.com/pg-sharding/spqr/pkg/models/topology"
"github.com/pg-sharding/spqr/pkg/pool"
routerproto "github.com/pg-sharding/spqr/pkg/protos"
"github.com/pg-sharding/spqr/pkg/rulemgr"
"github.com/pg-sharding/spqr/pkg/shard"
"github.com/pg-sharding/spqr/pkg/spqrlog"
"github.com/pg-sharding/spqr/qdb"
Expand Down Expand Up @@ -196,6 +197,7 @@ func DialRouter(r *topology.Router) (*grpc.ClientConn, error) {
const defaultWatchRouterTimeout = time.Second

type qdbCoordinator struct {
rmgr rulemgr.RulesMgr
tlsconfig *tls.Config
db qdb.XQDB
cache *cache.SchemaCache
Expand Down Expand Up @@ -314,6 +316,7 @@ func NewCoordinator(tlsconfig *tls.Config, db qdb.XQDB) (*qdbCoordinator, error)
return &qdbCoordinator{
db: db,
tlsconfig: tlsconfig,
rmgr: rulemgr.NewMgr(config.CoordinatorConfig().FrontendRules, []*config.BackendRule{}),
}, nil
}

Expand Down Expand Up @@ -1876,19 +1879,24 @@ func (qc *qdbCoordinator) PrepareClient(nconn net.Conn, pt port.RouterPortType)
Bool("ssl", tlsconfig != nil).
Msg("init client connection OK")

var authRule *config.AuthCfg
if config.CoordinatorConfig().Auth != nil {
authRule = config.CoordinatorConfig().Auth
} else {
spqrlog.Zero.Warn().Msg("ATTENTION! Skipping auth checking!")
authRule = &config.AuthCfg{
Method: config.AuthOK,
// match client to frontend rule
key := *route.NewRouteKey(cl.Usr(), cl.DB())
frRule, err := qc.rmgr.MatchKeyFrontend(key)
if err != nil {
for _, msg := range []pgproto3.BackendMessage{
&pgproto3.ErrorResponse{
Severity: "ERROR",
Message: err.Error(),
},
} {
if err := cl.Send(msg); err != nil {
return nil, fmt.Errorf("failed to make route failure response: %w", err)
}
}
return nil, err
}

if err := cl.AssignRule(&config.FrontendRule{
AuthRule: authRule,
}); err != nil {
if err := cl.AssignRule(frRule); err != nil {
return nil, err
}

Expand Down
38 changes: 25 additions & 13 deletions docs/configuration/coordinator.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -12,18 +12,30 @@ Refer to the [pkg/config/coordinator.go](https://github.com/pg-sharding/spqr/blo

## Coordinator Settings

| Setting | Description | Possible Values |
|--------------------------|--------------------------------------------------------------------|-----------------------|
| Setting | Description | Possible Values |
|--------------------------|--------------------------------------------------------------------|------------------------|
| `log_level` | The level of logging output. | `debug`, `info`, `warning`, `error`, `fatal`|
| `pretty_logging` | Whether to write logs in an colorized, human-friendly format. | `true`, `false` |
| `qdb_addr` | the address of the QDB server | Any valid address |
| `host` | The host address the coordinator listens on. | Any valid hostname |
| `coordinator_port` | The port number for the coordinator. | Any valid port number |
| `grpc_api_port` | The port number for the gRPC API. | Any valid port number |
| `auth` | See [auth.mdx](./auth) | Object of `AuthCfg` |
| `frontend_tls` | See [auth.mdx](./auth) | Object of `TLSConfig` |
| `use_systemd_notifier` | Whether to use systemd notifier. | `true`, `false` |
| `systemd_notifier_debug` | Whether to run systemd notifier in debug mode. | `true`, `false` |
| `enable_role_system` | Whether to enable the [role-based access control system](./roles). | `true`, `false` |
| `roles_file` | The file path to the [roles](./roles) configuration. | Any valid file path |
| `pretty_logging` | Whether to write logs in an colorized, human-friendly format. | `true`, `false` |
| `qdb_addr` | the address of the QDB server | Any valid address |
| `host` | The host address the coordinator listens on. | Any valid hostname |
| `coordinator_port` | The port number for the coordinator. | Any valid port number |
| `grpc_api_port` | The port number for the gRPC API. | Any valid port number |
| `auth` | See [auth.mdx](./auth) | Object of `AuthCfg` |
| `frontend_tls` | See [auth.mdx](./auth) | Object of `TLSConfig` |
| `frontend_rules` | The rules for frontend connections. | List of `FrontendRule` |
| `use_systemd_notifier` | Whether to use systemd notifier. | `true`, `false` |
| `systemd_notifier_debug` | Whether to run systemd notifier in debug mode. | `true`, `false` |
| `enable_role_system` | Whether to enable the [role-based access control system](./roles). | `true`, `false` |
| `roles_file` | The file path to the [roles](./roles) configuration. | Any valid file path |

## Frontend Rules

Frontend rule is a specification of how clients connect to the admin console.

Refer to the `FrontendRule` struct in the [pkg/config/rules.go](https://github.com/pg-sharding/spqr/blob/master/pkg/config/rules.go) file for the most up-to-date configuration options.

| Setting | Description | Possible Values |
|---------------------------|--------------------------------------------------------------------------------|--------------------------|
| `db` | The database name to which the rule applies | Any valid database name |
| `usr` | The user name for which the rule is applicable | Any valid username |
| `auth_rule` | See [General Auth Settings](./auth.go) | Object of `AuthCfg` |
2 changes: 1 addition & 1 deletion docs/configuration/router.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ Refer to the [pkg/config/router.go](https://github.com/pg-sharding/spqr/blob/mas

Frontend rule is a specification of how clients connect to the router.

Refer to the `FrontendRule` struct in the [pkg/config/router.go](https://github.com/pg-sharding/spqr/blob/master/pkg/config/router.go) file for the most up-to-date configuration options.
Refer to the `FrontendRule` struct in the [pkg/config/rules.go](https://github.com/pg-sharding/spqr/blob/master/pkg/config/rules.go) file for the most up-to-date configuration options.

| Setting | Description | Possible Values |
|---------------------------|--------------------------------------------------------------------------------|--------------------------|
Expand Down
28 changes: 14 additions & 14 deletions pkg/config/coordinator.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,20 +14,20 @@ import (
var cfgCoordinator Coordinator

type Coordinator struct {
LogLevel string `json:"log_level" toml:"log_level" yaml:"log_level"`
PrettyLogging bool `json:"pretty_logging" toml:"pretty_logging" yaml:"pretty_logging"`
QdbAddr string `json:"qdb_addr" toml:"qdb_addr" yaml:"qdb_addr"`
CoordinatorPort string `json:"coordinator_port" toml:"coordinator_port" yaml:"coordinator_port"`
GrpcApiPort string `json:"grpc_api_port" toml:"grpc_api_port" yaml:"grpc_api_port"`
Host string `json:"host" toml:"host" yaml:"host"`
Auth *AuthCfg `json:"auth" toml:"auth" yaml:"auth"`
FrontendTLS *TLSConfig `json:"frontend_tls" yaml:"frontend_tls" toml:"frontend_tls"`
ShardDataCfg string `json:"shard_data" toml:"shard_data" yaml:"shard_data"`
UseSystemdNotifier bool `json:"use_systemd_notifier" toml:"use_systemd_notifier" yaml:"use_systemd_notifier"`
SystemdNotifierDebug bool `json:"systemd_notifier_debug" toml:"systemd_notifier_debug" yaml:"systemd_notifier_debug"`
IterationTimeout time.Duration `json:"iteration_timeout" toml:"iteration_timeout" yaml:"iteration_timeout"`
EnableRoleSystem bool `json:"enable_role_system" toml:"enable_role_system" yaml:"enable_role_system"`
RolesFile string `json:"roles_file" toml:"roles_file" yaml:"roles_file"`
LogLevel string `json:"log_level" toml:"log_level" yaml:"log_level"`
PrettyLogging bool `json:"pretty_logging" toml:"pretty_logging" yaml:"pretty_logging"`
QdbAddr string `json:"qdb_addr" toml:"qdb_addr" yaml:"qdb_addr"`
CoordinatorPort string `json:"coordinator_port" toml:"coordinator_port" yaml:"coordinator_port"`
GrpcApiPort string `json:"grpc_api_port" toml:"grpc_api_port" yaml:"grpc_api_port"`
Host string `json:"host" toml:"host" yaml:"host"`
FrontendTLS *TLSConfig `json:"frontend_tls" yaml:"frontend_tls" toml:"frontend_tls"`
FrontendRules []*FrontendRule `json:"frontend_rules" toml:"frontend_rules" yaml:"frontend_rules"`
ShardDataCfg string `json:"shard_data" toml:"shard_data" yaml:"shard_data"`
UseSystemdNotifier bool `json:"use_systemd_notifier" toml:"use_systemd_notifier" yaml:"use_systemd_notifier"`
SystemdNotifierDebug bool `json:"systemd_notifier_debug" toml:"systemd_notifier_debug" yaml:"systemd_notifier_debug"`
IterationTimeout time.Duration `json:"iteration_timeout" toml:"iteration_timeout" yaml:"iteration_timeout"`
EnableRoleSystem bool `json:"enable_role_system" toml:"enable_role_system" yaml:"enable_role_system"`
RolesFile string `json:"roles_file" toml:"roles_file" yaml:"roles_file"`
}

// LoadCoordinatorCfg loads the coordinator configuration from the specified file path.
Expand Down
26 changes: 0 additions & 26 deletions pkg/config/router.go
Original file line number Diff line number Diff line change
Expand Up @@ -108,32 +108,6 @@ type QRouter struct {
EnhancedMultiShardProcessing bool `json:"enhanced_multishard_processing" toml:"enhanced_multishard_processing" yaml:"enhanced_multishard_processing"`
}

type BackendRule struct {
DB string `json:"db" yaml:"db" toml:"db"`
Usr string `json:"usr" yaml:"usr" toml:"usr"`
AuthRules map[string]*AuthBackendCfg `json:"auth_rules" yaml:"auth_rules" toml:"auth_rules"`
DefaultAuthRule *AuthBackendCfg `json:"auth_rule" yaml:"auth_rule" toml:"auth_rule"`
PoolDefault bool `json:"pool_default" yaml:"pool_default" toml:"pool_default"`

ConnectionLimit int `json:"connection_limit" yaml:"connection_limit" toml:"connection_limit"`
ConnectionRetries int `json:"connection_retries" yaml:"connection_retries" toml:"connection_retries"`
ConnectionTimeout time.Duration `json:"connection_timeout" yaml:"connection_timeout" toml:"connection_timeout"`
KeepAlive time.Duration `json:"keep_alive" yaml:"keep_alive" toml:"keep_alive"`
TcpUserTimeout time.Duration `json:"tcp_user_timeout" yaml:"tcp_user_timeout" toml:"tcp_user_timeout"`
}

type FrontendRule struct {
DB string `json:"db" yaml:"db" toml:"db"`
Usr string `json:"usr" yaml:"usr" toml:"usr"`
SearchPath string `json:"search_path" yaml:"search_path" toml:"search_path"`
AuthRule *AuthCfg `json:"auth_rule" yaml:"auth_rule" toml:"auth_rule"`
PoolMode PoolMode `json:"pool_mode" yaml:"pool_mode" toml:"pool_mode"`
PoolDiscard bool `json:"pool_discard" yaml:"pool_discard" toml:"pool_discard"`
PoolRollback bool `json:"pool_rollback" yaml:"pool_rollback" toml:"pool_rollback"`
PoolPreparedStatement bool `json:"pool_prepared_statement" yaml:"pool_prepared_statement" toml:"pool_prepared_statement"`
PoolDefault bool `json:"pool_default" yaml:"pool_default" toml:"pool_default"`
}

const (
TargetSessionAttrsRW = "read-write"
TargetSessionAttrsRO = "read-only"
Expand Down
31 changes: 31 additions & 0 deletions pkg/config/rules.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package config

import "time"

type BackendRule struct {
DB string `json:"db" yaml:"db" toml:"db"`
Usr string `json:"usr" yaml:"usr" toml:"usr"`
AuthRules map[string]*AuthBackendCfg `json:"auth_rules" yaml:"auth_rules" toml:"auth_rules"`
DefaultAuthRule *AuthBackendCfg `json:"auth_rule" yaml:"auth_rule" toml:"auth_rule"`
PoolDefault bool `json:"pool_default" yaml:"pool_default" toml:"pool_default"`

ConnectionLimit int `json:"connection_limit" yaml:"connection_limit" toml:"connection_limit"`
ConnectionRetries int `json:"connection_retries" yaml:"connection_retries" toml:"connection_retries"`
ConnectionTimeout time.Duration `json:"connection_timeout" yaml:"connection_timeout" toml:"connection_timeout"`
KeepAlive time.Duration `json:"keep_alive" yaml:"keep_alive" toml:"keep_alive"`
TcpUserTimeout time.Duration `json:"tcp_user_timeout" yaml:"tcp_user_timeout" toml:"tcp_user_timeout"`
}

type FrontendRule struct {
DB string `json:"db" yaml:"db" toml:"db"`
Usr string `json:"usr" yaml:"usr" toml:"usr"`
AuthRule *AuthCfg `json:"auth_rule" yaml:"auth_rule" toml:"auth_rule"`

// Pool settings and search_path does not take effect for coordinator
SearchPath string `json:"search_path" yaml:"search_path" toml:"search_path"`
PoolMode PoolMode `json:"pool_mode" yaml:"pool_mode" toml:"pool_mode"`
PoolDiscard bool `json:"pool_discard" yaml:"pool_discard" toml:"pool_discard"`
PoolRollback bool `json:"pool_rollback" yaml:"pool_rollback" toml:"pool_rollback"`
PoolPreparedStatement bool `json:"pool_prepared_statement" yaml:"pool_prepared_statement" toml:"pool_prepared_statement"`
PoolDefault bool `json:"pool_default" yaml:"pool_default" toml:"pool_default"`
}
Loading
Loading