@@ -495,3 +495,166 @@ def test_checkdb_sigint_handling(self):
495
495
496
496
# Clean after yourself
497
497
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 ))