diff --git a/README.md b/README.md index 16559cb9..1eca071d 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,7 @@ Logo banner

License +Code style: Black Release Documentation Status

diff --git a/api-daemon/provisioner/examples/debootstrap_script.py b/api-daemon/provisioner/examples/debootstrap_script.py index c554ce5e..959aecc1 100644 --- a/api-daemon/provisioner/examples/debootstrap_script.py +++ b/api-daemon/provisioner/examples/debootstrap_script.py @@ -64,29 +64,35 @@ def install(**kwargs): # The provisioner has already mounted the disks on kwargs['temporary_directory']. # by this point, so we can get right to running the debootstrap after setting # some nicer variable names; you don't necessarily have to do this. - vm_name = kwargs['vm_name'] - temporary_directory = kwargs['temporary_directory'] - disks = kwargs['disks'] - networks = kwargs['networks'] + vm_name = kwargs["vm_name"] + temporary_directory = kwargs["temporary_directory"] + disks = kwargs["disks"] + networks = kwargs["networks"] # Our own required arguments. We should, though are not required to, handle # failures of these gracefully, should administrators forget to specify them. try: - deb_release = kwargs['deb_release'] + deb_release = kwargs["deb_release"] except Exception: deb_release = "stable" try: - deb_mirror = kwargs['deb_mirror'] + deb_mirror = kwargs["deb_mirror"] except Exception: deb_mirror = "http://ftp.debian.org/debian" try: - deb_packages = kwargs['deb_packages'].split(',') + deb_packages = kwargs["deb_packages"].split(",") except Exception: - deb_packages = ["linux-image-amd64", "grub-pc", "cloud-init", "python3-cffi-backend", "wget"] + deb_packages = [ + "linux-image-amd64", + "grub-pc", + "cloud-init", + "python3-cffi-backend", + "wget", + ] # We need to know our root disk root_disk = None for disk in disks: - if disk['mountpoint'] == '/': + if disk["mountpoint"] == "/": root_disk = disk if not root_disk: return @@ -95,9 +101,7 @@ def install(**kwargs): # good idea to include if you plan to use anything that is not part of the # base Debian host system, just in case the provisioner host is not properly # configured already. - os.system( - "apt-get install -y debootstrap" - ) + os.system("apt-get install -y debootstrap") # Perform a deboostrap installation os.system( @@ -105,16 +109,12 @@ def install(**kwargs): suite=deb_release, target=temporary_directory, mirror=deb_mirror, - pkgs=','.join(deb_packages) + pkgs=",".join(deb_packages), ) ) # Bind mount the devfs - os.system( - "mount --bind /dev {}/dev".format( - temporary_directory - ) - ) + os.system("mount --bind /dev {}/dev".format(temporary_directory)) # Create an fstab entry for each disk fstab_file = "{}/etc/fstab".format(temporary_directory) @@ -130,11 +130,11 @@ def install(**kwargs): options = "defaults,discard,noatime,nodiratime" # The root, var, and log volumes have specific values - if disk['mountpoint'] == "/": - root_disk['scsi_id'] = disk_id + if disk["mountpoint"] == "/": + root_disk["scsi_id"] = disk_id dump = 0 cpass = 1 - elif disk['mountpoint'] == '/var' or disk['mountpoint'] == '/var/log': + elif disk["mountpoint"] == "/var" or disk["mountpoint"] == "/var/log": dump = 0 cpass = 2 else: @@ -142,14 +142,14 @@ def install(**kwargs): cpass = 0 # Append the fstab line - with open(fstab_file, 'a') as fh: + with open(fstab_file, "a") as fh: data = "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi0-0-0-{disk} {mountpoint} {filesystem} {options} {dump} {cpass}\n".format( disk=disk_id, - mountpoint=disk['mountpoint'], - filesystem=disk['filesystem'], + mountpoint=disk["mountpoint"], + filesystem=disk["filesystem"], options=options, dump=dump, - cpass=cpass + cpass=cpass, ) fh.write(data) @@ -158,12 +158,14 @@ def install(**kwargs): # Write the hostname hostname_file = "{}/etc/hostname".format(temporary_directory) - with open(hostname_file, 'w') as fh: + with open(hostname_file, "w") as fh: fh.write("{}".format(vm_name)) # Fix the cloud-init.target since it's broken - cloudinit_target_file = "{}/etc/systemd/system/cloud-init.target".format(temporary_directory) - with open(cloudinit_target_file, 'w') as fh: + cloudinit_target_file = "{}/etc/systemd/system/cloud-init.target".format( + temporary_directory + ) + with open(cloudinit_target_file, "w") as fh: data = """[Install] WantedBy=multi-user.target [Unit] @@ -176,7 +178,7 @@ After=multi-user.target # will always be on PCI bus ID 2, hence the name "ens2". # Write a DHCP stanza for ens2 ens2_network_file = "{}/etc/network/interfaces.d/ens2".format(temporary_directory) - with open(ens2_network_file, 'w') as fh: + with open(ens2_network_file, "w") as fh: data = """auto ens2 iface ens2 inet dhcp """ @@ -184,25 +186,31 @@ iface ens2 inet dhcp # Write the DHCP config for ens2 dhclient_file = "{}/etc/dhcp/dhclient.conf".format(temporary_directory) - with open(dhclient_file, 'w') as fh: - data = """# DHCP client configuration + with open(dhclient_file, "w") as fh: + data = ( + """# DHCP client configuration # Written by the PVC provisioner option rfc3442-classless-static-routes code 121 = array of unsigned integer 8; interface "ens2" { -""" + """ send fqdn.fqdn = "{hostname}"; +""" + + """ send fqdn.fqdn = "{hostname}"; send host-name = "{hostname}"; -""".format(hostname=vm_name) + """ request subnet-mask, broadcast-address, time-offset, routers, +""".format( + hostname=vm_name + ) + + """ request subnet-mask, broadcast-address, time-offset, routers, domain-name, domain-name-servers, domain-search, host-name, dhcp6.name-servers, dhcp6.domain-search, dhcp6.fqdn, dhcp6.sntp-servers, netbios-name-servers, netbios-scope, interface-mtu, rfc3442-classless-static-routes, ntp-servers; } """ + ) fh.write(data) # Write the GRUB configuration grubcfg_file = "{}/etc/default/grub".format(temporary_directory) - with open(grubcfg_file, 'w') as fh: + with open(grubcfg_file, "w") as fh: data = """# Written by the PVC provisioner GRUB_DEFAULT=0 GRUB_TIMEOUT=1 @@ -212,35 +220,29 @@ GRUB_CMDLINE_LINUX="" GRUB_TERMINAL=console GRUB_SERIAL_COMMAND="serial --speed=115200 --unit=0 --word=8 --parity=no --stop=1" GRUB_DISABLE_LINUX_UUID=false -""".format(root_disk=root_disk['scsi_id']) +""".format( + root_disk=root_disk["scsi_id"] + ) fh.write(data) # Chroot, do some in-root tasks, then exit the chroot with chroot_target(temporary_directory): # Install and update GRUB os.system( - "grub-install --force /dev/rbd/{}/{}_{}".format(root_disk['pool'], vm_name, root_disk['disk_id']) - ) - os.system( - "update-grub" + "grub-install --force /dev/rbd/{}/{}_{}".format( + root_disk["pool"], vm_name, root_disk["disk_id"] + ) ) + os.system("update-grub") # Set a really dumb root password [TEMPORARY] - os.system( - "echo root:test123 | chpasswd" - ) + os.system("echo root:test123 | chpasswd") # Enable cloud-init target on (first) boot # NOTE: Your user-data should handle this and disable it once done, or things get messy. # That cloud-init won't run without this hack seems like a bug... but even the official # Debian cloud images are affected, so who knows. - os.system( - "systemctl enable cloud-init.target" - ) + os.system("systemctl enable cloud-init.target") # Unmount the bound devfs - os.system( - "umount {}/dev".format( - temporary_directory - ) - ) + os.system("umount {}/dev".format(temporary_directory)) # Everything else is done via cloud-init user-data diff --git a/api-daemon/provisioner/examples/dummy_script.py b/api-daemon/provisioner/examples/dummy_script.py index bb7bebb9..4a044585 100644 --- a/api-daemon/provisioner/examples/dummy_script.py +++ b/api-daemon/provisioner/examples/dummy_script.py @@ -35,9 +35,9 @@ def install(**kwargs): # The provisioner has already mounted the disks on kwargs['temporary_directory']. # by this point, so we can get right to running the debootstrap after setting # some nicer variable names; you don't necessarily have to do this. - vm_name = kwargs['vm_name'] - temporary_directory = kwargs['temporary_directory'] - disks = kwargs['disks'] - networks = kwargs['networks'] + vm_name = kwargs["vm_name"] + temporary_directory = kwargs["temporary_directory"] + disks = kwargs["disks"] + networks = kwargs["networks"] # No operation - this script just returns pass diff --git a/api-daemon/pvcapid-manage.py b/api-daemon/pvcapid-manage.py index 6916e938..21ca99b6 100755 --- a/api-daemon/pvcapid-manage.py +++ b/api-daemon/pvcapid-manage.py @@ -28,7 +28,7 @@ from pvcapid.models import * # noqa F401,F403 migrate = Migrate(app, db) manager = Manager(app) -manager.add_command('db', MigrateCommand) +manager.add_command("db", MigrateCommand) -if __name__ == '__main__': +if __name__ == "__main__": manager.run() diff --git a/api-daemon/pvcapid/Daemon.py b/api-daemon/pvcapid/Daemon.py index b2d7214a..6d18a0d7 100755 --- a/api-daemon/pvcapid/Daemon.py +++ b/api-daemon/pvcapid/Daemon.py @@ -25,7 +25,7 @@ import yaml from distutils.util import strtobool as dustrtobool # Daemon version -version = '0.9.42' +version = "0.9.42" # API version API_VERSION = 1.0 @@ -35,6 +35,7 @@ API_VERSION = 1.0 # Helper Functions ########################################################## + def strtobool(stringv): if stringv is None: return False @@ -52,54 +53,64 @@ def strtobool(stringv): # Parse the configuration file try: - pvcapid_config_file = os.environ['PVC_CONFIG_FILE'] + pvcapid_config_file = os.environ["PVC_CONFIG_FILE"] except Exception: - print('Error: The "PVC_CONFIG_FILE" environment variable must be set before starting pvcapid.') + print( + 'Error: The "PVC_CONFIG_FILE" environment variable must be set before starting pvcapid.' + ) exit(1) print('Loading configuration from file "{}"'.format(pvcapid_config_file)) # Read in the config try: - with open(pvcapid_config_file, 'r') as cfgfile: + with open(pvcapid_config_file, "r") as cfgfile: o_config = yaml.load(cfgfile, Loader=yaml.BaseLoader) except Exception as e: - print('ERROR: Failed to parse configuration file: {}'.format(e)) + print("ERROR: Failed to parse configuration file: {}".format(e)) exit(1) try: # Create the config object config = { - 'debug': strtobool(o_config['pvc']['debug']), - 'coordinators': o_config['pvc']['coordinators'], - 'listen_address': o_config['pvc']['api']['listen_address'], - 'listen_port': int(o_config['pvc']['api']['listen_port']), - 'auth_enabled': strtobool(o_config['pvc']['api']['authentication']['enabled']), - 'auth_secret_key': o_config['pvc']['api']['authentication']['secret_key'], - 'auth_tokens': o_config['pvc']['api']['authentication']['tokens'], - 'ssl_enabled': strtobool(o_config['pvc']['api']['ssl']['enabled']), - 'ssl_key_file': o_config['pvc']['api']['ssl']['key_file'], - 'ssl_cert_file': o_config['pvc']['api']['ssl']['cert_file'], - 'database_host': o_config['pvc']['provisioner']['database']['host'], - 'database_port': int(o_config['pvc']['provisioner']['database']['port']), - 'database_name': o_config['pvc']['provisioner']['database']['name'], - 'database_user': o_config['pvc']['provisioner']['database']['user'], - 'database_password': o_config['pvc']['provisioner']['database']['pass'], - 'queue_host': o_config['pvc']['provisioner']['queue']['host'], - 'queue_port': o_config['pvc']['provisioner']['queue']['port'], - 'queue_path': o_config['pvc']['provisioner']['queue']['path'], - 'storage_hosts': o_config['pvc']['provisioner']['ceph_cluster']['storage_hosts'], - 'storage_domain': o_config['pvc']['provisioner']['ceph_cluster']['storage_domain'], - 'ceph_monitor_port': o_config['pvc']['provisioner']['ceph_cluster']['ceph_monitor_port'], - 'ceph_storage_secret_uuid': o_config['pvc']['provisioner']['ceph_cluster']['ceph_storage_secret_uuid'] + "debug": strtobool(o_config["pvc"]["debug"]), + "coordinators": o_config["pvc"]["coordinators"], + "listen_address": o_config["pvc"]["api"]["listen_address"], + "listen_port": int(o_config["pvc"]["api"]["listen_port"]), + "auth_enabled": strtobool(o_config["pvc"]["api"]["authentication"]["enabled"]), + "auth_secret_key": o_config["pvc"]["api"]["authentication"]["secret_key"], + "auth_tokens": o_config["pvc"]["api"]["authentication"]["tokens"], + "ssl_enabled": strtobool(o_config["pvc"]["api"]["ssl"]["enabled"]), + "ssl_key_file": o_config["pvc"]["api"]["ssl"]["key_file"], + "ssl_cert_file": o_config["pvc"]["api"]["ssl"]["cert_file"], + "database_host": o_config["pvc"]["provisioner"]["database"]["host"], + "database_port": int(o_config["pvc"]["provisioner"]["database"]["port"]), + "database_name": o_config["pvc"]["provisioner"]["database"]["name"], + "database_user": o_config["pvc"]["provisioner"]["database"]["user"], + "database_password": o_config["pvc"]["provisioner"]["database"]["pass"], + "queue_host": o_config["pvc"]["provisioner"]["queue"]["host"], + "queue_port": o_config["pvc"]["provisioner"]["queue"]["port"], + "queue_path": o_config["pvc"]["provisioner"]["queue"]["path"], + "storage_hosts": o_config["pvc"]["provisioner"]["ceph_cluster"][ + "storage_hosts" + ], + "storage_domain": o_config["pvc"]["provisioner"]["ceph_cluster"][ + "storage_domain" + ], + "ceph_monitor_port": o_config["pvc"]["provisioner"]["ceph_cluster"][ + "ceph_monitor_port" + ], + "ceph_storage_secret_uuid": o_config["pvc"]["provisioner"]["ceph_cluster"][ + "ceph_storage_secret_uuid" + ], } # Use coordinators as storage hosts if not explicitly specified - if not config['storage_hosts']: - config['storage_hosts'] = config['coordinators'] + if not config["storage_hosts"]: + config["storage_hosts"] = config["coordinators"] except Exception as e: - print('ERROR: Failed to load configuration: {}'.format(e)) + print("ERROR: Failed to load configuration: {}".format(e)) exit(1) @@ -107,31 +118,41 @@ except Exception as e: # Entrypoint ########################################################## + def entrypoint(): import pvcapid.flaskapi as pvc_api # noqa: E402 - if config['ssl_enabled']: - context = (config['ssl_cert_file'], config['ssl_key_file']) + if config["ssl_enabled"]: + context = (config["ssl_cert_file"], config["ssl_key_file"]) else: context = None # Print our startup messages - print('') - print('|----------------------------------------------------------|') - print('| |') - print('| ███████████ ▜█▙ ▟█▛ █████ █ █ █ |') - print('| ██ ▜█▙ ▟█▛ ██ |') - print('| ███████████ ▜█▙ ▟█▛ ██ |') - print('| ██ ▜█▙▟█▛ ███████████ |') - print('| |') - print('|----------------------------------------------------------|') - print('| Parallel Virtual Cluster API daemon v{0: <19} |'.format(version)) - print('| Debug: {0: <49} |'.format(str(config['debug']))) - print('| API version: v{0: <42} |'.format(API_VERSION)) - print('| Listen: {0: <48} |'.format('{}:{}'.format(config['listen_address'], config['listen_port']))) - print('| SSL: {0: <51} |'.format(str(config['ssl_enabled']))) - print('| Authentication: {0: <40} |'.format(str(config['auth_enabled']))) - print('|----------------------------------------------------------|') - print('') + print("") + print("|----------------------------------------------------------|") + print("| |") + print("| ███████████ ▜█▙ ▟█▛ █████ █ █ █ |") + print("| ██ ▜█▙ ▟█▛ ██ |") + print("| ███████████ ▜█▙ ▟█▛ ██ |") + print("| ██ ▜█▙▟█▛ ███████████ |") + print("| |") + print("|----------------------------------------------------------|") + print("| Parallel Virtual Cluster API daemon v{0: <19} |".format(version)) + print("| Debug: {0: <49} |".format(str(config["debug"]))) + print("| API version: v{0: <42} |".format(API_VERSION)) + print( + "| Listen: {0: <48} |".format( + "{}:{}".format(config["listen_address"], config["listen_port"]) + ) + ) + print("| SSL: {0: <51} |".format(str(config["ssl_enabled"]))) + print("| Authentication: {0: <40} |".format(str(config["auth_enabled"]))) + print("|----------------------------------------------------------|") + print("") - pvc_api.app.run(config['listen_address'], config['listen_port'], threaded=True, ssl_context=context) + pvc_api.app.run( + config["listen_address"], + config["listen_port"], + threaded=True, + ssl_context=context, + ) diff --git a/api-daemon/pvcapid/benchmark.py b/api-daemon/pvcapid/benchmark.py index c54d800f..648f4a52 100755 --- a/api-daemon/pvcapid/benchmark.py +++ b/api-daemon/pvcapid/benchmark.py @@ -39,7 +39,10 @@ class BenchmarkError(Exception): """ An exception that results from the Benchmark job. """ - def __init__(self, message, job_name=None, db_conn=None, db_cur=None, zkhandler=None): + + def __init__( + self, message, job_name=None, db_conn=None, db_cur=None, zkhandler=None + ): self.message = message if job_name is not None: # Clean up our dangling result @@ -54,6 +57,7 @@ class BenchmarkError(Exception): def __str__(self): return str(self.message) + # # Common functions # @@ -62,11 +66,11 @@ class BenchmarkError(Exception): # Database connections def open_database(config): conn = psycopg2.connect( - host=config['database_host'], - port=config['database_port'], - dbname=config['database_name'], - user=config['database_user'], - password=config['database_password'] + host=config["database_host"], + port=config["database_port"], + dbname=config["database_name"], + user=config["database_user"], + password=config["database_password"], ) cur = conn.cursor(cursor_factory=psycopg2.extras.RealDictCursor) return conn, cur @@ -81,10 +85,10 @@ def close_database(conn, cur, failed=False): def list_benchmarks(job=None): if job is not None: - query = "SELECT * FROM {} WHERE job = %s;".format('storage_benchmarks') - args = (job, ) + query = "SELECT * FROM {} WHERE job = %s;".format("storage_benchmarks") + args = (job,) else: - query = "SELECT * FROM {} ORDER BY id DESC;".format('storage_benchmarks') + query = "SELECT * FROM {} ORDER BY id DESC;".format("storage_benchmarks") args = () conn, cur = open_database(config) @@ -93,23 +97,23 @@ def list_benchmarks(job=None): data = list() for benchmark in orig_data: benchmark_data = dict() - benchmark_data['id'] = benchmark['id'] - benchmark_data['job'] = benchmark['job'] - benchmark_data['test_format'] = benchmark['test_format'] - if benchmark['result'] == 'Running': - benchmark_data['benchmark_result'] = 'Running' + benchmark_data["id"] = benchmark["id"] + benchmark_data["job"] = benchmark["job"] + benchmark_data["test_format"] = benchmark["test_format"] + if benchmark["result"] == "Running": + benchmark_data["benchmark_result"] = "Running" else: try: - benchmark_data['benchmark_result'] = loads(benchmark['result']) + benchmark_data["benchmark_result"] = loads(benchmark["result"]) except Exception: - benchmark_data['benchmark_result'] = {} + benchmark_data["benchmark_result"] = {} # Append the new data to our actual output structure data.append(benchmark_data) close_database(conn, cur) if data: return data, 200 else: - return {'message': 'No benchmark found.'}, 404 + return {"message": "No benchmark found."}, 404 def run_benchmark(self, pool): @@ -126,46 +130,68 @@ def run_benchmark(self, pool): try: db_conn, db_cur = open_database(config) except Exception: - print('FATAL - failed to connect to Postgres') + print("FATAL - failed to connect to Postgres") raise Exception try: zkhandler = ZKHandler(config) zkhandler.connect() except Exception: - print('FATAL - failed to connect to Zookeeper') + print("FATAL - failed to connect to Zookeeper") raise Exception - cur_time = datetime.now().isoformat(timespec='seconds') - cur_primary = zkhandler.read('base.config.primary_node') - job_name = '{}_{}'.format(cur_time, cur_primary) + cur_time = datetime.now().isoformat(timespec="seconds") + cur_primary = zkhandler.read("base.config.primary_node") + job_name = "{}_{}".format(cur_time, cur_primary) print("Starting storage benchmark '{}' on pool '{}'".format(job_name, pool)) print("Storing running status for job '{}' in database".format(job_name)) try: query = "INSERT INTO storage_benchmarks (job, test_format, result) VALUES (%s, %s, %s);" - args = (job_name, TEST_FORMAT, "Running",) + args = ( + job_name, + TEST_FORMAT, + "Running", + ) db_cur.execute(query, args) db_conn.commit() except Exception as e: - raise BenchmarkError("Failed to store running status: {}".format(e), job_name=job_name, db_conn=db_conn, db_cur=db_cur, zkhandler=zkhandler) + raise BenchmarkError( + "Failed to store running status: {}".format(e), + job_name=job_name, + db_conn=db_conn, + db_cur=db_cur, + zkhandler=zkhandler, + ) # Phase 1 - volume preparation - self.update_state(state='RUNNING', meta={'current': 1, 'total': 3, 'status': 'Creating benchmark volume'}) + self.update_state( + state="RUNNING", + meta={"current": 1, "total": 3, "status": "Creating benchmark volume"}, + ) time.sleep(1) - volume = 'pvcbenchmark' + volume = "pvcbenchmark" # Create the RBD volume retcode, retmsg = pvc_ceph.add_volume(zkhandler, pool, volume, "8G") if not retcode: - raise BenchmarkError('Failed to create volume "{}": {}'.format(volume, retmsg), job_name=job_name, db_conn=db_conn, db_cur=db_cur, zkhandler=zkhandler) + raise BenchmarkError( + 'Failed to create volume "{}": {}'.format(volume, retmsg), + job_name=job_name, + db_conn=db_conn, + db_cur=db_cur, + zkhandler=zkhandler, + ) else: print(retmsg) # Phase 2 - benchmark run - self.update_state(state='RUNNING', meta={'current': 2, 'total': 3, 'status': 'Running fio benchmarks on volume'}) + self.update_state( + state="RUNNING", + meta={"current": 2, "total": 3, "status": "Running fio benchmarks on volume"}, + ) time.sleep(1) # We run a total of 8 tests, to give a generalized idea of performance on the cluster: @@ -180,53 +206,43 @@ def run_benchmark(self, pool): # Taken together, these 8 results should give a very good indication of the overall storage performance # for a variety of workloads. test_matrix = { - 'seq_read': { - 'direction': 'read', - 'iodepth': '64', - 'bs': '4M', - 'rw': 'read' + "seq_read": {"direction": "read", "iodepth": "64", "bs": "4M", "rw": "read"}, + "seq_write": {"direction": "write", "iodepth": "64", "bs": "4M", "rw": "write"}, + "rand_read_4M": { + "direction": "read", + "iodepth": "64", + "bs": "4M", + "rw": "randread", }, - 'seq_write': { - 'direction': 'write', - 'iodepth': '64', - 'bs': '4M', - 'rw': 'write' + "rand_write_4M": { + "direction": "write", + "iodepth": "64", + "bs": "4M", + "rw": "randwrite", }, - 'rand_read_4M': { - 'direction': 'read', - 'iodepth': '64', - 'bs': '4M', - 'rw': 'randread' + "rand_read_4K": { + "direction": "read", + "iodepth": "64", + "bs": "4K", + "rw": "randread", }, - 'rand_write_4M': { - 'direction': 'write', - 'iodepth': '64', - 'bs': '4M', - 'rw': 'randwrite' + "rand_write_4K": { + "direction": "write", + "iodepth": "64", + "bs": "4K", + "rw": "randwrite", }, - 'rand_read_4K': { - 'direction': 'read', - 'iodepth': '64', - 'bs': '4K', - 'rw': 'randread' + "rand_read_4K_lowdepth": { + "direction": "read", + "iodepth": "1", + "bs": "4K", + "rw": "randread", }, - 'rand_write_4K': { - 'direction': 'write', - 'iodepth': '64', - 'bs': '4K', - 'rw': 'randwrite' - }, - 'rand_read_4K_lowdepth': { - 'direction': 'read', - 'iodepth': '1', - 'bs': '4K', - 'rw': 'randread' - }, - 'rand_write_4K_lowdepth': { - 'direction': 'write', - 'iodepth': '1', - 'bs': '4K', - 'rw': 'randwrite' + "rand_write_4K_lowdepth": { + "direction": "write", + "iodepth": "1", + "bs": "4K", + "rw": "randwrite", }, } @@ -253,25 +269,41 @@ def run_benchmark(self, pool): test=test, pool=pool, volume=volume, - iodepth=test_matrix[test]['iodepth'], - bs=test_matrix[test]['bs'], - rw=test_matrix[test]['rw']) + iodepth=test_matrix[test]["iodepth"], + bs=test_matrix[test]["bs"], + rw=test_matrix[test]["rw"], + ) - print("Running fio job: {}".format(' '.join(fio_cmd.split()))) + print("Running fio job: {}".format(" ".join(fio_cmd.split()))) retcode, stdout, stderr = pvc_common.run_os_command(fio_cmd) if retcode: - raise BenchmarkError("Failed to run fio test: {}".format(stderr), job_name=job_name, db_conn=db_conn, db_cur=db_cur, zkhandler=zkhandler) + raise BenchmarkError( + "Failed to run fio test: {}".format(stderr), + job_name=job_name, + db_conn=db_conn, + db_cur=db_cur, + zkhandler=zkhandler, + ) results[test] = loads(stdout) # Phase 3 - cleanup - self.update_state(state='RUNNING', meta={'current': 3, 'total': 3, 'status': 'Cleaning up and storing results'}) + self.update_state( + state="RUNNING", + meta={"current": 3, "total": 3, "status": "Cleaning up and storing results"}, + ) time.sleep(1) # Remove the RBD volume retcode, retmsg = pvc_ceph.remove_volume(zkhandler, pool, volume) if not retcode: - raise BenchmarkError('Failed to remove volume "{}": {}'.format(volume, retmsg), job_name=job_name, db_conn=db_conn, db_cur=db_cur, zkhandler=zkhandler) + raise BenchmarkError( + 'Failed to remove volume "{}": {}'.format(volume, retmsg), + job_name=job_name, + db_conn=db_conn, + db_cur=db_cur, + zkhandler=zkhandler, + ) else: print(retmsg) @@ -282,10 +314,20 @@ def run_benchmark(self, pool): db_cur.execute(query, args) db_conn.commit() except Exception as e: - raise BenchmarkError("Failed to store test results: {}".format(e), job_name=job_name, db_conn=db_conn, db_cur=db_cur, zkhandler=zkhandler) + raise BenchmarkError( + "Failed to store test results: {}".format(e), + job_name=job_name, + db_conn=db_conn, + db_cur=db_cur, + zkhandler=zkhandler, + ) close_database(db_conn, db_cur) zkhandler.disconnect() del zkhandler - return {'status': "Storage benchmark '{}' completed successfully.", 'current': 3, 'total': 3} + return { + "status": "Storage benchmark '{}' completed successfully.", + "current": 3, + "total": 3, + } diff --git a/api-daemon/pvcapid/flaskapi.py b/api-daemon/pvcapid/flaskapi.py index e84c77ba..67811d64 100755 --- a/api-daemon/pvcapid/flaskapi.py +++ b/api-daemon/pvcapid/flaskapi.py @@ -37,31 +37,41 @@ from flask_sqlalchemy import SQLAlchemy # Create Flask app and set config values app = flask.Flask(__name__) -app.config['CELERY_BROKER_URL'] = 'redis://{}:{}{}'.format(config['queue_host'], config['queue_port'], config['queue_path']) -app.config['CELERY_RESULT_BACKEND'] = 'redis://{}:{}{}'.format(config['queue_host'], config['queue_port'], config['queue_path']) -app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False -app.config['SQLALCHEMY_DATABASE_URI'] = 'postgresql://{}:{}@{}:{}/{}'.format(config['database_user'], config['database_password'], config['database_host'], config['database_port'], config['database_name']) +app.config["CELERY_BROKER_URL"] = "redis://{}:{}{}".format( + config["queue_host"], config["queue_port"], config["queue_path"] +) +app.config["CELERY_RESULT_BACKEND"] = "redis://{}:{}{}".format( + config["queue_host"], config["queue_port"], config["queue_path"] +) +app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False +app.config["SQLALCHEMY_DATABASE_URI"] = "postgresql://{}:{}@{}:{}/{}".format( + config["database_user"], + config["database_password"], + config["database_host"], + config["database_port"], + config["database_name"], +) -if config['debug']: - app.config['DEBUG'] = True +if config["debug"]: + app.config["DEBUG"] = True else: - app.config['DEBUG'] = False + app.config["DEBUG"] = False -if config['auth_enabled']: - app.config["SECRET_KEY"] = config['auth_secret_key'] +if config["auth_enabled"]: + app.config["SECRET_KEY"] = config["auth_secret_key"] # Create SQLAlchemy database db = SQLAlchemy(app) # Create Flask blueprint -blueprint = flask.Blueprint('api', __name__, url_prefix='/api/v1') +blueprint = flask.Blueprint("api", __name__, url_prefix="/api/v1") # Create Flask-RESTful definition api = Api(blueprint) app.register_blueprint(blueprint) # Create celery definition -celery = Celery(app.name, broker=app.config['CELERY_BROKER_URL']) +celery = Celery(app.name, broker=app.config["CELERY_BROKER_URL"]) celery.conf.update(app.config) @@ -83,20 +93,21 @@ class RequestParser(object): parser = reqparse.RequestParser() # Parse and add each argument for reqarg in self.reqargs: - location = reqarg.get('location', None) + location = reqarg.get("location", None) if location is None: - location = ['args', 'form'] + location = ["args", "form"] parser.add_argument( - reqarg.get('name', None), - required=reqarg.get('required', False), - action=reqarg.get('action', None), - choices=reqarg.get('choices', ()), - help=reqarg.get('helptext', None), - location=location + reqarg.get("name", None), + required=reqarg.get("required", False), + action=reqarg.get("action", None), + choices=reqarg.get("choices", ()), + help=reqarg.get("helptext", None), + location=location, ) reqargs = parser.parse_args() - kwargs['reqargs'] = reqargs + kwargs["reqargs"] = reqargs return function(*args, **kwargs) + return wrapped_function @@ -105,19 +116,24 @@ def Authenticator(function): @wraps(function) def authenticate(*args, **kwargs): # No authentication required - if not config['auth_enabled']: + if not config["auth_enabled"]: return function(*args, **kwargs) # Session-based authentication - if 'token' in flask.session: + if "token" in flask.session: return function(*args, **kwargs) # Key header-based authentication - if 'X-Api-Key' in flask.request.headers: - if any(token for token in config['auth_tokens'] if flask.request.headers.get('X-Api-Key') == token.get('token')): + if "X-Api-Key" in flask.request.headers: + if any( + token + for token in config["auth_tokens"] + if flask.request.headers.get("X-Api-Key") == token.get("token") + ): return function(*args, **kwargs) else: return {"message": "X-Api-Key Authentication failed."}, 401 # All authentications failed return {"message": "X-Api-Key Authentication required."}, 401 + return authenticate @@ -125,8 +141,17 @@ def Authenticator(function): # Job functions # @celery.task(bind=True) -def create_vm(self, vm_name, profile_name, define_vm=True, start_vm=True, script_run_args=[]): - return api_provisioner.create_vm(self, vm_name, profile_name, define_vm=define_vm, start_vm=start_vm, script_run_args=script_run_args) +def create_vm( + self, vm_name, profile_name, define_vm=True, start_vm=True, script_run_args=[] +): + return api_provisioner.create_vm( + self, + vm_name, + profile_name, + define_vm=define_vm, + start_vm=start_vm, + script_run_args=script_run_args, + ) @celery.task(bind=True) @@ -161,7 +186,7 @@ class API_Root(Resource): return {"message": "PVC API version {}".format(API_VERSION)} -api.add_resource(API_Root, '/') +api.add_resource(API_Root, "/") # /doc - NOTE: Until flask_swagger is packaged for Debian this must be disabled @@ -217,17 +242,21 @@ class API_Login(Resource): type: object id: Message """ - if not config['auth_enabled']: + if not config["auth_enabled"]: return flask.redirect(Api.url_for(api, API_Root)) - if any(token for token in config['auth_tokens'] if flask.request.values['token'] in token['token']): - flask.session['token'] = flask.request.form['token'] + if any( + token + for token in config["auth_tokens"] + if flask.request.values["token"] in token["token"] + ): + flask.session["token"] = flask.request.form["token"] return {"message": "Authentication successful"}, 200 else: {"message": "Authentication failed"}, 401 -api.add_resource(API_Login, '/login') +api.add_resource(API_Login, "/login") # /logout @@ -247,22 +276,28 @@ class API_Logout(Resource): 302: description: Authentication disabled """ - if not config['auth_enabled']: + if not config["auth_enabled"]: return flask.redirect(Api.url_for(api, API_Root)) - flask.session.pop('token', None) + flask.session.pop("token", None) return {"message": "Deauthentication successful"}, 200 -api.add_resource(API_Logout, '/logout') +api.add_resource(API_Logout, "/logout") # /initialize class API_Initialize(Resource): - @RequestParser([ - {'name': 'overwrite', 'required': False}, - {'name': 'yes-i-really-mean-it', 'required': True, 'helptext': "Initialization is destructive; please confirm with the argument 'yes-i-really-mean-it'."}, - ]) + @RequestParser( + [ + {"name": "overwrite", "required": False}, + { + "name": "yes-i-really-mean-it", + "required": True, + "helptext": "Initialization is destructive; please confirm with the argument 'yes-i-really-mean-it'.", + }, + ] + ) @Authenticator def post(self, reqargs): """ @@ -299,7 +334,7 @@ class API_Initialize(Resource): 400: description: Bad request """ - if reqargs.get('overwrite', 'False') == 'True': + if reqargs.get("overwrite", "False") == "True": overwrite_flag = True else: overwrite_flag = False @@ -307,7 +342,7 @@ class API_Initialize(Resource): return api_helper.initialize_cluster(overwrite=overwrite_flag) -api.add_resource(API_Initialize, '/initialize') +api.add_resource(API_Initialize, "/initialize") # /backup @@ -331,15 +366,25 @@ class API_Backup(Resource): return api_helper.backup_cluster() -api.add_resource(API_Backup, '/backup') +api.add_resource(API_Backup, "/backup") # /restore class API_Restore(Resource): - @RequestParser([ - {'name': 'yes-i-really-mean-it', 'required': True, 'helptext': "Restore is destructive; please confirm with the argument 'yes-i-really-mean-it'."}, - {'name': 'cluster_data', 'required': True, 'helptext': "A cluster JSON backup must be provided."} - ]) + @RequestParser( + [ + { + "name": "yes-i-really-mean-it", + "required": True, + "helptext": "Restore is destructive; please confirm with the argument 'yes-i-really-mean-it'.", + }, + { + "name": "cluster_data", + "required": True, + "helptext": "A cluster JSON backup must be provided.", + }, + ] + ) @Authenticator def post(self, reqargs): """ @@ -376,14 +421,14 @@ class API_Restore(Resource): id: Message """ try: - cluster_data = reqargs.get('cluster_data') + cluster_data = reqargs.get("cluster_data") except Exception as e: return {"message": "Failed to load JSON backup: {}.".format(e)}, 400 return api_helper.restore_cluster(cluster_data) -api.add_resource(API_Restore, '/restore') +api.add_resource(API_Restore, "/restore") # /status @@ -465,9 +510,16 @@ class API_Status(Resource): """ return api_helper.cluster_status() - @RequestParser([ - {'name': 'state', 'choices': ('true', 'false'), 'required': True, 'helptext': "A valid state must be specified."} - ]) + @RequestParser( + [ + { + "name": "state", + "choices": ("true", "false"), + "required": True, + "helptext": "A valid state must be specified.", + } + ] + ) @Authenticator def post(self, reqargs): """ @@ -493,10 +545,10 @@ class API_Status(Resource): type: object id: Message """ - return api_helper.cluster_maintenance(reqargs.get('state', 'false')) + return api_helper.cluster_maintenance(reqargs.get("state", "false")) -api.add_resource(API_Status, '/status') +api.add_resource(API_Status, "/status") ########################################################## @@ -505,12 +557,14 @@ api.add_resource(API_Status, '/status') # /node class API_Node_Root(Resource): - @RequestParser([ - {'name': 'limit'}, - {'name': 'daemon_state'}, - {'name': 'coordinator_state'}, - {'name': 'domain_state'} - ]) + @RequestParser( + [ + {"name": "limit"}, + {"name": "daemon_state"}, + {"name": "coordinator_state"}, + {"name": "domain_state"}, + ] + ) @Authenticator def get(self, reqargs): """ @@ -617,14 +671,14 @@ class API_Node_Root(Resource): $ref: '#/definitions/node' """ return api_helper.node_list( - limit=reqargs.get('limit', None), - daemon_state=reqargs.get('daemon_state', None), - coordinator_state=reqargs.get('coordinator_state', None), - domain_state=reqargs.get('domain_state', None) + limit=reqargs.get("limit", None), + daemon_state=reqargs.get("daemon_state", None), + coordinator_state=reqargs.get("coordinator_state", None), + domain_state=reqargs.get("domain_state", None), ) -api.add_resource(API_Node_Root, '/node') +api.add_resource(API_Node_Root, "/node") # /node/ @@ -650,7 +704,7 @@ class API_Node_Element(Resource): return api_helper.node_list(node, is_fuzzy=False) -api.add_resource(API_Node_Element, '/node/') +api.add_resource(API_Node_Element, "/node/") # /node//daemon-state @@ -684,7 +738,7 @@ class API_Node_DaemonState(Resource): return api_helper.node_daemon_state(node) -api.add_resource(API_Node_DaemonState, '/node//daemon-state') +api.add_resource(API_Node_DaemonState, "/node//daemon-state") # /node//coordinator-state @@ -717,9 +771,16 @@ class API_Node_CoordinatorState(Resource): """ return api_helper.node_coordinator_state(node) - @RequestParser([ - {'name': 'state', 'choices': ('primary', 'secondary'), 'helptext': "A valid state must be specified", 'required': True} - ]) + @RequestParser( + [ + { + "name": "state", + "choices": ("primary", "secondary"), + "helptext": "A valid state must be specified", + "required": True, + } + ] + ) @Authenticator def post(self, node, reqargs): """ @@ -748,14 +809,14 @@ class API_Node_CoordinatorState(Resource): type: object id: Message """ - if reqargs['state'] == 'primary': + if reqargs["state"] == "primary": return api_helper.node_primary(node) - if reqargs['state'] == 'secondary': + if reqargs["state"] == "secondary": return api_helper.node_secondary(node) abort(400) -api.add_resource(API_Node_CoordinatorState, '/node//coordinator-state') +api.add_resource(API_Node_CoordinatorState, "/node//coordinator-state") # /node//domain-state @@ -788,10 +849,17 @@ class API_Node_DomainState(Resource): """ return api_helper.node_domain_state(node) - @RequestParser([ - {'name': 'state', 'choices': ('ready', 'flush'), 'helptext': "A valid state must be specified", 'required': True}, - {'name': 'wait'} - ]) + @RequestParser( + [ + { + "name": "state", + "choices": ("ready", "flush"), + "helptext": "A valid state must be specified", + "required": True, + }, + {"name": "wait"}, + ] + ) @Authenticator def post(self, node, reqargs): """ @@ -824,21 +892,23 @@ class API_Node_DomainState(Resource): type: object id: Message """ - if reqargs['state'] == 'flush': - return api_helper.node_flush(node, bool(strtobool(reqargs.get('wait', 'false')))) - if reqargs['state'] == 'ready': - return api_helper.node_ready(node, bool(strtobool(reqargs.get('wait', 'false')))) + if reqargs["state"] == "flush": + return api_helper.node_flush( + node, bool(strtobool(reqargs.get("wait", "false"))) + ) + if reqargs["state"] == "ready": + return api_helper.node_ready( + node, bool(strtobool(reqargs.get("wait", "false"))) + ) abort(400) -api.add_resource(API_Node_DomainState, '/node//domain-state') +api.add_resource(API_Node_DomainState, "/node//domain-state") # /node//log') +api.add_resource(API_Node_Log, "/node//log") ########################################################## @@ -886,13 +953,15 @@ api.add_resource(API_Node_Log, '/node//log') # /vm class API_VM_Root(Resource): - @RequestParser([ - {'name': 'limit'}, - {'name': 'node'}, - {'name': 'state'}, - {'name': 'tag'}, - {'name': 'negate'}, - ]) + @RequestParser( + [ + {"name": "limit"}, + {"name": "node"}, + {"name": "state"}, + {"name": "tag"}, + {"name": "negate"}, + ] + ) @Authenticator def get(self, reqargs): """ @@ -1170,23 +1239,37 @@ class API_VM_Root(Resource): $ref: '#/definitions/vm' """ return api_helper.vm_list( - node=reqargs.get('node', None), - state=reqargs.get('state', None), - tag=reqargs.get('tag', None), - limit=reqargs.get('limit', None), - negate=bool(strtobool(reqargs.get('negate', 'False'))), + node=reqargs.get("node", None), + state=reqargs.get("state", None), + tag=reqargs.get("tag", None), + limit=reqargs.get("limit", None), + negate=bool(strtobool(reqargs.get("negate", "False"))), ) - @RequestParser([ - {'name': 'limit'}, - {'name': 'node'}, - {'name': 'selector', 'choices': ('mem', 'vcpus', 'load', 'vms', 'none'), 'helptext': "A valid selector must be specified"}, - {'name': 'autostart'}, - {'name': 'migration_method', 'choices': ('live', 'shutdown', 'none'), 'helptext': "A valid migration_method must be specified"}, - {'name': 'user_tags', 'action': 'append'}, - {'name': 'protected_tags', 'action': 'append'}, - {'name': 'xml', 'required': True, 'helptext': "A Libvirt XML document must be specified"}, - ]) + @RequestParser( + [ + {"name": "limit"}, + {"name": "node"}, + { + "name": "selector", + "choices": ("mem", "vcpus", "load", "vms", "none"), + "helptext": "A valid selector must be specified", + }, + {"name": "autostart"}, + { + "name": "migration_method", + "choices": ("live", "shutdown", "none"), + "helptext": "A valid migration_method must be specified", + }, + {"name": "user_tags", "action": "append"}, + {"name": "protected_tags", "action": "append"}, + { + "name": "xml", + "required": True, + "helptext": "A Libvirt XML document must be specified", + }, + ] + ) @Authenticator def post(self, reqargs): """ @@ -1262,26 +1345,26 @@ class API_VM_Root(Resource): type: object id: Message """ - user_tags = reqargs.get('user_tags', None) + user_tags = reqargs.get("user_tags", None) if user_tags is None: user_tags = [] - protected_tags = reqargs.get('protected_tags', None) + protected_tags = reqargs.get("protected_tags", None) if protected_tags is None: protected_tags = [] return api_helper.vm_define( - reqargs.get('xml'), - reqargs.get('node', None), - reqargs.get('limit', None), - reqargs.get('selector', 'none'), - bool(strtobool(reqargs.get('autostart', 'false'))), - reqargs.get('migration_method', 'none'), + reqargs.get("xml"), + reqargs.get("node", None), + reqargs.get("limit", None), + reqargs.get("selector", "none"), + bool(strtobool(reqargs.get("autostart", "false"))), + reqargs.get("migration_method", "none"), user_tags, - protected_tags + protected_tags, ) -api.add_resource(API_VM_Root, '/vm') +api.add_resource(API_VM_Root, "/vm") # /vm/ @@ -1304,18 +1387,34 @@ class API_VM_Element(Resource): type: object id: Message """ - return api_helper.vm_list(node=None, state=None, tag=None, limit=vm, is_fuzzy=False, negate=False) + return api_helper.vm_list( + node=None, state=None, tag=None, limit=vm, is_fuzzy=False, negate=False + ) - @RequestParser([ - {'name': 'limit'}, - {'name': 'node'}, - {'name': 'selector', 'choices': ('mem', 'vcpus', 'load', 'vms', 'none'), 'helptext': "A valid selector must be specified"}, - {'name': 'autostart'}, - {'name': 'migration_method', 'choices': ('live', 'shutdown', 'none'), 'helptext': "A valid migration_method must be specified"}, - {'name': 'user_tags', 'action': 'append'}, - {'name': 'protected_tags', 'action': 'append'}, - {'name': 'xml', 'required': True, 'helptext': "A Libvirt XML document must be specified"}, - ]) + @RequestParser( + [ + {"name": "limit"}, + {"name": "node"}, + { + "name": "selector", + "choices": ("mem", "vcpus", "load", "vms", "none"), + "helptext": "A valid selector must be specified", + }, + {"name": "autostart"}, + { + "name": "migration_method", + "choices": ("live", "shutdown", "none"), + "helptext": "A valid migration_method must be specified", + }, + {"name": "user_tags", "action": "append"}, + {"name": "protected_tags", "action": "append"}, + { + "name": "xml", + "required": True, + "helptext": "A Libvirt XML document must be specified", + }, + ] + ) @Authenticator def post(self, vm, reqargs): """ @@ -1394,28 +1493,34 @@ class API_VM_Element(Resource): type: object id: Message """ - user_tags = reqargs.get('user_tags', None) + user_tags = reqargs.get("user_tags", None) if user_tags is None: user_tags = [] - protected_tags = reqargs.get('protected_tags', None) + protected_tags = reqargs.get("protected_tags", None) if protected_tags is None: protected_tags = [] return api_helper.vm_define( - reqargs.get('xml'), - reqargs.get('node', None), - reqargs.get('limit', None), - reqargs.get('selector', 'none'), - bool(strtobool(reqargs.get('autostart', 'false'))), - reqargs.get('migration_method', 'none'), + reqargs.get("xml"), + reqargs.get("node", None), + reqargs.get("limit", None), + reqargs.get("selector", "none"), + bool(strtobool(reqargs.get("autostart", "false"))), + reqargs.get("migration_method", "none"), user_tags, - protected_tags + protected_tags, ) - @RequestParser([ - {'name': 'restart'}, - {'name': 'xml', 'required': True, 'helptext': "A Libvirt XML document must be specified"}, - ]) + @RequestParser( + [ + {"name": "restart"}, + { + "name": "xml", + "required": True, + "helptext": "A Libvirt XML document must be specified", + }, + ] + ) @Authenticator def put(self, vm, reqargs): """ @@ -1447,13 +1552,15 @@ class API_VM_Element(Resource): """ return api_helper.vm_modify( vm, - bool(strtobool(reqargs.get('restart', 'false'))), - reqargs.get('xml', None) + bool(strtobool(reqargs.get("restart", "false"))), + reqargs.get("xml", None), ) - @RequestParser([ - {'name': 'delete_disks'}, - ]) + @RequestParser( + [ + {"name": "delete_disks"}, + ] + ) @Authenticator def delete(self, vm, reqargs): """ @@ -1484,13 +1591,13 @@ class API_VM_Element(Resource): type: object id: Message """ - if bool(strtobool(reqargs.get('delete_disks', 'false'))): + if bool(strtobool(reqargs.get("delete_disks", "false"))): return api_helper.vm_remove(vm) else: return api_helper.vm_undefine(vm) -api.add_resource(API_VM_Element, '/vm/') +api.add_resource(API_VM_Element, "/vm/") # /vm//meta @@ -1534,13 +1641,23 @@ class API_VM_Metadata(Resource): """ return api_helper.get_vm_meta(vm) - @RequestParser([ - {'name': 'limit'}, - {'name': 'selector', 'choices': ('mem', 'vcpus', 'load', 'vms', 'none'), 'helptext': "A valid selector must be specified"}, - {'name': 'autostart'}, - {'name': 'profile'}, - {'name': 'migration_method', 'choices': ('live', 'shutdown', 'none'), 'helptext': "A valid migration_method must be specified"}, - ]) + @RequestParser( + [ + {"name": "limit"}, + { + "name": "selector", + "choices": ("mem", "vcpus", "load", "vms", "none"), + "helptext": "A valid selector must be specified", + }, + {"name": "autostart"}, + {"name": "profile"}, + { + "name": "migration_method", + "choices": ("live", "shutdown", "none"), + "helptext": "A valid migration_method must be specified", + }, + ] + ) @Authenticator def post(self, vm, reqargs): """ @@ -1603,15 +1720,15 @@ class API_VM_Metadata(Resource): """ return api_helper.update_vm_meta( vm, - reqargs.get('limit', None), - reqargs.get('selector', None), - reqargs.get('autostart', None), - reqargs.get('profile', None), - reqargs.get('migration_method', None) + reqargs.get("limit", None), + reqargs.get("selector", None), + reqargs.get("autostart", None), + reqargs.get("profile", None), + reqargs.get("migration_method", None), ) -api.add_resource(API_VM_Metadata, '/vm//meta') +api.add_resource(API_VM_Metadata, "/vm//meta") # /vm//tags @@ -1647,11 +1764,17 @@ class API_VM_Tags(Resource): """ return api_helper.get_vm_tags(vm) - @RequestParser([ - {'name': 'action', 'choices': ('add', 'remove'), 'helptext': "A valid action must be specified"}, - {'name': 'tag'}, - {'name': 'protected'} - ]) + @RequestParser( + [ + { + "name": "action", + "choices": ("add", "remove"), + "helptext": "A valid action must be specified", + }, + {"name": "tag"}, + {"name": "protected"}, + ] + ) @Authenticator def post(self, vm, reqargs): """ @@ -1698,13 +1821,13 @@ class API_VM_Tags(Resource): """ return api_helper.update_vm_tag( vm, - reqargs.get('action'), - reqargs.get('tag'), - reqargs.get('protected', False) + reqargs.get("action"), + reqargs.get("tag"), + reqargs.get("protected", False), ) -api.add_resource(API_VM_Tags, '/vm//tags') +api.add_resource(API_VM_Tags, "/vm//tags") # /vm//state') +api.add_resource(API_VM_State, "/vm//state") # /vm//node @@ -1828,13 +1958,20 @@ class API_VM_Node(Resource): """ return api_helper.vm_node(vm) - @RequestParser([ - {'name': 'action', 'choices': ('migrate', 'unmigrate', 'move'), 'helptext': "A valid action must be specified", 'required': True}, - {'name': 'node'}, - {'name': 'force'}, - {'name': 'wait'}, - {'name': 'force_live'} - ]) + @RequestParser( + [ + { + "name": "action", + "choices": ("migrate", "unmigrate", "move"), + "helptext": "A valid action must be specified", + "required": True, + }, + {"name": "node"}, + {"name": "force"}, + {"name": "wait"}, + {"name": "force_live"}, + ] + ) @Authenticator def post(self, vm, reqargs): """ @@ -1880,22 +2017,22 @@ class API_VM_Node(Resource): type: object id: Message """ - action = reqargs.get('action', None) - node = reqargs.get('node', None) - force = bool(strtobool(reqargs.get('force', 'false'))) - wait = bool(strtobool(reqargs.get('wait', 'false'))) - force_live = bool(strtobool(reqargs.get('force_live', 'false'))) + action = reqargs.get("action", None) + node = reqargs.get("node", None) + force = bool(strtobool(reqargs.get("force", "false"))) + wait = bool(strtobool(reqargs.get("wait", "false"))) + force_live = bool(strtobool(reqargs.get("force_live", "false"))) - if action == 'move': + if action == "move": return api_helper.vm_move(vm, node, wait, force_live) - if action == 'migrate': + if action == "migrate": return api_helper.vm_migrate(vm, node, force, wait, force_live) - if action == 'unmigrate': + if action == "unmigrate": return api_helper.vm_unmigrate(vm, wait, force_live) abort(400) -api.add_resource(API_VM_Node, '/vm//node') +api.add_resource(API_VM_Node, "/vm//node") # /vm//locks @@ -1922,14 +2059,12 @@ class API_VM_Locks(Resource): return api_helper.vm_flush_locks(vm) -api.add_resource(API_VM_Locks, '/vm//locks') +api.add_resource(API_VM_Locks, "/vm//locks") # /vm//console') +api.add_resource(API_VM_Console, "/vm//console") # /vm//rename class API_VM_Rename(Resource): - @RequestParser([ - {'name': 'new_name'} - ]) + @RequestParser([{"name": "new_name"}]) @Authenticator def post(self, vm, reqargs): """ @@ -2001,20 +2131,23 @@ class API_VM_Rename(Resource): type: object id: Message """ - return api_helper.vm_rename( - vm, - reqargs.get('new_name', None) - ) + return api_helper.vm_rename(vm, reqargs.get("new_name", None)) -api.add_resource(API_VM_Rename, '/vm//rename') +api.add_resource(API_VM_Rename, "/vm//rename") # /vm//device class API_VM_Device(Resource): - @RequestParser([ - {'name': 'xml', 'required': True, 'helptext': "A Libvirt XML device document must be specified"}, - ]) + @RequestParser( + [ + { + "name": "xml", + "required": True, + "helptext": "A Libvirt XML device document must be specified", + }, + ] + ) @Authenticator def post(self, vm, reqargs): """ @@ -2040,11 +2173,17 @@ class API_VM_Device(Resource): type: object id: Message """ - return api_helper.vm_attach_device(vm, reqargs.get('xml', None)) + return api_helper.vm_attach_device(vm, reqargs.get("xml", None)) - @RequestParser([ - {'name': 'xml', 'required': True, 'helptext': "A Libvirt XML device document must be specified"}, - ]) + @RequestParser( + [ + { + "name": "xml", + "required": True, + "helptext": "A Libvirt XML device document must be specified", + }, + ] + ) @Authenticator def delete(self, vm, reqargs): """ @@ -2070,10 +2209,10 @@ class API_VM_Device(Resource): type: object id: Message """ - return api_helper.vm_detach_device(vm, reqargs.get('xml', None)) + return api_helper.vm_detach_device(vm, reqargs.get("xml", None)) -api.add_resource(API_VM_Device, '/vm//device') +api.add_resource(API_VM_Device, "/vm//device") ########################################################## @@ -2082,9 +2221,7 @@ api.add_resource(API_VM_Device, '/vm//device') # /network class API_Network_Root(Resource): - @RequestParser([ - {'name': 'limit'} - ]) + @RequestParser([{"name": "limit"}]) @Authenticator def get(self, reqargs): """ @@ -2166,23 +2303,30 @@ class API_Network_Root(Resource): items: $ref: '#/definitions/network' """ - return api_helper.net_list(reqargs.get('limit', None)) + return api_helper.net_list(reqargs.get("limit", None)) - @RequestParser([ - {'name': 'vni', 'required': True}, - {'name': 'description', 'required': True}, - {'name': 'nettype', 'choices': ('managed', 'bridged'), 'helptext': 'A valid nettype must be specified', 'required': True}, - {'name': 'mtu'}, - {'name': 'domain'}, - {'name': 'name_servers'}, - {'name': 'ip4_network'}, - {'name': 'ip4_gateway'}, - {'name': 'ip6_network'}, - {'name': 'ip6_gateway'}, - {'name': 'dhcp4'}, - {'name': 'dhcp4_start'}, - {'name': 'dhcp4_end'} - ]) + @RequestParser( + [ + {"name": "vni", "required": True}, + {"name": "description", "required": True}, + { + "name": "nettype", + "choices": ("managed", "bridged"), + "helptext": "A valid nettype must be specified", + "required": True, + }, + {"name": "mtu"}, + {"name": "domain"}, + {"name": "name_servers"}, + {"name": "ip4_network"}, + {"name": "ip4_gateway"}, + {"name": "ip6_network"}, + {"name": "ip6_gateway"}, + {"name": "dhcp4"}, + {"name": "dhcp4_start"}, + {"name": "dhcp4_end"}, + ] + ) @Authenticator def post(self, reqargs): """ @@ -2261,28 +2405,28 @@ class API_Network_Root(Resource): type: object id: Message """ - if reqargs.get('name_servers', None): - name_servers = ','.join(reqargs.get('name_servers', None)) + if reqargs.get("name_servers", None): + name_servers = ",".join(reqargs.get("name_servers", None)) else: - name_servers = '' + name_servers = "" return api_helper.net_add( - reqargs.get('vni', None), - reqargs.get('description', None), - reqargs.get('nettype', None), - reqargs.get('mtu', ''), - reqargs.get('domain', None), + reqargs.get("vni", None), + reqargs.get("description", None), + reqargs.get("nettype", None), + reqargs.get("mtu", ""), + reqargs.get("domain", None), name_servers, - reqargs.get('ip4_network', None), - reqargs.get('ip4_gateway', None), - reqargs.get('ip6_network', None), - reqargs.get('ip6_gateway', None), - bool(strtobool(reqargs.get('dhcp4', 'false'))), - reqargs.get('dhcp4_start', None), - reqargs.get('dhcp4_end', None), + reqargs.get("ip4_network", None), + reqargs.get("ip4_gateway", None), + reqargs.get("ip6_network", None), + reqargs.get("ip6_gateway", None), + bool(strtobool(reqargs.get("dhcp4", "false"))), + reqargs.get("dhcp4_start", None), + reqargs.get("dhcp4_end", None), ) -api.add_resource(API_Network_Root, '/network') +api.add_resource(API_Network_Root, "/network") # /network/ @@ -2307,20 +2451,27 @@ class API_Network_Element(Resource): """ return api_helper.net_list(vni, is_fuzzy=False) - @RequestParser([ - {'name': 'description', 'required': True}, - {'name': 'nettype', 'choices': ('managed', 'bridged'), 'helptext': 'A valid nettype must be specified', 'required': True}, - {'name': 'mtu'}, - {'name': 'domain'}, - {'name': 'name_servers'}, - {'name': 'ip4_network'}, - {'name': 'ip4_gateway'}, - {'name': 'ip6_network'}, - {'name': 'ip6_gateway'}, - {'name': 'dhcp4'}, - {'name': 'dhcp4_start'}, - {'name': 'dhcp4_end'} - ]) + @RequestParser( + [ + {"name": "description", "required": True}, + { + "name": "nettype", + "choices": ("managed", "bridged"), + "helptext": "A valid nettype must be specified", + "required": True, + }, + {"name": "mtu"}, + {"name": "domain"}, + {"name": "name_servers"}, + {"name": "ip4_network"}, + {"name": "ip4_gateway"}, + {"name": "ip6_network"}, + {"name": "ip6_gateway"}, + {"name": "dhcp4"}, + {"name": "dhcp4_start"}, + {"name": "dhcp4_end"}, + ] + ) @Authenticator def post(self, vni, reqargs): """ @@ -2394,39 +2545,41 @@ class API_Network_Element(Resource): type: object id: Message """ - if reqargs.get('name_servers', None): - name_servers = ','.join(reqargs.get('name_servers', None)) + if reqargs.get("name_servers", None): + name_servers = ",".join(reqargs.get("name_servers", None)) else: - name_servers = '' + name_servers = "" return api_helper.net_add( - reqargs.get('vni', None), - reqargs.get('description', None), - reqargs.get('nettype', None), - reqargs.get('mtu', ''), - reqargs.get('domain', None), + reqargs.get("vni", None), + reqargs.get("description", None), + reqargs.get("nettype", None), + reqargs.get("mtu", ""), + reqargs.get("domain", None), name_servers, - reqargs.get('ip4_network', None), - reqargs.get('ip4_gateway', None), - reqargs.get('ip6_network', None), - reqargs.get('ip6_gateway', None), - bool(strtobool(reqargs.get('dhcp4', 'false'))), - reqargs.get('dhcp4_start', None), - reqargs.get('dhcp4_end', None), + reqargs.get("ip4_network", None), + reqargs.get("ip4_gateway", None), + reqargs.get("ip6_network", None), + reqargs.get("ip6_gateway", None), + bool(strtobool(reqargs.get("dhcp4", "false"))), + reqargs.get("dhcp4_start", None), + reqargs.get("dhcp4_end", None), ) - @RequestParser([ - {'name': 'description'}, - {'name': 'mtu'}, - {'name': 'domain'}, - {'name': 'name_servers'}, - {'name': 'ip4_network'}, - {'name': 'ip4_gateway'}, - {'name': 'ip6_network'}, - {'name': 'ip6_gateway'}, - {'name': 'dhcp4'}, - {'name': 'dhcp4_start'}, - {'name': 'dhcp4_end'} - ]) + @RequestParser( + [ + {"name": "description"}, + {"name": "mtu"}, + {"name": "domain"}, + {"name": "name_servers"}, + {"name": "ip4_network"}, + {"name": "ip4_gateway"}, + {"name": "ip6_network"}, + {"name": "ip6_gateway"}, + {"name": "dhcp4"}, + {"name": "dhcp4_start"}, + {"name": "dhcp4_end"}, + ] + ) @Authenticator def put(self, vni, reqargs): """ @@ -2497,23 +2650,23 @@ class API_Network_Element(Resource): type: object id: Message """ - if reqargs.get('name_servers', None): - name_servers = ','.join(reqargs.get('name_servers', None)) + if reqargs.get("name_servers", None): + name_servers = ",".join(reqargs.get("name_servers", None)) else: - name_servers = '' + name_servers = "" return api_helper.net_modify( vni, - reqargs.get('description', None), - reqargs.get('mtu', None), - reqargs.get('domain', None), + reqargs.get("description", None), + reqargs.get("mtu", None), + reqargs.get("domain", None), name_servers, - reqargs.get('ip4_network', None), - reqargs.get('ip4_gateway', None), - reqargs.get('ip6_network', None), - reqargs.get('ip6_gateway', None), - reqargs.get('dhcp4', None), - reqargs.get('dhcp4_start', None), - reqargs.get('dhcp4_end', None), + reqargs.get("ip4_network", None), + reqargs.get("ip4_gateway", None), + reqargs.get("ip6_network", None), + reqargs.get("ip6_gateway", None), + reqargs.get("dhcp4", None), + reqargs.get("dhcp4_start", None), + reqargs.get("dhcp4_end", None), ) @Authenticator @@ -2543,15 +2696,12 @@ class API_Network_Element(Resource): return api_helper.net_remove(vni) -api.add_resource(API_Network_Element, '/network/') +api.add_resource(API_Network_Element, "/network/") # /network//lease class API_Network_Lease_Root(Resource): - @RequestParser([ - {'name': 'limit'}, - {'name': 'static'} - ]) + @RequestParser([{"name": "limit"}, {"name": "static"}]) @Authenticator def get(self, vni, reqargs): """ @@ -2608,15 +2758,17 @@ class API_Network_Lease_Root(Resource): """ return api_helper.net_dhcp_list( vni, - reqargs.get('limit', None), - bool(strtobool(reqargs.get('static', 'false'))) + reqargs.get("limit", None), + bool(strtobool(reqargs.get("static", "false"))), ) - @RequestParser([ - {'name': 'macaddress', 'required': True}, - {'name': 'ipaddress', 'required': True}, - {'name': 'hostname'} - ]) + @RequestParser( + [ + {"name": "macaddress", "required": True}, + {"name": "ipaddress", "required": True}, + {"name": "hostname"}, + ] + ) @Authenticator def post(self, vni, reqargs): """ @@ -2659,13 +2811,13 @@ class API_Network_Lease_Root(Resource): """ return api_helper.net_dhcp_add( vni, - reqargs.get('ipaddress', None), - reqargs.get('macaddress', None), - reqargs.get('hostname', None) + reqargs.get("ipaddress", None), + reqargs.get("macaddress", None), + reqargs.get("hostname", None), ) -api.add_resource(API_Network_Lease_Root, '/network//lease') +api.add_resource(API_Network_Lease_Root, "/network//lease") # /network//lease/{mac} @@ -2712,16 +2864,9 @@ class API_Network_Lease_Element(Resource): type: object id: Message """ - return api_helper.net_dhcp_list( - vni, - mac, - False - ) + return api_helper.net_dhcp_list(vni, mac, False) - @RequestParser([ - {'name': 'ipaddress', 'required': True}, - {'name': 'hostname'} - ]) + @RequestParser([{"name": "ipaddress", "required": True}, {"name": "hostname"}]) @Authenticator def post(self, vni, mac, reqargs): """ @@ -2763,10 +2908,7 @@ class API_Network_Lease_Element(Resource): id: Message """ return api_helper.net_dhcp_add( - vni, - reqargs.get('ipaddress', None), - mac, - reqargs.get('hostname', None) + vni, reqargs.get("ipaddress", None), mac, reqargs.get("hostname", None) ) @Authenticator @@ -2788,21 +2930,24 @@ class API_Network_Lease_Element(Resource): type: object id: Message """ - return api_helper.net_dhcp_remove( - vni, - mac - ) + return api_helper.net_dhcp_remove(vni, mac) -api.add_resource(API_Network_Lease_Element, '/network//lease/') +api.add_resource(API_Network_Lease_Element, "/network//lease/") # /network//acl class API_Network_ACL_Root(Resource): - @RequestParser([ - {'name': 'limit'}, - {'name': 'direction', 'choices': ('in', 'out'), 'helptext': "A valid direction must be specified."} - ]) + @RequestParser( + [ + {"name": "limit"}, + { + "name": "direction", + "choices": ("in", "out"), + "helptext": "A valid direction must be specified.", + }, + ] + ) @Authenticator def get(self, vni, reqargs): """ @@ -2857,17 +3002,25 @@ class API_Network_ACL_Root(Resource): id: Message """ return api_helper.net_acl_list( - vni, - reqargs.get('limit', None), - reqargs.get('direction', None) + vni, reqargs.get("limit", None), reqargs.get("direction", None) ) - @RequestParser([ - {'name': 'description', 'required': True, 'helptext': "A whitespace-free description must be specified."}, - {'name': 'rule', 'required': True, 'helptext': "A rule must be specified."}, - {'name': 'direction', 'choices': ('in', 'out'), 'helptext': "A valid direction must be specified."}, - {'name': 'order'} - ]) + @RequestParser( + [ + { + "name": "description", + "required": True, + "helptext": "A whitespace-free description must be specified.", + }, + {"name": "rule", "required": True, "helptext": "A rule must be specified."}, + { + "name": "direction", + "choices": ("in", "out"), + "helptext": "A valid direction must be specified.", + }, + {"name": "order"}, + ] + ) @Authenticator def post(self, vni, reqargs): """ @@ -2912,14 +3065,14 @@ class API_Network_ACL_Root(Resource): """ return api_helper.net_acl_add( vni, - reqargs.get('direction', 'in'), - reqargs.get('description', None), - reqargs.get('rule', None), - reqargs.get('order', None) + reqargs.get("direction", "in"), + reqargs.get("description", None), + reqargs.get("rule", None), + reqargs.get("order", None), ) -api.add_resource(API_Network_ACL_Root, '/network//acl') +api.add_resource(API_Network_ACL_Root, "/network//acl") # /network//acl/ @@ -2947,18 +3100,19 @@ class API_Network_ACL_Element(Resource): type: object id: Message """ - return api_helper.net_acl_list( - vni, - description, - None, - is_fuzzy=False - ) + return api_helper.net_acl_list(vni, description, None, is_fuzzy=False) - @RequestParser([ - {'name': 'rule', 'required': True, 'helptext': "A rule must be specified."}, - {'name': 'direction', 'choices': ('in', 'out'), 'helptext': "A valid direction must be specified."}, - {'name': 'order'} - ]) + @RequestParser( + [ + {"name": "rule", "required": True, "helptext": "A rule must be specified."}, + { + "name": "direction", + "choices": ("in", "out"), + "helptext": "A valid direction must be specified.", + }, + {"name": "order"}, + ] + ) @Authenticator def post(self, vni, description, reqargs): """ @@ -2998,10 +3152,10 @@ class API_Network_ACL_Element(Resource): """ return api_helper.net_acl_add( vni, - reqargs.get('direction', 'in'), + reqargs.get("direction", "in"), description, - reqargs.get('rule', None), - reqargs.get('order', None) + reqargs.get("rule", None), + reqargs.get("order", None), ) @Authenticator @@ -3023,13 +3177,10 @@ class API_Network_ACL_Element(Resource): type: object id: Message """ - return api_helper.net_acl_remove( - vni, - description - ) + return api_helper.net_acl_remove(vni, description) -api.add_resource(API_Network_ACL_Element, '/network//acl/') +api.add_resource(API_Network_ACL_Element, "/network//acl/") ########################################################## @@ -3043,14 +3194,20 @@ class API_SRIOV_Root(Resource): pass -api.add_resource(API_SRIOV_Root, '/sriov') +api.add_resource(API_SRIOV_Root, "/sriov") # /sriov/pf class API_SRIOV_PF_Root(Resource): - @RequestParser([ - {'name': 'node', 'required': True, 'helptext': "A valid node must be specified."}, - ]) + @RequestParser( + [ + { + "name": "node", + "required": True, + "helptext": "A valid node must be specified.", + }, + ] + ) @Authenticator def get(self, reqargs): """ @@ -3077,10 +3234,10 @@ class API_SRIOV_PF_Root(Resource): type: string description: The PHY name of a VF of this PF """ - return api_helper.sriov_pf_list(reqargs.get('node')) + return api_helper.sriov_pf_list(reqargs.get("node")) -api.add_resource(API_SRIOV_PF_Root, '/sriov/pf') +api.add_resource(API_SRIOV_PF_Root, "/sriov/pf") # /sriov/pf/ @@ -3101,15 +3258,25 @@ class API_SRIOV_PF_Node(Resource): return api_helper.sriov_pf_list(node) -api.add_resource(API_SRIOV_PF_Node, '/sriov/pf/') +api.add_resource(API_SRIOV_PF_Node, "/sriov/pf/") # /sriov/vf class API_SRIOV_VF_Root(Resource): - @RequestParser([ - {'name': 'node', 'required': True, 'helptext': "A valid node must be specified."}, - {'name': 'pf', 'required': False, 'helptext': "A PF parent may be specified."}, - ]) + @RequestParser( + [ + { + "name": "node", + "required": True, + "helptext": "A valid node must be specified.", + }, + { + "name": "pf", + "required": False, + "helptext": "A PF parent may be specified.", + }, + ] + ) @Authenticator def get(self, reqargs): """ @@ -3175,17 +3342,23 @@ class API_SRIOV_VF_Root(Resource): type: boolean description: The UUID of the domain the SR-IOV VF is currently used by """ - return api_helper.sriov_vf_list(reqargs.get('node'), reqargs.get('pf', None)) + return api_helper.sriov_vf_list(reqargs.get("node"), reqargs.get("pf", None)) -api.add_resource(API_SRIOV_VF_Root, '/sriov/vf') +api.add_resource(API_SRIOV_VF_Root, "/sriov/vf") # /sriov/vf/ class API_SRIOV_VF_Node(Resource): - @RequestParser([ - {'name': 'pf', 'required': False, 'helptext': "A PF parent may be specified."}, - ]) + @RequestParser( + [ + { + "name": "pf", + "required": False, + "helptext": "A PF parent may be specified.", + }, + ] + ) @Authenticator def get(self, node, reqargs): """ @@ -3199,10 +3372,10 @@ class API_SRIOV_VF_Node(Resource): schema: $ref: '#/definitions/sriov_vf' """ - return api_helper.sriov_vf_list(node, reqargs.get('pf', None)) + return api_helper.sriov_vf_list(node, reqargs.get("pf", None)) -api.add_resource(API_SRIOV_VF_Node, '/sriov/vf/') +api.add_resource(API_SRIOV_VF_Node, "/sriov/vf/") # /sriov/vf// @@ -3228,24 +3401,30 @@ class API_SRIOV_VF_Element(Resource): vf_list = list() full_vf_list, _ = api_helper.sriov_vf_list(node) for vf_element in full_vf_list: - if vf_element['phy'] == vf: + if vf_element["phy"] == vf: vf_list.append(vf_element) if len(vf_list) == 1: return vf_list, 200 else: - return {'message': "No VF '{}' found on node '{}'".format(vf, node)}, 404 + return {"message": "No VF '{}' found on node '{}'".format(vf, node)}, 404 - @RequestParser([ - {'name': 'vlan_id'}, - {'name': 'vlan_qos'}, - {'name': 'tx_rate_min'}, - {'name': 'tx_rate_max'}, - {'name': 'link_state', 'choices': ('auto', 'enable', 'disable'), 'helptext': "A valid state must be specified"}, - {'name': 'spoof_check'}, - {'name': 'trust'}, - {'name': 'query_rss'}, - ]) + @RequestParser( + [ + {"name": "vlan_id"}, + {"name": "vlan_qos"}, + {"name": "tx_rate_min"}, + {"name": "tx_rate_max"}, + { + "name": "link_state", + "choices": ("auto", "enable", "disable"), + "helptext": "A valid state must be specified", + }, + {"name": "spoof_check"}, + {"name": "trust"}, + {"name": "query_rss"}, + ] + ) @Authenticator def put(self, node, vf, reqargs): """ @@ -3313,18 +3492,18 @@ class API_SRIOV_VF_Element(Resource): return api_helper.update_sriov_vf_config( node, vf, - reqargs.get('vlan_id', None), - reqargs.get('vlan_qos', None), - reqargs.get('tx_rate_min', None), - reqargs.get('tx_rate_max', None), - reqargs.get('link_state', None), - reqargs.get('spoof_check', None), - reqargs.get('trust', None), - reqargs.get('query_rss', None), + reqargs.get("vlan_id", None), + reqargs.get("vlan_qos", None), + reqargs.get("tx_rate_min", None), + reqargs.get("tx_rate_max", None), + reqargs.get("link_state", None), + reqargs.get("spoof_check", None), + reqargs.get("trust", None), + reqargs.get("query_rss", None), ) -api.add_resource(API_SRIOV_VF_Element, '/sriov/vf//') +api.add_resource(API_SRIOV_VF_Element, "/sriov/vf//") ########################################################## @@ -3342,7 +3521,7 @@ class API_Storage_Root(Resource): pass -api.add_resource(API_Storage_Root, '/storage') +api.add_resource(API_Storage_Root, "/storage") # /storage/ceph @@ -3352,7 +3531,7 @@ class API_Storage_Ceph_Root(Resource): pass -api.add_resource(API_Storage_Ceph_Root, '/storage/ceph') +api.add_resource(API_Storage_Ceph_Root, "/storage/ceph") # /storage/ceph/status @@ -3383,7 +3562,7 @@ class API_Storage_Ceph_Status(Resource): return api_helper.ceph_status() -api.add_resource(API_Storage_Ceph_Status, '/storage/ceph/status') +api.add_resource(API_Storage_Ceph_Status, "/storage/ceph/status") # /storage/ceph/utilization @@ -3414,14 +3593,12 @@ class API_Storage_Ceph_Utilization(Resource): return api_helper.ceph_util() -api.add_resource(API_Storage_Ceph_Utilization, '/storage/ceph/utilization') +api.add_resource(API_Storage_Ceph_Utilization, "/storage/ceph/utilization") # /storage/ceph/benchmark class API_Storage_Ceph_Benchmark(Resource): - @RequestParser([ - {'name': 'job'} - ]) + @RequestParser([{"name": "job"}]) @Authenticator def get(self, reqargs): """ @@ -3543,11 +3720,17 @@ class API_Storage_Ceph_Benchmark(Resource): type: string (integer) description: The number of minor page faults during the test """ - return api_benchmark.list_benchmarks(reqargs.get('job', None)) + return api_benchmark.list_benchmarks(reqargs.get("job", None)) - @RequestParser([ - {'name': 'pool', 'required': True, 'helptext': "A valid pool must be specified."}, - ]) + @RequestParser( + [ + { + "name": "pool", + "required": True, + "helptext": "A valid pool must be specified.", + }, + ] + ) @Authenticator def post(self, reqargs): """ @@ -3569,25 +3752,42 @@ class API_Storage_Ceph_Benchmark(Resource): description: The Celery job ID of the benchmark (unused elsewhere) """ # Verify that the pool is valid - _list, code = api_helper.ceph_pool_list(reqargs.get('pool', None), is_fuzzy=False) - if code != 200: - return {'message': 'Pool "{}" is not valid.'.format(reqargs.get('pool'))}, 400 - - task = run_benchmark.delay( - reqargs.get('pool', None) + _list, code = api_helper.ceph_pool_list( + reqargs.get("pool", None), is_fuzzy=False + ) + if code != 200: + return { + "message": 'Pool "{}" is not valid.'.format(reqargs.get("pool")) + }, 400 + + task = run_benchmark.delay(reqargs.get("pool", None)) + return ( + {"task_id": task.id}, + 202, + {"Location": Api.url_for(api, API_Storage_Ceph_Benchmark, task_id=task.id)}, ) - return {"task_id": task.id}, 202, {'Location': Api.url_for(api, API_Storage_Ceph_Benchmark, task_id=task.id)} -api.add_resource(API_Storage_Ceph_Benchmark, '/storage/ceph/benchmark') +api.add_resource(API_Storage_Ceph_Benchmark, "/storage/ceph/benchmark") # /storage/ceph/option class API_Storage_Ceph_Option(Resource): - @RequestParser([ - {'name': 'option', 'required': True, 'helptext': "A valid option must be specified."}, - {'name': 'action', 'required': True, 'choices': ('set', 'unset'), 'helptext': "A valid action must be specified."}, - ]) + @RequestParser( + [ + { + "name": "option", + "required": True, + "helptext": "A valid option must be specified.", + }, + { + "name": "action", + "required": True, + "choices": ("set", "unset"), + "helptext": "A valid action must be specified.", + }, + ] + ) @Authenticator def post(self, reqargs): """ @@ -3621,22 +3821,32 @@ class API_Storage_Ceph_Option(Resource): type: object id: Message """ - if reqargs.get('action') == 'set': - return api_helper.ceph_osd_set(reqargs.get('option')) - if reqargs.get('action') == 'unset': - return api_helper.ceph_osd_unset(reqargs.get('option')) + if reqargs.get("action") == "set": + return api_helper.ceph_osd_set(reqargs.get("option")) + if reqargs.get("action") == "unset": + return api_helper.ceph_osd_unset(reqargs.get("option")) abort(400) -api.add_resource(API_Storage_Ceph_Option, '/storage/ceph/option') +api.add_resource(API_Storage_Ceph_Option, "/storage/ceph/option") # /storage/ceph/osddb class API_Storage_Ceph_OSDDB_Root(Resource): - @RequestParser([ - {'name': 'node', 'required': True, 'helptext': "A valid node must be specified."}, - {'name': 'device', 'required': True, 'helptext': "A valid device must be specified."}, - ]) + @RequestParser( + [ + { + "name": "node", + "required": True, + "helptext": "A valid node must be specified.", + }, + { + "name": "device", + "required": True, + "helptext": "A valid device must be specified.", + }, + ] + ) @Authenticator def post(self, reqargs): """ @@ -3669,19 +3879,20 @@ class API_Storage_Ceph_OSDDB_Root(Resource): id: Message """ return api_helper.ceph_osd_db_vg_add( - reqargs.get('node', None), - reqargs.get('device', None) + reqargs.get("node", None), reqargs.get("device", None) ) -api.add_resource(API_Storage_Ceph_OSDDB_Root, '/storage/ceph/osddb') +api.add_resource(API_Storage_Ceph_OSDDB_Root, "/storage/ceph/osddb") # /storage/ceph/osd class API_Storage_Ceph_OSD_Root(Resource): - @RequestParser([ - {'name': 'limit'}, - ]) + @RequestParser( + [ + {"name": "limit"}, + ] + ) @Authenticator def get(self, reqargs): """ @@ -3774,17 +3985,37 @@ class API_Storage_Ceph_OSD_Root(Resource): items: $ref: '#/definitions/osd' """ - return api_helper.ceph_osd_list( - reqargs.get('limit', None) - ) + return api_helper.ceph_osd_list(reqargs.get("limit", None)) - @RequestParser([ - {'name': 'node', 'required': True, 'helptext': "A valid node must be specified."}, - {'name': 'device', 'required': True, 'helptext': "A valid device must be specified."}, - {'name': 'weight', 'required': True, 'helptext': "An OSD weight must be specified."}, - {'name': 'ext_db', 'required': False, 'helptext': "Whether to use an external OSD DB LV device."}, - {'name': 'ext_db_ratio', 'required': False, 'helptext': "Decimal size ratio of the external OSD DB LV device."}, - ]) + @RequestParser( + [ + { + "name": "node", + "required": True, + "helptext": "A valid node must be specified.", + }, + { + "name": "device", + "required": True, + "helptext": "A valid device must be specified.", + }, + { + "name": "weight", + "required": True, + "helptext": "An OSD weight must be specified.", + }, + { + "name": "ext_db", + "required": False, + "helptext": "Whether to use an external OSD DB LV device.", + }, + { + "name": "ext_db_ratio", + "required": False, + "helptext": "Decimal size ratio of the external OSD DB LV device.", + }, + ] + ) @Authenticator def post(self, reqargs): """ @@ -3832,15 +4063,15 @@ class API_Storage_Ceph_OSD_Root(Resource): id: Message """ return api_helper.ceph_osd_add( - reqargs.get('node', None), - reqargs.get('device', None), - reqargs.get('weight', None), - reqargs.get('ext_db', False), - float(reqargs.get('ext_db_ratio', 0.05)), + reqargs.get("node", None), + reqargs.get("device", None), + reqargs.get("weight", None), + reqargs.get("ext_db", False), + float(reqargs.get("ext_db_ratio", 0.05)), ) -api.add_resource(API_Storage_Ceph_OSD_Root, '/storage/ceph/osd') +api.add_resource(API_Storage_Ceph_OSD_Root, "/storage/ceph/osd") # /storage/ceph/osd/ @@ -3858,13 +4089,17 @@ class API_Storage_Ceph_OSD_Element(Resource): schema: $ref: '#/definitions/osd' """ - return api_helper.ceph_osd_list( - osdid - ) + return api_helper.ceph_osd_list(osdid) - @RequestParser([ - {'name': 'yes-i-really-mean-it', 'required': True, 'helptext': "Please confirm that 'yes-i-really-mean-it'."} - ]) + @RequestParser( + [ + { + "name": "yes-i-really-mean-it", + "required": True, + "helptext": "Please confirm that 'yes-i-really-mean-it'.", + } + ] + ) @Authenticator def delete(self, osdid, reqargs): """ @@ -3897,12 +4132,10 @@ class API_Storage_Ceph_OSD_Element(Resource): type: object id: Message """ - return api_helper.ceph_osd_remove( - osdid - ) + return api_helper.ceph_osd_remove(osdid) -api.add_resource(API_Storage_Ceph_OSD_Element, '/storage/ceph/osd/') +api.add_resource(API_Storage_Ceph_OSD_Element, "/storage/ceph/osd/") # /storage/ceph/osd//state @@ -3924,13 +4157,18 @@ class API_Storage_Ceph_OSD_State(Resource): type: string description: The current OSD state """ - return api_helper.ceph_osd_state( - osdid - ) + return api_helper.ceph_osd_state(osdid) - @RequestParser([ - {'name': 'state', 'choices': ('in', 'out'), 'required': True, 'helptext': "A valid state must be specified."}, - ]) + @RequestParser( + [ + { + "name": "state", + "choices": ("in", "out"), + "required": True, + "helptext": "A valid state must be specified.", + }, + ] + ) @Authenticator def post(self, osdid, reqargs): """ @@ -3951,25 +4189,19 @@ class API_Storage_Ceph_OSD_State(Resource): type: object id: Message """ - if reqargs.get('state', None) == 'in': - return api_helper.ceph_osd_in( - osdid - ) - if reqargs.get('state', None) == 'out': - return api_helper.ceph_osd_out( - osdid - ) + if reqargs.get("state", None) == "in": + return api_helper.ceph_osd_in(osdid) + if reqargs.get("state", None) == "out": + return api_helper.ceph_osd_out(osdid) abort(400) -api.add_resource(API_Storage_Ceph_OSD_State, '/storage/ceph/osd//state') +api.add_resource(API_Storage_Ceph_OSD_State, "/storage/ceph/osd//state") # /storage/ceph/pool class API_Storage_Ceph_Pool_Root(Resource): - @RequestParser([ - {'name': 'limit'} - ]) + @RequestParser([{"name": "limit"}]) @Authenticator def get(self, reqargs): """ @@ -4050,15 +4282,27 @@ class API_Storage_Ceph_Pool_Root(Resource): items: $ref: '#/definitions/pool' """ - return api_helper.ceph_pool_list( - reqargs.get('limit', None) - ) + return api_helper.ceph_pool_list(reqargs.get("limit", None)) - @RequestParser([ - {'name': 'pool', 'required': True, 'helptext': "A pool name must be specified."}, - {'name': 'pgs', 'required': True, 'helptext': "A placement group count must be specified."}, - {'name': 'replcfg', 'required': True, 'helptext': "A valid replication configuration must be specified."} - ]) + @RequestParser( + [ + { + "name": "pool", + "required": True, + "helptext": "A pool name must be specified.", + }, + { + "name": "pgs", + "required": True, + "helptext": "A placement group count must be specified.", + }, + { + "name": "replcfg", + "required": True, + "helptext": "A valid replication configuration must be specified.", + }, + ] + ) @Authenticator def post(self, reqargs): """ @@ -4095,13 +4339,13 @@ class API_Storage_Ceph_Pool_Root(Resource): id: Message """ return api_helper.ceph_pool_add( - reqargs.get('pool', None), - reqargs.get('pgs', None), - reqargs.get('replcfg', None) + reqargs.get("pool", None), + reqargs.get("pgs", None), + reqargs.get("replcfg", None), ) -api.add_resource(API_Storage_Ceph_Pool_Root, '/storage/ceph/pool') +api.add_resource(API_Storage_Ceph_Pool_Root, "/storage/ceph/pool") # /storage/ceph/pool/ @@ -4124,15 +4368,22 @@ class API_Storage_Ceph_Pool_Element(Resource): type: object id: Message """ - return api_helper.ceph_pool_list( - pool, - is_fuzzy=False - ) + return api_helper.ceph_pool_list(pool, is_fuzzy=False) - @RequestParser([ - {'name': 'pgs', 'required': True, 'helptext': "A placement group count must be specified."}, - {'name': 'replcfg', 'required': True, 'helptext': "A valid replication configuration must be specified."} - ]) + @RequestParser( + [ + { + "name": "pgs", + "required": True, + "helptext": "A placement group count must be specified.", + }, + { + "name": "replcfg", + "required": True, + "helptext": "A valid replication configuration must be specified.", + }, + ] + ) @Authenticator def post(self, pool, reqargs): """ @@ -4169,14 +4420,18 @@ class API_Storage_Ceph_Pool_Element(Resource): id: Message """ return api_helper.ceph_pool_add( - pool, - reqargs.get('pgs', None), - reqargs.get('replcfg', None) + pool, reqargs.get("pgs", None), reqargs.get("replcfg", None) ) - @RequestParser([ - {'name': 'yes-i-really-mean-it', 'required': True, 'helptext': "Please confirm that 'yes-i-really-mean-it'."} - ]) + @RequestParser( + [ + { + "name": "yes-i-really-mean-it", + "required": True, + "helptext": "Please confirm that 'yes-i-really-mean-it'.", + } + ] + ) @Authenticator def delete(self, pool, reqargs): """ @@ -4208,20 +4463,15 @@ class API_Storage_Ceph_Pool_Element(Resource): type: object id: Message """ - return api_helper.ceph_pool_remove( - pool - ) + return api_helper.ceph_pool_remove(pool) -api.add_resource(API_Storage_Ceph_Pool_Element, '/storage/ceph/pool/') +api.add_resource(API_Storage_Ceph_Pool_Element, "/storage/ceph/pool/") # /storage/ceph/volume class API_Storage_Ceph_Volume_Root(Resource): - @RequestParser([ - {'name': 'limit'}, - {'name': 'pool'} - ]) + @RequestParser([{"name": "limit"}, {"name": "pool"}]) @Authenticator def get(self, reqargs): """ @@ -4314,15 +4564,28 @@ class API_Storage_Ceph_Volume_Root(Resource): $ref: '#/definitions/volume' """ return api_helper.ceph_volume_list( - reqargs.get('pool', None), - reqargs.get('limit', None) + reqargs.get("pool", None), reqargs.get("limit", None) ) - @RequestParser([ - {'name': 'volume', 'required': True, 'helptext': "A volume name must be specified."}, - {'name': 'pool', 'required': True, 'helptext': "A valid pool name must be specified."}, - {'name': 'size', 'required': True, 'helptext': "A volume size in bytes (or with k/M/G/T suffix) must be specified."} - ]) + @RequestParser( + [ + { + "name": "volume", + "required": True, + "helptext": "A volume name must be specified.", + }, + { + "name": "pool", + "required": True, + "helptext": "A valid pool name must be specified.", + }, + { + "name": "size", + "required": True, + "helptext": "A volume size in bytes (or with k/M/G/T suffix) must be specified.", + }, + ] + ) @Authenticator def post(self, reqargs): """ @@ -4359,13 +4622,13 @@ class API_Storage_Ceph_Volume_Root(Resource): id: Message """ return api_helper.ceph_volume_add( - reqargs.get('pool', None), - reqargs.get('volume', None), - reqargs.get('size', None) + reqargs.get("pool", None), + reqargs.get("volume", None), + reqargs.get("size", None), ) -api.add_resource(API_Storage_Ceph_Volume_Root, '/storage/ceph/volume') +api.add_resource(API_Storage_Ceph_Volume_Root, "/storage/ceph/volume") # /storage/ceph/volume// @@ -4388,15 +4651,17 @@ class API_Storage_Ceph_Volume_Element(Resource): type: object id: Message """ - return api_helper.ceph_volume_list( - pool, - volume, - is_fuzzy=False - ) + return api_helper.ceph_volume_list(pool, volume, is_fuzzy=False) - @RequestParser([ - {'name': 'size', 'required': True, 'helptext': "A volume size in bytes (or with k/M/G/T suffix) must be specified."} - ]) + @RequestParser( + [ + { + "name": "size", + "required": True, + "helptext": "A volume size in bytes (or with k/M/G/T suffix) must be specified.", + } + ] + ) @Authenticator def post(self, pool, volume, reqargs): """ @@ -4427,16 +4692,9 @@ class API_Storage_Ceph_Volume_Element(Resource): type: object id: Message """ - return api_helper.ceph_volume_add( - pool, - volume, - reqargs.get('size', None) - ) + return api_helper.ceph_volume_add(pool, volume, reqargs.get("size", None)) - @RequestParser([ - {'name': 'new_size'}, - {'name': 'new_name'} - ]) + @RequestParser([{"name": "new_size"}, {"name": "new_name"}]) @Authenticator def put(self, pool, volume, reqargs): """ @@ -4472,21 +4730,13 @@ class API_Storage_Ceph_Volume_Element(Resource): type: object id: Message """ - if reqargs.get('new_size', None) and reqargs.get('new_name', None): + if reqargs.get("new_size", None) and reqargs.get("new_name", None): return {"message": "Can only perform one modification at once"}, 400 - if reqargs.get('new_size', None): - return api_helper.ceph_volume_resize( - pool, - volume, - reqargs.get('new_size') - ) - if reqargs.get('new_name', None): - return api_helper.ceph_volume_rename( - pool, - volume, - reqargs.get('new_name') - ) + if reqargs.get("new_size", None): + return api_helper.ceph_volume_resize(pool, volume, reqargs.get("new_size")) + if reqargs.get("new_name", None): + return api_helper.ceph_volume_rename(pool, volume, reqargs.get("new_name")) return {"message": "At least one modification must be specified"}, 400 @Authenticator @@ -4509,20 +4759,25 @@ class API_Storage_Ceph_Volume_Element(Resource): type: object id: Message """ - return api_helper.ceph_volume_remove( - pool, - volume - ) + return api_helper.ceph_volume_remove(pool, volume) -api.add_resource(API_Storage_Ceph_Volume_Element, '/storage/ceph/volume//') +api.add_resource( + API_Storage_Ceph_Volume_Element, "/storage/ceph/volume//" +) # /storage/ceph/volume///clone class API_Storage_Ceph_Volume_Element_Clone(Resource): - @RequestParser([ - {'name': 'new_volume', 'required': True, 'helptext': "A new volume name must be specified."} - ]) + @RequestParser( + [ + { + "name": "new_volume", + "required": True, + "helptext": "A new volume name must be specified.", + } + ] + ) @Authenticator def post(self, pool, volume, reqargs): """ @@ -4554,20 +4809,27 @@ class API_Storage_Ceph_Volume_Element_Clone(Resource): id: Message """ return api_helper.ceph_volume_clone( - pool, - reqargs.get('new_volume', None), - volume + pool, reqargs.get("new_volume", None), volume ) -api.add_resource(API_Storage_Ceph_Volume_Element_Clone, '/storage/ceph/volume///clone') +api.add_resource( + API_Storage_Ceph_Volume_Element_Clone, "/storage/ceph/volume///clone" +) # /storage/ceph/volume///upload class API_Storage_Ceph_Volume_Element_Upload(Resource): - @RequestParser([ - {'name': 'image_format', 'required': True, 'location': ['args'], 'helptext': "A source image format must be specified."} - ]) + @RequestParser( + [ + { + "name": "image_format", + "required": True, + "location": ["args"], + "helptext": "A source image format must be specified.", + } + ] + ) @Authenticator def post(self, pool, volume, reqargs): """ @@ -4608,22 +4870,25 @@ class API_Storage_Ceph_Volume_Element_Upload(Resource): id: Message """ return api_helper.ceph_volume_upload( - pool, - volume, - reqargs.get('image_format', None) + pool, volume, reqargs.get("image_format", None) ) -api.add_resource(API_Storage_Ceph_Volume_Element_Upload, '/storage/ceph/volume///upload') +api.add_resource( + API_Storage_Ceph_Volume_Element_Upload, + "/storage/ceph/volume///upload", +) # /storage/ceph/snapshot class API_Storage_Ceph_Snapshot_Root(Resource): - @RequestParser([ - {'name': 'pool'}, - {'name': 'volume'}, - {'name': 'limit'}, - ]) + @RequestParser( + [ + {"name": "pool"}, + {"name": "volume"}, + {"name": "limit"}, + ] + ) @Authenticator def get(self, reqargs): """ @@ -4670,16 +4935,30 @@ class API_Storage_Ceph_Snapshot_Root(Resource): $ref: '#/definitions/snapshot' """ return api_helper.ceph_volume_snapshot_list( - reqargs.get('pool', None), - reqargs.get('volume', None), - reqargs.get('limit', None) + reqargs.get("pool", None), + reqargs.get("volume", None), + reqargs.get("limit", None), ) - @RequestParser([ - {'name': 'snapshot', 'required': True, 'helptext': "A snapshot name must be specified."}, - {'name': 'volume', 'required': True, 'helptext': "A volume name must be specified."}, - {'name': 'pool', 'required': True, 'helptext': "A pool name must be specified."} - ]) + @RequestParser( + [ + { + "name": "snapshot", + "required": True, + "helptext": "A snapshot name must be specified.", + }, + { + "name": "volume", + "required": True, + "helptext": "A volume name must be specified.", + }, + { + "name": "pool", + "required": True, + "helptext": "A pool name must be specified.", + }, + ] + ) @Authenticator def post(self, reqargs): """ @@ -4716,13 +4995,13 @@ class API_Storage_Ceph_Snapshot_Root(Resource): id: Message """ return api_helper.ceph_volume_snapshot_add( - reqargs.get('pool', None), - reqargs.get('volume', None), - reqargs.get('snapshot', None) + reqargs.get("pool", None), + reqargs.get("volume", None), + reqargs.get("snapshot", None), ) -api.add_resource(API_Storage_Ceph_Snapshot_Root, '/storage/ceph/snapshot') +api.add_resource(API_Storage_Ceph_Snapshot_Root, "/storage/ceph/snapshot") # /storage/ceph/snapshot/// @@ -4746,10 +5025,7 @@ class API_Storage_Ceph_Snapshot_Element(Resource): id: Message """ return api_helper.ceph_volume_snapshot_list( - pool, - volume, - snapshot, - is_fuzzy=False + pool, volume, snapshot, is_fuzzy=False ) @Authenticator @@ -4792,15 +5068,17 @@ class API_Storage_Ceph_Snapshot_Element(Resource): type: object id: Message """ - return api_helper.ceph_volume_snapshot_add( - pool, - volume, - snapshot - ) + return api_helper.ceph_volume_snapshot_add(pool, volume, snapshot) - @RequestParser([ - {'name': 'new_name', 'required': True, 'helptext': "A new name must be specified."} - ]) + @RequestParser( + [ + { + "name": "new_name", + "required": True, + "helptext": "A new name must be specified.", + } + ] + ) @Authenticator def put(self, pool, volume, snapshot, reqargs): """ @@ -4832,10 +5110,7 @@ class API_Storage_Ceph_Snapshot_Element(Resource): id: Message """ return api_helper.ceph_volume_snapshot_rename( - pool, - volume, - snapshot, - reqargs.get('new_name', None) + pool, volume, snapshot, reqargs.get("new_name", None) ) @Authenticator @@ -4858,14 +5133,13 @@ class API_Storage_Ceph_Snapshot_Element(Resource): type: object id: Message """ - return api_helper.ceph_volume_snapshot_remove( - pool, - volume, - snapshot - ) + return api_helper.ceph_volume_snapshot_remove(pool, volume, snapshot) -api.add_resource(API_Storage_Ceph_Snapshot_Element, '/storage/ceph/snapshot///') +api.add_resource( + API_Storage_Ceph_Snapshot_Element, + "/storage/ceph/snapshot///", +) ########################################################## @@ -4882,14 +5156,12 @@ class API_Provisioner_Root(Resource): abort(404) -api.add_resource(API_Provisioner_Root, '/provisioner') +api.add_resource(API_Provisioner_Root, "/provisioner") # /provisioner/template class API_Provisioner_Template_Root(Resource): - @RequestParser([ - {'name': 'limit'} - ]) + @RequestParser([{"name": "limit"}]) @Authenticator def get(self, reqargs): """ @@ -4926,19 +5198,15 @@ class API_Provisioner_Template_Root(Resource): schema: $ref: '#/definitions/all-templates' """ - return api_provisioner.template_list( - reqargs.get('limit', None) - ) + return api_provisioner.template_list(reqargs.get("limit", None)) -api.add_resource(API_Provisioner_Template_Root, '/provisioner/template') +api.add_resource(API_Provisioner_Template_Root, "/provisioner/template") # /provisioner/template/system class API_Provisioner_Template_System_Root(Resource): - @RequestParser([ - {'name': 'limit'} - ]) + @RequestParser([{"name": "limit"}]) @Authenticator def get(self, reqargs): """ @@ -4998,22 +5266,38 @@ class API_Provisioner_Template_System_Root(Resource): items: $ref: '#/definitions/system-template' """ - return api_provisioner.list_template_system( - reqargs.get('limit', None) - ) + return api_provisioner.list_template_system(reqargs.get("limit", None)) - @RequestParser([ - {'name': 'name', 'required': True, 'helptext': "A name must be specified."}, - {'name': 'vcpus', 'required': True, 'helptext': "A vcpus value must be specified."}, - {'name': 'vram', 'required': True, 'helptext': "A vram value in MB must be specified."}, - {'name': 'serial', 'required': True, 'helptext': "A serial value must be specified."}, - {'name': 'vnc', 'required': True, 'helptext': "A vnc value must be specified."}, - {'name': 'vnc_bind'}, - {'name': 'node_limit'}, - {'name': 'node_selector'}, - {'name': 'node_autostart'}, - {'name': 'migration_method'} - ]) + @RequestParser( + [ + {"name": "name", "required": True, "helptext": "A name must be specified."}, + { + "name": "vcpus", + "required": True, + "helptext": "A vcpus value must be specified.", + }, + { + "name": "vram", + "required": True, + "helptext": "A vram value in MB must be specified.", + }, + { + "name": "serial", + "required": True, + "helptext": "A serial value must be specified.", + }, + { + "name": "vnc", + "required": True, + "helptext": "A vnc value must be specified.", + }, + {"name": "vnc_bind"}, + {"name": "node_limit"}, + {"name": "node_selector"}, + {"name": "node_autostart"}, + {"name": "migration_method"}, + ] + ) @Authenticator def post(self, reqargs): """ @@ -5086,44 +5370,46 @@ class API_Provisioner_Template_System_Root(Resource): """ # Validate arguments try: - vcpus = int(reqargs.get('vcpus')) + vcpus = int(reqargs.get("vcpus")) except Exception: return {"message": "A vcpus value must be an integer"}, 400 try: - vram = int(reqargs.get('vram')) + vram = int(reqargs.get("vram")) except Exception: return {"message": "A vram value must be an integer"}, 400 # Cast boolean arguments - if bool(strtobool(reqargs.get('serial', 'false'))): + if bool(strtobool(reqargs.get("serial", "false"))): serial = True else: serial = False - if bool(strtobool(reqargs.get('vnc', 'false'))): + if bool(strtobool(reqargs.get("vnc", "false"))): vnc = True - vnc_bind = reqargs.get('vnc_bind', None) + vnc_bind = reqargs.get("vnc_bind", None) else: vnc = False vnc_bind = None - if reqargs.get('node_autostart', None) and bool(strtobool(reqargs.get('node_autostart', 'false'))): + if reqargs.get("node_autostart", None) and bool( + strtobool(reqargs.get("node_autostart", "false")) + ): node_autostart = True else: node_autostart = False return api_provisioner.create_template_system( - reqargs.get('name'), + reqargs.get("name"), vcpus, vram, serial, vnc, vnc_bind, - reqargs.get('node_limit', None), - reqargs.get('node_selector', None), + reqargs.get("node_limit", None), + reqargs.get("node_selector", None), node_autostart, - reqargs.get('migration_method', None), + reqargs.get("migration_method", None), ) -api.add_resource(API_Provisioner_Template_System_Root, '/provisioner/template/system') +api.add_resource(API_Provisioner_Template_System_Root, "/provisioner/template/system") # /provisioner/template/system/