From cc18fae55ae22c3b151c5c709187a9be89880072 Mon Sep 17 00:00:00 2001 From: Mats Kindahl Date: Mon, 12 Apr 2021 17:04:00 +0200 Subject: [PATCH] Copy recreated object permissions on update Tables, indexes, and sequences that are recreated as part of an update does not propagate permissions to the recreated object. This commit fixes that by saving away the permissions in `pg_class` temporarily and then copying them back into the `pg_class` table. Fixes #3078 --- sql/updates/1.5.1--1.6.0.sql | 4 ++++ sql/updates/1.7.5--2.0.0-rc1.sql | 16 ++++++++++++++-- sql/updates/2.0.0-rc1--2.0.0-rc2.sql | 6 ++++++ sql/updates/2.0.0-rc3--2.0.0-rc4.sql | 9 +++++++++ sql/updates/post-update.sql | 9 +++++++++ sql/updates/pre-update.sql | 6 ++++++ test/sql/updates/post.catalog.sql | 11 +++++++---- test/sql/updates/post.continuous_aggs.sql | 8 ++++---- test/sql/updates/setup.catalog.sql | 4 ++++ 9 files changed, 63 insertions(+), 10 deletions(-) diff --git a/sql/updates/1.5.1--1.6.0.sql b/sql/updates/1.5.1--1.6.0.sql index da5faf05d16..688650d3f7c 100644 --- a/sql/updates/1.5.1--1.6.0.sql +++ b/sql/updates/1.5.1--1.6.0.sql @@ -23,6 +23,10 @@ BEGIN END $BODY$; +INSERT INTO saved_acl SELECT oid, relnamespace, relacl FROM pg_class +WHERE oid IN ('_timescaledb_catalog.continuous_aggs_hypertable_invalidation_log'::regclass, + '_timescaledb_catalog.continuous_aggs_materialization_invalidation_log'::regclass) + ON CONFLICT DO NOTHING; ALTER TABLE _timescaledb_catalog.continuous_agg ADD COLUMN ignore_invalidation_older_than BIGINT NOT NULL DEFAULT BIGINT '9223372036854775807'; diff --git a/sql/updates/1.7.5--2.0.0-rc1.sql b/sql/updates/1.7.5--2.0.0-rc1.sql index 8b0cff9833f..bfd9cd1e798 100644 --- a/sql/updates/1.7.5--2.0.0-rc1.sql +++ b/sql/updates/1.7.5--2.0.0-rc1.sql @@ -1,3 +1,10 @@ +-- Save away ACL for objects being re-created +INSERT INTO saved_acl SELECT oid, relnamespace, relacl FROM pg_class +WHERE oid IN ('_timescaledb_config.bgw_job'::regclass, + '_timescaledb_catalog.continuous_agg'::regclass, + '_timescaledb_config.bgw_job_id_seq'::regclass) + ON CONFLICT DO NOTHING; + --Drop functions in size_utils and dependencies, ordering matters. -- Do not reorder DROP VIEW IF EXISTS timescaledb_information.hypertable; @@ -89,8 +96,6 @@ CREATE INDEX IF NOT EXISTS remote_txn_data_node_name_idx ON _timescaledb_catalog.remote_txn(data_node_name); SELECT pg_catalog.pg_extension_config_dump('_timescaledb_catalog.remote_txn', ''); -GRANT SELECT ON _timescaledb_catalog.remote_txn TO PUBLIC; - DROP VIEW IF EXISTS timescaledb_information.compressed_hypertable_stats; DROP VIEW IF EXISTS timescaledb_information.compressed_chunk_stats; @@ -264,6 +269,12 @@ DROP VIEW IF EXISTS timescaledb_information.continuous_aggregates; DROP VIEW IF EXISTS timescaledb_information.continuous_aggregate_stats; ALTER TABLE IF EXISTS _timescaledb_catalog.continuous_agg DROP COLUMN IF EXISTS job_id; +INSERT INTO saved_acl SELECT oid, relnamespace, relacl FROM pg_class +WHERE oid IN ('_timescaledb_config.bgw_job'::regclass, + '_timescaledb_catalog.continuous_agg'::regclass, + '_timescaledb_config.bgw_job_id_seq'::regclass) + ON CONFLICT DO NOTHING; + -- rebuild bgw_job table CREATE TABLE _timescaledb_config.bgw_job_tmp AS SELECT * FROM _timescaledb_config.bgw_job; ALTER EXTENSION timescaledb DROP TABLE _timescaledb_config.bgw_job; @@ -421,3 +432,4 @@ CREATE FOREIGN DATA WRAPPER timescaledb_fdw HANDLER timescaledb_fdw_handler VALIDATOR timescaledb_fdw_validator; +GRANT SELECT ON _timescaledb_catalog.remote_txn TO PUBLIC; diff --git a/sql/updates/2.0.0-rc1--2.0.0-rc2.sql b/sql/updates/2.0.0-rc1--2.0.0-rc2.sql index 9f5ee45f30b..c439e5c5cfd 100644 --- a/sql/updates/2.0.0-rc1--2.0.0-rc2.sql +++ b/sql/updates/2.0.0-rc1--2.0.0-rc2.sql @@ -6,6 +6,11 @@ DROP PROCEDURE IF EXISTS refresh_continuous_aggregate(regclass,"any","any"); DROP VIEW IF EXISTS timescaledb_information.continuous_aggregates; +INSERT INTO saved_acl SELECT oid, relnamespace, relacl FROM pg_class +WHERE oid IN ('_timescaledb_catalog.continuous_aggs_hypertable_invalidation_log'::regclass, + '_timescaledb_catalog.continuous_aggs_materialization_invalidation_log'::regclass) + ON CONFLICT DO NOTHING; + -- Rebuild hypertable invalidation log CREATE TABLE _timescaledb_catalog.continuous_aggs_hypertable_invalidation_log_tmp AS SELECT hypertable_id, lowest_modified_value, greatest_modified_value @@ -163,3 +168,4 @@ SELECT DISTINCT END END AS range_end FROM unparsed_missing_slices; + diff --git a/sql/updates/2.0.0-rc3--2.0.0-rc4.sql b/sql/updates/2.0.0-rc3--2.0.0-rc4.sql index f3710714c37..13e0d68c932 100644 --- a/sql/updates/2.0.0-rc3--2.0.0-rc4.sql +++ b/sql/updates/2.0.0-rc3--2.0.0-rc4.sql @@ -1,3 +1,11 @@ +-- Save away ACL for objects being re-created +INSERT INTO saved_acl SELECT oid, relnamespace, relacl FROM pg_class +WHERE oid IN ('_timescaledb_catalog.hypertable'::regclass, + '_timescaledb_catalog.hypertable_id_seq'::regclass, + '_timescaledb_internal.hypertable_chunk_local_size'::regclass, + '_timescaledb_internal.compressed_chunk_stats'::regclass) + ON CONFLICT DO NOTHING; + DROP VIEW IF EXISTS timescaledb_information.continuous_aggregates; DROP VIEW IF EXISTS timescaledb_information.job_stats; DROP FUNCTION IF EXISTS _timescaledb_internal.get_git_commit; @@ -126,4 +134,5 @@ ON DELETE CASCADE; GRANT SELECT ON _timescaledb_catalog.hypertable_id_seq TO PUBLIC; GRANT SELECT ON _timescaledb_catalog.hypertable TO PUBLIC; + --End Modify hypertable table diff --git a/sql/updates/post-update.sql b/sql/updates/post-update.sql index 4910c225d59..b229c12eba7 100644 --- a/sql/updates/post-update.sql +++ b/sql/updates/post-update.sql @@ -30,3 +30,12 @@ $$; -- can only be dropped after views have been rebuilt DROP FUNCTION IF EXISTS _timescaledb_internal.cagg_watermark(oid); + +-- Can only restore permissions on views after they have been rebuilt, +-- so we restore for all types of objects here. Newly created objects +-- will have saved permissions set to NULL. For those cases, we do not +-- overwrite the permissions that have already been granted. +UPDATE pg_class SET relacl = tmpacl FROM saved_acl +WHERE oid = tmpoid AND relnamespace = tmpns AND tmpacl IS NOT NULL; + +DROP TABLE saved_acl; diff --git a/sql/updates/pre-update.sql b/sql/updates/pre-update.sql index f550c8a0c73..3b0cb4f8713 100644 --- a/sql/updates/pre-update.sql +++ b/sql/updates/pre-update.sql @@ -27,3 +27,9 @@ AS '@LOADER_PATHNAME@', 'ts_bgw_db_workers_restart' LANGUAGE C VOLATILE; SELECT _timescaledb_internal.restart_background_workers(); + +-- Table for ACL of tables that are being rebuilt. +-- +-- Each update should populate this with whatever tables are being +-- re-built and the post-restore file will copy back the permissions. +CREATE TABLE saved_acl(tmpoid oid, tmpns oid, tmpacl aclitem[], UNIQUE (tmpoid, tmpns)); diff --git a/test/sql/updates/post.catalog.sql b/test/sql/updates/post.catalog.sql index 8b5944c1f7c..ee4db29d6fb 100644 --- a/test/sql/updates/post.catalog.sql +++ b/test/sql/updates/post.catalog.sql @@ -10,10 +10,13 @@ \d+ _timescaledb_catalog.chunk_index \d+ _timescaledb_catalog.tablespace -\z _timescaledb_cache.* -\z _timescaledb_catalog.* -\z _timescaledb_config.* -\z _timescaledb_internal.* +SELECT nspname AS Schema, + relname AS Name, + unnest(relacl)::text as ACL +FROM pg_class JOIN pg_namespace ns ON relnamespace = ns.oid +WHERE nspname IN ('_timescaledb_cache', '_timescaledb_catalog', + '_timescaledb_config', '_timescaledb_internal') +ORDER BY Schema, Name, ACL; \di _timescaledb_catalog.* \ds+ _timescaledb_catalog.*; diff --git a/test/sql/updates/post.continuous_aggs.sql b/test/sql/updates/post.continuous_aggs.sql index f055ec9f3b0..a9ee6ef7daa 100644 --- a/test/sql/updates/post.continuous_aggs.sql +++ b/test/sql/updates/post.continuous_aggs.sql @@ -20,7 +20,7 @@ SELECT * FROM mat_before ORDER BY bucket, location; -- Output the ACLs for each internal cagg object SELECT cl.oid::regclass::text AS reloid, - relacl + unnest(relacl)::text AS relacl FROM _timescaledb_catalog.continuous_agg ca JOIN _timescaledb_catalog.hypertable h ON (ca.mat_hypertable_id = h.id) @@ -28,19 +28,19 @@ JOIN pg_class cl ON (cl.oid IN (format('%I.%I', h.schema_name, h.table_name)::regclass, format('%I.%I', direct_view_schema, direct_view_name)::regclass, format('%I.%I', partial_view_schema, partial_view_name)::regclass)) -ORDER BY reloid; +ORDER BY reloid, relacl; -- Output ACLs for chunks on materialized hypertables SELECT inhparent::regclass::text AS parent, cl.oid::regclass::text AS chunk, - relacl + unnest(relacl)::text AS acl FROM _timescaledb_catalog.continuous_agg ca JOIN _timescaledb_catalog.hypertable h ON (ca.mat_hypertable_id = h.id) JOIN pg_inherits inh ON (inh.inhparent = format('%I.%I', h.schema_name, h.table_name)::regclass) JOIN pg_class cl ON (cl.oid = inh.inhrelid) -ORDER BY parent, chunk; +ORDER BY parent, chunk, acl; -- Verify privileges on internal cagg objects. The privileges on the -- materialized hypertable, partial view, and direct view should match diff --git a/test/sql/updates/setup.catalog.sql b/test/sql/updates/setup.catalog.sql index cdcf6924223..50ce5cd6d59 100644 --- a/test/sql/updates/setup.catalog.sql +++ b/test/sql/updates/setup.catalog.sql @@ -11,3 +11,7 @@ GRANT SELECT ON ALL TABLES IN SCHEMA _timescaledb_catalog TO tsdbadmin; GRANT SELECT ON ALL TABLES IN SCHEMA _timescaledb_config TO tsdbadmin; GRANT SELECT ON ALL TABLES IN SCHEMA _timescaledb_internal TO tsdbadmin; + +ALTER DEFAULT PRIVILEGES IN SCHEMA _timescaledb_catalog GRANT SELECT ON tables TO tsdbadmin; +ALTER DEFAULT PRIVILEGES IN SCHEMA _timescaledb_config GRANT SELECT ON tables TO tsdbadmin; +ALTER DEFAULT PRIVILEGES IN SCHEMA _timescaledb_internal GRANT SELECT ON tables TO tsdbadmin;