[PBS 4.2.5] Datastore > Content: Bulk Change Owner in GUI?

Sep 1, 2022
570
217
68
42
I'm redoing the API tokens on my PBS server for ... reasons mostly related to ending up with multiple PVE clusters in my homelab and needing to use namespaces. Reasons that I hope I don't end up regretting. :P

As part of that, I need to change the owner of every backup currently on the PBS server so things can keep going as they were before.

It's easy to do this per-VM/LXC Backup Group, using the little human figure icon.

Is there a way in the PBS GUI to do it to multiple backup groups at once? That is, a bulk backup group ownership change?

If not, is there some reason this is a bad idea? Otherwise, I was going to put in an enhancement request.

(Aside: The last time I set up backup schedules and tokens from scratch was around the end of PBS 3. It's so, so much easier to manage everything with an ownership change feature in the GUI, as well as a way to easily migrate backup groups between namespaces. I really appreciate the work the devs put in to making that possible.)
 
Not in the GUI, no. I checked on 4.2.5 and it is still one group at a time. The Content list is a tree (namespace, group, snapshot, file) rather than a grid with checkboxes, so there is no multi-select for a bulk action to hang off. proxmox-backup-manager has nothing for ownership either, so the CLI is not a way around it.
The API will do it though, and it lines up nicely:
  • GET /api2/json/admin/datastore/{store}/groups returns every group with its backup-type, backup-id and owner
  • POST /api2/json/admin/datastore/{store}/change-owner takes backup-type, backup-id, new-owner, plus an optional ns for namespaces
Everything below is from my lab, so substitute your own: backup@pbs for your user, new-token for the token you are moving to, store1 for your datastore and pbs.example.com for your host.
Starting from scratch, the token you want to hand the backups to:
Bash:
proxmox-backup-manager user generate-token backup@pbs new-token
Both API calls authenticate with a login ticket:
Bash:
PBS='https://pbs.example.com:8007'
read -rsp 'password: ' PW; echo
RESP=$(curl -sk -d 'username=backup@pbs' -d "password=$PW" \
  "$PBS/api2/json/access/ticket")
TICKET=$(jq -r .data.ticket <<<"$RESP")
CSRF=$(jq -r .data.CSRFPreventionToken <<<"$RESP")
The ticket goes in a cookie and the CSRF token in a header. A POST needs both, a GET only the cookie. Tickets last about two hours. You can use an API token header instead, but see below.
The first endpoint gives you exactly the fields the second wants, so it loops:
Bash:
NEW='backup@pbs!new-token'
curl -sk -b "PBSAuthCookie=$TICKET" "$PBS/api2/json/admin/datastore/store1/groups" \
| jq -r '.data[] | [.["backup-type"], .["backup-id"], .owner] | @tsv' \
| while IFS=$'\t' read -r TYPE ID OWNER; do
    [ "$OWNER" = "$NEW" ] && continue
    echo -n "$TYPE/$ID: $OWNER -> $NEW ... "
    curl -sk -o /dev/null -w '%{http_code}\n' -X POST \
      -b "PBSAuthCookie=$TICKET" -H "CSRFPreventionToken: $CSRF" \
      -d "backup-type=$TYPE" -d "backup-id=$ID" -d "new-owner=$NEW" \
      "$PBS/api2/json/admin/datastore/store1/change-owner"
  done

1789180277384.png

One thing that caught me out, and it is probably relevant to your setup: you may not need Datastore.Modify at all. If the old and new tokens both belong to the same user, authenticate as that user and Datastore.Backup is enough. Tested on 4.2.5 with a user holding DatastorePowerUser:
  • user to one of its own tokens: 200
  • user moving a group from one of its own tokens to another: 200
  • token to its own user: refused, does not have permission to change owner of backup group ...
So the direction matters, not just the privilege level. A token cannot hand ownership back up, which makes sense as a safety property.
Worth knowing for the listing step too: a token only sees groups it owns unless it has Datastore.Audit, while the user does see the groups owned by its own tokens. Enumerate as the new token and you will get an empty list and conclude there is nothing to re-own.
On the enhancement request, I cannot see a reason it would be a bad idea. The API is one group per call, but that looks like the shape of the endpoint rather than anything deliberate about ownership.
 
  • Like
Reactions: UdoB