mirror of
https://github.com/timescale/timescaledb.git
synced 2025-05-14 17:43:34 +08:00
Add test for superuser chunk copy/move
Add isolation test case to check that the chunk object created during chunk copy/move operation on the destination datanode always has superuser credentials till the end of the operation.
This commit is contained in:
parent
ff5959f8f9
commit
517dee9f6b
126
tsl/test/isolation/expected/dist_su_copy_chunk.out
Normal file
126
tsl/test/isolation/expected/dist_su_copy_chunk.out
Normal file
@ -0,0 +1,126 @@
|
||||
Parsed test spec with 3 sessions
|
||||
|
||||
starting permutation: s1_wait1 s2_copy1 s3_check1 s3_check2 s3_check3 s1_release1 s3_check2
|
||||
node_name
|
||||
---------
|
||||
dn_1
|
||||
(1 row)
|
||||
|
||||
node_name
|
||||
---------
|
||||
dn_2
|
||||
(1 row)
|
||||
|
||||
step s1_wait1: SELECT debug_waitpoint_enable('chunk_copy_after_empty_chunk');
|
||||
debug_waitpoint_enable
|
||||
----------------------
|
||||
|
||||
(1 row)
|
||||
|
||||
step s2_copy1:
|
||||
CALL timescaledb_experimental.move_chunk(chunk=>'public._dist_hyper_X_X_chunk', source_node=> 'dn_1', destination_node => 'dn_2')
|
||||
<waiting ...>
|
||||
s3: NOTICE: [dn_1]:
|
||||
SELECT 1 FROM pg_catalog.pg_tables WHERE schemaname = 'public' AND tablename =
|
||||
'_dist_hyper_X_X_chunk' AND tableowner != 'htowner1'
|
||||
s3: NOTICE: [dn_1]:
|
||||
?column?
|
||||
--------
|
||||
(0 rows)
|
||||
|
||||
|
||||
s3: NOTICE: [dn_2]:
|
||||
SELECT 1 FROM pg_catalog.pg_tables WHERE schemaname = 'public' AND tablename =
|
||||
'_dist_hyper_X_X_chunk' AND tableowner != 'htowner1'
|
||||
s3: NOTICE: [dn_2]:
|
||||
?column?
|
||||
--------
|
||||
1
|
||||
(1 row)
|
||||
|
||||
|
||||
step s3_check1:
|
||||
SELECT * FROM remote_exec(ARRAY['dn_1', 'dn_2'], $DIST$
|
||||
SELECT 1 FROM pg_catalog.pg_tables WHERE schemaname = 'public' AND tablename =
|
||||
'_dist_hyper_X_X_chunk' AND tableowner != 'htowner1'; $DIST$);
|
||||
|
||||
remote_exec
|
||||
-----------
|
||||
|
||||
(1 row)
|
||||
|
||||
s3: NOTICE: [dn_1]:
|
||||
SELECT usesuper FROM pg_user WHERE usename IN (SELECT tableowner FROM pg_catalog.pg_tables WHERE schemaname =
|
||||
'public' AND tablename = '_dist_hyper_X_X_chunk')
|
||||
s3: NOTICE: [dn_1]:
|
||||
usesuper
|
||||
--------
|
||||
f
|
||||
(1 row)
|
||||
|
||||
|
||||
s3: NOTICE: [dn_2]:
|
||||
SELECT usesuper FROM pg_user WHERE usename IN (SELECT tableowner FROM pg_catalog.pg_tables WHERE schemaname =
|
||||
'public' AND tablename = '_dist_hyper_X_X_chunk')
|
||||
s3: NOTICE: [dn_2]:
|
||||
usesuper
|
||||
--------
|
||||
t
|
||||
(1 row)
|
||||
|
||||
|
||||
step s3_check2:
|
||||
SELECT * FROM remote_exec(ARRAY['dn_1', 'dn_2'], $DIST$
|
||||
SELECT usesuper FROM pg_user WHERE usename IN (SELECT tableowner FROM pg_catalog.pg_tables WHERE schemaname =
|
||||
'public' AND tablename = '_dist_hyper_X_X_chunk'); $DIST$);
|
||||
|
||||
remote_exec
|
||||
-----------
|
||||
|
||||
(1 row)
|
||||
|
||||
step s3_check3:
|
||||
SET ROLE htowner1;
|
||||
SELECT * FROM remote_exec(ARRAY['dn_2'], $DIST$
|
||||
CREATE INDEX ON public._dist_hyper_X_X_chunk (lower(temp));
|
||||
$DIST$);
|
||||
|
||||
s3: NOTICE: [dn_2]:
|
||||
CREATE INDEX ON public._dist_hyper_X_X_chunk (lower(temp))
|
||||
ERROR: [dn_2]: must be owner of table _dist_hyper_X_X_chunk
|
||||
step s1_release1: SELECT debug_waitpoint_release('chunk_copy_after_empty_chunk');
|
||||
debug_waitpoint_release
|
||||
-----------------------
|
||||
|
||||
(1 row)
|
||||
|
||||
step s2_copy1: <... completed>
|
||||
s3: NOTICE: [dn_1]:
|
||||
SELECT usesuper FROM pg_user WHERE usename IN (SELECT tableowner FROM pg_catalog.pg_tables WHERE schemaname =
|
||||
'public' AND tablename = '_dist_hyper_X_X_chunk')
|
||||
s3: NOTICE: [dn_1]:
|
||||
usesuper
|
||||
--------
|
||||
(0 rows)
|
||||
|
||||
|
||||
s3: NOTICE: [dn_2]:
|
||||
SELECT usesuper FROM pg_user WHERE usename IN (SELECT tableowner FROM pg_catalog.pg_tables WHERE schemaname =
|
||||
'public' AND tablename = '_dist_hyper_X_X_chunk')
|
||||
s3: NOTICE: [dn_2]:
|
||||
usesuper
|
||||
--------
|
||||
f
|
||||
(1 row)
|
||||
|
||||
|
||||
step s3_check2:
|
||||
SELECT * FROM remote_exec(ARRAY['dn_1', 'dn_2'], $DIST$
|
||||
SELECT usesuper FROM pg_user WHERE usename IN (SELECT tableowner FROM pg_catalog.pg_tables WHERE schemaname =
|
||||
'public' AND tablename = '_dist_hyper_X_X_chunk'); $DIST$);
|
||||
|
||||
remote_exec
|
||||
-----------
|
||||
|
||||
(1 row)
|
||||
|
@ -6,6 +6,7 @@ set(TEST_TEMPLATES_MODULE_DEBUG
|
||||
reorder_vs_insert.spec.in
|
||||
reorder_vs_select.spec.in
|
||||
remote_create_chunk.spec.in
|
||||
dist_su_copy_chunk.spec.in
|
||||
dist_ha_chunk_drop.spec.in
|
||||
dist_restore_point.spec.in
|
||||
dist_cmd_exec.spec.in
|
||||
|
109
tsl/test/isolation/specs/dist_su_copy_chunk.spec.in
Normal file
109
tsl/test/isolation/specs/dist_su_copy_chunk.spec.in
Normal file
@ -0,0 +1,109 @@
|
||||
# This file and its contents are licensed under the Timescale License.
|
||||
# Please see the included NOTICE for copyright information and
|
||||
# LICENSE-TIMESCALE for a copy of the license.
|
||||
|
||||
# Test that when the empty chunk is created as part of a copy or move chunk, that
|
||||
# its owner is a superuser and different from the original hypertable owner
|
||||
#
|
||||
# This change necessitated due to a security hole in logical replication in Postgres
|
||||
|
||||
setup
|
||||
{
|
||||
SET timescaledb_experimental.enable_distributed_ddl=off;
|
||||
|
||||
CREATE OR REPLACE FUNCTION debug_waitpoint_enable(TEXT) RETURNS VOID LANGUAGE C VOLATILE STRICT
|
||||
AS '@TS_MODULE_PATHNAME@', 'ts_debug_point_enable';
|
||||
|
||||
CREATE OR REPLACE FUNCTION debug_waitpoint_release(TEXT) RETURNS VOID LANGUAGE C VOLATILE STRICT
|
||||
AS '@TS_MODULE_PATHNAME@', 'ts_debug_point_release';
|
||||
|
||||
CREATE OR REPLACE FUNCTION remote_exec(srv_name name[], command text)
|
||||
RETURNS VOID AS '@TSL_MODULE_PATHNAME@', 'ts_remote_exec' LANGUAGE C;
|
||||
|
||||
DROP ROLE IF EXISTS htowner1;
|
||||
CREATE ROLE htowner1 LOGIN;
|
||||
GRANT CREATE ON SCHEMA public TO htowner1;
|
||||
SET ROLE htowner1;
|
||||
CREATE TABLE test(time timestamp NOT NULL, device int, temp text);
|
||||
RESET ROLE;
|
||||
ALTER SEQUENCE _timescaledb_catalog.hypertable_id_seq RESTART;
|
||||
ALTER SEQUENCE _timescaledb_catalog.chunk_id_seq RESTART;
|
||||
}
|
||||
setup { SELECT node_name FROM add_data_node('dn_1', host => 'localhost', database => 'dn1', if_not_exists => true); }
|
||||
setup { SELECT node_name FROM add_data_node('dn_2', host => 'localhost', database => 'dn2', if_not_exists => true); }
|
||||
setup { CALL distributed_exec('GRANT CREATE ON SCHEMA public TO htowner1;'); }
|
||||
setup
|
||||
{
|
||||
GRANT USAGE ON FOREIGN SERVER dn_1, dn_2 TO PUBLIC;
|
||||
SET ROLE htowner1;
|
||||
SET timescaledb_experimental.enable_distributed_ddl=on;
|
||||
}
|
||||
setup
|
||||
{
|
||||
SELECT create_distributed_hypertable('test', 'time', 'device', 3, associated_schema_name => 'public');
|
||||
INSERT INTO test SELECT t, (abs(timestamp_hash(t::timestamp)) % 10) + 1, 0.10 FROM generate_series('2018-03-02 1:00'::TIMESTAMPTZ, '2018-03-08 1:00', '1 hour') t;
|
||||
}
|
||||
|
||||
teardown
|
||||
{
|
||||
DROP TABLE test CASCADE;
|
||||
}
|
||||
|
||||
session "s1"
|
||||
setup
|
||||
{
|
||||
SET application_name = 's1';
|
||||
}
|
||||
step "s1_wait1" { SELECT debug_waitpoint_enable('chunk_copy_after_empty_chunk'); }
|
||||
step "s1_release1" { SELECT debug_waitpoint_release('chunk_copy_after_empty_chunk'); }
|
||||
|
||||
session "s2"
|
||||
setup
|
||||
{
|
||||
SET application_name = 's2';
|
||||
SET ROLE htowner1;
|
||||
}
|
||||
step "s2_copy1" {
|
||||
CALL timescaledb_experimental.move_chunk(chunk=>'public._dist_hyper_1_1_chunk', source_node=> 'dn_1', destination_node => 'dn_2')
|
||||
}
|
||||
|
||||
session "s3"
|
||||
setup
|
||||
{
|
||||
SET application_name = 's3';
|
||||
}
|
||||
|
||||
# this should show 1 on "dn_2" and nothing on "dn_1"
|
||||
step "s3_check1"
|
||||
{
|
||||
SELECT * FROM remote_exec(ARRAY['dn_1', 'dn_2'], $DIST$
|
||||
SELECT 1 FROM pg_catalog.pg_tables WHERE schemaname = 'public' AND tablename =
|
||||
'_dist_hyper_1_1_chunk' AND tableowner != 'htowner1'; $DIST$);
|
||||
}
|
||||
|
||||
# this should show true on "dn_2" and false on "dn_1" on first invocation
|
||||
# it should show false on "dn_2" and nothing on "dn_1" after the move
|
||||
step "s3_check2"
|
||||
{
|
||||
SELECT * FROM remote_exec(ARRAY['dn_1', 'dn_2'], $DIST$
|
||||
SELECT usesuper FROM pg_user WHERE usename IN (SELECT tableowner FROM pg_catalog.pg_tables WHERE schemaname =
|
||||
'public' AND tablename = '_dist_hyper_1_1_chunk'); $DIST$);
|
||||
}
|
||||
|
||||
# this should fail on dn_2 since superuser owns the chunk object. Kinda superfluous since
|
||||
# we already checked for superuser above
|
||||
step "s3_check3"
|
||||
{
|
||||
SET ROLE htowner1;
|
||||
SELECT * FROM remote_exec(ARRAY['dn_2'], $DIST$
|
||||
CREATE INDEX ON public._dist_hyper_1_1_chunk (lower(temp));
|
||||
$DIST$);
|
||||
}
|
||||
|
||||
#
|
||||
# Test that when the empty chunk is created as part of a copy or move chunk, that
|
||||
# its owner is a superuser and different from the original hypertable owner
|
||||
#
|
||||
# This change necessitated due to a security hole in logical replication in Postgres
|
||||
#
|
||||
permutation "s1_wait1" "s2_copy1" "s3_check1" "s3_check2" "s3_check3" "s1_release1" "s3_check2"
|
Loading…
x
Reference in New Issue
Block a user