There is an official api client written in python. I wrote a tool to perform configuration backups using that API client (which I attached below). Maybe it will help you.
Example Usage:
$ python backup.py --verbose --secretseed --secure --host my-truenas --port 8443 --username truenas_admin --password mypassword backup.tar
computed urls (ws_url=wss://my-truenas:8443/api/current, http_url=https://my-truenas:8443)
call to config.save succeeded (JobID=46061, DownloadURL=/_download/46061?auth_token=xxxx)
starting download (FullURL=xxxx)
successfully opened output file (outfile=backup.tar)
successfully wrote configuration backup
An api key (-key) can also be supplied as an alternative to --username/--password.
This also works if you execute it locally on the TrueNAS system, in which case you do not have to supply a hostname/port. If you execute it as root (for example using sudo) you also don’t have to provide any authentication.
import requests
import argparse
import sys
import subprocess
from truenas_api_client import Client
SOCK_PATH = "/var/run/middleware/middlewared.sock"
parser = argparse.ArgumentParser(prog='ConfigDL', description='Downloads TrueNAS Scale Configuration Backup')
parser.add_argument('-s', '--secretseed', action='store_true', help='if specified, output will be a tar file that includes the the secret seed')
parser.add_argument('-v', '--verbose', action='store_true')
parser.add_argument('outfile', help='Output File')
parser.add_argument("--disable-ssl-verify", action="store_true", help="When using --secure, skips ssl certificate verification")
parser.add_argument("--secure", action="store_true", help="If set, use secure protocols (HTTPS and WSS)")
parser.add_argument("--host", type=str, help="Hostname or IP Address of TrueNAS instance")
parser.add_argument("--port", type=int, help="WebServer Port of the TrueNAS instance")
parser.add_argument("--key", type=str, help="TrueNAS API Key")
parser.add_argument("--username", type=str)
parser.add_argument("--password", type=str)
args = parser.parse_args()
if args.host is not None and args.port is None:
print("you must set --port when using --host", file=sys.stderr)
sys.exit(1)
if args.username is not None and args.password is None:
print("you must set --password when using --username", file=sys.stderr)
sys.exit(1)
if args.password is not None and args.username is None:
print("you must set --username when using --password", file=sys.stderr)
sys.exit(1)
if args.username is not None and args.key is not None:
print("--key is incompatible with --username", file=sys.stderr)
sys.exit(1)
use_unix_socket = args.host is None
def derive_ws_url(host, port, secure):
if host is None:
return "ws+unix://" + SOCK_PATH
else:
return ("wss://" if secure else "ws://") + host + ":" + str(port) + "/api/current"
def derive_http_url(host, port, secure):
if host is None:
return "http://127.0.0.1"
else:
return ("https://" if secure else "http://") + host + ":" + str(port)
http_url = derive_http_url(args.host, args.port, args.secure)
ws_url = derive_ws_url(args.host, args.port, args.secure)
if args.verbose:
print("computed urls (ws_url={}, http_url={})".format(ws_url, http_url))
with Client(uri=ws_url, verify_ssl=not args.disable_ssl_verify) as c:
if args.key:
c.call("auth.login_with_api_key", args.key)
elif args.username:
c.call("auth.login", args.username, args.password)
config_save_opts = {}
if args.secretseed:
config_save_opts['secretseed'] = True
job_id, download_url = c.call("core.download", "config.save", [config_save_opts], "backup")
assert isinstance(job_id, int)
assert isinstance(download_url, str)
if args.verbose:
print("call to config.save succeeded (JobID={}, DownloadURL={})".format(job_id, download_url))
full_url = http_url + download_url
if args.verbose:
print("starting download (FullURL={})".format(full_url))
if use_unix_socket:
argv = ["curl", "--unix-socket", SOCK_PATH, "--output", args.outfile, "--", full_url]
result = subprocess.run(argv, check=True)
else:
rv = requests.get(full_url)
rv.raise_for_status()
with open(args.outfile, "wb") as f:
if args.verbose:
print("successfully opened output file (outfile={})".format(args.outfile))
for chunk in rv.iter_content(chunk_size=8192):
f.write(chunk)
print("successfully wrote configuration backup")