Add groups (#559)

This commit is contained in:
NikitaUnisikhin 2024-05-14 11:20:50 +03:00 committed by GitHub
parent 3f50c152a2
commit 8ba1e233a1
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
18 changed files with 815 additions and 22 deletions

View File

View File

@ -45,7 +45,6 @@ listen {
compression yes
}
storage "postgres_server" {
type "remote"
host "localhost"

View File

@ -79,6 +79,7 @@ COPY ./docker/ldap /ldap
COPY ./docker/lagpolling /lagpolling
COPY ./docker/shell-test /shell-test
COPY ./docker/tsa /tsa
COPY ./docker/group /group
COPY ./docker/xproto /xproto
COPY ./docker/copy /copy
COPY ./docker/gorm /gorm

View File

@ -49,7 +49,7 @@ sudo -u postgres /usr/bin/pg_basebackup -D /var/lib/postgresql/14/repl -R -h loc
sudo -u postgres /usr/lib/postgresql/14/bin/pg_ctl -D /var/lib/postgresql/14/repl/ -o '-p 5433' start
# Create databases
for database_name in db scram_db ldap_db auth_query_db db1 hba_db tsa_db addr_db xproto_db "spqr-console"; do
for database_name in db scram_db ldap_db auth_query_db db1 hba_db tsa_db group_db addr_db xproto_db "spqr-console"; do
sudo -u postgres createdb $database_name >> "$SETUP_LOG" 2>&1 || {
echo "ERROR: 'createdb $database_name' failed, examine the log"
cat "$SETUP_LOG"
@ -63,6 +63,14 @@ mkdir /var/cores
sudo sysctl -w kernel.core_pattern=/var/cores/core.%p.%e
pgbench -i -h localhost -p 5432 -U postgres postgres
# Create users
psql -h localhost -p 5432 -U postgres -c "create role group1; create role group2; create user group_checker; create user group_user1; create user group_user2; create user group_user3; create user group_user4; create user group_user5; create user group_checker1; create user group_checker2;" -d group_db >> $SETUP_LOG 2>&1 || {
echo "ERROR: users creation failed, examine the log"
cat "$SETUP_LOG"
cat "$PG_LOG"
exit 1
}
# Create users
psql -h localhost -p 5432 -U postgres -c "set password_encryption = 'scram-sha-256'; create user scram_user password 'scram_user_password';" -d scram_db >> $SETUP_LOG 2>&1 || {
echo "ERROR: users creation failed, examine the log"

View File

@ -6,6 +6,13 @@ cd /test_dir/test && /usr/bin/odyssey_test
setup
# group
/group/test_group.sh
if [ $? -eq 1 ]
then
exit 1
fi
# gorm
ody-start
/gorm/test.sh

122
docker/group/config.conf Normal file
View File

@ -0,0 +1,122 @@
listen {
host "*"
port 6432
}
storage "postgres_server" {
type "remote"
host "localhost"
port 5432
}
database "group_db" {
user "group_user1" {
authentication "none"
storage "postgres_server"
pool "session"
}
group "group1" {
authentication "md5"
password "password1"
storage "postgres_server"
storage_db "postgres"
storage_user "postgres"
pool_routing "internal"
pool "session"
group_query "SELECT rolname FROM pg_roles WHERE pg_has_role(rolname, 'group1', 'member');"
}
user "group_user2" {
authentication "none"
storage "postgres_server"
pool "session"
}
user "group_user3" {
authentication "none"
storage "postgres_server"
pool "session"
}
group "group2" {
authentication "md5"
password "password2"
storage "postgres_server"
storage_db "postgres"
storage_user "postgres"
pool_routing "internal"
pool "session"
group_query "SELECT rolname FROM pg_roles WHERE pg_has_role(rolname, 'group2', 'member');"
}
user "group_user4" {
authentication "none"
storage "postgres_server"
pool "session"
}
user "group_user5" {
authentication "none"
storage "postgres_server"
pool "session"
}
}
database default {
user default {
authentication "none"
storage "postgres_server"
pool "session"
pool_size 0
pool_timeout 0
pool_ttl 1201
pool_discard no
pool_cancel yes
pool_rollback yes
# seconds
pool_client_idle_timeout 20
# seconds
pool_idle_in_transaction_timeout 20
client_fwd_error yes
application_name_add_host yes
server_lifetime 1901
log_debug no
quantiles "0.99,0.95,0.5"
client_max 107
}
}
unix_socket_dir "/tmp"
unix_socket_mode "0644"
log_file "/var/log/odyssey.log"
log_format "%p %t %l [%i %s] (%c) %m\n"
log_debug no
log_config yes
log_session no
log_query no
log_stats yes
daemonize yes
locks_dir "/tmp/odyssey"
graceful_die_on_errors yes
enable_online_restart yes
bindwith_reuseport yes
stats_interval 60
pid_file "/var/run/odyssey.pid"

81
docker/group/test_group.sh Executable file
View File

@ -0,0 +1,81 @@
#!/bin/bash -x
set -ex
/usr/bin/odyssey /group/config.conf
users=("group_user1" "group_user2" "group_user3" "group_user4" "group_user5")
for user in "${users[@]}"; do
psql -h localhost -p 6432 -U "$user" -c "SELECT 1" group_db >/dev/null 2>&1 || {
echo "ERROR: failed backend auth with correct user auth"
cat /var/log/odyssey.log
echo "
"
cat /var/log/postgresql/postgresql-14-main.log
exit 1
}
done
ody-stop
psql -h localhost -p 5432 -U postgres -c "GRANT group1 TO group_user2;" group_db
psql -h localhost -p 5432 -U postgres -c "GRANT group1 TO group_user4;" group_db
psql -h localhost -p 5432 -U postgres -c "GRANT group2 TO group_user4;" group_db
psql -h localhost -p 5432 -U postgres -c "GRANT group1 TO group_user1;" group_db
/usr/bin/odyssey /group/config.conf
sleep 1
psql -h localhost -p 6432 -U group_user1 -c "SELECT 1" group_db >/dev/null 2>&1 || {
echo "ERROR: group auth apply for over user at config"
cat /var/log/odyssey.log
echo "
"
cat /var/log/postgresql/postgresql-14-main.log
exit 1
}
psql -h localhost -p 6432 -U group_user2 -c "SELECT 1" group_db >/dev/null 2>&1 && {
echo "ERROR: group auth not apply"
cat /var/log/odyssey.log
echo "
"
cat /var/log/postgresql/postgresql-14-main.log
exit 1
}
PGPASSWORD=password1 psql -h localhost -p 6432 -U group_user4 -c "SELECT 1" group_db >/dev/null 2>&1 && {
echo "ERROR: group auth not accepted down group"
cat /var/log/odyssey.log
echo "
"
cat /var/log/postgresql/postgresql-14-main.log
exit 1
}
PGPASSWORD=password2 psql -h localhost -p 6432 -U group_user4 -c "SELECT 1" group_db >/dev/null 2>&1 || {
echo "ERROR: group auth not apply"
cat /var/log/odyssey.log
echo "
"
cat /var/log/postgresql/postgresql-14-main.log
exit 1
}
ody-stop

View File

@ -52,7 +52,8 @@ set(od_src
hba.c
hba_reader.c
hba_rule.c
mdb_iamproxy.c)
mdb_iamproxy.c
group.c)
if (PAM_FOUND)
list(APPEND od_src pam.c)

View File

@ -83,6 +83,7 @@ typedef enum {
OD_LDEFAULT,
OD_LDATABASE,
OD_LUSER,
OD_LGROUP,
OD_LPASSWORD,
OD_LROLE,
OD_LPOOL,
@ -146,6 +147,7 @@ typedef enum {
OD_LOPTIONS,
OD_LBACKEND_STARTUP_OPTIONS,
OD_LHBA_FILE,
OD_LGROUP_QUERY,
} od_lexeme_t;
static od_keyword_t od_config_keywords[] = {
@ -238,6 +240,7 @@ static od_keyword_t od_config_keywords[] = {
/* database */
od_keyword("database", OD_LDATABASE),
od_keyword("group", OD_LGROUP),
od_keyword("user", OD_LUSER),
od_keyword("password", OD_LPASSWORD),
od_keyword("role", OD_LROLE),
@ -268,6 +271,9 @@ static od_keyword_t od_config_keywords[] = {
od_keyword("storage_user", OD_LSTORAGE_USER),
od_keyword("storage_password", OD_LSTORAGE_PASSWORD),
/* group */
od_keyword("group_query", OD_LGROUP_QUERY),
/* auth */
od_keyword("authentication", OD_LAUTHENTICATION),
od_keyword("auth_common_name", OD_LAUTH_COMMON_NAME),
@ -1722,6 +1728,19 @@ static int od_config_reader_rule_settings(od_config_reader_t *reader,
return NOT_OK_RESPONSE;
}
continue;
/* group_query */
case OD_LGROUP_QUERY:
if (rule->group == NULL) {
od_config_reader_error(
reader, NULL,
"group settings specified for non-group route");
return NOT_OK_RESPONSE;
}
if (!od_config_reader_string(
reader, &rule->group->group_query)) {
return NOT_OK_RESPONSE;
}
continue;
default:
return NOT_OK_RESPONSE;
}
@ -1865,6 +1884,80 @@ static int od_config_reader_route(od_config_reader_t *reader, char *db_name,
return od_config_reader_rule_settings(reader, rule, extentions, NULL);
}
static int od_config_reader_group(od_config_reader_t *reader, char *db_name,
od_group_t *group, od_extention_t *extentions)
{
/* group name */
char *group_name = NULL;
if (!od_config_reader_is(reader, OD_PARSER_STRING))
return NOT_OK_RESPONSE;
if (!od_config_reader_string(reader, &group_name))
return NOT_OK_RESPONSE;
// TODO: need to find a way to create internal rules for a specific database
char route_usr[strlen("group_") + strlen(group_name) + 1];
char route_db[strlen("group_") + strlen(group_name) + 1];
snprintf(route_usr, sizeof route_usr, "%s%s", "group_", group_name);
snprintf(route_db, sizeof route_db, "%s%s", "group_", group_name);
od_rule_t *rule;
od_address_range_t default_address_range =
od_address_range_create_default();
rule = od_rules_match(reader->rules, route_db, route_usr,
&default_address_range, 0, 0, 1);
if (rule) {
od_errorf(reader->error, "route '%s.%s': is redefined",
route_usr, route_usr);
return NOT_OK_RESPONSE;
}
rule = od_rules_add(reader->rules);
if (rule == NULL) {
return NOT_OK_RESPONSE;
}
rule->user_is_default = 0;
rule->user_name = strdup(route_usr);
rule->user_name_len = strlen(rule->user_name);
if (rule->user_name == NULL) {
return NOT_OK_RESPONSE;
}
rule->db_is_default = 0;
rule->db_name = strdup(route_db);
rule->db_name_len = strlen(rule->db_name);
if (rule->db_name == NULL)
return NOT_OK_RESPONSE;
rule->address_range = default_address_range;
group->group_name = strdup(group_name);
group->route_usr = strdup(rule->user_name);
group->route_db = strdup(rule->db_name);
rule->group = group;
/* { */
if (!od_config_reader_symbol(reader, '{'))
return NOT_OK_RESPONSE;
/* unreach */
if (od_config_reader_rule_settings(reader, rule, extentions, NULL) ==
NOT_OK_RESPONSE) {
goto error;
}
free(group_name);
// force several settings
group->storage_db = rule->storage_db;
group->storage_user = rule->storage_user;
rule->pool->routing = OD_RULE_POOL_INTERNAL;
return OK_RESPONSE;
error:
free(group_name);
return NOT_OK_RESPONSE;
}
static inline int od_config_reader_watchdog(od_config_reader_t *reader,
od_storage_watchdog_t *watchdog,
od_extention_t *extentions)
@ -1915,7 +2008,7 @@ static inline int od_config_reader_watchdog(od_config_reader_t *reader,
// force several settings
watchdog->storage_db = rule->storage_db;
watchdog->storage_user = rule->storage_user;
rule->pool->routing = OD_RULE_POOL_INTERVAL;
rule->pool->routing = OD_RULE_POOL_INTERNAL;
return OK_RESPONSE;
}
@ -2189,6 +2282,17 @@ static int od_config_reader_database(od_config_reader_t *reader,
if (rc == -1)
goto error;
continue;
case OD_LGROUP:;
od_group_t *group;
group = od_rules_group_allocate(reader->global);
if (group == NULL) {
return NOT_OK_RESPONSE;
}
rc = od_config_reader_group(reader, db_name, group,
extentions);
if (rc == -1)
goto error;
continue;
default:
od_config_reader_error(reader, &token,
"unexpected parameter");

78
sources/group.c Normal file
View File

@ -0,0 +1,78 @@
/*
* Odyssey.
*
* Scalable PostgreSQL connection pooler.
*/
#include <kiwi.h>
#include <machinarium.h>
#include <odyssey.h>
int od_group_free(od_group_t *group)
{
if (group == NULL)
return NOT_OK_RESPONSE;
if (group->route_usr)
free(group->route_usr);
if (group->route_db)
free(group->route_db);
if (group->storage_user)
free(group->storage_user);
if (group->storage_db)
free(group->storage_db);
if (group->group_name)
free(group->group_name);
if (group->group_query)
free(group->group_query);
free(group);
return OK_RESPONSE;
}
int od_group_parse_val_datarow(machine_msg_t *msg, char **group_member)
{
char *pos = (char *)machine_msg_data(msg) + 1;
uint32_t pos_size = machine_msg_size(msg) - 1;
/* size */
uint32_t size;
int rc;
rc = kiwi_read32(&size, &pos, &pos_size);
if (kiwi_unlikely(rc == -1))
goto error;
/* count */
uint16_t count;
rc = kiwi_read16(&count, &pos, &pos_size);
if (kiwi_unlikely(rc == -1))
goto error;
if (count != 1)
goto error;
/* (not used) */
uint32_t val_len;
rc = kiwi_read32(&val_len, &pos, &pos_size);
if (kiwi_unlikely(rc == -1)) {
goto error;
}
*group_member = strdup(pos);
return OK_RESPONSE;
error:
return NOT_OK_RESPONSE;
}
od_group_member_name_item_t *od_group_member_name_item_add(od_list_t *members)
{
od_group_member_name_item_t *item;
item = (od_group_member_name_item_t *)malloc(sizeof(*item));
if (item == NULL)
return NULL;
memset(item, 0, sizeof(*item));
od_list_init(&item->link);
od_list_append(members, &item->link);
return item;
}

41
sources/group.h Normal file
View File

@ -0,0 +1,41 @@
/*
* Odyssey.
*
* Scalable PostgreSQL connection pooler.
*/
#ifndef ODYSSEY_GROUP_CHECK_ITER_INTERVAL
#define ODYSSEY_GROUP_CHECK_ITER_INTERVAL 500 // ms
typedef struct od_group od_group_t;
struct od_group {
char *route_usr;
char *route_db;
char *storage_user;
char *storage_db;
char *group_name;
char *group_query;
int check_retry;
int online;
od_global_t *global;
od_list_t link;
};
typedef struct od_group_member_name_item od_group_member_name_item_t;
struct od_group_member_name_item {
char *value;
int is_checked;
od_list_t link;
};
int od_group_free(od_group_t *);
int od_group_parse_val_datarow(machine_msg_t *, char **);
od_group_member_name_item_t *od_group_member_name_item_add(od_list_t *);
#endif /* ODYSSEY_GROUP_CHECK_ITER_INTERVAL */

View File

@ -68,4 +68,7 @@ static inline int od_list_empty(od_list_t *list)
for (iterator = (list)->next; \
iterator != list && (safe = iterator->next); iterator = safe)
#define od_list_foreach_with_start(list, iterator) \
for (; iterator != list; iterator = (iterator)->next)
#endif /* ODYSSEY_LIST_H */

View File

@ -55,6 +55,7 @@
#include "sources/address.h"
#include "sources/storage.h"
#include "sources/group.h"
#include "sources/pool.h"
#include "sources/rules.h"
#include "sources/hba_rule.h"

View File

@ -98,7 +98,7 @@ int od_rule_matches_client(od_rule_pool_t *pool, od_pool_client_type_t t)
{
switch (t) {
case OD_POOL_CLIENT_INTERNAL:
return pool->routing == OD_RULE_POOL_INTERVAL;
return pool->routing == OD_RULE_POOL_INTERNAL;
case OD_POOL_CLIENT_EXTERNAL:
return pool->routing == OD_RULE_POOL_CLIENT_VISIBLE;
default:

View File

@ -16,7 +16,7 @@ typedef enum {
} od_rule_pool_type_t;
typedef enum {
OD_RULE_POOL_INTERVAL,
OD_RULE_POOL_INTERNAL,
OD_RULE_POOL_CLIENT_VISIBLE,
} od_rule_routing_type_t;

View File

@ -125,6 +125,324 @@ static inline od_rule_auth_t *od_rules_auth_find(od_rule_t *rule, char *name)
return NULL;
}
od_group_t *od_rules_group_allocate(od_global_t *global)
{
/* Allocate and force defaults */
od_group_t *group;
group = calloc(1, sizeof(*group));
if (group == NULL)
return NULL;
group->global = global;
group->check_retry = 10;
group->online = 1;
od_list_init(&group->link);
return group;
}
static inline int od_rule_update_auth(od_route_t *route, void **argv)
{
od_rule_t *rule = (od_rule_t *)argv[0];
od_rule_t *group_rule = (od_rule_t *)argv[1];
/* auth */
rule->auth = group_rule->auth;
rule->auth_mode = group_rule->auth_mode;
rule->auth_query = group_rule->auth_query;
rule->auth_query_db = group_rule->auth_query_db;
rule->auth_query_user = group_rule->auth_query_user;
rule->auth_common_name_default = group_rule->auth_common_name_default;
rule->auth_common_names = group_rule->auth_common_names;
rule->auth_common_names_count = group_rule->auth_common_names_count;
#ifdef PAM_FOUND
rule->auth_pam_service = group_rule->auth_pam_service;
rule->auth_pam_data = group_rule->auth_pam_data;
#endif
#ifdef LDAP_FOUND
rule->ldap_endpoint_name = group_rule->ldap_endpoint_name;
rule->ldap_endpoint = group_rule->ldap_endpoint;
rule->ldap_pool_timeout = group_rule->ldap_pool_timeout;
rule->ldap_pool_size = group_rule->ldap_pool_size;
rule->ldap_pool_ttl = group_rule->ldap_pool_ttl;
rule->ldap_storage_creds_list = group_rule->ldap_storage_creds_list;
rule->ldap_storage_credentials_attr =
group_rule->ldap_storage_credentials_attr;
#endif
rule->auth_module = group_rule->auth_module;
/* password */
rule->password = group_rule->password;
rule->password_len = group_rule->password_len;
return 0;
}
void od_rules_group_checker_run(void *arg)
{
od_group_checker_run_args *args = (od_group_checker_run_args *)arg;
od_rule_t *group_rule = args->rule;
od_group_t *group = group_rule->group;
od_rules_t *rules = args->rules;
od_list_t *i_copy = args->i_copy;
od_global_t *global = group->global;
od_router_t *router = global->router;
od_instance_t *instance = global->instance;
od_debug(&instance->logger, "group_checker", NULL, NULL,
"start group checking");
/* create internal auth client */
od_client_t *group_checker_client;
group_checker_client =
od_client_allocate_internal(global, "rule-group-checker");
if (group_checker_client == NULL) {
od_error(&instance->logger, "group_checker", NULL, NULL,
"route rule group_checker failed to allocate client");
return;
}
group_checker_client->global = global;
group_checker_client->type = OD_POOL_CLIENT_INTERNAL;
od_id_generate(&group_checker_client->id, "a");
/* set storage user and database */
kiwi_var_set(&group_checker_client->startup.user, KIWI_VAR_UNDEF,
group->route_usr, strlen(group->route_usr) + 1);
kiwi_var_set(&group_checker_client->startup.database, KIWI_VAR_UNDEF,
group->route_db, strlen(group->route_db) + 1);
machine_msg_t *msg;
char *group_member;
int rc;
/* route */
od_router_status_t status;
status = od_router_route(router, group_checker_client);
od_debug(&instance->logger, "group_checker", group_checker_client, NULL,
"routing to internal group_checker route status: %s",
od_router_status_to_str(status));
if (status != OD_ROUTER_OK) {
od_error(&instance->logger, "group_checker",
group_checker_client, NULL,
"route rule group_checker failed: %s",
od_router_status_to_str(status));
return;
}
for (;;) {
/* attach client to some route */
status = od_router_attach(router, group_checker_client, false);
od_debug(
&instance->logger, "group_checker",
group_checker_client, NULL,
"attaching group_checker client to backend connection status: %s",
od_router_status_to_str(status));
if (status != OD_ROUTER_OK) {
/* 1 second soft interval */
machine_sleep(1000);
continue;
}
od_server_t *server;
server = group_checker_client->server;
od_debug(&instance->logger, "group_checker",
group_checker_client, server,
"attached to server %s%.*s", server->id.id_prefix,
(int)sizeof(server->id.id), server->id.id);
/* connect to server, if necessary */
if (server->io.io == NULL) {
rc = od_backend_connect(server, "group_checker", NULL,
group_checker_client);
if (rc == NOT_OK_RESPONSE) {
od_debug(
&instance->logger, "group_checker",
group_checker_client, server,
"backend connect failed, retry after 1 sec");
od_router_close(router, group_checker_client);
/* 1 second soft interval */
machine_sleep(1000);
continue;
}
}
for (int retry = 0; retry < group->check_retry; ++retry) {
if (od_backend_query_send(
server, "group_checker", group->group_query,
NULL, strlen(group->group_query) + 1) ==
NOT_OK_RESPONSE) {
/* Retry later. TODO: Add logging. */
break;
}
int response_is_read = 0;
od_list_t members;
od_list_init(&members);
od_group_member_name_item_t *member;
while (1) {
msg = od_read(&server->io, UINT32_MAX);
if (msg == NULL) {
if (!machine_timedout()) {
od_error(&instance->logger,
"group_checker",
server->client, server,
"read error: %s",
od_io_error(
&server->io));
}
}
kiwi_be_type_t type;
type = *(char *)machine_msg_data(msg);
od_debug(&instance->logger, "group_checker",
server->client, server, "%s",
kiwi_be_type_to_string(type));
switch (type) {
case KIWI_BE_ERROR_RESPONSE:
od_backend_error(server,
"group_checker",
machine_msg_data(msg),
machine_msg_size(msg));
{
rc = NOT_OK_RESPONSE;
response_is_read = 1;
break;
}
case KIWI_BE_DATA_ROW: {
rc = od_group_parse_val_datarow(
msg, &group_member);
member = od_group_member_name_item_add(
&members);
member->value = group_member;
break;
}
case KIWI_BE_READY_FOR_QUERY:
od_backend_ready(server,
machine_msg_data(msg),
machine_msg_size(msg));
machine_msg_free(msg);
response_is_read = 1;
break;
default:
break;
}
if (response_is_read)
break;
}
od_router_close(router, group_checker_client);
bool have_default = false;
od_list_t *i;
od_list_foreach(&members, i)
{
od_group_member_name_item_t *member_name;
member_name = od_container_of(
i, od_group_member_name_item_t, link);
od_list_t *j = i_copy;
od_list_foreach_with_start(&rules->rules, j)
{
od_rule_t *rule;
rule = od_container_of(j, od_rule_t,
link);
if (rule->obsolete ||
rule->pool->routing ==
OD_RULE_POOL_INTERNAL ||
rule->db_is_default !=
group_rule->db_is_default)
continue;
if (rule->user_is_default) {
have_default = true;
} else if (strcmp(member_name->value,
rule->user_name) ==
0) {
void *argv[] = { rule,
group_rule };
od_router_foreach(
router,
od_rule_update_auth,
argv);
member_name->is_checked = 1;
}
}
}
// TODO: handle members with is_checked = 0. these rules should be inherited from the default one, if there is one
if (rc == OK_RESPONSE) {
od_debug(&instance->logger, "group_checker",
group_checker_client, server,
"group check success");
break;
}
// retry
}
/* detach and unroute */
if (group_checker_client->server) {
od_router_detach(router, group_checker_client);
}
if (group->online == 0) {
od_debug(&instance->logger, "group_checker",
group_checker_client, NULL,
"deallocating obsolete group_checker");
od_client_free(group_checker_client);
od_group_free(group);
return;
}
/* 7 second soft interval */
machine_sleep(7000);
}
}
od_retcode_t od_rules_groups_checkers_run(od_logger_t *logger,
od_rules_t *rules)
{
od_list_t *i;
od_list_foreach(&rules->rules, i)
{
od_rule_t *rule;
rule = od_container_of(i, od_rule_t, link);
if (rule->group) {
od_group_checker_run_args *args =
malloc(sizeof(od_group_checker_run_args));
args->rules = rules;
args->rule = rule;
args->i_copy = i->next;
int64_t coroutine_id;
coroutine_id = machine_coroutine_create(
od_rules_group_checker_run, args);
if (coroutine_id == INVALID_COROUTINE_ID) {
od_error(
logger, "system", NULL, NULL,
"failed to start group_checker coroutine");
return NOT_OK_RESPONSE;
}
machine_sleep(1000);
}
}
return OK_RESPONSE;
}
od_rule_t *od_rules_add(od_rules_t *rules)
{
od_rule_t *rule;
@ -202,6 +520,8 @@ void od_rules_rule_free(od_rule_t *rule)
free(rule->storage_password);
if (rule->pool)
od_rule_pool_free(rule->pool);
if (rule->group)
rule->group->online = 0;
if (rule->mdb_iamproxy_socket_path)
free(rule->mdb_iamproxy_socket_path);
@ -279,7 +599,7 @@ static od_rule_t *od_rules_forward_default(od_rules_t *rules, char *db_name,
if (rule->obsolete)
continue;
if (pool_internal) {
if (rule->pool->routing != OD_RULE_POOL_INTERVAL) {
if (rule->pool->routing != OD_RULE_POOL_INTERNAL) {
continue;
}
} else {
@ -416,7 +736,7 @@ od_rule_t *od_rules_match(od_rules_t *rules, char *db_name, char *user_name,
rule = od_container_of(i, od_rule_t, link);
/* filter out internal or client-vidible rules */
if (pool_internal) {
if (rule->pool->routing != OD_RULE_POOL_INTERVAL) {
if (rule->pool->routing != OD_RULE_POOL_INTERNAL) {
continue;
}
} else {
@ -890,13 +1210,13 @@ __attribute__((hot)) int od_rules_merge(od_rules_t *rules, od_rules_t *src,
}
int od_pool_validate(od_logger_t *logger, od_rule_pool_t *pool, char *db_name,
char *user_name, char *address_range_string)
char *user_name, od_address_range_t *address_range)
{
/* pooling mode */
if (!pool->type) {
od_error(logger, "rules", NULL, NULL,
"rule '%s.%s %s': pooling mode is not set", db_name,
user_name, address_range_string);
user_name, address_range->string_value);
return NOT_OK_RESPONSE;
}
if (strcmp(pool->type, "session") == 0) {
@ -908,7 +1228,7 @@ int od_pool_validate(od_logger_t *logger, od_rule_pool_t *pool, char *db_name,
} else {
od_error(logger, "rules", NULL, NULL,
"rule '%s.%s %s': unknown pooling mode", db_name,
user_name, address_range_string);
user_name, address_range->string_value);
return NOT_OK_RESPONSE;
}
@ -917,15 +1237,24 @@ int od_pool_validate(od_logger_t *logger, od_rule_pool_t *pool, char *db_name,
od_debug(
logger, "rules", NULL, NULL,
"rule '%s.%s %s': pool routing mode is not set, assuming \"client_visible\" by default",
db_name, user_name, address_range_string);
db_name, user_name, address_range->string_value);
} else if (strcmp(pool->routing_type, "internal") == 0) {
pool->routing = OD_RULE_POOL_INTERVAL;
pool->routing = OD_RULE_POOL_INTERNAL;
} else if (strcmp(pool->routing_type, "client_visible") == 0) {
pool->routing = OD_RULE_POOL_CLIENT_VISIBLE;
} else {
od_error(logger, "rules", NULL, NULL,
"rule '%s.%s %s': unknown pool routing mode", db_name,
user_name, address_range_string);
user_name, address_range->string_value);
return NOT_OK_RESPONSE;
}
if (pool->routing == OD_RULE_POOL_INTERNAL &&
!address_range->is_default) {
od_error(
logger, "rules", NULL, NULL,
"rule '%s.%s %s': internal rules must have default address_range",
db_name, user_name, address_range->string_value);
return NOT_OK_RESPONSE;
}
@ -935,7 +1264,7 @@ int od_pool_validate(od_logger_t *logger, od_rule_pool_t *pool, char *db_name,
od_error(
logger, "rules", NULL, NULL,
"rule '%s.%s %s': prepared statements support in session pool makes no sence",
db_name, user_name, address_range_string);
db_name, user_name, address_range->string_value);
return NOT_OK_RESPONSE;
}
@ -943,7 +1272,7 @@ int od_pool_validate(od_logger_t *logger, od_rule_pool_t *pool, char *db_name,
od_error(
logger, "rules", NULL, NULL,
"rule '%s.%s %s': pool discard is forbidden when using prepared statements support",
db_name, user_name, address_range_string);
db_name, user_name, address_range->string_value);
return NOT_OK_RESPONSE;
}
@ -951,7 +1280,7 @@ int od_pool_validate(od_logger_t *logger, od_rule_pool_t *pool, char *db_name,
od_error(
logger, "rules", NULL, NULL,
"rule '%s.%s %s': pool smart discard is forbidden without using prepared statements support",
db_name, user_name, address_range_string);
db_name, user_name, address_range->string_value);
return NOT_OK_RESPONSE;
}
@ -960,7 +1289,8 @@ int od_pool_validate(od_logger_t *logger, od_rule_pool_t *pool, char *db_name,
od_error(
logger, "rules", NULL, NULL,
"rule '%s.%s %s': cannot support prepared statements when 'DEALLOCATE ALL' present in discard string",
db_name, user_name, address_range_string);
db_name, user_name,
address_range->string_value);
return NOT_OK_RESPONSE;
}
}
@ -1043,7 +1373,7 @@ int od_rules_autogenerate_defaults(od_rules_t *rules, od_logger_t *logger)
rule->pool->pool = OD_RULE_POOL_TRANSACTION;
rule->pool->routing_type = strdup("internal");
rule->pool->routing = OD_RULE_POOL_INTERVAL;
rule->pool->routing = OD_RULE_POOL_INTERNAL;
rule->pool->size = OD_DEFAULT_INTERNAL_POLL_SZ;
rule->enable_password_passthrough = true;
@ -1180,8 +1510,7 @@ int od_rules_validate(od_rules_t *rules, od_config_t *config,
if (od_pool_validate(logger, rule->pool, rule->db_name,
rule->user_name,
rule->address_range.string_value) ==
NOT_OK_RESPONSE) {
&rule->address_range) == NOT_OK_RESPONSE) {
return NOT_OK_RESPONSE;
}

View File

@ -21,6 +21,12 @@ typedef enum {
OD_RULE_AUTH_CERT
} od_rule_auth_type_t;
typedef struct {
od_rule_t *rule;
od_rules_t *rules;
od_list_t *i_copy;
} od_group_checker_run_args;
struct od_rule_auth {
char *common_name;
od_list_t link;
@ -122,6 +128,10 @@ struct od_rule {
int catchup_timeout;
int catchup_checks;
/* group */
od_group_t *group; // set if rule is group
od_rule_t *group_rule;
/* PostgreSQL options */
kiwi_vars_t vars;
@ -182,6 +192,9 @@ od_rule_t *od_rules_match(od_rules_t *rules, char *db_name, char *user_name,
od_address_range_t *address_range, int db_is_default,
int user_is_default, int pool_internal);
/* group */
od_group_t *od_rules_group_allocate(od_global_t *global);
void od_rules_rule_free(od_rule_t *rule);
/* storage API */
@ -206,4 +219,7 @@ od_rule_auth_t *od_rules_auth_add(od_rule_t *);
void od_rules_auth_free(od_rule_auth_t *);
#endif /* ODYSSEY_RULES_H */
od_retcode_t od_rules_groups_checkers_run(od_logger_t *logger,
od_rules_t *rules);
#endif /* ODYSSEY_RULES_H */

View File

@ -581,6 +581,8 @@ static inline void od_system(void *arg)
if (rc == NOT_OK_RESPONSE)
return;
}
od_rules_groups_checkers_run(&instance->logger, &router->rules);
}
void od_system_init(od_system_t *system)