@@ -495,3 +495,166 @@ def test_checkdb_sigint_handling(self):
495495
496496 # Clean after yourself
497497 self .del_test_dir (module_name , fname )
498+
499+ # @unittest.skip("skip")
500+ def test_checkdb_with_least_privileges (self ):
501+ """"""
502+ fname = self .id ().split ('.' )[3 ]
503+ backup_dir = os .path .join (self .tmp_path , module_name , fname , 'backup' )
504+ node = self .make_simple_node (
505+ base_dir = os .path .join (module_name , fname , 'node' ),
506+ initdb_params = ['--data-checksums' ])
507+
508+ self .init_pb (backup_dir )
509+ self .add_instance (backup_dir , 'node' , node )
510+ node .slow_start ()
511+
512+ node .safe_psql (
513+ 'postgres' ,
514+ 'CREATE DATABASE backupdb' )
515+
516+ try :
517+ node .safe_psql (
518+ "backupdb" ,
519+ "create extension amcheck" )
520+ except QueryException as e :
521+ node .safe_psql (
522+ "backupdb" ,
523+ "create extension amcheck_next" )
524+
525+ node .safe_psql (
526+ 'backupdb' ,
527+ "REVOKE ALL ON DATABASE backupdb from PUBLIC; "
528+ "REVOKE ALL ON SCHEMA public from PUBLIC; "
529+ "REVOKE ALL ON ALL TABLES IN SCHEMA public FROM PUBLIC; "
530+ "REVOKE ALL ON ALL FUNCTIONS IN SCHEMA public FROM PUBLIC; "
531+ "REVOKE ALL ON ALL SEQUENCES IN SCHEMA public FROM PUBLIC; "
532+ "REVOKE ALL ON SCHEMA pg_catalog from PUBLIC; "
533+ "REVOKE ALL ON ALL TABLES IN SCHEMA pg_catalog FROM PUBLIC; "
534+ "REVOKE ALL ON ALL FUNCTIONS IN SCHEMA pg_catalog FROM PUBLIC; "
535+ "REVOKE ALL ON ALL SEQUENCES IN SCHEMA pg_catalog FROM PUBLIC; "
536+ "REVOKE ALL ON SCHEMA information_schema from PUBLIC; "
537+ "REVOKE ALL ON ALL TABLES IN SCHEMA information_schema FROM PUBLIC; "
538+ "REVOKE ALL ON ALL FUNCTIONS IN SCHEMA information_schema FROM PUBLIC; "
539+ "REVOKE ALL ON ALL SEQUENCES IN SCHEMA information_schema FROM PUBLIC;" )
540+
541+ # PG 9.5
542+ if self .get_version (node ) < 90600 :
543+ node .safe_psql (
544+ 'backupdb' ,
545+ 'CREATE ROLE backup WITH LOGIN; '
546+ 'GRANT CONNECT ON DATABASE backupdb to backup; '
547+ 'GRANT USAGE ON SCHEMA pg_catalog TO backup; '
548+ 'GRANT USAGE ON SCHEMA public TO backup; '
549+ 'GRANT SELECT ON TABLE pg_catalog.pg_proc TO backup; '
550+ 'GRANT SELECT ON TABLE pg_catalog.pg_extension TO backup; '
551+ 'GRANT SELECT ON TABLE pg_catalog.pg_database TO backup; '
552+ 'GRANT SELECT ON TABLE pg_catalog.pg_am TO backup; '
553+ 'GRANT SELECT ON TABLE pg_catalog.pg_class TO backup; '
554+ 'GRANT SELECT ON TABLE pg_catalog.pg_index TO backup; '
555+ 'GRANT SELECT ON TABLE pg_catalog.pg_namespace TO backup; '
556+ 'GRANT EXECUTE ON FUNCTION pg_catalog.current_setting(text) TO backup; '
557+ 'GRANT EXECUTE ON FUNCTION pg_catalog.nameeq(name, name) TO backup; '
558+ 'GRANT EXECUTE ON FUNCTION pg_catalog.namene(name, name) TO backup; '
559+ 'GRANT EXECUTE ON FUNCTION pg_catalog.int8(integer) TO backup; '
560+ 'GRANT EXECUTE ON FUNCTION pg_catalog.oideq(oid, oid) TO backup; '
561+ 'GRANT EXECUTE ON FUNCTION pg_catalog.charne("char", "char") TO backup; '
562+ 'GRANT EXECUTE ON FUNCTION pg_catalog.pg_is_in_recovery() TO backup; '
563+ 'GRANT EXECUTE ON FUNCTION pg_catalog.pg_control_system() TO backup; '
564+ 'GRANT EXECUTE ON FUNCTION bt_index_check(regclass) TO backup; '
565+ 'GRANT EXECUTE ON FUNCTION bt_index_check(regclass, bool) TO backup;'
566+ )
567+ # PG 9.6
568+ elif self .get_version (node ) > 90600 and self .get_version (node ) < 100000 :
569+ node .safe_psql (
570+ 'backupdb' ,
571+ 'CREATE ROLE backup WITH LOGIN; '
572+ 'GRANT CONNECT ON DATABASE backupdb to backup; '
573+ 'GRANT USAGE ON SCHEMA pg_catalog TO backup; '
574+ 'GRANT USAGE ON SCHEMA public TO backup; '
575+ 'GRANT SELECT ON TABLE pg_catalog.pg_proc TO backup; '
576+ 'GRANT SELECT ON TABLE pg_catalog.pg_extension TO backup; '
577+ 'GRANT SELECT ON TABLE pg_catalog.pg_database TO backup; '
578+ 'GRANT SELECT ON TABLE pg_catalog.pg_am TO backup; '
579+ 'GRANT SELECT ON TABLE pg_catalog.pg_class TO backup; '
580+ 'GRANT SELECT ON TABLE pg_catalog.pg_index TO backup; '
581+ 'GRANT SELECT ON TABLE pg_catalog.pg_namespace TO backup; '
582+ 'GRANT EXECUTE ON FUNCTION pg_catalog.current_setting(text) TO backup; '
583+ 'GRANT EXECUTE ON FUNCTION pg_catalog.nameeq(name, name) TO backup; '
584+ 'GRANT EXECUTE ON FUNCTION pg_catalog.namene(name, name) TO backup; '
585+ 'GRANT EXECUTE ON FUNCTION pg_catalog.int8(integer) TO backup; '
586+ 'GRANT EXECUTE ON FUNCTION pg_catalog.oideq(oid, oid) TO backup; '
587+ 'GRANT EXECUTE ON FUNCTION pg_catalog.charne("char", "char") TO backup; '
588+ 'GRANT EXECUTE ON FUNCTION pg_catalog.pg_is_in_recovery() TO backup; '
589+ 'GRANT EXECUTE ON FUNCTION pg_catalog.pg_control_system() TO backup; '
590+ 'GRANT EXECUTE ON FUNCTION bt_index_check(regclass) TO backup; '
591+ 'GRANT EXECUTE ON FUNCTION bt_index_check(regclass, bool) TO backup;'
592+ )
593+ # >= 10
594+ else :
595+ node .safe_psql (
596+ 'backupdb' ,
597+ 'CREATE ROLE backup WITH LOGIN; '
598+ 'GRANT CONNECT ON DATABASE backupdb to backup; '
599+ 'GRANT USAGE ON SCHEMA pg_catalog TO backup; '
600+ 'GRANT USAGE ON SCHEMA public TO backup; '
601+ 'GRANT SELECT ON TABLE pg_catalog.pg_proc TO backup; '
602+ 'GRANT SELECT ON TABLE pg_catalog.pg_extension TO backup; '
603+ 'GRANT SELECT ON TABLE pg_catalog.pg_database TO backup; '
604+ 'GRANT SELECT ON TABLE pg_catalog.pg_am TO backup; '
605+ 'GRANT SELECT ON TABLE pg_catalog.pg_class TO backup; '
606+ 'GRANT SELECT ON TABLE pg_catalog.pg_index TO backup; '
607+ 'GRANT SELECT ON TABLE pg_catalog.pg_namespace TO backup; '
608+ 'GRANT EXECUTE ON FUNCTION pg_catalog.current_setting(text) TO backup; '
609+ 'GRANT EXECUTE ON FUNCTION pg_catalog.nameeq(name, name) TO backup; '
610+ 'GRANT EXECUTE ON FUNCTION pg_catalog.namene(name, name) TO backup; '
611+ 'GRANT EXECUTE ON FUNCTION pg_catalog.int8(integer) TO backup; '
612+ 'GRANT EXECUTE ON FUNCTION pg_catalog.oideq(oid, oid) TO backup; '
613+ 'GRANT EXECUTE ON FUNCTION pg_catalog.charne("char", "char") TO backup; '
614+ 'GRANT EXECUTE ON FUNCTION pg_catalog.pg_is_in_recovery() TO backup; '
615+ 'GRANT EXECUTE ON FUNCTION pg_catalog.pg_control_system() TO backup; '
616+ 'GRANT EXECUTE ON FUNCTION bt_index_check(regclass) TO backup; '
617+ 'GRANT EXECUTE ON FUNCTION bt_index_check(regclass, bool) TO backup;'
618+ )
619+
620+ # if ProbackupTest.enterprise:
621+ # node.safe_psql(
622+ # "backupdb",
623+ # "GRANT EXECUTE ON FUNCTION pg_catalog.pgpro_edition() TO backup")
624+ #
625+ # node.safe_psql(
626+ # "backupdb",
627+ # "GRANT EXECUTE ON FUNCTION pg_catalog.pgpro_version() TO backup")
628+
629+ # checkdb
630+ try :
631+ self .checkdb_node (
632+ backup_dir , 'node' ,
633+ options = [
634+ '--amcheck' , '-U' , 'backup' ,
635+ '-d' , 'backupdb' , '-p' , str (node .port )])
636+ # we should die here because exception is what we expect to happen
637+ self .assertEqual (
638+ 1 , 0 ,
639+ "Expecting Error because permissions are missing\n "
640+ " Output: {0} \n CMD: {1}" .format (
641+ repr (self .output ), self .cmd ))
642+ except ProbackupException as e :
643+ self .assertIn (
644+ "INFO: Amcheck succeeded for database 'backupdb'" ,
645+ e .message ,
646+ "\n Unexpected Error Message: {0}\n CMD: {1}" .format (
647+ repr (e .message ), self .cmd ))
648+
649+ self .assertIn (
650+ "WARNING: Extension 'amcheck' or 'amcheck_next' are "
651+ "not installed in database postgres" ,
652+ e .message ,
653+ "\n Unexpected Error Message: {0}\n CMD: {1}" .format (
654+ repr (e .message ), self .cmd ))
655+
656+ self .assertIn (
657+ "ERROR: Some databases were not amchecked" ,
658+ e .message ,
659+ "\n Unexpected Error Message: {0}\n CMD: {1}" .format (
660+ repr (e .message ), self .cmd ))
0 commit comments