-- idempotently remove the coordinator from metadata SELECT COUNT(citus_remove_node(nodename, nodeport)) >= 0 FROM pg_dist_node WHERE nodename = 'localhost' AND nodeport = :master_port; ?column? --------------------------------------------------------------------- t (1 row) -- make sure that CREATE ROLE from workers is not supported when coordinator is not added to metadata SELECT result FROM run_command_on_workers('CREATE ROLE test_role'); result --------------------------------------------------------------------- ERROR: coordinator is not added to the metadata ERROR: coordinator is not added to the metadata (2 rows) \c - - - :master_port CREATE SCHEMA role_command_from_any_node; SET search_path TO role_command_from_any_node; SET client_min_messages TO WARNING; SELECT 1 FROM citus_add_node('localhost', :master_port, groupid => 0); ?column? --------------------------------------------------------------------- 1 (1 row) CREATE OR REPLACE FUNCTION check_role_on_all_nodes(p_role_name text) RETURNS TABLE (node_type text, result text) AS $func$ DECLARE v_worker_query text; BEGIN v_worker_query := format( $$ SELECT to_jsonb(q1.*) FROM ( SELECT ( SELECT COUNT(*) = 1 FROM pg_roles WHERE rolname = '%s' ) AS role_exists, ( SELECT to_jsonb(q.*) FROM (SELECT * FROM pg_roles WHERE rolname = '%s') q ) AS role_properties, ( SELECT COUNT(*) = 1 FROM pg_dist_object WHERE objid = (SELECT oid FROM pg_roles WHERE rolname = '%s') ) AS pg_dist_object_record_for_role_exists, ( SELECT COUNT(*) > 0 FROM pg_dist_object WHERE classid = 1260 AND objid NOT IN (SELECT oid FROM pg_roles) ) AS stale_pg_dist_object_record_for_a_role_exists ) q1 $$, p_role_name, p_role_name, p_role_name ); RETURN QUERY SELECT CASE WHEN (groupid = 0 AND groupid = (SELECT groupid FROM pg_dist_local_group)) THEN 'coordinator (local)' WHEN (groupid = 0) THEN 'coordinator (remote)' WHEN (groupid = (SELECT groupid FROM pg_dist_local_group)) THEN 'worker node (local)' ELSE 'worker node (remote)' END AS node_type, q2.result FROM run_command_on_all_nodes(v_worker_query) q2 JOIN pg_dist_node USING (nodeid); END; $func$ LANGUAGE plpgsql; \c - - - :worker_1_port SET search_path TO role_command_from_any_node; SET client_min_messages TO NOTICE; SET citus.enable_create_role_propagation TO OFF; CREATE ROLE test_role; NOTICE: not propagating CREATE ROLE/USER commands to other nodes HINT: Connect to other nodes directly to manually create all necessary users and roles. SELECT node_type, (result::jsonb - 'role_properties') as result FROM check_role_on_all_nodes('test_role') ORDER BY node_type; node_type | result --------------------------------------------------------------------- coordinator (remote) | {"role_exists": false, "pg_dist_object_record_for_role_exists": false, "stale_pg_dist_object_record_for_a_role_exists": false} worker node (local) | {"role_exists": true, "pg_dist_object_record_for_role_exists": false, "stale_pg_dist_object_record_for_a_role_exists": false} worker node (remote) | {"role_exists": false, "pg_dist_object_record_for_role_exists": false, "stale_pg_dist_object_record_for_a_role_exists": false} (3 rows) DROP ROLE test_role; SELECT node_type, (result::jsonb - 'role_properties') as result FROM check_role_on_all_nodes('test_role') ORDER BY node_type; node_type | result --------------------------------------------------------------------- coordinator (remote) | {"role_exists": false, "pg_dist_object_record_for_role_exists": false, "stale_pg_dist_object_record_for_a_role_exists": false} worker node (local) | {"role_exists": false, "pg_dist_object_record_for_role_exists": false, "stale_pg_dist_object_record_for_a_role_exists": false} worker node (remote) | {"role_exists": false, "pg_dist_object_record_for_role_exists": false, "stale_pg_dist_object_record_for_a_role_exists": false} (3 rows) CREATE ROLE test_role; NOTICE: not propagating CREATE ROLE/USER commands to other nodes HINT: Connect to other nodes directly to manually create all necessary users and roles. SELECT node_type, (result::jsonb - 'role_properties') as result FROM check_role_on_all_nodes('test_role') ORDER BY node_type; node_type | result --------------------------------------------------------------------- coordinator (remote) | {"role_exists": false, "pg_dist_object_record_for_role_exists": false, "stale_pg_dist_object_record_for_a_role_exists": false} worker node (local) | {"role_exists": true, "pg_dist_object_record_for_role_exists": false, "stale_pg_dist_object_record_for_a_role_exists": false} worker node (remote) | {"role_exists": false, "pg_dist_object_record_for_role_exists": false, "stale_pg_dist_object_record_for_a_role_exists": false} (3 rows) SET citus.enable_create_role_propagation TO ON; -- doesn't fail even if the role doesn't exist on other nodes DROP ROLE test_role; SELECT node_type, (result::jsonb - 'role_properties') as result FROM check_role_on_all_nodes('test_role') ORDER BY node_type; node_type | result --------------------------------------------------------------------- coordinator (remote) | {"role_exists": false, "pg_dist_object_record_for_role_exists": false, "stale_pg_dist_object_record_for_a_role_exists": false} worker node (local) | {"role_exists": false, "pg_dist_object_record_for_role_exists": false, "stale_pg_dist_object_record_for_a_role_exists": false} worker node (remote) | {"role_exists": false, "pg_dist_object_record_for_role_exists": false, "stale_pg_dist_object_record_for_a_role_exists": false} (3 rows) CREATE ROLE test_role; SELECT node_type, (result::jsonb - 'role_properties') as result FROM check_role_on_all_nodes('test_role') ORDER BY node_type; node_type | result --------------------------------------------------------------------- coordinator (remote) | {"role_exists": true, "pg_dist_object_record_for_role_exists": true, "stale_pg_dist_object_record_for_a_role_exists": false} worker node (local) | {"role_exists": true, "pg_dist_object_record_for_role_exists": true, "stale_pg_dist_object_record_for_a_role_exists": false} worker node (remote) | {"role_exists": true, "pg_dist_object_record_for_role_exists": true, "stale_pg_dist_object_record_for_a_role_exists": false} (3 rows) DROP ROLE test_role; SELECT node_type, (result::jsonb - 'role_properties') as result FROM check_role_on_all_nodes('test_role') ORDER BY node_type; node_type | result --------------------------------------------------------------------- coordinator (remote) | {"role_exists": false, "pg_dist_object_record_for_role_exists": false, "stale_pg_dist_object_record_for_a_role_exists": false} worker node (local) | {"role_exists": false, "pg_dist_object_record_for_role_exists": false, "stale_pg_dist_object_record_for_a_role_exists": false} worker node (remote) | {"role_exists": false, "pg_dist_object_record_for_role_exists": false, "stale_pg_dist_object_record_for_a_role_exists": false} (3 rows) CREATE ROLE test_role; SET citus.enable_alter_role_propagation TO OFF; ALTER ROLE test_role RENAME TO test_role_renamed; SELECT node_type, (result::jsonb - 'role_properties') as result FROM check_role_on_all_nodes('test_role_renamed') ORDER BY node_type; node_type | result --------------------------------------------------------------------- coordinator (remote) | {"role_exists": false, "pg_dist_object_record_for_role_exists": false, "stale_pg_dist_object_record_for_a_role_exists": false} worker node (local) | {"role_exists": true, "pg_dist_object_record_for_role_exists": true, "stale_pg_dist_object_record_for_a_role_exists": false} worker node (remote) | {"role_exists": false, "pg_dist_object_record_for_role_exists": false, "stale_pg_dist_object_record_for_a_role_exists": false} (3 rows) ALTER ROLE test_role_renamed RENAME TO test_role; SET citus.enable_alter_role_propagation TO ON; ALTER ROLE test_role RENAME TO test_role_renamed; SELECT node_type, (result::jsonb - 'role_properties') as result FROM check_role_on_all_nodes('test_role_renamed') ORDER BY node_type; node_type | result --------------------------------------------------------------------- coordinator (remote) | {"role_exists": true, "pg_dist_object_record_for_role_exists": true, "stale_pg_dist_object_record_for_a_role_exists": false} worker node (local) | {"role_exists": true, "pg_dist_object_record_for_role_exists": true, "stale_pg_dist_object_record_for_a_role_exists": false} worker node (remote) | {"role_exists": true, "pg_dist_object_record_for_role_exists": true, "stale_pg_dist_object_record_for_a_role_exists": false} (3 rows) SET citus.enable_alter_role_propagation TO OFF; ALTER ROLE test_role_renamed CREATEDB; SET citus.enable_alter_role_propagation TO ON; SELECT node_type, (result::jsonb)->'role_properties'->'rolcreatedb' as result FROM check_role_on_all_nodes('test_role_renamed') ORDER BY node_type; node_type | result --------------------------------------------------------------------- coordinator (remote) | false worker node (local) | true worker node (remote) | false (3 rows) ALTER ROLE test_role_renamed CREATEDB; SELECT node_type, (result::jsonb)->'role_properties'->'rolcreatedb' as result FROM check_role_on_all_nodes('test_role_renamed') ORDER BY node_type; node_type | result --------------------------------------------------------------------- coordinator (remote) | true worker node (local) | true worker node (remote) | true (3 rows) SET citus.enable_alter_role_set_propagation TO ON; ALTER ROLE current_user IN DATABASE "regression" SET enable_hashjoin TO OFF; SELECT result FROM run_command_on_all_nodes('SHOW enable_hashjoin') ORDER BY result; result --------------------------------------------------------------------- off off off (3 rows) SET citus.enable_alter_role_set_propagation TO OFF; ALTER ROLE current_user IN DATABASE "regression" SET enable_hashjoin TO ON; SELECT result FROM run_command_on_all_nodes('SHOW enable_hashjoin') ORDER BY result; result --------------------------------------------------------------------- off off on (3 rows) SET citus.enable_alter_role_set_propagation TO ON; ALTER ROLE current_user IN DATABASE "regression" RESET enable_hashjoin; CREATE ROLE another_user; SET citus.enable_create_role_propagation TO OFF; GRANT another_user TO test_role_renamed; SELECT result FROM run_command_on_all_nodes($$ SELECT COUNT(*)=1 FROM pg_auth_members WHERE roleid = 'another_user'::regrole AND member = 'test_role_renamed'::regrole $$) ORDER BY result; result --------------------------------------------------------------------- f f t (3 rows) SET citus.enable_create_role_propagation TO ON; SET client_min_messages TO ERROR; GRANT another_user TO test_role_renamed; SET client_min_messages TO NOTICE; SELECT result FROM run_command_on_all_nodes($$ SELECT COUNT(*)=1 FROM pg_auth_members WHERE roleid = 'another_user'::regrole AND member = 'test_role_renamed'::regrole $$) ORDER BY result; result --------------------------------------------------------------------- t t t (3 rows) \c - - - :master_port SET search_path TO role_command_from_any_node; SET client_min_messages TO NOTICE; SELECT citus_remove_node('localhost', :worker_1_port); citus_remove_node --------------------------------------------------------------------- (1 row) SELECT 1 FROM citus_add_node('localhost', :worker_1_port); ?column? --------------------------------------------------------------------- 1 (1 row) -- make sure that citus_add_node() propagates the roles created via a worker SELECT node_type, (result::jsonb - 'role_properties') as result FROM check_role_on_all_nodes('test_role_renamed') ORDER BY node_type; node_type | result --------------------------------------------------------------------- coordinator (local) | {"role_exists": true, "pg_dist_object_record_for_role_exists": true, "stale_pg_dist_object_record_for_a_role_exists": false} worker node (remote) | {"role_exists": true, "pg_dist_object_record_for_role_exists": true, "stale_pg_dist_object_record_for_a_role_exists": false} worker node (remote) | {"role_exists": true, "pg_dist_object_record_for_role_exists": true, "stale_pg_dist_object_record_for_a_role_exists": false} (3 rows) SELECT citus_remove_node('localhost', :master_port); citus_remove_node --------------------------------------------------------------------- (1 row) \c - - - :worker_1_port -- they fail because the coordinator is not added to metadata DROP ROLE test_role_renamed; ERROR: coordinator is not added to the metadata HINT: Use SELECT citus_set_coordinator_host('') on coordinator to configure the coordinator hostname ALTER ROLE test_role_renamed RENAME TO test_role; ERROR: coordinator is not added to the metadata HINT: Use SELECT citus_set_coordinator_host('') on coordinator to configure the coordinator hostname ALTER ROLE test_role_renamed CREATEDB; ERROR: coordinator is not added to the metadata HINT: Use SELECT citus_set_coordinator_host('') on coordinator to configure the coordinator hostname ALTER ROLE current_user IN DATABASE "regression" SET enable_hashjoin TO OFF; ERROR: coordinator is not added to the metadata HINT: Use SELECT citus_set_coordinator_host('') on coordinator to configure the coordinator hostname GRANT another_user TO test_role_renamed; ERROR: coordinator is not added to the metadata HINT: Use SELECT citus_set_coordinator_host('') on coordinator to configure the coordinator hostname \c - - - :master_port DROP ROLE test_role_renamed, another_user; SET client_min_messages TO WARNING; DROP SCHEMA role_command_from_any_node CASCADE;