I’m dealing with an issue on an old TrueNAS server that is joined to my company’s domain and is being used as a Windows file share. This server has been in use for years (but kept updated) and has hundreds of nested datasets, each configured with specific ACL permissions using groups via the web UI.
The problem lies in the IDMAP range. The old TrueNAS server uses the legacy IDMAP range starting from 20000, whereas newer TrueNAS servers use a range starting from 100000001. While changing the IDMAP range in the web interface is quick and easy, the real challenge is updating the ACL permissions across all the datasets to match the new IDMAP range.
Manually updating ACLs for hundreds of datasets is impractical, so I’m looking for a way to automate this process. Does anyone have suggestions for a script or a method to iterate through each dataset and update the ACL permissions to align with the new IDMAP range?
If anyone has dealt with a similar situation or has ideas on how to script this, I would greatly appreciate your advice!
Unfortunately, I don’t want to keep the old range because I manage 14 TrueNAS installations, and only 2 of them use the old IDMAP range. Keeping the old range creates significant inconsistency when datasets are moved between servers.
For example, if a dataset is moved from a server with the new IDMAP range (starting at 1000000) to a server with the old range (starting at 20000), the permissions become inconsistent, and I lose access to the files. This creates a major administrative headache.
That’s why I’m looking for a way to update all ACL permissions on the datasets to align with the new range and ensure everything is consistent across all servers. If you have any ideas or know of a script to automate this process, I’d really appreciate your help!
I’m in a similar boat however decided to just keep the old range even on newly built systems to keep the consistency and like you say if I need to move datasets or migrate to new hardware. I also have hundreds of datasets with nested permissions so not really plausible to update them all. It’s a great question and I’d be very interested to see if anyone has a fix.
Actually, I’ve been working on a Python script to do exactly what I need. In a very brute-force way, it would work like this:
Get the list of all datasets.
Add the mountpoint.
Use getfacl on the dataset path to get the current ACL state.
Save everything to a JSON file.
Change the IDMAP range via the UI.
Run the script again, read the saved groups, and save the new ACLs.
While this would technically work, it’s a rather dangerous approach, to say the least. That’s why I’m asking if anyone has a more elegant or safe solution. If you have any suggestions or better ways to automate this, I’d be extremely grateful!
I wrote a minimal python library on TrueNAS SCALE that can be used change NFSv4 ACLs:
import zfsacl
In principle you can write a script to walk dataset by dataset and rewrite the ACLs. Trivial example:
import zfsacl
ACL_OLD_LOW = 20000
ACL_NEW_LOW = 1000000
ACL_ID_OFFSET = 980000
def get_converted_acl(path: str) -> zfsacl.Acl:
# Read ACL on path and convert underlying IDs
# returns an ACL object ready to set on same path
acl = zfsacl.Acl(path=path)
i = 0
while i < acl.ace_count:
ace = acl.get_entry(i)
who_type, who_id = ace.who
# We need to make sure it's not a local user (lower than the old low)
# and whether it has already been converted (higher than new low)
if who_id > ACL_OLD_LOW and who_id < ACL_NEW_LOW:
match who_type:
case zfsacl.WHOTYPE_GROUP | zfsacl.WHOTYPE_USER:
ace.who = (who_type, who_id + ACL_ID_OFFSET)
case _:
# other ACL types do not store ids
pass
i += 1
return acl
def convert_acl(path: str) -> None:
acl = get_converted_acl(path)
acl.setacl(path=path)
convert_acl("/mnt/dozer/SHARE/acltest")
You’d be on your own to test / validate remainder of script and add chown to change owners as well.
@awalkerix ,Want to marry me?
Thanks so much for the suggestion! I really appreciate it. I’m away today and tomorrow, but I’ll definitely give it a try first thing Tuesday morning. I’ll keep you posted on how it goes!
Do note that changing the IDs within the ACL entries does not change the owner / group of the file. So you’ll need to write your own logic for os.chown in python to cover all your bases. Also this is the easy part. The hard part is writing error handling, logging what has changed, etc, etc. Testing is also important. You’ll probably want to snapshot before redoing IDs.
At this point, I’m hands-off unless you find a library bug.
I don’t believe I wrote that tool to convert gids to names. The correct way to test would be to see whether getent group 1000512 resolves to the group you expect it to.
It’s also possible you have an off-by-one in the script you wrote. You’ll need to of course tweak it to make sure your numbers line up correctly.
As far as “not working” goes, that’s not really how this works. The only thing stored on-disk is the numeric id (names aren’t a part of it). The number is either correct or it isn’t.