@@ -21,6 +21,7 @@ const buffer_utils = require('../../../util/buffer_utils');
21
21
const crypto = require ( 'crypto' ) ;
22
22
const NsfsObjectSDK = require ( '../../../sdk/nsfs_object_sdk' ) ;
23
23
const nb_native = require ( '../../../util/nb_native' ) ;
24
+ const native_fs_utils = require ( '../../../util/native_fs_utils' ) ;
24
25
25
26
const LIFECYCLE_RULE_STATUS_ENUM = Object . freeze ( {
26
27
ENABLED : 'Enabled' ,
@@ -578,6 +579,93 @@ describe('noobaa nc - lifecycle versioning ENABLE', () => {
578
579
} ) ;
579
580
expect ( has_delete_marker ) . toBe ( true ) ;
580
581
} ) ;
582
+
583
+ it ( 'nc lifecycle - noncurrent expiration rule - expire older versions by number of days with filter - regular key' , async ( ) => {
584
+ const lifecycle_rule = [ {
585
+ "id" : "expire noncurrent versions after 3 days with size " ,
586
+ "status" : LIFECYCLE_RULE_STATUS_ENUM . ENABLED ,
587
+ "filter" : {
588
+ "prefix" : prefix ,
589
+ "object_size_greater_than" : 80 ,
590
+ } ,
591
+ "noncurrent_version_expiration" : {
592
+ "noncurrent_days" : 3
593
+ }
594
+ } ] ;
595
+ await object_sdk . set_bucket_lifecycle_configuration_rules ( { name : test_bucket , rules : lifecycle_rule } ) ;
596
+
597
+ let res = await create_object ( object_sdk , test_bucket , test_key1_regular , 100 , false ) ;
598
+ await create_object ( object_sdk , test_bucket , test_key1_regular , 100 , false ) ;
599
+ await update_version_xattr ( test_bucket , test_key1_regular , res . version_id ) ;
600
+
601
+ const expected_res = await create_object ( object_sdk , test_bucket , test_prefix_key_regular , 100 , false ) ;
602
+ res = await create_object ( object_sdk , test_bucket , test_prefix_key_regular , 60 , false ) ;
603
+ await create_object ( object_sdk , test_bucket , test_prefix_key_regular , 100 , false ) ;
604
+ await create_object ( object_sdk , test_bucket , test_prefix_key_regular , 100 , false ) ;
605
+ await update_version_xattr ( test_bucket , test_prefix_key_regular , expected_res . version_id ) ;
606
+ await update_version_xattr ( test_bucket , test_prefix_key_regular , res . version_id ) ;
607
+
608
+ await exec_manage_cli ( TYPES . LIFECYCLE , '' , { disable_service_validation : 'true' , disable_runtime_validation : 'true' , config_root } , undefined , undefined ) ;
609
+ const object_list = await object_sdk . list_object_versions ( { bucket : test_bucket } ) ;
610
+ expect ( object_list . objects . length ) . toBe ( 5 ) ;
611
+ object_list . objects . forEach ( element => {
612
+ expect ( element . version_id ) . not . toBe ( expected_res . version_id ) ;
613
+ } ) ;
614
+ } ) ;
615
+
616
+ it ( 'nc lifecycle - noncurrent expiration rule - both noncurrent days and older versions' , async ( ) => {
617
+ const lifecycle_rule = [ {
618
+ "id" : "expire noncurrent versions after 3 days with size " ,
619
+ "status" : LIFECYCLE_RULE_STATUS_ENUM . ENABLED ,
620
+ "filter" : {
621
+ "prefix" : '' ,
622
+ } ,
623
+ "noncurrent_version_expiration" : {
624
+ "noncurrent_days" : 3 ,
625
+ "newer_noncurrent_versions" : 1
626
+ }
627
+ } ] ;
628
+ await object_sdk . set_bucket_lifecycle_configuration_rules ( { name : test_bucket , rules : lifecycle_rule } ) ;
629
+
630
+ const expected_res = await create_object ( object_sdk , test_bucket , test_key1_regular , 100 , false ) ;
631
+ const res = await create_object ( object_sdk , test_bucket , test_key1_regular , 100 , false ) ;
632
+ await create_object ( object_sdk , test_bucket , test_key1_regular , 100 , false ) ;
633
+ // older than 3 days but no more than one noncurrent version - don't delete
634
+ await update_version_xattr ( test_bucket , test_key1_regular , expected_res . version_id ) ;
635
+ // both older than 3 days and more than one noncurrent version - delete
636
+ await update_version_xattr ( test_bucket , test_key1_regular , res . version_id ) ;
637
+
638
+ await exec_manage_cli ( TYPES . LIFECYCLE , '' , { disable_service_validation : 'true' , disable_runtime_validation : 'true' , config_root } , undefined , undefined ) ;
639
+ const object_list = await object_sdk . list_object_versions ( { bucket : test_bucket } ) ;
640
+ expect ( object_list . objects . length ) . toBe ( 2 ) ;
641
+ object_list . objects . forEach ( element => {
642
+ expect ( element . version_id ) . not . toBe ( expected_res . version_id ) ;
643
+ } ) ;
644
+ } ) ;
645
+
646
+ it ( 'nc lifecycle - noncurrent expiration rule - older versions valid but noncurrent_days not valid' , async ( ) => {
647
+ const lifecycle_rule = [ {
648
+ "id" : "expire noncurrent versions after 3 days with size " ,
649
+ "status" : LIFECYCLE_RULE_STATUS_ENUM . ENABLED ,
650
+ "filter" : {
651
+ "prefix" : '' ,
652
+ } ,
653
+ "noncurrent_version_expiration" : {
654
+ "noncurrent_days" : 3 ,
655
+ "newer_noncurrent_versions" : 1
656
+ }
657
+ } ] ;
658
+ await object_sdk . set_bucket_lifecycle_configuration_rules ( { name : test_bucket , rules : lifecycle_rule } ) ;
659
+
660
+ await create_object ( object_sdk , test_bucket , test_key1_regular , 100 , false ) ;
661
+ await create_object ( object_sdk , test_bucket , test_key1_regular , 100 , false ) ;
662
+ // more than one noncurrent version but not older than 3 days - don't delete
663
+ await create_object ( object_sdk , test_bucket , test_key1_regular , 100 , false ) ;
664
+
665
+ await exec_manage_cli ( TYPES . LIFECYCLE , '' , { disable_service_validation : 'true' , disable_runtime_validation : 'true' , config_root } , undefined , undefined ) ;
666
+ const object_list = await object_sdk . list_object_versions ( { bucket : test_bucket } ) ;
667
+ expect ( object_list . objects . length ) . toBe ( 3 ) ;
668
+ } ) ;
581
669
} ) ;
582
670
583
671
describe ( 'noobaa nc - lifecycle versioning ENABLE - expiration rule - delete marker' , ( ) => {
@@ -1682,16 +1770,16 @@ describe('noobaa nc - lifecycle notifications', () => {
1682
1770
/**
1683
1771
* create_object creates an object with random data in the bucket
1684
1772
* Note: is_old - if true, would update the mtime of the file.
1685
- * @param {object } sdk
1773
+ * @param {object } object_sdk
1686
1774
* @param {string } bucket
1687
1775
* @param {string } key
1688
1776
* @param {number } size
1689
1777
* @param {boolean } [is_old]
1690
1778
* @param {{ key: string; value: string; }[] } [tagging]
1691
1779
*/
1692
- async function create_object ( sdk , bucket , key , size , is_old , tagging ) {
1780
+ async function create_object ( object_sdk , bucket , key , size , is_old , tagging ) {
1693
1781
const data = crypto . randomBytes ( size ) ;
1694
- const res = await sdk . upload_object ( {
1782
+ const res = await object_sdk . upload_object ( {
1695
1783
bucket,
1696
1784
key,
1697
1785
source_stream : buffer_utils . buffer_to_read_stream ( data ) ,
@@ -1720,6 +1808,33 @@ async function update_file_mtime(target_path) {
1720
1808
await os_utils . exec ( update_file_mtime_cmp , { return_stdout : true } ) ;
1721
1809
}
1722
1810
1811
+ /**
1812
+ * updates the number of noncurrent days xattr of target path to be 5 days older. use only on noncurrent objects.
1813
+ * is use this function on latest object the xattr will be changed when the object turns noncurrent
1814
+ * how to use this function:
1815
+ * 1. create a new object but don't change its mtime (changing mtime will cause versioning functions to fail)
1816
+ * 2. create a new object with the same key to make the object noncurrent
1817
+ * 3. call this function to change the xattr of the noncurrent object
1818
+ * @param {String } bucket
1819
+ * @param {String } key
1820
+ * @param {String } version_id
1821
+ * @returns {Promise<Void> }
1822
+ */
1823
+ async function update_version_xattr ( bucket , key , version_id ) {
1824
+ const older_time = new Date ( ) ;
1825
+ older_time . setDate ( yesterday . getDate ( ) - 5 ) ; // 5 days ago
1826
+
1827
+ const target_path = path . join ( root_path , bucket , path . dirname ( key ) , '.versions' , `${ path . basename ( key ) } _${ version_id } ` ) ;
1828
+ const file = await nb_native ( ) . fs . open ( config_fs . fs_context , target_path , config . NSFS_OPEN_READ_MODE ,
1829
+ native_fs_utils . get_umasked_mode ( config . BASE_MODE_FILE ) ) ;
1830
+ const stat = await file . stat ( config_fs . fs_context ) ;
1831
+ const xattr = Object . assign ( stat . xattr , {
1832
+ 'user.noobaa.non_current_timestamp' : older_time . getTime ( ) ,
1833
+ } ) ;
1834
+ await file . replacexattr ( config_fs . fs_context , xattr , undefined ) ;
1835
+ await file . close ( config_fs . fs_context ) ;
1836
+ }
1837
+
1723
1838
/**
1724
1839
* date_to_run_time_format coverts a date to run time format HH:MM
1725
1840
* @param {Date } date
0 commit comments