updated for new api

This commit is contained in:
2025-10-24 01:41:46 +00:00
parent b6aa8121b8
commit eb226df901

View File

@@ -9,7 +9,7 @@ import base64
import argparse
import configparser
import getpass
import requests
from truenas_api_client import Client
import platform
import subprocess
import time
@@ -19,39 +19,12 @@ except ImportError:
import json
import hmac as pyhmac
import datetime
import urllib3
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
from kmip.core import enums
from kmip.demos import utils
from kmip.pie import client
def request(resource, api_key, method='GET', data=None):
if data is None:
data = ''
else:
data = json.dumps(data)
url = 'https://127.0.0.1/api/v2.0/{}'.format(resource)
logger.debug('Request URL: {}'.format(url))
logger.debug('Request Data: {}'.format(data))
r = requests.request(
method,
url,
data=data,
headers={'Content-Type': 'application/json', 'Authorization': 'Bearer {}'.format(api_key)},
verify=False
)
logger.debug('Request Status Code: {}'.format(r.status_code))
if r.ok:
try:
logger.debug('Request Returned JSON: {}'.format(r.json()))
return {'ok': r.ok, 'status_code': r.status_code, 'response': r.json()}
except:
logger.debug('Request Returned Text: {}'.format(r.text))
return {'ok': r.ok, 'status_code': r.status_code, 'response': r.text}
raise ValueError(r)
def build_logger(level):
logger = logging.getLogger()
logger.setLevel(level)
@@ -296,7 +269,7 @@ def edit_pool_details(pools, pool_to_edit):
array[pool_name] = dict()
array[pool_name]["pool_passphrase"] = pool_passphrase
return array
def select_pool(pools, wording = "edit"):
print("Which pool would you like to {}:".format(wording))
print(" ")
@@ -324,13 +297,13 @@ if __name__ == '__main__':
dest="config",
help="Edit pools configuration."
)
parser.add_argument(
"-r",
"--restartJails",
action="store_true",
dest="restartJails",
help="Restarts jails if running"
)
#parser.add_argument(
# "-r",
# "--restartAppsVMs",
# action="store_true",
# dest="restartAppsVMs",
# help="Restarts apps and VMs if running"
#)
parser.add_argument (
"-v",
"--verbose",
@@ -367,9 +340,13 @@ if __name__ == '__main__':
user_input = input("n/q> ")
if user_input.casefold() == "n":
config = dict()
config['URI'] = input("Please enter your hostname or IP address (default: localhost): ") or "localhost"
if ask_for_confirmation("Would you like to verify the TLS cert?"):
config['Verify TLS'] = True
else:
config['Verify TLS'] = False
config['API Key'] = input("Please enter your API key: ")
config['Pools'] = new_pool_details()
config['jailStoragePool'] = select_pool(config['Pools'], "select for jail storage")
write_config_file(config, secrets_config_file)
break
elif user_input.casefold() == "q":
@@ -383,20 +360,28 @@ if __name__ == '__main__':
for pool in config['Pools']:
print(pool)
print(" ")
print("Jail storage pool: {}".format(config['jailStoragePool']))
print("URI: {}".format(config['URI']))
print("Verify TLS Cert: {}".format(config['Verify TLS']))
print(" ")
print("a) Edit API Key")
print("h) Edit Host, TLS, and API Key")
print("e) Edit pool")
print("j) Edit jail storage pool")
print("n) New pool")
print("d) Delete pool")
print("q) Quit config")
user_input = input("a/e/j/n/d/q> ")
# Edit API Key
if user_input.casefold() == "a":
config['API Key'] = input("Please enter your API key: ")
user_input = input("h/e/n/d/q> ")
# Edit Host, TLS, and API Key
if user_input.casefold() == "h":
if ask_for_confirmation("Would you like to edit the hostname or IP address?\nCurrent Value: {}".format(config['URI'])):
config['URI'] = input("Please enter your hostname or IP address: ")
if ask_for_confirmation("Would you like to edit verify TLS cert?\nCurrent Value: {}".format(config['Verify TLS'])):
if ask_for_confirmation("Would you like to verify the TLS cert?"):
config['Verify TLS'] = True
else:
config['Verify TLS'] = False
if ask_for_confirmation("Would you like to edit the API key?"):
config['API Key'] = input("Please enter your API key: ")
write_config_file(config, secrets_config_file)
# Editing an account
# Editing a pool
elif user_input.casefold() == "e":
pool_to_edit = select_pool(config['Pools'])
pool_details = edit_pool_details(config['Pools'], pool_to_edit)
@@ -404,27 +389,22 @@ if __name__ == '__main__':
config['Pools'].update(pool_details)
write_config_file(config, secrets_config_file)
break
# Editing jail storage pool
elif user_input.casefold() == "j":
config['jailStoragePool'] = select_pool(config['Pools'], "select for jail storage")
write_config_file(config, secrets_config_file)
break
# Createing a new account
# Createing a new pool
elif user_input.casefold() == "n":
pool_details = new_pool_details()
config['Pools'].update(pool_details)
write_config_file(config, secrets_config_file)
break
# Deleting an account
# Deleting a pool
elif user_input.casefold() == "d":
pool_to_delete = select_pool(config['Pools'], "delete")
if not ask_for_confirmation("Are you sure you wish to delete {} pool? ".format(pool_to_delete)):
break
del config['Pools'][pool_to_delete]
if len(config['Pools']) == 0:
# no more accounts, remove secrets file
os.remove(secrets_config_file)
if ask_for_confirmation("There are no pools left in the config, do you want to remove the secrets file?"):
# no more accounts, remove secrets file if requests
os.remove(secrets_config_file)
else:
write_config_file(config, secrets_config_file)
break
@@ -435,119 +415,46 @@ if __name__ == '__main__':
# Catch all for non-valid characters
else:
print("This value must be one of the following characters: a, e, j, n, d, q.")
print("This value must be one of the following characters: h, e, n, d, q")
if not os.path.exists(secrets_config_file):
print("No configuration file found. Please run {} -c for configuration.".format(script_name))
print("No configuration file found. Please run {} -c/--config for configuration".format(script_name))
sys.exit(-1)
# run the decryption of the keys and unlock the pool
config = read_config_file(secrets_config_file)
api_key = config['API Key']
jail_storage_pool = config['jailStoragePool']
API_POOLS = request('pool', api_key)['response']
API_DATASETS = request('pool/dataset', api_key)['response']
for pool_dataset_name in config['Pools']:
if pool_dataset_name != 'DEFAULT':
name = pool_dataset_name
pool_passphrase = config['Pools'][name]['pool_passphrase']
logger.info("Attempting to unlock {} pool.".format(name))
for pool in API_POOLS:
if pool['name'] == name:
# GELI encrypted pool
if 'encrypt' in pool:
if pool['encrypt'] == 2:
if pool['is_decrypted'] == False:
logger.info('Pool {} is locked'.format(pool['name']))
services_to_restart = request('pool/unlock_services_restart_choices', api_key, "POST", pool['id'])['response']
first = True
for service_to_restart in services_to_restart:
if service_to_restart == "jails":
logger.debug('Skipping adding the {} service'.format(services_to_restart[service_to_restart]))
continue
if first:
pool_services = "'{}'".format(service_to_restart)
first = False
else:
pool_services += ", '{}'".format(service_to_restart)
logger.debug('Restarting {} services when unlocking pool.'.format(pool_services))
response = request('pool/id/{}/unlock'.format(pool['id']), api_key, 'POST', {'passphrase': '{}'.format(pool_passphrase), 'services_restart': "[" + pool_services + "]"})
if response['ok']:
logger.info('Pool {} was unlocked and services restarted successfully'.format(pool['name']))
else:
logger.error('Pool {} was NOT unlocked and services NOT restarted'.format(pool['name']))
else:
logger.info('Pool {} is already unlocked'.format(pool['name']))
# start detection of locked zfs dataset
else:
# loop through the datasets to find the one we are looking for
for dataset in API_DATASETS:
if dataset['name'] == name:
if dataset['locked'] == True:
logger.info('Dataset {} is locked'.format(dataset['name']))
response = request('pool/dataset/unlock', api_key, 'POST', {'id': '{}'.format(dataset['id']), 'unlock_options': {'recursive': True, 'datasets': [{'name': '{}'.format(dataset['name']), 'passphrase': '{}'.format(pool_passphrase)}]}})
if response['ok']:
logger.info('Dataset {} was unlocked successfully'.format(dataset['name']))
# restart services since the dataset was unlocked
logger.info('Restarting services')
try:
services_to_restart = request('pool/unlock_services_restart_choices', api_key, "POST", pool['id'])['response']
except:
services_to_restart = request('pool/dataset/unlock_services_restart_choices', api_key, "POST", dataset['name'])['response']
for service_to_restart in services_to_restart:
if service_to_restart == "jails":
logger.debug('Skipping restarting the {} service'.format(services_to_restart[service_to_restart]))
continue
logger.debug('Restarting the {} service'.format(services_to_restart[service_to_restart]))
response = request('service/restart', api_key, 'POST', {'service': service_to_restart})
if response['ok']:
logger.debug('Service {} was restarted successfully'.format(services_to_restart[service_to_restart]))
else:
logger.error('Service {} was NOT restarted'.format(services_to_restart[service_to_restart]))
else:
logger.error('Dataset {} was NOT unlocked'.format(dataset['name']))
else:
logger.info('Dataset {} is already unlocked'.format(dataset['name']))
'''
# make sure jail storage pool is set
logger.info('Setting jail storage pool to {}'.format(jail_storage_pool))
response = request('jail/activate', api_key, 'POST', '{}'.format(jail_storage_pool))
if response['ok']:
logger.info('Successfully set jail storage pool to {}'.format(jail_storage_pool))
logger.debug("Sleeping for 120 seconds")
time.sleep(120)
# restart the jails service
#jails_service_name = 'jails'
#logger.debug('Restarting the {} service'.format(jails_service_name))
#response = request('service/restart', api_key, 'POST', {'service': jails_service_name})
#if response['ok']:
#logger.debug('Service {} was restarted successfully'.format(jails_service_name))
#else:
#logger.error('Service {} was NOT restarted'.format(jails_service_name))
# start any jails that are set to start on boot but are most likely on an encrypted pool
API_JAILS = request('jail', api_key)['response']
for jail in API_JAILS:
if jail['boot'] == 1:
logger.info('Jail {} is set to start on boot'.format(jail['id']))
if jail['state'] == 'down':
logger.info('Jail {} is stopped'.format(jail['id']))
logger.info('Starting jail {}'.format(jail['id']))
response = request('jail/start', api_key, 'POST', '{}'.format(jail['id']))
if response['ok']:
logger.info('Started jail {} successfully'.format(jail['id']))
else:
logger.error('Jail {} was NOT started'.format(jail['id']))
else:
if opts.restartJails:
logger.info('Jail {} is already started but --restartJails was passed in. Restarting jail.'.format(jail['id']))
response = request('jail/restart', api_key, 'POST', '{}'.format(jail['id']))
if response['ok']:
logger.info('Restarted jail {} successfully'.format(jail['id']))
URI = config['URI']
VERIFY_TLS = config['Verify TLS']
API_KEY = config['API Key']
with Client(uri="wss://{}/api/current".format(URI), verify_ssl=VERIFY_TLS) as c:
if c.call("auth.login_with_api_key", API_KEY):
logger.debug('Successfully logged into {}'.format(URI))
else:
logger.error('Unable to login to {}'.format(URI))
SYSTEM_INFORMATION = c.call("system.info")
logger.debug('System Info: {}'.format(SYSTEM_INFORMATION))
POOL_DATASETS = c.call("pool.dataset.details")
logger.debug('Pool Datasets: {}'.format(POOL_DATASETS))
for config_pool in config['Pools']:
config_pool_name = config_pool
pool_passphrase = config['Pools'][config_pool_name]['pool_passphrase']
logger.info("Attempting to unlock {} pool".format(config_pool_name))
for pool_dataset in POOL_DATASETS:
pool_name = pool_dataset['name']
if pool_name == config_pool_name:
pool_encrypted = pool_dataset['encrypted']
pool_unlocked = pool_dataset['key_loaded']
if pool_encrypted == True and pool_unlocked == False:
logger.info('Dataset {} is locked'.format(pool_name))
unlock_args = {"datasets": [{"name": pool_name, "passphrase": pool_passphrase}]}
unlock_status = c.call("pool.dataset.unlock", pool_name, unlock_args, job=True)
# return will look like this: {'unlocked': ['test'], 'failed': {}}
if pool_name in unlock_status.get('unlocked', []):
logger.info('Dataset {} was unlocked successfully'.format(pool_name))
else:
logger.error('Jail {} was NOT restarted'.format(jail['id']))
logger.error('Dataset {} was NOT unlocked'.format(pool_name))
else:
logger.info('Jail {} is already started'.format(jail['id']))
else:
logger.error('Unable to set jail storage pool to {}'.format(jail_storage_pool)
'''
logger.info('Dataset {} is already unlocked'.format(pool_name))
client.close()
sys.exit(0)