@@ -2367,6 +2367,124 @@ def test_subvolume_create_and_ls_providing_group_as_nogroup(self):
23672367
23682368 # verify trash dir is clean.
23692369 self ._wait_for_trash_empty ()
2370+
2371+ def test_subvolume_create_with_earmark (self ):
2372+ # create subvolume with earmark
2373+ subvolume = self ._gen_subvol_name ()
2374+ earmark = "nfs.test"
2375+ self ._fs_cmd ("subvolume" , "create" , self .volname , subvolume , "--earmark" , earmark )
2376+
2377+ # make sure it exists
2378+ subvolpath = self ._get_subvolume_path (self .volname , subvolume )
2379+ self .assertNotEqual (subvolpath , None )
2380+
2381+ # verify the earmark
2382+ get_earmark = self ._fs_cmd ("subvolume" , "earmark" , "get" , self .volname , subvolume )
2383+ self .assertEqual (get_earmark .rstrip ('\n ' ), earmark )
2384+
2385+ def test_subvolume_set_and_get_earmark (self ):
2386+ # create subvolume
2387+ subvolume = self ._gen_subvol_name ()
2388+ self ._fs_cmd ("subvolume" , "create" , self .volname , subvolume )
2389+
2390+ # set earmark
2391+ earmark = "smb.test"
2392+ self ._fs_cmd ("subvolume" , "earmark" , "set" , self .volname , subvolume , "--earmark" , earmark )
2393+
2394+ # get earmark
2395+ get_earmark = self ._fs_cmd ("subvolume" , "earmark" , "get" , self .volname , subvolume )
2396+ self .assertEqual (get_earmark .rstrip ('\n ' ), earmark )
2397+
2398+ def test_subvolume_clear_earmark (self ):
2399+ # create subvolume
2400+ subvolume = self ._gen_subvol_name ()
2401+ self ._fs_cmd ("subvolume" , "create" , self .volname , subvolume )
2402+
2403+ # set earmark
2404+ earmark = "smb.test"
2405+ self ._fs_cmd ("subvolume" , "earmark" , "set" , self .volname , subvolume , "--earmark" , earmark )
2406+
2407+ # remove earmark
2408+ self ._fs_cmd ("subvolume" , "earmark" , "rm" , self .volname , subvolume )
2409+
2410+ # get earmark
2411+ get_earmark = self ._fs_cmd ("subvolume" , "earmark" , "get" , self .volname , subvolume )
2412+ self .assertEqual (get_earmark , "" )
2413+
2414+ def test_earmark_on_non_existing_subvolume (self ):
2415+ subvolume = "non_existing_subvol"
2416+ earmark = "nfs.test"
2417+ commands = [
2418+ ("set" , earmark ),
2419+ ("get" , None ),
2420+ ("rm" , None ),
2421+ ]
2422+
2423+ for action , arg in commands :
2424+ try :
2425+ # Build the command arguments
2426+ cmd_args = ["subvolume" , "earmark" , action , self .volname , subvolume ]
2427+ if arg is not None :
2428+ cmd_args .extend (["--earmark" , arg ])
2429+
2430+ # Execute the command with built arguments
2431+ self ._fs_cmd (* cmd_args )
2432+ except CommandFailedError as ce :
2433+ self .assertEqual (ce .exitstatus , errno .ENOENT )
2434+
2435+ def test_get_remove_earmark_when_not_set (self ):
2436+ # Create a subvolume without setting an earmark
2437+ subvolume = self ._gen_subvol_name ()
2438+ self ._fs_cmd ("subvolume" , "create" , self .volname , subvolume )
2439+
2440+ # Attempt to get an earmark when it's not set
2441+ get_earmark = self ._fs_cmd ("subvolume" , "earmark" , "get" , self .volname , subvolume )
2442+ self .assertEqual (get_earmark , "" )
2443+
2444+ # Attempt to remove an earmark when it's not set
2445+ self ._fs_cmd ("subvolume" , "earmark" , "rm" , self .volname , subvolume )
2446+
2447+ def test_set_invalid_earmark (self ):
2448+ # Create a subvolume
2449+ subvolume = self ._gen_subvol_name ()
2450+ self ._fs_cmd ("subvolume" , "create" , self .volname , subvolume )
2451+
2452+ # Attempt to set an invalid earmark
2453+ invalid_earmark = "invalid_format"
2454+ expected_message = (
2455+ f"Invalid earmark specified: '{ invalid_earmark } '. A valid earmark should "
2456+ "either be empty or start with 'nfs' or 'smb', followed by dot-separated "
2457+ "non-empty components."
2458+ )
2459+ try :
2460+ self ._fs_cmd ("subvolume" , "earmark" , "set" , self .volname , subvolume , "--earmark" , invalid_earmark )
2461+ except CommandFailedError as ce :
2462+ self .assertEqual (ce .exitstatus , errno .EINVAL , expected_message )
2463+
2464+ def test_earmark_on_deleted_subvolume_with_retained_snapshot (self ):
2465+ subvolume = self ._gen_subvol_name ()
2466+ snapshot = self ._gen_subvol_snap_name ()
2467+
2468+ # Create subvolume and snapshot
2469+ self ._fs_cmd ("subvolume" , "create" , self .volname , subvolume )
2470+ self ._fs_cmd ("subvolume" , "snapshot" , "create" , self .volname , subvolume , snapshot )
2471+
2472+ # Delete subvolume while retaining the snapshot
2473+ self ._fs_cmd ("subvolume" , "rm" , self .volname , subvolume , "--retain-snapshots" )
2474+
2475+ # Define the expected error message
2476+ error_message = f'subvolume "{ subvolume } " is removed and has only snapshots retained'
2477+
2478+ # Test cases for setting, getting, and removing earmarks
2479+ for operation in ["get" , "rm" , "set" ]:
2480+ try :
2481+ extra_arg = "smb" if operation == "set" else None
2482+ if operation == "set" :
2483+ self ._fs_cmd ("subvolume" , "earmark" , operation , self .volname , subvolume , "--earmark" , extra_arg )
2484+ else :
2485+ self ._fs_cmd ("subvolume" , "earmark" , operation , self .volname , subvolume )
2486+ except CommandFailedError as ce :
2487+ self .assertEqual (ce .exitstatus , errno .ENOENT , error_message )
23702488
23712489 def test_subvolume_expand (self ):
23722490 """
@@ -2440,6 +2558,14 @@ def test_subvolume_info(self):
24402558 for feature in ['snapshot-clone' , 'snapshot-autoprotect' , 'snapshot-retention' ]:
24412559 self .assertIn (feature , subvol_info ["features" ], msg = "expected feature '{0}' in subvolume" .format (feature ))
24422560
2561+ # set earmark
2562+ earmark = "smb.test"
2563+ self ._fs_cmd ("subvolume" , "earmark" , "set" , self .volname , subvolume , "--earmark" , earmark )
2564+
2565+ subvol_info = json .loads (self ._get_subvolume_info (self .volname , subvolume ))
2566+
2567+ self .assertEqual (subvol_info ["earmark" ], earmark )
2568+
24432569 # remove subvolumes
24442570 self ._fs_cmd ("subvolume" , "rm" , self .volname , subvolume )
24452571
0 commit comments