@@ -2930,140 +2930,6 @@ def test_partial_restore_backward_compatibility_merge(self):
29302930
29312931 self .compare_pgdata (pgdata_restored , pgdata_restored_1 )
29322932
2933- def test_missing_database_map (self ):
2934- """
2935- """
2936- fname = self .id ().split ('.' )[3 ]
2937- backup_dir = os .path .join (self .tmp_path , module_name , fname , 'backup' )
2938- node = self .make_simple_node (
2939- base_dir = os .path .join (module_name , fname , 'node' ),
2940- set_replication = True ,
2941- initdb_params = ['--data-checksums' ])
2942-
2943- self .init_pb (backup_dir )
2944- self .add_instance (backup_dir , 'node' , node )
2945-
2946- node .slow_start ()
2947-
2948- # create databases
2949- for i in range (1 , 10 , 1 ):
2950- node .safe_psql (
2951- 'postgres' ,
2952- 'CREATE database db{0}' .format (i ))
2953-
2954- node .safe_psql (
2955- "postgres" ,
2956- "CREATE DATABASE backupdb" )
2957-
2958- if self .get_version (node ) > self .version_to_num ('10.0' ):
2959- # bootstrap for 10/11
2960- node .safe_psql (
2961- "backupdb" ,
2962- "REVOKE ALL on SCHEMA public from public; "
2963- "REVOKE ALL on SCHEMA pg_catalog from public; "
2964- "REVOKE ALL ON ALL TABLES IN SCHEMA pg_catalog FROM public; "
2965- "REVOKE ALL ON ALL TABLES IN SCHEMA public FROM public; "
2966- "CREATE ROLE backup WITH LOGIN REPLICATION; "
2967- "GRANT CONNECT ON DATABASE postgres to backup; "
2968- "GRANT USAGE ON SCHEMA pg_catalog TO backup; "
2969- "GRANT SELECT ON TABLE pg_catalog.pg_proc TO backup; "
2970- # we use it for partial restore and checkdb
2971- # "GRANT SELECT ON TABLE pg_catalog.pg_database TO backup; "
2972- "GRANT EXECUTE ON FUNCTION pg_catalog.current_setting(text) TO backup; "
2973- "GRANT EXECUTE ON FUNCTION pg_catalog.pg_is_in_recovery() TO backup; "
2974- "GRANT EXECUTE ON FUNCTION pg_catalog.pg_start_backup(text, boolean, boolean) TO backup; "
2975- "GRANT EXECUTE ON FUNCTION pg_catalog.pg_stop_backup(boolean, boolean) TO backup; "
2976- "GRANT EXECUTE ON FUNCTION pg_catalog.pg_create_restore_point(text) TO backup; "
2977- "GRANT EXECUTE ON FUNCTION pg_catalog.pg_switch_wal() TO backup; "
2978- "GRANT EXECUTE ON FUNCTION pg_catalog.pg_last_wal_replay_lsn() TO backup; "
2979- "GRANT EXECUTE ON FUNCTION pg_catalog.txid_current_snapshot() TO backup; "
2980- "GRANT EXECUTE ON FUNCTION pg_catalog.txid_snapshot_xmax(txid_snapshot) TO backup; "
2981- "GRANT EXECUTE ON FUNCTION pg_catalog.pg_ptrack_clear() TO backup; "
2982- "GRANT EXECUTE ON FUNCTION pg_catalog.pg_ptrack_get_and_clear(oid, oid) TO backup; "
2983- # "GRANT EXECUTE ON FUNCTION pg_catalog.pg_ptrack_get_block_2(oid, oid, oid, oid) TO backup;"
2984- )
2985- else :
2986- # bootstrap for 9.5/9.6
2987- node .safe_psql (
2988- "backupdb" ,
2989- "REVOKE ALL on SCHEMA public from public; "
2990- "REVOKE ALL on SCHEMA pg_catalog from public; "
2991- "REVOKE ALL ON ALL TABLES IN SCHEMA pg_catalog FROM public; "
2992- "REVOKE ALL ON ALL TABLES IN SCHEMA public FROM public; "
2993- "CREATE ROLE backup WITH LOGIN REPLICATION; "
2994- "GRANT CONNECT ON DATABASE postgres to backup; "
2995- "GRANT USAGE ON SCHEMA pg_catalog TO backup; "
2996- # we use it for ptrack
2997- "GRANT SELECT ON TABLE pg_catalog.pg_proc TO backup; "
2998- # we use it for partial restore and checkdb
2999- # "GRANT SELECT ON TABLE pg_catalog.pg_database TO backup; "
3000- "GRANT EXECUTE ON FUNCTION pg_catalog.current_setting(text) TO backup; "
3001- "GRANT EXECUTE ON FUNCTION pg_catalog.pg_is_in_recovery() TO backup; "
3002- "GRANT EXECUTE ON FUNCTION pg_catalog.pg_start_backup(text, boolean, boolean) TO backup; "
3003- "GRANT EXECUTE ON FUNCTION pg_catalog.pg_stop_backup() TO backup; "
3004- "GRANT EXECUTE ON FUNCTION pg_catalog.pg_stop_backup(boolean) TO backup; "
3005- "GRANT EXECUTE ON FUNCTION pg_catalog.pg_create_restore_point(text) TO backup; "
3006- "GRANT EXECUTE ON FUNCTION pg_catalog.pg_switch_xlog() TO backup; "
3007- "GRANT EXECUTE ON FUNCTION pg_catalog.pg_last_xlog_replay_location() TO backup; "
3008- "GRANT EXECUTE ON FUNCTION pg_catalog.txid_current_snapshot() TO backup; "
3009- "GRANT EXECUTE ON FUNCTION pg_catalog.txid_snapshot_xmax(txid_snapshot) TO backup; "
3010- "GRANT EXECUTE ON FUNCTION pg_catalog.pg_ptrack_clear() TO backup; "
3011- "GRANT EXECUTE ON FUNCTION pg_catalog.pg_ptrack_get_and_clear(oid, oid) TO backup; "
3012- # "GRANT EXECUTE ON FUNCTION pg_catalog.pg_ptrack_get_block_2(oid, oid, oid, oid) TO backup;"
3013- )
3014-
3015- # FULL backup without database_map
3016- backup_id = self .backup_node (
3017- backup_dir , 'node' , node , datname = 'backupdb' ,
3018- options = ['--stream' , "-U" , "backup" ])
3019-
3020- pgdata = self .pgdata_content (node .data_dir )
3021-
3022- node_restored = self .make_simple_node (
3023- base_dir = os .path .join (module_name , fname , 'node_restored' ))
3024- node_restored .cleanup ()
3025-
3026- # backup has missing database_map and that is legal
3027- try :
3028- self .restore_node (
3029- backup_dir , 'node' , node_restored ,
3030- options = ["--db-exclude=db5" , "--db-exclude=db9" ])
3031- self .assertEqual (
3032- 1 , 0 ,
3033- "Expecting Error because user do not have pg_database access.\n "
3034- "Output: {0} \n CMD: {1}" .format (
3035- self .output , self .cmd ))
3036- except ProbackupException as e :
3037- self .assertIn (
3038- "ERROR: Backup {0} has missing database_map, "
3039- "partial restore is impossible." .format (
3040- backup_id ), e .message ,
3041- '\n Unexpected Error Message: {0}\n CMD: {1}' .format (
3042- repr (e .message ), self .cmd ))
3043-
3044- try :
3045- self .restore_node (
3046- backup_dir , 'node' , node_restored ,
3047- options = ["--db-include=db1" ])
3048- self .assertEqual (
3049- 1 , 0 ,
3050- "Expecting Error because user do not have pg_database access.\n "
3051- "Output: {0} \n CMD: {1}" .format (
3052- self .output , self .cmd ))
3053- except ProbackupException as e :
3054- self .assertIn (
3055- "ERROR: Backup {0} has missing database_map, "
3056- "partial restore is impossible." .format (
3057- backup_id ), e .message ,
3058- '\n Unexpected Error Message: {0}\n CMD: {1}' .format (
3059- repr (e .message ), self .cmd ))
3060-
3061- # check that simple restore is still possible
3062- self .restore_node (backup_dir , 'node' , node_restored )
3063-
3064- pgdata_restored = self .pgdata_content (node_restored .data_dir )
3065- self .compare_pgdata (pgdata , pgdata_restored )
3066-
30672933 def test_empty_and_mangled_database_map (self ):
30682934 """
30692935 """
@@ -3176,3 +3042,203 @@ def test_empty_and_mangled_database_map(self):
31763042
31773043 pgdata_restored = self .pgdata_content (node_restored .data_dir )
31783044 self .compare_pgdata (pgdata , pgdata_restored )
3045+
3046+ def test_missing_database_map (self ):
3047+ """
3048+ """
3049+ fname = self .id ().split ('.' )[3 ]
3050+ backup_dir = os .path .join (self .tmp_path , module_name , fname , 'backup' )
3051+ node = self .make_simple_node (
3052+ base_dir = os .path .join (module_name , fname , 'node' ),
3053+ set_replication = True ,
3054+ initdb_params = ['--data-checksums' ],
3055+ pg_options = {'autovacuum' : 'off' })
3056+
3057+ self .init_pb (backup_dir )
3058+ self .add_instance (backup_dir , 'node' , node )
3059+
3060+ node .slow_start ()
3061+
3062+ # create databases
3063+ for i in range (1 , 10 , 1 ):
3064+ node .safe_psql (
3065+ 'postgres' ,
3066+ 'CREATE database db{0}' .format (i ))
3067+
3068+ node .safe_psql (
3069+ "postgres" ,
3070+ "CREATE DATABASE backupdb" )
3071+
3072+ # PG 9.5
3073+ if self .get_version (node ) < 90600 :
3074+ node .safe_psql (
3075+ 'backupdb' ,
3076+ "REVOKE ALL ON DATABASE backupdb from PUBLIC; "
3077+ "REVOKE ALL ON SCHEMA public from PUBLIC; "
3078+ "REVOKE ALL ON ALL TABLES IN SCHEMA public FROM PUBLIC; "
3079+ "REVOKE ALL ON ALL FUNCTIONS IN SCHEMA public FROM PUBLIC; "
3080+ "REVOKE ALL ON ALL SEQUENCES IN SCHEMA public FROM PUBLIC; "
3081+ "REVOKE ALL ON SCHEMA pg_catalog from PUBLIC; "
3082+ "REVOKE ALL ON ALL TABLES IN SCHEMA pg_catalog FROM PUBLIC; "
3083+ "REVOKE ALL ON ALL FUNCTIONS IN SCHEMA pg_catalog FROM PUBLIC; "
3084+ "REVOKE ALL ON ALL SEQUENCES IN SCHEMA pg_catalog FROM PUBLIC; "
3085+ "REVOKE ALL ON SCHEMA information_schema from PUBLIC; "
3086+ "REVOKE ALL ON ALL TABLES IN SCHEMA information_schema FROM PUBLIC; "
3087+ "REVOKE ALL ON ALL FUNCTIONS IN SCHEMA information_schema FROM PUBLIC; "
3088+ "REVOKE ALL ON ALL SEQUENCES IN SCHEMA information_schema FROM PUBLIC; "
3089+ "CREATE ROLE backup WITH LOGIN REPLICATION; "
3090+ "GRANT CONNECT ON DATABASE backupdb to backup; "
3091+ "GRANT USAGE ON SCHEMA pg_catalog TO backup; "
3092+ "GRANT SELECT ON TABLE pg_catalog.pg_proc TO backup; "
3093+ "GRANT SELECT ON TABLE pg_catalog.pg_database TO backup; " # for partial restore, checkdb and ptrack
3094+ "GRANT EXECUTE ON FUNCTION pg_catalog.nameeq(name, name) TO backup; "
3095+ "GRANT EXECUTE ON FUNCTION pg_catalog.textout(text) TO backup; "
3096+ "GRANT EXECUTE ON FUNCTION pg_catalog.timestamptz(timestamp with time zone, integer) TO backup; "
3097+ "GRANT EXECUTE ON FUNCTION pg_catalog.current_setting(text) TO backup; "
3098+ "GRANT EXECUTE ON FUNCTION pg_catalog.pg_is_in_recovery() TO backup; "
3099+ "GRANT EXECUTE ON FUNCTION pg_catalog.pg_start_backup(text, boolean) TO backup; "
3100+ "GRANT EXECUTE ON FUNCTION pg_catalog.pg_stop_backup() TO backup; "
3101+ "GRANT EXECUTE ON FUNCTION pg_catalog.txid_current_snapshot() TO backup; "
3102+ "GRANT EXECUTE ON FUNCTION pg_catalog.txid_snapshot_xmax(txid_snapshot) TO backup;"
3103+ )
3104+ # PG 9.6
3105+ elif self .get_version (node ) > 90600 and self .get_version (node ) < 100000 :
3106+ node .safe_psql (
3107+ 'backupdb' ,
3108+ "REVOKE ALL ON DATABASE backupdb from PUBLIC; "
3109+ "REVOKE ALL ON SCHEMA public from PUBLIC; "
3110+ "REVOKE ALL ON ALL TABLES IN SCHEMA public FROM PUBLIC; "
3111+ "REVOKE ALL ON ALL FUNCTIONS IN SCHEMA public FROM PUBLIC; "
3112+ "REVOKE ALL ON ALL SEQUENCES IN SCHEMA public FROM PUBLIC; "
3113+ "REVOKE ALL ON SCHEMA pg_catalog from PUBLIC; "
3114+ "REVOKE ALL ON ALL TABLES IN SCHEMA pg_catalog FROM PUBLIC; "
3115+ "REVOKE ALL ON ALL FUNCTIONS IN SCHEMA pg_catalog FROM PUBLIC; "
3116+ "REVOKE ALL ON ALL SEQUENCES IN SCHEMA pg_catalog FROM PUBLIC; "
3117+ "REVOKE ALL ON SCHEMA information_schema from PUBLIC; "
3118+ "REVOKE ALL ON ALL TABLES IN SCHEMA information_schema FROM PUBLIC; "
3119+ "REVOKE ALL ON ALL FUNCTIONS IN SCHEMA information_schema FROM PUBLIC; "
3120+ "REVOKE ALL ON ALL SEQUENCES IN SCHEMA information_schema FROM PUBLIC; "
3121+ "CREATE ROLE backup WITH LOGIN REPLICATION; "
3122+ "GRANT CONNECT ON DATABASE backupdb to backup; "
3123+ "GRANT USAGE ON SCHEMA pg_catalog TO backup; "
3124+ "GRANT SELECT ON TABLE pg_catalog.pg_proc TO backup; "
3125+ "GRANT SELECT ON TABLE pg_catalog.pg_database TO backup; " # for partial restore, checkdb and ptrack
3126+ "GRANT EXECUTE ON FUNCTION pg_catalog.nameeq(name, name) TO backup; "
3127+ "GRANT EXECUTE ON FUNCTION pg_catalog.textout(text) TO backup; "
3128+ "GRANT EXECUTE ON FUNCTION pg_catalog.timestamptz(timestamp with time zone, integer) TO backup; "
3129+ "GRANT EXECUTE ON FUNCTION pg_catalog.current_setting(text) TO backup; "
3130+ "GRANT EXECUTE ON FUNCTION pg_catalog.pg_is_in_recovery() TO backup; "
3131+ "GRANT EXECUTE ON FUNCTION pg_catalog.pg_control_system() TO backup; "
3132+ "GRANT EXECUTE ON FUNCTION pg_catalog.pg_start_backup(text, boolean, boolean) TO backup; "
3133+ "GRANT EXECUTE ON FUNCTION pg_catalog.pg_stop_backup(boolean) TO backup; "
3134+ "GRANT EXECUTE ON FUNCTION pg_catalog.pg_create_restore_point(text) TO backup; "
3135+ "GRANT EXECUTE ON FUNCTION pg_catalog.pg_switch_xlog() TO backup; "
3136+ "GRANT EXECUTE ON FUNCTION pg_catalog.pg_last_xlog_replay_location() TO backup; "
3137+ "GRANT EXECUTE ON FUNCTION pg_catalog.txid_current_snapshot() TO backup; "
3138+ "GRANT EXECUTE ON FUNCTION pg_catalog.txid_snapshot_xmax(txid_snapshot) TO backup;"
3139+ )
3140+ # >= 10
3141+ else :
3142+ node .safe_psql (
3143+ 'backupdb' ,
3144+ "REVOKE ALL ON DATABASE backupdb from PUBLIC; "
3145+ "REVOKE ALL ON SCHEMA public from PUBLIC; "
3146+ "REVOKE ALL ON ALL TABLES IN SCHEMA public FROM PUBLIC; "
3147+ "REVOKE ALL ON ALL FUNCTIONS IN SCHEMA public FROM PUBLIC; "
3148+ "REVOKE ALL ON ALL SEQUENCES IN SCHEMA public FROM PUBLIC; "
3149+ "REVOKE ALL ON SCHEMA pg_catalog from PUBLIC; "
3150+ "REVOKE ALL ON ALL TABLES IN SCHEMA pg_catalog FROM PUBLIC; "
3151+ "REVOKE ALL ON ALL FUNCTIONS IN SCHEMA pg_catalog FROM PUBLIC; "
3152+ "REVOKE ALL ON ALL SEQUENCES IN SCHEMA pg_catalog FROM PUBLIC; "
3153+ "REVOKE ALL ON SCHEMA information_schema from PUBLIC; "
3154+ "REVOKE ALL ON ALL TABLES IN SCHEMA information_schema FROM PUBLIC; "
3155+ "REVOKE ALL ON ALL FUNCTIONS IN SCHEMA information_schema FROM PUBLIC; "
3156+ "REVOKE ALL ON ALL SEQUENCES IN SCHEMA information_schema FROM PUBLIC; "
3157+ "CREATE ROLE backup WITH LOGIN REPLICATION; "
3158+ "GRANT CONNECT ON DATABASE backupdb to backup; "
3159+ "GRANT USAGE ON SCHEMA pg_catalog TO backup; "
3160+ "GRANT SELECT ON TABLE pg_catalog.pg_proc TO backup; "
3161+ "GRANT SELECT ON TABLE pg_catalog.pg_database TO backup; " # for partial restore, checkdb and ptrack
3162+ "GRANT EXECUTE ON FUNCTION pg_catalog.nameeq(name, name) TO backup; "
3163+ "GRANT EXECUTE ON FUNCTION pg_catalog.current_setting(text) TO backup; "
3164+ "GRANT EXECUTE ON FUNCTION pg_catalog.pg_is_in_recovery() TO backup; "
3165+ "GRANT EXECUTE ON FUNCTION pg_catalog.pg_control_system() TO backup; "
3166+ "GRANT EXECUTE ON FUNCTION pg_catalog.pg_start_backup(text, boolean, boolean) TO backup; "
3167+ "GRANT EXECUTE ON FUNCTION pg_catalog.pg_stop_backup(boolean, boolean) TO backup; "
3168+ "GRANT EXECUTE ON FUNCTION pg_catalog.pg_create_restore_point(text) TO backup; "
3169+ "GRANT EXECUTE ON FUNCTION pg_catalog.pg_switch_wal() TO backup; "
3170+ "GRANT EXECUTE ON FUNCTION pg_catalog.pg_last_wal_replay_lsn() TO backup; "
3171+ "GRANT EXECUTE ON FUNCTION pg_catalog.txid_current_snapshot() TO backup; "
3172+ "GRANT EXECUTE ON FUNCTION pg_catalog.txid_snapshot_xmax(txid_snapshot) TO backup;"
3173+ )
3174+
3175+ if self .ptrack :
3176+ for fname in [
3177+ 'pg_catalog.oideq(oid, oid)' ,
3178+ 'pg_catalog.ptrack_version()' ,
3179+ 'pg_catalog.pg_ptrack_clear()' ,
3180+ 'pg_catalog.pg_ptrack_control_lsn()' ,
3181+ 'pg_catalog.pg_ptrack_get_and_clear_db(oid, oid)' ,
3182+ 'pg_catalog.pg_ptrack_get_and_clear(oid, oid)' ,
3183+ 'pg_catalog.pg_ptrack_get_block_2(oid, oid, oid, bigint)' ,
3184+ 'pg_catalog.pg_stop_backup()' ]:
3185+
3186+ node .safe_psql (
3187+ "backupdb" ,
3188+ "GRANT EXECUTE ON FUNCTION {0} "
3189+ "TO backup" .format (fname ))
3190+
3191+ # FULL backup without database_map
3192+ backup_id = self .backup_node (
3193+ backup_dir , 'node' , node , datname = 'backupdb' ,
3194+ options = ['--stream' , "-U" , "backup" , '--log-level-file=verbose' ])
3195+
3196+ pgdata = self .pgdata_content (node .data_dir )
3197+
3198+ node_restored = self .make_simple_node (
3199+ base_dir = os .path .join (module_name , fname , 'node_restored' ))
3200+ node_restored .cleanup ()
3201+
3202+ # backup has missing database_map and that is legal
3203+ try :
3204+ self .restore_node (
3205+ backup_dir , 'node' , node_restored ,
3206+ options = ["--db-exclude=db5" , "--db-exclude=db9" ])
3207+ self .assertEqual (
3208+ 1 , 0 ,
3209+ "Expecting Error because user do not have pg_database access.\n "
3210+ "Output: {0} \n CMD: {1}" .format (
3211+ self .output , self .cmd ))
3212+ except ProbackupException as e :
3213+ self .assertIn (
3214+ "ERROR: Backup {0} doesn't contain a database_map, "
3215+ "partial restore is impossible." .format (
3216+ backup_id ), e .message ,
3217+ '\n Unexpected Error Message: {0}\n CMD: {1}' .format (
3218+ repr (e .message ), self .cmd ))
3219+
3220+ try :
3221+ self .restore_node (
3222+ backup_dir , 'node' , node_restored ,
3223+ options = ["--db-include=db1" ])
3224+ self .assertEqual (
3225+ 1 , 0 ,
3226+ "Expecting Error because user do not have pg_database access.\n "
3227+ "Output: {0} \n CMD: {1}" .format (
3228+ self .output , self .cmd ))
3229+ except ProbackupException as e :
3230+ self .assertIn (
3231+ "ERROR: Backup {0} doesn't contain a database_map, "
3232+ "partial restore is impossible." .format (
3233+ backup_id ), e .message ,
3234+ '\n Unexpected Error Message: {0}\n CMD: {1}' .format (
3235+ repr (e .message ), self .cmd ))
3236+
3237+ # check that simple restore is still possible
3238+ self .restore_node (backup_dir , 'node' , node_restored )
3239+
3240+ pgdata_restored = self .pgdata_content (node_restored .data_dir )
3241+ self .compare_pgdata (pgdata , pgdata_restored )
3242+
3243+ # Clean after yourself
3244+ self .del_test_dir (module_name , fname )
0 commit comments