matthewalanpenning 1 year ago
parent
commit
287d28fb10
67 changed files with 1999 additions and 9043 deletions
  1. 7 0
      CHANGELOG.md
  2. 4 8
      lxconsole/api/__init__.py
  3. 0 1156
      lxconsole/api/container.py
  4. 165 68
      lxconsole/api/instance.py
  5. 42 29
      lxconsole/api/instances.py
  6. 0 217
      lxconsole/api/virtual_machines.py
  7. 5 21
      lxconsole/routes.py
  8. 0 0
      lxconsole/static/css/bootstrap/bootstrap.min.css.map
  9. 6 1
      lxconsole/static/css/styles.css
  10. 4 5
      lxconsole/static/js/sidebar.js
  11. 6 3
      lxconsole/templates/access-controls.html
  12. 6 3
      lxconsole/templates/certificates.html
  13. 6 3
      lxconsole/templates/cluster-groups.html
  14. 6 3
      lxconsole/templates/cluster-members.html
  15. 0 332
      lxconsole/templates/containers.html
  16. 6 3
      lxconsole/templates/groups.html
  17. 5 9
      lxconsole/templates/head.html
  18. 6 3
      lxconsole/templates/images.html
  19. 272 200
      lxconsole/templates/instance.html
  20. 632 0
      lxconsole/templates/instances.html
  21. 4 1
      lxconsole/templates/logs.html
  22. 7 12
      lxconsole/templates/main.html
  23. 14 14
      lxconsole/templates/modals/access-controls.html
  24. 10 10
      lxconsole/templates/modals/certificates.html
  25. 18 18
      lxconsole/templates/modals/cluster-groups.html
  26. 17 17
      lxconsole/templates/modals/cluster-members.html
  27. 6 6
      lxconsole/templates/modals/groups.html
  28. 18 18
      lxconsole/templates/modals/images.html
  29. 151 137
      lxconsole/templates/modals/instance.html
  30. 196 100
      lxconsole/templates/modals/instances.html
  31. 6 6
      lxconsole/templates/modals/main.html
  32. 11 11
      lxconsole/templates/modals/network-acl.html
  33. 13 13
      lxconsole/templates/modals/network-acls.html
  34. 17 17
      lxconsole/templates/modals/network-zones.html
  35. 35 35
      lxconsole/templates/modals/network.html
  36. 35 35
      lxconsole/templates/modals/networks.html
  37. 2 2
      lxconsole/templates/modals/operations.html
  38. 13 13
      lxconsole/templates/modals/profiles.html
  39. 40 40
      lxconsole/templates/modals/projects.html
  40. 4 4
      lxconsole/templates/modals/roles.html
  41. 15 15
      lxconsole/templates/modals/servers.html
  42. 3 3
      lxconsole/templates/modals/simplestreams.html
  43. 21 21
      lxconsole/templates/modals/storage-pools.html
  44. 17 17
      lxconsole/templates/modals/storage-volumes.html
  45. 17 17
      lxconsole/templates/modals/users.html
  46. 0 2361
      lxconsole/templates/modals/virtual-machine.html
  47. 0 655
      lxconsole/templates/modals/virtual-machines.html
  48. 6 6
      lxconsole/templates/navbar.html
  49. 12 6
      lxconsole/templates/network-acl.html
  50. 6 3
      lxconsole/templates/network-acls.html
  51. 6 3
      lxconsole/templates/network-zones.html
  52. 31 20
      lxconsole/templates/network.html
  53. 6 3
      lxconsole/templates/networks.html
  54. 4 1
      lxconsole/templates/operations.html
  55. 6 3
      lxconsole/templates/profiles.html
  56. 6 3
      lxconsole/templates/projects.html
  57. 6 3
      lxconsole/templates/roles.html
  58. 4 5
      lxconsole/templates/server.html
  59. 6 3
      lxconsole/templates/servers.html
  60. 4 12
      lxconsole/templates/sidebar.html
  61. 6 3
      lxconsole/templates/simplestreams.html
  62. 6 3
      lxconsole/templates/storage-pools.html
  63. 6 3
      lxconsole/templates/storage-volumes.html
  64. 6 3
      lxconsole/templates/users.html
  65. 0 2965
      lxconsole/templates/virtual-machine.html
  66. 0 328
      lxconsole/templates/virtual-machines.html
  67. 4 5
      roadmap.txt

+ 7 - 0
CHANGELOG.md

@@ -1,3 +1,10 @@
+# 0.4.0
+ - Upgraded Bootstrap from version 4 to version 5
+ - Converted containers and virtual-machines endpoints to instances endpoint
+ - Combined containers and virtual-machines pages to instances page
+ - Datatable errors now display on console.log rather than the default alert
+ - Handled 404 Error on new virtual machine without logs
+
 # 0.3.0
  - Improved Dockerfile for quicker builds
  - Added version specific flask and werkzeug to requirements due to build error in dependencies

+ 4 - 8
lxconsole/api/__init__.py

@@ -5,8 +5,8 @@ from . import certificates
 from . import cluster_groups
 from . import cluster_members
 from . import images
-from . import container
-from . import containers
+from . import instance
+from . import instances
 from . import network
 from . import networks
 from . import network_acl
@@ -18,8 +18,6 @@ from . import projects
 from . import simplestreams
 from . import storage_pools
 from . import storage_volumes
-from . import virtual_machine
-from . import virtual_machines
 
 from . import users
 from . import groups
@@ -32,8 +30,8 @@ api = Blueprint('api', __name__, url_prefix='/api')
 
 
 # URLs are prefixed with /api...
-api.add_url_rule('/container/<endpoint>', view_func=container.api_container_endpoint, methods=['GET', 'POST'])
-api.add_url_rule('/containers/<endpoint>', view_func=containers.api_containers_endpoint, methods=['GET', 'POST'])
+api.add_url_rule('/instance/<endpoint>', view_func=instance.api_instance_endpoint, methods=['GET', 'POST'])
+api.add_url_rule('/instances/<endpoint>', view_func=instances.api_instances_endpoint, methods=['GET', 'POST'])
 api.add_url_rule('/servers/<endpoint>', view_func=servers.api_servers_endpoint, methods=['GET', 'POST'])
 api.add_url_rule('/server/<endpoint>', view_func=server.api_server_endpoint)
 api.add_url_rule('/certificates/<endpoint>', view_func=certificates.api_certificates_endpoint, methods=['GET', 'POST'])
@@ -51,8 +49,6 @@ api.add_url_rule('/projects/<endpoint>', view_func=projects.api_projects_endpoin
 api.add_url_rule('/simplestreams/<endpoint>', view_func=simplestreams.api_simplestreams_endpoint, methods=['GET', 'POST'])
 api.add_url_rule('/storage-pools/<endpoint>', view_func=storage_pools.api_storage_pools_endpoint, methods=['GET', 'POST'])
 api.add_url_rule('/storage-volumes/<endpoint>', view_func=storage_volumes.api_storage_volumes_endpoint, methods=['GET', 'POST'])
-api.add_url_rule('/virtual-machine/<endpoint>', view_func=virtual_machine.api_virtual_machine_endpoint, methods=['GET', 'POST'])
-api.add_url_rule('/virtual-machines/<endpoint>', view_func=virtual_machines.api_virtual_machines_endpoint, methods=['GET', 'POST'])
 
 api.add_url_rule('/users/<endpoint>', view_func=users.api_users_endpoint, methods=['GET', 'POST'])
 api.add_url_rule('/groups/<endpoint>', view_func=groups.api_groups_endpoint, methods=['GET', 'POST'])

+ 0 - 1156
lxconsole/api/container.py

@@ -1,1156 +0,0 @@
-from flask import jsonify, request
-import json
-import requests
-import os
-from lxconsole import db
-from lxconsole.models import Server
-from datetime import datetime
-from flask_login import login_required
-from lxconsole.api.access_controls import privilege_check
-
-
-def get_client_crt():
-  return 'certs/client.crt'
-
-def get_client_key():
-  return 'certs/client.key'
-
-@login_required
-def api_container_endpoint(endpoint):
-
-  if not privilege_check(endpoint, request.args.get('id')):
-    return jsonify({'data': [], 'metadata':[], 'error': 'not authorized', 'error_code': 403})
-
-
-  if endpoint == 'add_instance_disk_device':
-    id = request.args.get('id')
-    project = request.args.get('project')
-    instance = request.args.get('instance')
-    server = Server.query.filter_by(id=id).first()
-    url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/containers/' + instance + '?project=' + project
-    client_cert = get_client_crt()
-    client_key = get_client_key()
-    results = requests.get(url, verify=server.ssl_verify, cert=(client_cert, client_key))
-    instance = json.dumps(results.json())
-    instance = json.loads(instance)
-    # Before applying PATCH, check to make sure device does not already exists so that we do not overwrite an existing device
-    if request.form.get('name') in instance['metadata']['devices'].keys():
-      return jsonify({"type": "error","error": "Unable to add new device. Device name already exists","error_code": 409,"metadata": {"error": "Unable to add new device. Device name already exists"}})
-    description = instance['metadata']['description']
-    data = {}
-    device = {}
-    device.update({'type': 'disk'})
-    device.update({'pool': request.form.get('pool')}) if request.form.get('pool') else False
-    device.update({'source': request.form.get('source')}) if request.form.get('source') else False
-    device.update({'path': request.form.get('path')}) if request.form.get('path') else False
-    device.update({'limits_read': request.form.get('limits_read')}) if request.form.get('limits_read') else False
-    device.update({'limits_write': request.form.get('limits_write')}) if request.form.get('limits_write') else False
-    device.update({'limits_max': request.form.get('limits_max')}) if request.form.get('limits_max') else False
-    device.update({'required': request.form.get('required')}) if request.form.get('required') else False
-    device.update({'read_only': request.form.get('read_only')}) if request.form.get('read_only') else False
-    device.update({'size': request.form.get('size')}) if request.form.get('size') else False
-    device.update({'size_state': request.form.get('size_state')}) if request.form.get('size_state') else False
-    device.update({'recursive': request.form.get('recursive')}) if request.form.get('recursive') else False
-    device.update({'propagation': request.form.get('propagation')}) if request.form.get('propagation') else False
-    device.update({'shift': request.form.get('shift')}) if request.form.get('shift') else False
-    device.update({'raw_mount_options': request.form.get('raw_mount_options')}) if request.form.get('raw_mount_options') else False
-    device.update({'ceph_user_name': request.form.get('ceph_user_name')}) if request.form.get('ceph_user_name') else False
-    device.update({'ceph_cluster_name': request.form.get('ceph_cluster_name')}) if request.form.get('ceph_cluster_name') else False
-    device.update({'boot_priority': request.form.get('boot_priority')}) if request.form.get('boot_priority') else False
-
-    devices = {}
-    devices.update({request.form.get('name'): device})
-    data.update({'description': description})
-    data.update({'devices': devices})
-    results = requests.patch(url, verify=server.ssl_verify, cert=(client_cert, client_key), json=data)
-    return jsonify(results.json())
-
-
-  if endpoint == 'add_instance_gpu_device':
-    id = request.args.get('id')
-    project = request.args.get('project')
-    instance = request.args.get('instance')
-    server = Server.query.filter_by(id=id).first()
-    url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/containers/' + instance + '?project=' + project
-    client_cert = get_client_crt()
-    client_key = get_client_key()
-    results = requests.get(url, verify=server.ssl_verify, cert=(client_cert, client_key))
-    instance = json.dumps(results.json())
-    instance = json.loads(instance)
-    # Before applying PATCH, check to make sure device does not already exists so that we do not overwrite an existing device
-    if request.form.get('name') in instance['metadata']['devices'].keys():
-      return jsonify({"type": "error","error": "Unable to add new device. Device name already exists","error_code": 409,"metadata": {"error": "Unable to add new device. Device name already exists"}})
-    description = instance['metadata']['description']
-    data = {}
-    device = {}
-    device.update({'type': 'gpu'})
-    device.update({'gputype': request.form.get('gputype')}) if request.form.get('gputype') else False
-    device.update({'vendorid': request.form.get('vendorid')}) if request.form.get('vendorid') else False
-    device.update({'productid': request.form.get('productid')}) if request.form.get('productid') else False
-    device.update({'id': request.form.get('id')}) if request.form.get('id') else False
-    device.update({'pci': request.form.get('pci')}) if request.form.get('pci') else False
-    device.update({'uid': request.form.get('uid')}) if request.form.get('uid') else False
-    device.update({'gid': request.form.get('gid')}) if request.form.get('gid') else False
-    device.update({'mode': request.form.get('mode')}) if request.form.get('mode') else False
-    device.update({'mig.ci': request.form.get('mig.ci')}) if request.form.get('mig.ci') else False
-    device.update({'mig.gi': request.form.get('mig.gi')}) if request.form.get('mig.gi') else False
-    devices = {}
-    devices.update({request.form.get('name'): device})
-    data.update({'description': description})
-    data.update({'devices': devices})
-    results = requests.patch(url, verify=server.ssl_verify, cert=(client_cert, client_key), json=data)
-    return jsonify(results.json())
-
-
-  if endpoint == 'add_instance_network_device':
-    id = request.args.get('id')
-    project = request.args.get('project')
-    instance = request.args.get('instance')
-    server = Server.query.filter_by(id=id).first()
-    url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/containers/' + instance + '?project=' + project
-    client_cert = get_client_crt()
-    client_key = get_client_key()
-    results = requests.get(url, verify=server.ssl_verify, cert=(client_cert, client_key))
-    instance = json.dumps(results.json())
-    instance = json.loads(instance)
-    # Before applying PATCH, check to make sure device does not already exists so that we do not overwrite an existing device
-    if request.form.get('name') in instance['metadata']['devices'].keys():
-      return jsonify({"type": "error","error": "Unable to add new device. Device name already exists","error_code": 409,"metadata": {"error": "Unable to add new device. Device name already exists"}})
-    description = instance['metadata']['description']
-    data = {}
-    device = {}
-    device.update({'type': 'nic'})
-    device.update({'nictype': request.form.get('nictype')}) if request.form.get('nictype') else False
-    device.update({'parent': request.form.get('parent')}) if request.form.get('parent') else False
-    device.update({'network': request.form.get('network')}) if request.form.get('network') else False
-    device.update({'interface_name': request.form.get('interface_name')}) if request.form.get('interface_name') else False
-    device.update({'mtu': request.form.get('mtu')}) if request.form.get('mtu') else False
-    device.update({'mode': request.form.get('mode')}) if request.form.get('mode') else False
-    device.update({'hwaddr': request.form.get('hwaddr')}) if request.form.get('hwaddr') else False
-    device.update({'host_name': request.form.get('host_name')}) if request.form.get('host_name') else False
-    device.update({'limits_ingress': request.form.get('limits_ingress')}) if request.form.get('limits_ingress') else False
-    device.update({'limits_egress': request.form.get('limits_egress')}) if request.form.get('limits_egress') else False
-    device.update({'limits_max': request.form.get('limits_max')}) if request.form.get('limits_max') else False
-    device.update({'ipv4_address': request.form.get('ipv4_address')}) if request.form.get('ipv4_address') else False
-    device.update({'ipv4_gateway': request.form.get('ipv4_gateway')}) if request.form.get('ipv4_gateway') else False
-    device.update({'ipv4_host_table': request.form.get('ipv4_host_table')}) if request.form.get('ipv4_host_table') else False
-    device.update({'ipv4_host_address': request.form.get('ipv4_host_address')}) if request.form.get('ipv4_host_address') else False
-    device.update({'ipv4_routes': request.form.get('ipv4_routes')}) if request.form.get('ipv4_routes') else False
-    device.update({'ipv4_routes_external': request.form.get('ipv4_routes_external')}) if request.form.get('ipv4_routes_external') else False
-    device.update({'ipv6_address': request.form.get('ipv6_address')}) if request.form.get('ipv6_address') else False
-    device.update({'ipv6_gateway': request.form.get('ipv6_gateway')}) if request.form.get('ipv6_gateway') else False
-    device.update({'ipv6_host_table': request.form.get('ipv6_host_table')}) if request.form.get('ipv6_host_table') else False
-    device.update({'ipv6_host_address': request.form.get('ipv6_host_address')}) if request.form.get('ipv6_host_address') else False
-    device.update({'ipv6_routes': request.form.get('ipv6_routes')}) if request.form.get('ipv6_routes') else False
-    device.update({'ipv6_routes_external': request.form.get('ipv6_routes_external')}) if request.form.get('ipv6_routes_external') else False
-    device.update({'security_mac_filtering': request.form.get('security_mac_filtering')}) if request.form.get('security_mac_filtering') else False
-    device.update({'security_ipv4_filtering': request.form.get('security_ipv4_filtering')}) if request.form.get('security_ipv4_filtering') else False
-    device.update({'security_ipv6_filtering': request.form.get('security_ipv6_filtering')}) if request.form.get('security_ipv6_filtering') else False
-    device.update({'maas_subnet_ipv4': request.form.get('maas_subnet_ipv4')}) if request.form.get('maas_subnet_ipv4') else False
-    device.update({'maas_subnet_ipv6': request.form.get('maas_subnet_ipv6')}) if request.form.get('maas_subnet_ipv6') else False
-    device.update({'boot_priority': request.form.get('boot_priority')}) if request.form.get('boot_priority') else False
-    device.update({'vlan': request.form.get('vlan')}) if request.form.get('vlan') else False
-    device.update({'vlan_tagged': request.form.get('vlan_tagged')}) if request.form.get('vlan_tagged') else False
-    device.update({'security_port_isolation': request.form.get('security_port_isolation')}) if request.form.get('security_port_isolation') else False
-    device.update({'gvrp': request.form.get('gvrp')}) if request.form.get('gvrp') else False
-    device.update({'security_acls': request.form.get('security_acls')}) if request.form.get('security_acls') else False
-    device.update({'security_acls_default_ingress_action': request.form.get('security_acls_default_ingress_action')}) if request.form.get('security_acls_default_ingress_action') else False
-    device.update({'security_acls_default_egress_action': request.form.get('security_acls_default_egress_action')}) if request.form.get('security_acls_default_egress_action') else False
-    device.update({'security_acls_default_ingress_logged': request.form.get('security_acls_default_ingress_logged')}) if request.form.get('security_acls_default_ingress_logged') else False
-    device.update({'security_acls_default_egress_logged': request.form.get('security_acls_default_egress_logged')}) if request.form.get('security_acls_default_egress_logged') else False    
-    devices = {}
-    devices.update({request.form.get('name'): device})
-    data.update({'description': description})
-    data.update({'devices': devices})
-    results = requests.patch(url, verify=server.ssl_verify, cert=(client_cert, client_key), json=data)
-    return jsonify(results.json())
-
-
-  if endpoint == 'add_instance_proxy_device':
-    id = request.args.get('id')
-    project = request.args.get('project')
-    instance = request.args.get('instance')
-    server = Server.query.filter_by(id=id).first()
-    url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/containers/' + instance + '?project=' + project
-    client_cert = get_client_crt()
-    client_key = get_client_key()
-    results = requests.get(url, verify=server.ssl_verify, cert=(client_cert, client_key))
-    instance = json.dumps(results.json())
-    instance = json.loads(instance)
-    # Before applying PATCH, check to make sure device does not already exists so that we do not overwrite an existing device
-    if request.form.get('name') in instance['metadata']['devices'].keys():
-      return jsonify({"type": "error","error": "Unable to add new device. Device name already exists","error_code": 409,"metadata": {"error": "Unable to add new device. Device name already exists"}})
-    description = instance['metadata']['description']
-    data = {}
-    device = {}
-    device.update({'type': 'proxy'})
-    device.update({'listen': request.form.get('listen')}) if request.form.get('listen') else False
-    device.update({'connect': request.form.get('connect')}) if request.form.get('connect') else False
-    device.update({'bind': request.form.get('bind')}) if request.form.get('bind') else False
-    device.update({'uid': request.form.get('uid')}) if request.form.get('uid') else False
-    device.update({'gid': request.form.get('gid')}) if request.form.get('gid') else False
-    device.update({'mode': request.form.get('mode')}) if request.form.get('mode') else False
-    device.update({'nat': request.form.get('nat')}) if request.form.get('nat') else False
-    device.update({'proxy_protocol': request.form.get('proxy_protocol')}) if request.form.get('proxy_protocol') else False
-    device.update({'security_uid': request.form.get('security_uid')}) if request.form.get('security_uid') else False
-    device.update({'security_gid': request.form.get('security_gid')}) if request.form.get('security_gid') else False
-    devices = {}
-    devices.update({request.form.get('name'): device})
-    data.update({'description': description})
-    data.update({'devices': devices})
-    results = requests.patch(url, verify=server.ssl_verify, cert=(client_cert, client_key), json=data)
-    return jsonify(results.json())
-
-
-  if endpoint == 'add_instance_unix_device':
-    id = request.args.get('id')
-    project = request.args.get('project')
-    instance = request.args.get('instance')
-    server = Server.query.filter_by(id=id).first()
-    url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/containers/' + instance + '?project=' + project
-    client_cert = get_client_crt()
-    client_key = get_client_key()
-    results = requests.get(url, verify=server.ssl_verify, cert=(client_cert, client_key))
-    instance = json.dumps(results.json())
-    instance = json.loads(instance)
-    # Before applying PATCH, check to make sure device does not already exists so that we do not overwrite an existing device
-    if request.form.get('name') in instance['metadata']['devices'].keys():
-      return jsonify({"type": "error","error": "Unable to add new device. Device name already exists","error_code": 409,"metadata": {"error": "Unable to add new device. Device name already exists"}})
-    description = instance['metadata']['description']
-    data = {}
-    device = {}
-    device.update({'type': request.form.get('type')}) if request.form.get('type') else False
-    device.update({'source': request.form.get('source')}) if request.form.get('source') else False
-    device.update({'path': request.form.get('path')}) if request.form.get('path') else False
-    device.update({'major': request.form.get('major')}) if request.form.get('major') else False
-    device.update({'minor': request.form.get('minor')}) if request.form.get('minor') else False
-    device.update({'uid': request.form.get('uid')}) if request.form.get('uid') else False
-    device.update({'gid': request.form.get('gid')}) if request.form.get('gid') else False
-    device.update({'mode': request.form.get('mode')}) if request.form.get('mode') else False
-    device.update({'required': request.form.get('required')}) if request.form.get('required') else False
-    devices = {}
-    devices.update({request.form.get('name'): device})
-    data.update({'description': description})
-    data.update({'devices': devices})
-    results = requests.patch(url, verify=server.ssl_verify, cert=(client_cert, client_key), json=data)
-    return jsonify(results.json())
-  
-
-  if endpoint == 'add_instance_usb_device':
-    id = request.args.get('id')
-    project = request.args.get('project')
-    instance = request.args.get('instance')
-    server = Server.query.filter_by(id=id).first()
-    url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/containers/' + instance + '?project=' + project
-    client_cert = get_client_crt()
-    client_key = get_client_key()
-    results = requests.get(url, verify=server.ssl_verify, cert=(client_cert, client_key))
-    instance = json.dumps(results.json())
-    instance = json.loads(instance)
-    # Before applying PATCH, check to make sure device does not already exists so that we do not overwrite an existing device
-    if request.form.get('name') in instance['metadata']['devices'].keys():
-      return jsonify({"type": "error","error": "Unable to add new device. Device name already exists","error_code": 409,"metadata": {"error": "Unable to add new device. Device name already exists"}})
-    description = instance['metadata']['description']
-    data = {}
-    device = {}
-    device.update({'type': 'usb'})
-    device.update({'vendorid': request.form.get('vendorid')}) if request.form.get('vendorid') else False
-    device.update({'productid': request.form.get('productid')}) if request.form.get('productid') else False
-    device.update({'uid': request.form.get('uid')}) if request.form.get('uid') else False
-    device.update({'gid': request.form.get('gid')}) if request.form.get('gid') else False
-    device.update({'mode': request.form.get('mode')}) if request.form.get('mode') else False
-    devices = {}
-    devices.update({request.form.get('name'): device})
-    data.update({'description': description})
-    data.update({'devices': devices})
-    results = requests.patch(url, verify=server.ssl_verify, cert=(client_cert, client_key), json=data)
-    return jsonify(results.json())
-
-
-  if endpoint == 'attach_instance_profile':
-    id = request.args.get('id')
-    project = request.args.get('project')
-    instance = request.args.get('instance')
-    server = Server.query.filter_by(id=id).first()
-    url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/containers/' + instance + '?project=' + project
-    client_cert = get_client_crt()
-    client_key = get_client_key()
-    results = requests.get(url, verify=server.ssl_verify, cert=(client_cert, client_key))
-    instance = json.dumps(results.json())
-    instance = json.loads(instance)
-    description = instance['metadata']['description']
-    data = {}
-    profiles = instance['metadata']['profiles']
-    if request.form.get('name') not in profiles:
-      profiles.append(request.form.get('name'))
-    data.update({'description': description})
-    data.update({'profiles': profiles})
-    results = requests.patch(url, verify=server.ssl_verify, cert=(client_cert, client_key), json=data)
-    return jsonify(results.json())
-
-
-  if endpoint == 'change_instance_state':
-    id = request.args.get('id')
-    project = request.args.get('project')
-    instance = request.form.get('instance')
-    action = request.form.get('action')
-    force = request.form.get('force')
-    server = Server.query.filter_by(id=id).first()
-    url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/containers/' + instance + '/state?project=' + project
-    client_cert = get_client_crt()
-    client_key = get_client_key()
-    if force == 'true':
-      data = { 'action': action, 'force': True }
-    else:
-      data = { 'action': action, 'force': False }
-    results = requests.put(url, verify=server.ssl_verify, cert=(client_cert, client_key), json=data)
-    return jsonify(results.json())
-
-
-  if endpoint == 'copy_instance':
-    id = request.args.get('id')
-    project = request.args.get('project')
-    instance = request.args.get('instance')
-    server = Server.query.filter_by(id=id).first()
-    location = request.args.get('location')
-    #Target location is needed for clustered servers and not allowed on non-clustered servers
-    if location == 'none':
-      url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/containers?project=' + project
-    else:
-      url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/containers?target='+location+'&project=' + project
-    client_cert = get_client_crt()
-    client_key = get_client_key()
-    data = {}
-    data.update({'name': request.form.get('name')})
-    source = {}
-    source.update({'type': 'copy'})
-    source.update({'source': instance })
-    source.update({'project': project})
-    data.update({'source': source})
-    results = requests.post(url, verify=server.ssl_verify, cert=(client_cert, client_key), json=data)
-    return jsonify(results.json())
-
-
-  if endpoint == 'create_instance_backup':
-    id = request.args.get('id')
-    project = request.args.get('project')
-    instance = request.args.get('instance')
-    server = Server.query.filter_by(id=id).first()
-    url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/containers/' + instance + '/backups?project=' + project
-    client_cert = get_client_crt()
-    client_key = get_client_key()
-    
-    # Determine file name
-    name = request.form.get('name')
-    if not name:
-      now = datetime.now()
-      dt_string = now.strftime("%Y%m%d%H%M%S")
-      name = instance + '-' + dt_string
-
-    # Determine file extenstion
-    compression_algorithm = request.form.get('compression_algorithm')
-    if compression_algorithm == 'bzip2':
-      extenstion = '.tar.bz2'
-    elif compression_algorithm == 'gzip':
-      extenstion = '.tar.gz'
-    elif compression_algorithm == 'lzma':
-      extenstion = '.tar.lzma'
-    elif compression_algorithm == 'xz':
-      extenstion = '.tar.xz'
-    elif compression_algorithm == 'zstd':
-      extenstion = '.tar.zst'
-    else: 
-      extenstion = '.tar'
-
-    # Append file extension to name
-    name = name + extenstion
-
-    data = {}
-    data.update({'name': name})
-    data.update({'instance_only': True }) if request.form.get('instance_only') == 'true' else data.update({'instance_only': False })
-    data.update({'optimized_storage': True }) if request.form.get('optimized_storage') == 'true' else data.update({'optimized_storage': False })
-    data.update({'compression_algorithm': request.form.get('compression_algorithm')}) if request.form.get('compression_algorithm') else False
-    results = requests.post(url, verify=server.ssl_verify, cert=(client_cert, client_key), json=data)
-    return jsonify(results.json())
-  
-
-  if endpoint == 'create_instance_snapshot':
-    id = request.args.get('id')
-    project = request.args.get('project')
-    instance = request.args.get('instance')
-    server = Server.query.filter_by(id=id).first()
-    url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/containers/' + instance + '/snapshots?project=' + project
-    client_cert = get_client_crt()
-    client_key = get_client_key()
-    data = {}
-    data.update({'name': request.form.get('name')})
-    if request.form.get('stateful') == 'true':
-      data.update({'stateful': True})
-    else:
-      data.update({'stateful': False})
-    results = requests.post(url, verify=server.ssl_verify, cert=(client_cert, client_key), json=data)
-    return jsonify(results.json())
-
-
-  if endpoint == 'create_instance_snapshot_instance':
-    id = request.args.get('id')
-    project = request.args.get('project')
-    instance = request.args.get('instance')
-    server = Server.query.filter_by(id=id).first()
-    location = request.args.get('location')
-    #Target location is needed for clustered servers and not allowed on non-clustered servers
-    if location == 'none':
-      url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/containers?project=' + project
-    else:
-      url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/containers?target='+location+'&project=' + project
-    client_cert = get_client_crt()
-    client_key = get_client_key()
-    data = {}
-    data.update({'name': request.form.get('name')})
-    source = {}
-    source.update({'type': 'copy'})
-    source.update({'instance_only': True})
-    source.update({'source': instance + '/' + request.form.get('snapshot')})
-    source.update({'project': project})
-    data.update({'source': source})
-    results = requests.post(url, verify=server.ssl_verify, cert=(client_cert, client_key), json=data)
-    return jsonify(results.json())
-
-
-  if endpoint == 'delete_instance_backup':
-    id = request.args.get('id')
-    project = request.args.get('project')
-    instance = request.args.get('instance')
-    backup = request.args.get('backup')
-    server = Server.query.filter_by(id=id).first()
-    url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/containers/' + instance + '/backups/' + backup + '?project=' + project
-    client_cert = get_client_crt()
-    client_key = get_client_key()
-    if os.path.isfile('backups/' + str(server.id) + '/' + project + '/' + instance + '/' + backup):
-      os.unlink('backups/' + str(server.id) + '/' + project + '/' + instance + '/' + backup)
-    results = requests.delete(url, verify=server.ssl_verify, cert=(client_cert, client_key))
-    return jsonify(results.json())
-
-
-  if endpoint == 'delete_instance_device':
-    id = request.args.get('id')
-    project = request.args.get('project')
-    instance = request.args.get('instance')
-    device = request.args.get('device')
-    server = Server.query.filter_by(id=id).first()
-    url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/containers/' + instance + '?project=' + project
-    client_cert = get_client_crt()
-    client_key = get_client_key()
-    results = requests.get(url, verify=server.ssl_verify, cert=(client_cert, client_key))
-    instance = json.dumps(results.json())
-    instance = json.loads(instance)
-    data = instance['metadata']
-    data['devices'].pop(device)
-    results = requests.put(url, verify=server.ssl_verify, cert=(client_cert, client_key), json=data)
-    return jsonify(results.json())
-
-
-  if endpoint == 'delete_instance':
-    id = request.args.get('id')
-    project = request.args.get('project')
-    instance = request.form.get('instance')
-    server = Server.query.filter_by(id=id).first()
-    url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/containers/' + instance + '?project=' + project
-    client_cert = get_client_crt()
-    client_key = get_client_key()
-    results = requests.delete(url, verify=server.ssl_verify, cert=(client_cert, client_key))
-    return jsonify(results.json())
-
-
-  if endpoint == 'delete_instance_log':
-    id = request.args.get('id')
-    project = request.args.get('project')
-    log = request.args.get('log')
-    server = Server.query.filter_by(id=id).first()
-    url = 'https://' + server.addr + ':' + str(server.port) + log + '?project=' + project
-    client_cert = get_client_crt()
-    client_key = get_client_key()
-    results = requests.delete(url, verify=server.ssl_verify, cert=(client_cert, client_key))
-    return jsonify(results.json())
-
-
-  if endpoint == 'delete_instance_snapshot':
-    id = request.args.get('id')
-    project = request.args.get('project')
-    instance = request.args.get('instance')
-    snapshot = request.args.get('snapshot')
-    server = Server.query.filter_by(id=id).first()
-    url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/containers/' + instance + '/snapshots/' + snapshot + '?project=' + project
-    client_cert = get_client_crt()
-    client_key = get_client_key()
-    results = requests.delete(url, verify=server.ssl_verify, cert=(client_cert, client_key))
-    return jsonify(results.json())
-
-
-  if endpoint == 'detach_instance_profile':
-    id = request.args.get('id')
-    project = request.args.get('project')
-    instance = request.args.get('instance')
-    profile = request.args.get('profile')
-    server = Server.query.filter_by(id=id).first()
-    url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/containers/' + instance + '?project=' + project
-    client_cert = get_client_crt()
-    client_key = get_client_key()
-    results = requests.get(url, verify=server.ssl_verify, cert=(client_cert, client_key))
-    instance = json.dumps(results.json())
-    instance = json.loads(instance)
-    instance = instance['metadata']
-    description = instance['description']
-    instance_profiles = instance['profiles']
-    instance_profiles.remove(profile)
-    data = {}
-    data.update({ 'description': description })
-    data.update({ 'profiles': instance_profiles})
-    results = requests.patch(url, verify=server.ssl_verify, cert=(client_cert, client_key), json=data)
-    return jsonify(results.json())
-
-
-  if endpoint == 'display_instance_log':
-    id = request.args.get('id')
-    project = request.args.get('project')
-    server = Server.query.filter_by(id=id).first()
-    log = request.args.get('log')
-    url = 'https://' + server.addr + ':' + str(server.port) + log + '?project=' + project
-    client_cert = get_client_crt()
-    client_key = get_client_key()
-    results = requests.get(url, verify=server.ssl_verify, cert=(client_cert, client_key))
-    return results.text
-  
-
-  if endpoint == 'establish_instance_console_websocket':
-    id = request.args.get('id')
-    project = request.args.get('project')
-    instance = request.args.get('instance')
-    server = Server.query.filter_by(id=id).first()
-    url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/containers/' + instance + '/console?project=' + project
-    client_cert = get_client_crt()
-    client_key = get_client_key()
-    data = {}
-    data.update({'type': 'console'})
-    data.update({'width': int(request.form.get('width'))})
-    data.update({'height': int(request.form.get('height'))})
-    results = requests.post(url, verify=server.ssl_verify, cert=(client_cert, client_key), json=data)
-    results = json.dumps(results.json())
-    results = json.loads(results)
-
-    operation = results['operation'] if results['operation'] else ''
-    secret = str(results['metadata']['metadata']['fds']['0']) if str(results['metadata']['metadata']['fds']['0']) else ''
-    control = str(results['metadata']['metadata']['fds']['control']) if str(results['metadata']['metadata']['fds']['control']) else ''
-
-    return jsonify({'operation': operation, 'secret': secret, 'control': control})
-  
-
-  if endpoint == 'establish_instance_exec_websocket':
-    id = request.args.get('id')
-    project = request.args.get('project')
-    instance = request.args.get('instance')
-    server = Server.query.filter_by(id=id).first()
-    url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/containers/' + instance + '/exec?project=' + project
-    client_cert = get_client_crt()
-    client_key = get_client_key()
-    data = {}
-    if request.form.get('shell') == "sh":
-        data.update({'command': ["/bin/sh"]})
-    else:
-        data.update({'command': ["/bin/bash"]})
-    data.update({'wait-for-websocket':True})
-    data.update({'interactive': True})
-    data.update({'width': int(request.form.get('width'))})
-    data.update({'height': int(request.form.get('height'))})
-    environment = {}
-    environment.update({'HOME': '/root'})
-    environment.update({'TERM': 'xterm'})
-    environment.update({'USER': 'root'})
-    data.update({'environment': environment})
-    results = requests.post(url, verify=server.ssl_verify, cert=(client_cert, client_key), json=data)
-    results = json.dumps(results.json())
-    results = json.loads(results)
-
-    operation = results['operation'] if results['operation'] else ''
-    secret = str(results['metadata']['metadata']['fds']['0']) if str(results['metadata']['metadata']['fds']['0']) else ''
-    control = str(results['metadata']['metadata']['fds']['control']) if str(results['metadata']['metadata']['fds']['control']) else ''
-
-    return jsonify({'operation': operation, 'secret': secret, 'control': control})
-  
-
-  if endpoint == 'export_instance_backup':
-    id = request.args.get('id')
-    project = request.args.get('project')
-    server = Server.query.filter_by(id=id).first()
-    instance = request.args.get('instance')
-    backup = request.args.get('backup')
-    url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/containers/' + instance + '/backups/' + backup + '/export?project=' + project
-    client_cert = get_client_crt()
-    client_key = get_client_key()
-    os.system('mkdir -p backups/' + str(server.id) + '/' + project + '/' + instance)
-    filename = 'backups/' + str(server.id) + '/' + project + '/' + instance + '/' + backup
-    with requests.get(url, stream=True, verify=server.ssl_verify, cert=(client_cert, client_key)) as r:
-      r.raise_for_status()
-      with open(filename, 'wb') as f:
-        for chunk in r.iter_content(chunk_size=8192): 
-          f.write(chunk)
-    return jsonify({"status": "Ok", "status_code": 200, "metadata": "{}"})
-
-
-  if endpoint == 'get_instance_cpu_usage':
-
-    id = request.args.get('id')
-    project = request.args.get('project')
-    server = Server.query.filter_by(id=id).first()
-    name = request.args.get('name')    
-    client_cert = get_client_crt()
-    client_key = get_client_key()
-
-    #Get instance state to retrieve container cpu usage
-    url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/containers/' + name + '/state?project=' + project
-    results = requests.get(url, verify=server.ssl_verify, cert=(client_cert, client_key))
-    results = json.dumps(results.json())
-    results = json.loads(results)
-    #Get cpu usage
-    if 'cpu' in results['metadata']:
-      if 'usage' in results['metadata']['cpu']:
-        #Usage is reported in nanoseconds
-        instance_cpu_time = int(results['metadata']['cpu']['usage'])
-      else:
-        instance_cpu_time = 0
-    else:
-      instance_cpu_time = 0
-
-    #Get /proc/stat information
-    url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/containers/' + name + '/files?project=' + project + '&path=/proc/stat'
-    results = requests.get(url, verify=server.ssl_verify, cert=(client_cert, client_key))
-    if 'cpu' in results.text:
-      results = results.text.split('\n')
-      for result in results:
-        stats = result.split()
-        if stats[0] == 'cpu':
-          #0 = 'cpu'
-          #1 = <user time>
-          #2 = <nice time>
-          #3 = <system time>
-          #4 = <idle time>
-          user_time = int(stats[1])
-          system_time= int(stats[3])
-          idle_time = int(stats[4])
-          host_cpu_time = user_time + system_time + idle_time
-
-          return jsonify({'instance_cpu_time':instance_cpu_time,'host_cpu_time': host_cpu_time})
-      
-    return jsonify({'instance_cpu_time':0,'host_cpu_time': 0})
-  
-
-  if endpoint == 'get_instance':
-    id = request.args.get('id')
-    project = request.args.get('project')
-    server = Server.query.filter_by(id=id).first()
-    name = request.args.get('name')
-    recursion = request.args.get('recursion')
-    if recursion == '1':
-      url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/containers/' + name + '?recursion=1&project=' + project
-    else:
-      url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/containers/' + name + '?project=' + project
-    client_cert = get_client_crt()
-    client_key = get_client_key()
-    results = requests.get(url, verify=server.ssl_verify, cert=(client_cert, client_key))
-    return jsonify(results.json())
-  
-
-  if endpoint == 'get_instance_disk_devices':
-    id = request.args.get('id')
-    project = request.args.get('project')
-    server = Server.query.filter_by(id=id).first()
-    name = request.args.get('name')
-    recursion = request.args.get('recursion')
-    if recursion == '1':
-      url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/containers/' + name + '?recursion=1&project=' + project
-    else:
-      url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/containers/' + name + '?project=' + project
-    client_cert = get_client_crt()
-    client_key = get_client_key()
-    results = requests.get(url, verify=server.ssl_verify, cert=(client_cert, client_key))
-    instance = json.dumps(results.json())
-    instance = json.loads(instance)
-    expanded_devices = instance['metadata']['expanded_devices']
-    devices = []
-    instance_state_url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/containers/' + name + '/state?project=' + project
-    instance_state = requests.get(instance_state_url, verify=server.ssl_verify, cert=(client_cert, client_key))
-    instance_state = json.dumps(instance_state.json())
-    instance_state = json.loads(instance_state)
-    if expanded_devices:
-      for expanded_device in expanded_devices:
-        if expanded_devices[expanded_device]['type'] == 'disk':
-          device = {}
-          device.update({ 'device': expanded_device })
-          device.update({ 'type': expanded_devices[expanded_device]['type'] })
-          if 'path' in expanded_devices[expanded_device]:
-            device.update({ 'path': expanded_devices[expanded_device]['path'] })
-          if 'pool' in expanded_devices[expanded_device]:
-            device.update({ 'pool': expanded_devices[expanded_device]['pool'] })
-          if expanded_device in instance_state['metadata']['disk']:
-            if 'usage' in instance_state['metadata']['disk'][expanded_device]:
-              device.update({ 'usage': instance_state['metadata']['disk'][expanded_device]['usage'] })
-
-          devices.append(device)
-    return jsonify({ 'data': devices })
-
-
-  if endpoint == 'get_instance_gpu_devices':
-    id = request.args.get('id')
-    project = request.args.get('project')
-    server = Server.query.filter_by(id=id).first()
-    name = request.args.get('name')
-    recursion = request.args.get('recursion')
-    if recursion == '1':
-      url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/containers/' + name + '?recursion=1&project=' + project
-    else:
-      url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/containers/' + name + '?project=' + project
-    client_cert = get_client_crt()
-    client_key = get_client_key()
-    results = requests.get(url, verify=server.ssl_verify, cert=(client_cert, client_key))
-    instance = json.dumps(results.json())
-    instance = json.loads(instance)
-    expanded_devices = instance['metadata']['expanded_devices']
-    devices = []
-    if expanded_devices:
-      for expanded_device in expanded_devices:
-        if expanded_devices[expanded_device]['type'] == 'gpu':
-          device = {}
-          device.update({ 'device': expanded_device })
-          device.update({ 'type': expanded_devices[expanded_device]['type'] })
-          if 'gputype' in expanded_devices[expanded_device]:
-            device.update({ 'gputype': expanded_devices[expanded_device]['gputype'] })
-          if 'vendorid' in expanded_devices[expanded_device]:
-            device.update({ 'vendorid': expanded_devices[expanded_device]['vendorid'] })
-          if 'productid' in expanded_devices[expanded_device]:
-            device.update({ 'productid': expanded_devices[expanded_device]['productid'] })
-          if 'id' in expanded_devices[expanded_device]:
-            device.update({ 'id': expanded_devices[expanded_device]['id'] })
-          if 'pci' in expanded_devices[expanded_device]:
-            device.update({ 'pci': expanded_devices[expanded_device]['pci'] })
-          if 'uid' in expanded_devices[expanded_device]:
-            device.update({ 'uid': expanded_devices[expanded_device]['uid'] })
-          if 'gid' in expanded_devices[expanded_device]:
-            device.update({ 'gid': expanded_devices[expanded_device]['gid'] })
-          if 'mode' in expanded_devices[expanded_device]:
-            device.update({ 'mode': expanded_devices[expanded_device]['mode'] })
-          if 'mig.ci' in expanded_devices[expanded_device]:
-            device.update({ 'mig.ci': expanded_devices[expanded_device]['mig.ci'] })
-          if 'mig.gi' in expanded_devices[expanded_device]:
-            device.update({ 'mig.gi': expanded_devices[expanded_device]['mig.gi'] })
-          devices.append(device)
-    return jsonify({ 'data': devices })
-
-
-  if endpoint == 'get_instance_interfaces':
-    id = request.args.get('id')
-    project = request.args.get('project')
-    server = Server.query.filter_by(id=id).first()
-    name = request.args.get('name')
-    recursion = request.args.get('recursion')
-    if recursion == '1':
-      url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/containers/' + name + '/state?recursion=1&project=' + project
-    else:
-      url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/containers/' + name + '/state?project=' + project
-    client_cert = get_client_crt()
-    client_key = get_client_key()
-    results = requests.get(url, verify=server.ssl_verify, cert=(client_cert, client_key))
-    instance = json.dumps(results.json())
-    instance = json.loads(instance)
-    networks = instance['metadata']['network']
-    interfaces = []
-    if networks:
-      for network in networks:
-        if network:
-          interface = {}
-          interface.update({ 'name': network })
-          interface.update({ 'hwaddr': networks[network]['hwaddr'] })
-          interface.update({ 'state': networks[network]['state'] })
-          addresses = networks[network]['addresses']
-          interface.update({ 'ipv4_addresses': [] })
-          interface.update({ 'ipv6_addresses': [] })
-          for address in addresses:
-            #if address['family'] == 'inet' and address['scope'] == 'global':
-            if address['family'] == 'inet':
-              interface['ipv4_addresses'] += [ address['address'] ]
-            if address['family'] == 'inet6':
-              interface['ipv6_addresses'] += [ address['address'] ]
-          interfaces.append(interface)
-    return jsonify({ 'data': interfaces })
-
-
-  if endpoint == 'get_instance_network_devices':
-    id = request.args.get('id')
-    project = request.args.get('project')
-    server = Server.query.filter_by(id=id).first()
-    name = request.args.get('name')
-    recursion = request.args.get('recursion')
-    if recursion == '1':
-      url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/containers/' + name + '?recursion=1&project=' + project
-    else:
-      url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/containers/' + name + '?project=' + project
-    client_cert = get_client_crt()
-    client_key = get_client_key()
-    results = requests.get(url, verify=server.ssl_verify, cert=(client_cert, client_key))
-    instance = json.dumps(results.json())
-    instance = json.loads(instance)
-    expanded_devices = instance['metadata']['expanded_devices']
-    devices = []
-    if expanded_devices:
-      for expanded_device in expanded_devices:
-        if expanded_devices[expanded_device]['type'] == 'nic':
-          device = {}
-          device.update({ 'device': expanded_device })
-          device.update({ 'type': expanded_devices[expanded_device]['type'] })
-          if 'name' in expanded_devices[expanded_device]:
-            device.update({ 'name': expanded_devices[expanded_device]['name'] })
-          if 'network' in expanded_devices[expanded_device]:
-            device.update({ 'network': expanded_devices[expanded_device]['network'] })
-          if 'nictype' in expanded_devices[expanded_device]:
-            device.update({ 'nictype': expanded_devices[expanded_device]['nictype'] })
-          if 'parent' in expanded_devices[expanded_device]:
-            device.update({ 'parent': expanded_devices[expanded_device]['parent'] })
-          devices.append(device)
-    return jsonify({ 'data': devices })
-
-
-  if endpoint == 'get_instance_proxy_devices':
-    id = request.args.get('id')
-    project = request.args.get('project')
-    server = Server.query.filter_by(id=id).first()
-    name = request.args.get('name')
-    recursion = request.args.get('recursion')
-    if recursion == '1':
-      url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/containers/' + name + '?recursion=1&project=' + project
-    else:
-      url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/containers/' + name + '?project=' + project
-    client_cert = get_client_crt()
-    client_key = get_client_key()
-    results = requests.get(url, verify=server.ssl_verify, cert=(client_cert, client_key))
-    instance = json.dumps(results.json())
-    instance = json.loads(instance)
-    expanded_devices = instance['metadata']['expanded_devices']
-    devices = []
-    if expanded_devices:
-      for expanded_device in expanded_devices:
-        if expanded_devices[expanded_device]['type'] == 'proxy':
-          device = {}
-          device.update({ 'device': expanded_device })
-          device.update({ 'type': expanded_devices[expanded_device]['type'] })
-          if 'connect' in expanded_devices[expanded_device]:
-            device.update({ 'connect': expanded_devices[expanded_device]['connect'] })
-          if 'listen' in expanded_devices[expanded_device]:
-            device.update({ 'listen': expanded_devices[expanded_device]['listen'] })
-          devices.append(device)
-    return jsonify({ 'data': devices })
-
-
-  if endpoint == 'get_instance_state':
-    id = request.args.get('id')
-    project = request.args.get('project')
-    server = Server.query.filter_by(id=id).first()
-    name = request.args.get('name')
-    recursion = request.args.get('recursion')
-    if recursion == '1':
-      url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/containers/' + name + '/state?recursion=1&project=' + project
-    else:
-      url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/containers/' + name + '/state?project=' + project
-    client_cert = get_client_crt()
-    client_key = get_client_key()
-    results = requests.get(url, verify=server.ssl_verify, cert=(client_cert, client_key))
-    return jsonify(results.json())
-
-
-  if endpoint == 'get_instance_unix_devices':
-    id = request.args.get('id')
-    project = request.args.get('project')
-    server = Server.query.filter_by(id=id).first()
-    name = request.args.get('name')
-    recursion = request.args.get('recursion')
-    if recursion == '1':
-      url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/containers/' + name + '?recursion=1&project=' + project
-    else:
-      url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/containers/' + name + '?project=' + project
-    client_cert = get_client_crt()
-    client_key = get_client_key()
-    results = requests.get(url, verify=server.ssl_verify, cert=(client_cert, client_key))
-    instance = json.dumps(results.json())
-    instance = json.loads(instance)
-    expanded_devices = instance['metadata']['expanded_devices']
-    devices = []
-    if expanded_devices:
-      for expanded_device in expanded_devices:
-        if expanded_devices[expanded_device]['type'] == 'unix-block' or expanded_devices[expanded_device]['type'] == 'unix-char':
-          device = {}
-          device.update({ 'device': expanded_device })
-          device.update({ 'type': expanded_devices[expanded_device]['type'] })
-          if 'source' in expanded_devices[expanded_device]:
-            device.update({ 'source': expanded_devices[expanded_device]['source'] })
-          if 'path' in expanded_devices[expanded_device]:
-            device.update({ 'path': expanded_devices[expanded_device]['path'] })
-          if 'major' in expanded_devices[expanded_device]:
-            device.update({ 'major': expanded_devices[expanded_device]['major'] })
-          if 'minor' in expanded_devices[expanded_device]:
-            device.update({ 'minor': expanded_devices[expanded_device]['minor'] })
-          if 'uid' in expanded_devices[expanded_device]:
-            device.update({ 'uid': expanded_devices[expanded_device]['uid'] })
-          if 'gid' in expanded_devices[expanded_device]:
-            device.update({ 'gid': expanded_devices[expanded_device]['gid'] })
-          if 'mode' in expanded_devices[expanded_device]:
-            device.update({ 'mode': expanded_devices[expanded_device]['mode'] })
-          if 'required' in expanded_devices[expanded_device]:
-            device.update({ 'required': expanded_devices[expanded_device]['required'] })
-          devices.append(device)
-    return jsonify({ 'data': devices })
-
-
-  if endpoint == 'get_instance_usb_devices':
-    id = request.args.get('id')
-    project = request.args.get('project')
-    server = Server.query.filter_by(id=id).first()
-    name = request.args.get('name')
-    recursion = request.args.get('recursion')
-    if recursion == '1':
-      url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/containers/' + name + '?recursion=1&project=' + project
-    else:
-      url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/containers/' + name + '?project=' + project
-    client_cert = get_client_crt()
-    client_key = get_client_key()
-    results = requests.get(url, verify=server.ssl_verify, cert=(client_cert, client_key))
-    instance = json.dumps(results.json())
-    instance = json.loads(instance)
-    expanded_devices = instance['metadata']['expanded_devices']
-    devices = []
-    if expanded_devices:
-      for expanded_device in expanded_devices:
-        if expanded_devices[expanded_device]['type'] == 'usb':
-          device = {}
-          device.update({ 'device': expanded_device })
-          device.update({ 'type': expanded_devices[expanded_device]['type'] })
-          if 'vendorid' in expanded_devices[expanded_device]:
-            device.update({ 'vendorid': expanded_devices[expanded_device]['vendorid'] })
-          if 'productid' in expanded_devices[expanded_device]:
-            device.update({ 'productid': expanded_devices[expanded_device]['productid'] })
-          if 'uid' in expanded_devices[expanded_device]:
-            device.update({ 'uid': expanded_devices[expanded_device]['uid'] })
-          if 'gid' in expanded_devices[expanded_device]:
-            device.update({ 'gid': expanded_devices[expanded_device]['gid'] })
-          if 'mode' in expanded_devices[expanded_device]:
-            device.update({ 'mode': expanded_devices[expanded_device]['mode'] })
-          if 'required' in expanded_devices[expanded_device]:
-            device.update({ 'required': expanded_devices[expanded_device]['required'] })
-          devices.append(device)
-    return jsonify({ 'data': devices })
-
-
-  if endpoint == 'get_instance_websocket_host':
-    id = request.args.get('id')
-    server = Server.query.filter_by(id=id).first()
-    return jsonify({ 'addr': server.addr, 'port': server.port, 'proxy': server.proxy })
-  
-
-  if endpoint == 'list_instance_backups':
-    id = request.args.get('id')
-    project = request.args.get('project')
-    server = Server.query.filter_by(id=id).first()
-    name = request.args.get('name')
-    recursion = request.args.get('recursion')
-    if recursion == '1':
-      url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/containers/' + name + '/backups?recursion=1&project=' + project
-    else:
-      url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/containers/' + name + '/backups?project=' + project
-    client_cert = get_client_crt()
-    client_key = get_client_key()
-    results = requests.get(url, verify=server.ssl_verify, cert=(client_cert, client_key))
-    backups = json.dumps(results.json())
-    backups = json.loads(backups)
-    devices = []
-    if backups:
-      for backup in backups['metadata']:
-        # Check if backup file exists
-        if os.path.isfile('backups/' + str(server.id) + '/' + project + '/' + name + '/' + backup['name']):
-          backup.update({'backup_file_exists': True})
-          backup.update({'backup_file_size': os.path.getsize('backups/' + str(server.id) + '/' + project + '/' + name + '/' + backup['name'])})
-        else:
-          backup.update({'backup_file_exists': False})
-
-    return jsonify(backups)
-
-
-  if endpoint == 'list_instance_logs':
-    id = request.args.get('id')
-    project = request.args.get('project')
-    server = Server.query.filter_by(id=id).first()
-    name = request.args.get('name')
-    recursion = request.args.get('recursion')
-    if recursion == '1':
-      url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/containers/' + name + '/logs?recursion=1&project=' + project
-    else:
-      url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/containers/' + name + '/logs?project=' + project
-    client_cert = get_client_crt()
-    client_key = get_client_key()
-    results = requests.get(url, verify=server.ssl_verify, cert=(client_cert, client_key))
-    return jsonify(results.json())
-
-
-  if endpoint == 'list_instance_snapshots':
-    id = request.args.get('id')
-    project = request.args.get('project')
-    server = Server.query.filter_by(id=id).first()
-    name = request.args.get('name')
-    recursion = request.args.get('recursion')
-    if recursion == '1':
-      url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/containers/' + name + '/snapshots?recursion=1&project=' + project
-    else:
-      url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/containers/' + name + '/snapshots?project=' + project
-    client_cert = get_client_crt()
-    client_key = get_client_key()
-    results = requests.get(url, verify=server.ssl_verify, cert=(client_cert, client_key))
-    return jsonify(results.json())
-
-
-  if endpoint == 'migrate_instance':
-    id = request.args.get('id')
-    project = request.args.get('project')
-    instance = request.args.get('instance')
-    server = Server.query.filter_by(id=id).first()
-    location = request.args.get('location')
-    url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/containers/' + instance + '?target='+location+'&project=' + project
-    client_cert = get_client_crt()
-    client_key = get_client_key()
-    data = {}
-    data.update({'name': instance })
-    data.update({'migration': True})
-    data.update({'live': False})
-    results = requests.post(url, verify=server.ssl_verify, cert=(client_cert, client_key), json=data)
-    return jsonify(results.json())
-
-
-  if endpoint == 'publish_instance':
-    id = request.args.get('id')
-    project = request.args.get('project')
-    instance = request.args.get('instance')
-    server = Server.query.filter_by(id=id).first()
-    url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/images?project=' + project
-    client_cert = get_client_crt()
-    client_key = get_client_key()
-    data = {}
-    properties = {}
-    properties.update({ 'description':request.form.get('description') })
-    properties.update({ 'os': request.form.get('os') })
-    properties.update({ 'release': request.form.get('release') })
-    data.update({ 'properties': properties })
-    source = {}
-    source.update({ 'type': 'instance' })
-    source.update({ 'name': instance })
-    data.update({ 'source': source })
-    if request.form.get('public') == 'true':
-      data.update({'public': True})
-    else:
-      data.update({'public': False})
-    results = requests.post(url, verify=server.ssl_verify, cert=(client_cert, client_key), json=data)
-    return jsonify(results.json())
-
-
-  if endpoint == 'publish_instance_snapshot':
-    id = request.args.get('id')
-    project = request.args.get('project')
-    instance = request.args.get('instance')
-    snapshot = request.args.get('snapshot')
-    server = Server.query.filter_by(id=id).first()
-    url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/images?project=' + project
-    client_cert = get_client_crt()
-    client_key = get_client_key()
-    data = {}
-    properties = {}
-    properties.update({ 'description':request.form.get('description') })
-    properties.update({ 'os': request.form.get('os') })
-    properties.update({ 'release': request.form.get('release') })
-    data.update({ 'properties': properties })
-    source = {}
-    source.update({ 'type': 'snapshot' })
-    source.update({ 'name': instance + '/' + snapshot })
-    data.update({ 'source': source })
-    if request.form.get('public') == 'true':
-      data.update({'public': True})
-    else:
-      data.update({'public': False})
-    results = requests.post(url, verify=server.ssl_verify, cert=(client_cert, client_key), json=data)
-    return jsonify(results.json())
-
-
-  if endpoint == 'rename_instance':
-      id = request.args.get('id')
-      project = request.args.get('project')
-      instance = request.args.get('instance')
-      server = Server.query.filter_by(id=id).first()
-      url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/containers/' + instance + '?project=' + project
-      client_cert = get_client_crt()
-      client_key = get_client_key()
-      data = {}
-      data.update({'name': request.form.get('name')})
-      results = requests.post(url, verify=server.ssl_verify, cert=(client_cert, client_key), json=data)
-      return jsonify(results.json())
-
-
-  if endpoint == 'restore_instance_snapshot':
-    id = request.args.get('id')
-    project = request.args.get('project')
-    instance = request.args.get('instance')
-    server = Server.query.filter_by(id=id).first()
-    url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/containers/' + instance + '?project=' + project
-    client_cert = get_client_crt()
-    client_key = get_client_key()
-
-    data = {}
-    data.update({'restore': request.form.get('name')})
-    results = requests.put(url, verify=server.ssl_verify, cert=(client_cert, client_key), json=data)
-    
-    return jsonify(results.json())
-
-
-  if endpoint == 'update_instance':
-    id = request.args.get('id')
-    project = request.args.get('project')
-    instance = request.args.get('instance')
-    server = Server.query.filter_by(id=id).first()
-    url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/containers/' + instance + '?project=' + project
-    client_cert = get_client_crt()
-    client_key = get_client_key()
-
-    # If the update was from JSON tab, update it with a PUT request
-    if request.form.get('json'):
-      data = request.form.get('json')
-      results = requests.put(url, verify=server.ssl_verify, cert=(client_cert, client_key), data=data)
-      return jsonify(results.json())
-
-    # Get the current config
-    results = requests.get(url, verify=server.ssl_verify, cert=(client_cert, client_key))
-    instance = json.dumps(results.json())
-    instance = json.loads(instance)
-    existing_config = instance['metadata']['config']
- 
-    # Create a new dict to hold the differences between existing config and form config
-    updated_config = {}
-    # Loop through and compare differences between existing config and form config
-    for key, val in request.form.items():
-      # If key is description, continue as it is not part of config
-      if key == 'description':
-        continue
-      # If the key does not exist in existing config, create and set it to empty string so we can compare it to form config
-      if not key in existing_config:
-        existing_config.update( { key: '' } )
-      # If the post key is different than existing key capture this difference in new dict
-      if request.form.get(key) != existing_config[key]:
-        updated_config.update({key: request.form.get(key)})
-
-    # Send a PATCH request to update only the differences in config
-    data = {}
-    data.update({'description': request.form.get('description')})
-    data.update({'config' : updated_config })
-    results = requests.patch(url, verify=server.ssl_verify, cert=(client_cert, client_key), json=data)
-    return jsonify(results.json())

+ 165 - 68
lxconsole/api/virtual_machine.py → lxconsole/api/instance.py

@@ -17,7 +17,7 @@ def get_client_key():
   return 'certs/client.key'
 
 @login_required
-def api_virtual_machine_endpoint(endpoint):
+def api_instance_endpoint(endpoint):
 
   if not privilege_check(endpoint, request.args.get('id')):
     return jsonify({'data': [], 'metadata':[], 'error': 'not authorized', 'error_code': 403})
@@ -28,7 +28,7 @@ def api_virtual_machine_endpoint(endpoint):
     project = request.args.get('project')
     instance = request.args.get('instance')
     server = Server.query.filter_by(id=id).first()
-    url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/virtual-machines/' + instance + '?project=' + project
+    url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/instances/' + instance + '?project=' + project
     client_cert = get_client_crt()
     client_key = get_client_key()
     results = requests.get(url, verify=server.ssl_verify, cert=(client_cert, client_key))
@@ -72,7 +72,7 @@ def api_virtual_machine_endpoint(endpoint):
     project = request.args.get('project')
     instance = request.args.get('instance')
     server = Server.query.filter_by(id=id).first()
-    url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/virtual-machines/' + instance + '?project=' + project
+    url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/instances/' + instance + '?project=' + project
     client_cert = get_client_crt()
     client_key = get_client_key()
     results = requests.get(url, verify=server.ssl_verify, cert=(client_cert, client_key))
@@ -108,7 +108,7 @@ def api_virtual_machine_endpoint(endpoint):
     project = request.args.get('project')
     instance = request.args.get('instance')
     server = Server.query.filter_by(id=id).first()
-    url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/virtual-machines/' + instance + '?project=' + project
+    url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/instances/' + instance + '?project=' + project
     client_cert = get_client_crt()
     client_key = get_client_key()
     results = requests.get(url, verify=server.ssl_verify, cert=(client_cert, client_key))
@@ -172,7 +172,7 @@ def api_virtual_machine_endpoint(endpoint):
     project = request.args.get('project')
     instance = request.args.get('instance')
     server = Server.query.filter_by(id=id).first()
-    url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/virtual-machines/' + instance + '?project=' + project
+    url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/instances/' + instance + '?project=' + project
     client_cert = get_client_crt()
     client_key = get_client_key()
     results = requests.get(url, verify=server.ssl_verify, cert=(client_cert, client_key))
@@ -208,7 +208,7 @@ def api_virtual_machine_endpoint(endpoint):
     project = request.args.get('project')
     instance = request.args.get('instance')
     server = Server.query.filter_by(id=id).first()
-    url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/virtual-machines/' + instance + '?project=' + project
+    url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/instances/' + instance + '?project=' + project
     client_cert = get_client_crt()
     client_key = get_client_key()
     results = requests.get(url, verify=server.ssl_verify, cert=(client_cert, client_key))
@@ -235,14 +235,14 @@ def api_virtual_machine_endpoint(endpoint):
     data.update({'devices': devices})
     results = requests.patch(url, verify=server.ssl_verify, cert=(client_cert, client_key), json=data)
     return jsonify(results.json())
-
+  
 
   if endpoint == 'add_instance_usb_device':
     id = request.args.get('id')
     project = request.args.get('project')
     instance = request.args.get('instance')
     server = Server.query.filter_by(id=id).first()
-    url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/virtual-machines/' + instance + '?project=' + project
+    url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/instances/' + instance + '?project=' + project
     client_cert = get_client_crt()
     client_key = get_client_key()
     results = requests.get(url, verify=server.ssl_verify, cert=(client_cert, client_key))
@@ -267,12 +267,13 @@ def api_virtual_machine_endpoint(endpoint):
     results = requests.patch(url, verify=server.ssl_verify, cert=(client_cert, client_key), json=data)
     return jsonify(results.json())
 
+
   if endpoint == 'attach_instance_profile':
     id = request.args.get('id')
     project = request.args.get('project')
     instance = request.args.get('instance')
     server = Server.query.filter_by(id=id).first()
-    url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/virtual-machines/' + instance + '?project=' + project
+    url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/instances/' + instance + '?project=' + project
     client_cert = get_client_crt()
     client_key = get_client_key()
     results = requests.get(url, verify=server.ssl_verify, cert=(client_cert, client_key))
@@ -296,7 +297,7 @@ def api_virtual_machine_endpoint(endpoint):
     action = request.form.get('action')
     force = request.form.get('force')
     server = Server.query.filter_by(id=id).first()
-    url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/virtual-machines/' + instance + '/state?project=' + project
+    url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/instances/' + instance + '/state?project=' + project
     client_cert = get_client_crt()
     client_key = get_client_key()
     if force == 'true':
@@ -315,9 +316,9 @@ def api_virtual_machine_endpoint(endpoint):
     location = request.args.get('location')
     #Target location is needed for clustered servers and not allowed on non-clustered servers
     if location == 'none':
-      url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/virtual-machines?project=' + project
+      url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/instances?project=' + project
     else:
-      url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/virtual-machines?target='+location+'&project=' + project
+      url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/instances?target='+location+'&project=' + project
     client_cert = get_client_crt()
     client_key = get_client_key()
     data = {}
@@ -336,7 +337,7 @@ def api_virtual_machine_endpoint(endpoint):
     project = request.args.get('project')
     instance = request.args.get('instance')
     server = Server.query.filter_by(id=id).first()
-    url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/virtual-machines/' + instance + '/backups?project=' + project
+    url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/instances/' + instance + '/backups?project=' + project
     client_cert = get_client_crt()
     client_key = get_client_key()
     
@@ -372,14 +373,14 @@ def api_virtual_machine_endpoint(endpoint):
     data.update({'compression_algorithm': request.form.get('compression_algorithm')}) if request.form.get('compression_algorithm') else False
     results = requests.post(url, verify=server.ssl_verify, cert=(client_cert, client_key), json=data)
     return jsonify(results.json())
-
+  
 
   if endpoint == 'create_instance_snapshot':
     id = request.args.get('id')
     project = request.args.get('project')
     instance = request.args.get('instance')
     server = Server.query.filter_by(id=id).first()
-    url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/virtual-machines/' + instance + '/snapshots?project=' + project
+    url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/instances/' + instance + '/snapshots?project=' + project
     client_cert = get_client_crt()
     client_key = get_client_key()
     data = {}
@@ -400,9 +401,9 @@ def api_virtual_machine_endpoint(endpoint):
     location = request.args.get('location')
     #Target location is needed for clustered servers and not allowed on non-clustered servers
     if location == 'none':
-      url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/virtual-machines?project=' + project
+      url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/instances?project=' + project
     else:
-      url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/virtual-machines?target='+location+'&project=' + project
+      url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/instances?target='+location+'&project=' + project
     client_cert = get_client_crt()
     client_key = get_client_key()
     data = {}
@@ -423,7 +424,7 @@ def api_virtual_machine_endpoint(endpoint):
     instance = request.args.get('instance')
     backup = request.args.get('backup')
     server = Server.query.filter_by(id=id).first()
-    url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/virtual-machines/' + instance + '/backups/' + backup + '?project=' + project
+    url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/instances/' + instance + '/backups/' + backup + '?project=' + project
     client_cert = get_client_crt()
     client_key = get_client_key()
     if os.path.isfile('backups/' + str(server.id) + '/' + project + '/' + instance + '/' + backup):
@@ -438,7 +439,7 @@ def api_virtual_machine_endpoint(endpoint):
     instance = request.args.get('instance')
     device = request.args.get('device')
     server = Server.query.filter_by(id=id).first()
-    url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/virtual-machines/' + instance + '?project=' + project
+    url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/instances/' + instance + '?project=' + project
     client_cert = get_client_crt()
     client_key = get_client_key()
     results = requests.get(url, verify=server.ssl_verify, cert=(client_cert, client_key))
@@ -455,7 +456,7 @@ def api_virtual_machine_endpoint(endpoint):
     project = request.args.get('project')
     instance = request.form.get('instance')
     server = Server.query.filter_by(id=id).first()
-    url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/virtual-machines/' + instance + '?project=' + project
+    url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/instances/' + instance + '?project=' + project
     client_cert = get_client_crt()
     client_key = get_client_key()
     results = requests.delete(url, verify=server.ssl_verify, cert=(client_cert, client_key))
@@ -480,7 +481,7 @@ def api_virtual_machine_endpoint(endpoint):
     instance = request.args.get('instance')
     snapshot = request.args.get('snapshot')
     server = Server.query.filter_by(id=id).first()
-    url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/virtual-machines/' + instance + '/snapshots/' + snapshot + '?project=' + project
+    url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/instances/' + instance + '/snapshots/' + snapshot + '?project=' + project
     client_cert = get_client_crt()
     client_key = get_client_key()
     results = requests.delete(url, verify=server.ssl_verify, cert=(client_cert, client_key))
@@ -493,7 +494,7 @@ def api_virtual_machine_endpoint(endpoint):
     instance = request.args.get('instance')
     profile = request.args.get('profile')
     server = Server.query.filter_by(id=id).first()
-    url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/virtual-machines/' + instance + '?project=' + project
+    url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/instances/' + instance + '?project=' + project
     client_cert = get_client_crt()
     client_key = get_client_key()
     results = requests.get(url, verify=server.ssl_verify, cert=(client_cert, client_key))
@@ -520,14 +521,14 @@ def api_virtual_machine_endpoint(endpoint):
     client_key = get_client_key()
     results = requests.get(url, verify=server.ssl_verify, cert=(client_cert, client_key))
     return results.text
-
+  
 
   if endpoint == 'establish_instance_console_websocket':
     id = request.args.get('id')
     project = request.args.get('project')
     instance = request.args.get('instance')
     server = Server.query.filter_by(id=id).first()
-    url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/virtual-machines/' + instance + '/console?project=' + project
+    url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/instances/' + instance + '/console?project=' + project
     client_cert = get_client_crt()
     client_key = get_client_key()
     data = {}
@@ -550,7 +551,7 @@ def api_virtual_machine_endpoint(endpoint):
     project = request.args.get('project')
     instance = request.args.get('instance')
     server = Server.query.filter_by(id=id).first()
-    url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/virtual-machines/' + instance + '/exec?project=' + project
+    url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/instances/' + instance + '/exec?project=' + project
     client_cert = get_client_crt()
     client_key = get_client_key()
     data = {}
@@ -576,7 +577,7 @@ def api_virtual_machine_endpoint(endpoint):
     control = str(results['metadata']['metadata']['fds']['control']) if str(results['metadata']['metadata']['fds']['control']) else ''
 
     return jsonify({'operation': operation, 'secret': secret, 'control': control})
-
+  
 
   if endpoint == 'export_instance_backup':
     id = request.args.get('id')
@@ -584,7 +585,7 @@ def api_virtual_machine_endpoint(endpoint):
     server = Server.query.filter_by(id=id).first()
     instance = request.args.get('instance')
     backup = request.args.get('backup')
-    url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/virtual-machines/' + instance + '/backups/' + backup + '/export?project=' + project
+    url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/instances/' + instance + '/backups/' + backup + '/export?project=' + project
     client_cert = get_client_crt()
     client_key = get_client_key()
     os.system('mkdir -p backups/' + str(server.id) + '/' + project + '/' + instance)
@@ -604,15 +605,15 @@ def api_virtual_machine_endpoint(endpoint):
     name = request.args.get('name')
     recursion = request.args.get('recursion')
     if recursion == '1':
-      url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/virtual-machines/' + name + '?recursion=1&project=' + project
+      url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/instances/' + name + '?recursion=1&project=' + project
     else:
-      url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/virtual-machines/' + name + '?project=' + project
+      url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/instances/' + name + '?project=' + project
     client_cert = get_client_crt()
     client_key = get_client_key()
     results = requests.get(url, verify=server.ssl_verify, cert=(client_cert, client_key))
     return jsonify(results.json())
-
- 
+  
+  # Virtual Machine only
   if endpoint == 'get_instance_cpu_percentage':
     id = request.args.get('id')
     project = request.args.get('project')
@@ -629,7 +630,7 @@ def api_virtual_machine_endpoint(endpoint):
     # Unable to read /proc/stat directly on virtual machines use lxd files api...getting an EOF error
     # So we will copy /proc/stat to /tmp/stat and then read that file as a work around
     data = {}
-    data.update({'command': ['cp', '/proc/stat', '/tmp/stat']})
+    data.update({'command': ['cp', '/proc/stat', '/tmp/stat1']})
     data.update({'wait-for-websocket': False})
     data.update({'interactive': False})
     data.update({'width': 80 })
@@ -640,14 +641,14 @@ def api_virtual_machine_endpoint(endpoint):
     data.update({'record-output': False })
     data.update({'environment': {} })
     
-    url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/virtual-machines/' + name + '/exec?project=' + project
+    url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/instances/' + name + '/exec?project=' + project
     results = requests.post(url, verify=server.ssl_verify, cert=(client_cert, client_key), json=data)
   
     # Sleep to allow time for copy to complete
     time.sleep(.5)
 
     #Get first /proc/stat information but from /tmp/stat
-    url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/virtual-machines/' + name + '/files?project=' + project + '&path=/tmp/stat'
+    url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/instances/' + name + '/files?project=' + project + '&path=/tmp/stat1'
     results = requests.get(url, verify=server.ssl_verify, cert=(client_cert, client_key))
     if 'cpu' in results.text:
       results = results.text.split('\n')
@@ -665,7 +666,7 @@ def api_virtual_machine_endpoint(endpoint):
 
     # Copy /proc/stat to /tmp/stat and then read that file as a work around
     data = {}
-    data.update({'command': ['cp', '/proc/stat', '/tmp/stat']})
+    data.update({'command': ['cp', '/proc/stat', '/tmp/stat2']})
     data.update({'wait-for-websocket': False})
     data.update({'interactive': False})
     data.update({'width': 80 })
@@ -676,14 +677,14 @@ def api_virtual_machine_endpoint(endpoint):
     data.update({'record-output': False })
     data.update({'environment': {} })
     
-    url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/virtual-machines/' + name + '/exec?project=' + project
+    url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/instances/' + name + '/exec?project=' + project
     results = requests.post(url, verify=server.ssl_verify, cert=(client_cert, client_key), json=data)
 
     # Sleep to allow time for copy to complete
     time.sleep(.5)
 
     #Get second /proc/stat information
-    url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/virtual-machines/' + name + '/files?project=' + project + '&path=/tmp/stat'
+    url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/instances/' + name + '/files?project=' + project + '&path=/tmp/stat2'
     results = requests.get(url, verify=server.ssl_verify, cert=(client_cert, client_key))
     if 'cpu' in results.text:
       results = results.text.split('\n')
@@ -703,6 +704,53 @@ def api_virtual_machine_endpoint(endpoint):
       return jsonify({'percentage': 0, 'cpu1': first_cpu_time, 'cpu2': second_cpu_time, 'idle1': first_idle_time, 'idle2': second_idle_time})
     percentage = 100 * (1 - idle_time / total_time)
     return jsonify({'percentage': percentage, 'cpu1': first_cpu_time, 'cpu2': second_cpu_time, 'idle1': first_idle_time, 'idle2': second_idle_time})
+
+
+  if endpoint == 'get_instance_cpu_usage':
+
+    id = request.args.get('id')
+    project = request.args.get('project')
+    server = Server.query.filter_by(id=id).first()
+    name = request.args.get('name')    
+    client_cert = get_client_crt()
+    client_key = get_client_key()
+
+    #Get instance state to retrieve instance cpu usage
+    url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/instances/' + name + '/state?project=' + project
+    results = requests.get(url, verify=server.ssl_verify, cert=(client_cert, client_key))
+    results = json.dumps(results.json())
+    results = json.loads(results)
+    #Get cpu usage
+    if 'cpu' in results['metadata']:
+      if 'usage' in results['metadata']['cpu']:
+        #Usage is reported in nanoseconds
+        instance_cpu_time = int(results['metadata']['cpu']['usage'])
+      else:
+        instance_cpu_time = 0
+    else:
+      instance_cpu_time = 0
+
+    #Get /proc/stat information
+    url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/instances/' + name + '/files?project=' + project + '&path=/proc/stat'
+    results = requests.get(url, verify=server.ssl_verify, cert=(client_cert, client_key))
+    if 'cpu' in results.text:
+      results = results.text.split('\n')
+      for result in results:
+        stats = result.split()
+        if stats[0] == 'cpu':
+          #0 = 'cpu'
+          #1 = <user time>
+          #2 = <nice time>
+          #3 = <system time>
+          #4 = <idle time>
+          user_time = int(stats[1])
+          system_time= int(stats[3])
+          idle_time = int(stats[4])
+          host_cpu_time = user_time + system_time + idle_time
+
+          return jsonify({'instance_cpu_time':instance_cpu_time,'host_cpu_time': host_cpu_time})
+      
+    return jsonify({'instance_cpu_time':0,'host_cpu_time': 0})
   
 
   if endpoint == 'get_instance_disk_devices':
@@ -712,9 +760,9 @@ def api_virtual_machine_endpoint(endpoint):
     name = request.args.get('name')
     recursion = request.args.get('recursion')
     if recursion == '1':
-      url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/virtual-machines/' + name + '?recursion=1&project=' + project
+      url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/instances/' + name + '?recursion=1&project=' + project
     else:
-      url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/virtual-machines/' + name + '?project=' + project
+      url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/instances/' + name + '?project=' + project
     client_cert = get_client_crt()
     client_key = get_client_key()
     results = requests.get(url, verify=server.ssl_verify, cert=(client_cert, client_key))
@@ -722,7 +770,7 @@ def api_virtual_machine_endpoint(endpoint):
     instance = json.loads(instance)
     expanded_devices = instance['metadata']['expanded_devices']
     devices = []
-    instance_state_url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/virtual-machines/' + name + '/state?project=' + project
+    instance_state_url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/instances/' + name + '/state?project=' + project
     instance_state = requests.get(instance_state_url, verify=server.ssl_verify, cert=(client_cert, client_key))
     instance_state = json.dumps(instance_state.json())
     instance_state = json.loads(instance_state)
@@ -751,9 +799,9 @@ def api_virtual_machine_endpoint(endpoint):
     name = request.args.get('name')
     recursion = request.args.get('recursion')
     if recursion == '1':
-      url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/virtual-machines/' + name + '?recursion=1&project=' + project
+      url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/instances/' + name + '?recursion=1&project=' + project
     else:
-      url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/virtual-machines/' + name + '?project=' + project
+      url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/instances/' + name + '?project=' + project
     client_cert = get_client_crt()
     client_key = get_client_key()
     results = requests.get(url, verify=server.ssl_verify, cert=(client_cert, client_key))
@@ -798,9 +846,9 @@ def api_virtual_machine_endpoint(endpoint):
     name = request.args.get('name')
     recursion = request.args.get('recursion')
     if recursion == '1':
-      url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/virtual-machines/' + name + '/state?recursion=1&project=' + project
+      url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/instances/' + name + '/state?recursion=1&project=' + project
     else:
-      url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/virtual-machines/' + name + '/state?project=' + project
+      url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/instances/' + name + '/state?project=' + project
     client_cert = get_client_crt()
     client_key = get_client_key()
     results = requests.get(url, verify=server.ssl_verify, cert=(client_cert, client_key))
@@ -827,7 +875,7 @@ def api_virtual_machine_endpoint(endpoint):
           interfaces.append(interface)
     return jsonify({ 'data': interfaces })
 
-
+  # Virtual Machine only
   if endpoint == 'get_instance_memory_percentage':
     id = request.args.get('id')
     project = request.args.get('project')
@@ -854,14 +902,14 @@ def api_virtual_machine_endpoint(endpoint):
     data.update({'record-output': False })
     data.update({'environment': {} })
     
-    url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/virtual-machines/' + name + '/exec?project=' + project
+    url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/instances/' + name + '/exec?project=' + project
     results = requests.post(url, verify=server.ssl_verify, cert=(client_cert, client_key), json=data)
   
     # Sleep a second to give time to copy file
     time.sleep(1)
 
     #Get /proc/meminfo information but from /tmp/meminfo
-    url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/virtual-machines/' + name + '/files?project=' + project + '&path=/tmp/meminfo'
+    url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/instances/' + name + '/files?project=' + project + '&path=/tmp/meminfo'
     results = requests.get(url, verify=server.ssl_verify, cert=(client_cert, client_key))
     if 'MemTotal' in results.text:
       results = results.text.split('\n')
@@ -879,9 +927,9 @@ def api_virtual_machine_endpoint(endpoint):
     name = request.args.get('name')
     recursion = request.args.get('recursion')
     if recursion == '1':
-      url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/virtual-machines/' + name + '?recursion=1&project=' + project
+      url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/instances/' + name + '?recursion=1&project=' + project
     else:
-      url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/virtual-machines/' + name + '?project=' + project
+      url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/instances/' + name + '?project=' + project
     client_cert = get_client_crt()
     client_key = get_client_key()
     results = requests.get(url, verify=server.ssl_verify, cert=(client_cert, client_key))
@@ -914,9 +962,9 @@ def api_virtual_machine_endpoint(endpoint):
     name = request.args.get('name')
     recursion = request.args.get('recursion')
     if recursion == '1':
-      url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/virtual-machines/' + name + '?recursion=1&project=' + project
+      url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/instances/' + name + '?recursion=1&project=' + project
     else:
-      url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/virtual-machines/' + name + '?project=' + project
+      url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/instances/' + name + '?project=' + project
     client_cert = get_client_crt()
     client_key = get_client_key()
     results = requests.get(url, verify=server.ssl_verify, cert=(client_cert, client_key))
@@ -945,14 +993,57 @@ def api_virtual_machine_endpoint(endpoint):
     name = request.args.get('name')
     recursion = request.args.get('recursion')
     if recursion == '1':
-      url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/virtual-machines/' + name + '/state?recursion=1&project=' + project
+      url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/instances/' + name + '/state?recursion=1&project=' + project
     else:
-      url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/virtual-machines/' + name + '/state?project=' + project
+      url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/instances/' + name + '/state?project=' + project
     client_cert = get_client_crt()
     client_key = get_client_key()
     results = requests.get(url, verify=server.ssl_verify, cert=(client_cert, client_key))
     return jsonify(results.json())
 
+  # Container only
+  if endpoint == 'get_instance_unix_devices':
+    id = request.args.get('id')
+    project = request.args.get('project')
+    server = Server.query.filter_by(id=id).first()
+    name = request.args.get('name')
+    recursion = request.args.get('recursion')
+    if recursion == '1':
+      url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/instances/' + name + '?recursion=1&project=' + project
+    else:
+      url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/instances/' + name + '?project=' + project
+    client_cert = get_client_crt()
+    client_key = get_client_key()
+    results = requests.get(url, verify=server.ssl_verify, cert=(client_cert, client_key))
+    instance = json.dumps(results.json())
+    instance = json.loads(instance)
+    expanded_devices = instance['metadata']['expanded_devices']
+    devices = []
+    if expanded_devices:
+      for expanded_device in expanded_devices:
+        if expanded_devices[expanded_device]['type'] == 'unix-block' or expanded_devices[expanded_device]['type'] == 'unix-char':
+          device = {}
+          device.update({ 'device': expanded_device })
+          device.update({ 'type': expanded_devices[expanded_device]['type'] })
+          if 'source' in expanded_devices[expanded_device]:
+            device.update({ 'source': expanded_devices[expanded_device]['source'] })
+          if 'path' in expanded_devices[expanded_device]:
+            device.update({ 'path': expanded_devices[expanded_device]['path'] })
+          if 'major' in expanded_devices[expanded_device]:
+            device.update({ 'major': expanded_devices[expanded_device]['major'] })
+          if 'minor' in expanded_devices[expanded_device]:
+            device.update({ 'minor': expanded_devices[expanded_device]['minor'] })
+          if 'uid' in expanded_devices[expanded_device]:
+            device.update({ 'uid': expanded_devices[expanded_device]['uid'] })
+          if 'gid' in expanded_devices[expanded_device]:
+            device.update({ 'gid': expanded_devices[expanded_device]['gid'] })
+          if 'mode' in expanded_devices[expanded_device]:
+            device.update({ 'mode': expanded_devices[expanded_device]['mode'] })
+          if 'required' in expanded_devices[expanded_device]:
+            device.update({ 'required': expanded_devices[expanded_device]['required'] })
+          devices.append(device)
+    return jsonify({ 'data': devices })
+
 
   if endpoint == 'get_instance_usb_devices':
     id = request.args.get('id')
@@ -961,9 +1052,9 @@ def api_virtual_machine_endpoint(endpoint):
     name = request.args.get('name')
     recursion = request.args.get('recursion')
     if recursion == '1':
-      url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/virtual-machines/' + name + '?recursion=1&project=' + project
+      url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/instances/' + name + '?recursion=1&project=' + project
     else:
-      url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/virtual-machines/' + name + '?project=' + project
+      url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/instances/' + name + '?project=' + project
     client_cert = get_client_crt()
     client_key = get_client_key()
     results = requests.get(url, verify=server.ssl_verify, cert=(client_cert, client_key))
@@ -997,7 +1088,7 @@ def api_virtual_machine_endpoint(endpoint):
     id = request.args.get('id')
     server = Server.query.filter_by(id=id).first()
     return jsonify({ 'addr': server.addr, 'port': server.port, 'proxy': server.proxy })
-
+  
 
   if endpoint == 'list_instance_backups':
     id = request.args.get('id')
@@ -1006,9 +1097,9 @@ def api_virtual_machine_endpoint(endpoint):
     name = request.args.get('name')
     recursion = request.args.get('recursion')
     if recursion == '1':
-      url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/virtual-machines/' + name + '/backups?recursion=1&project=' + project
+      url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/instances/' + name + '/backups?recursion=1&project=' + project
     else:
-      url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/virtual-machines/' + name + '/backups?project=' + project
+      url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/instances/' + name + '/backups?project=' + project
     client_cert = get_client_crt()
     client_key = get_client_key()
     results = requests.get(url, verify=server.ssl_verify, cert=(client_cert, client_key))
@@ -1034,13 +1125,19 @@ def api_virtual_machine_endpoint(endpoint):
     name = request.args.get('name')
     recursion = request.args.get('recursion')
     if recursion == '1':
-      url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/virtual-machines/' + name + '/logs?recursion=1&project=' + project
+      url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/instances/' + name + '/logs?recursion=1&project=' + project
     else:
-      url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/virtual-machines/' + name + '/logs?project=' + project
+      url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/instances/' + name + '/logs?project=' + project
     client_cert = get_client_crt()
     client_key = get_client_key()
     results = requests.get(url, verify=server.ssl_verify, cert=(client_cert, client_key))
-    return jsonify(results.json())
+    
+    # Newly created VMs will not have logs until it starts, causing a 404 error
+    results = json.dumps(results.json())
+    results = json.loads(results)
+    if results['metadata'] is None:
+      return jsonify({"metadata":[]})
+    return jsonify(results)
 
 
   if endpoint == 'list_instance_snapshots':
@@ -1050,14 +1147,14 @@ def api_virtual_machine_endpoint(endpoint):
     name = request.args.get('name')
     recursion = request.args.get('recursion')
     if recursion == '1':
-      url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/virtual-machines/' + name + '/snapshots?recursion=1&project=' + project
+      url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/instances/' + name + '/snapshots?recursion=1&project=' + project
     else:
-      url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/virtual-machines/' + name + '/snapshots?project=' + project
+      url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/instances/' + name + '/snapshots?project=' + project
     client_cert = get_client_crt()
     client_key = get_client_key()
     results = requests.get(url, verify=server.ssl_verify, cert=(client_cert, client_key))
     return jsonify(results.json())
-  
+
 
   if endpoint == 'migrate_instance':
     id = request.args.get('id')
@@ -1065,7 +1162,7 @@ def api_virtual_machine_endpoint(endpoint):
     instance = request.args.get('instance')
     server = Server.query.filter_by(id=id).first()
     location = request.args.get('location')
-    url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/virtual-machines/' + instance + '?target='+location+'&project=' + project
+    url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/instances/' + instance + '?target='+location+'&project=' + project
     client_cert = get_client_crt()
     client_key = get_client_key()
     data = {}
@@ -1134,7 +1231,7 @@ def api_virtual_machine_endpoint(endpoint):
       project = request.args.get('project')
       instance = request.args.get('instance')
       server = Server.query.filter_by(id=id).first()
-      url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/virtual-machines/' + instance + '?project=' + project
+      url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/instances/' + instance + '?project=' + project
       client_cert = get_client_crt()
       client_key = get_client_key()
       data = {}
@@ -1148,7 +1245,7 @@ def api_virtual_machine_endpoint(endpoint):
     project = request.args.get('project')
     instance = request.args.get('instance')
     server = Server.query.filter_by(id=id).first()
-    url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/virtual-machines/' + instance + '?project=' + project
+    url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/instances/' + instance + '?project=' + project
     client_cert = get_client_crt()
     client_key = get_client_key()
 
@@ -1164,7 +1261,7 @@ def api_virtual_machine_endpoint(endpoint):
     project = request.args.get('project')
     instance = request.args.get('instance')
     server = Server.query.filter_by(id=id).first()
-    url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/virtual-machines/' + instance + '?project=' + project
+    url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/instances/' + instance + '?project=' + project
     client_cert = get_client_crt()
     client_key = get_client_key()
 

+ 42 - 29
lxconsole/api/containers.py → lxconsole/api/instances.py

@@ -13,7 +13,7 @@ def get_client_key():
   return 'certs/client.key'
 
 @login_required
-def api_containers_endpoint(endpoint):
+def api_instances_endpoint(endpoint):
 
   if not privilege_check(endpoint, request.args.get('id')):
     return jsonify({'data': [], 'metadata':[], 'error': 'not authorized', 'error_code': 403})
@@ -25,9 +25,9 @@ def api_containers_endpoint(endpoint):
     server = Server.query.filter_by(id=id).first()
     location = request.form.get('location')
     if location == 'none':
-      url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/containers?project=' + project
+      url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/instances?project=' + project
     else:
-      url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/containers?target=' + location + '&project=' + project
+      url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/instances?target=' + location + '&project=' + project
     client_cert = get_client_crt()
     client_key = get_client_key()
 
@@ -40,7 +40,7 @@ def api_containers_endpoint(endpoint):
     data.update({'name': request.form.get('name')})
     data.update({'description': request.form.get('description')})
     data.update({'location': request.form.get('location')})
-    #data.update({'type': request.form.get('type')})
+    data.update({'type': request.form.get('type')})
     data.update({'instance_type': request.form.get('instance_type')})
     profiles = []
     profiles.append(request.form.get('profiles'))
@@ -56,48 +56,51 @@ def api_containers_endpoint(endpoint):
       data.update({'source': source})
 
     config = {}
+
+    #Options shared between containers and virtual machines
     config.update({'boot.autostart': request.form.get('boot.autostart')}) if request.form.get('boot.autostart') else False
     config.update({'boot.autostart.delay': request.form.get('boot.autostart.delay')}) if request.form.get('boot.autostart.delay') else False
     config.update({'boot.autostart.priority': request.form.get('boot.autostart.priority')}) if request.form.get('boot.autostart.priority') else False
     config.update({'boot.host_shutdown_timeout': request.form.get('boot.host_shutdown_timeout')}) if request.form.get('boot.host_shutdown_timeout') else False
     config.update({'boot.stop.priority': request.form.get('boot.stop.priority')}) if request.form.get('boot.stop.priority') else False
-
     config.update({'cloud-init.network-config': request.form.get('cloud-init.network-config')}) if request.form.get('cloud-init.network-config') else False
     config.update({'cloud-init.user-data': request.form.get('cloud-init.user-data')}) if request.form.get('cloud-init.user-data') else False
     config.update({'cloud-init.vendor-data': request.form.get('cloud-init.vendor-data')}) if request.form.get('cloud-init.vendor-data') else False
-
+    config.update({'cluster.evacuate': request.form.get('cluster.evacuate')}) if request.form.get('cluster.evacuate') else False
     config.update({'limits.cpu': request.form.get('limits.cpu')}) if request.form.get('limits.cpu') else False
+    config.update({'limits.disk.priority': request.form.get('limits.disk.priority')}) if request.form.get('limits.disk.priority') else False
+    config.update({'limits.memory': request.form.get('limits.memory')}) if request.form.get('limits.memory') else False
+    config.update({'limits.network.priority': request.form.get('limits.network.priority')}) if request.form.get('limits.network.priority') else False
+    config.update({'raw.apparmor': request.form.get('raw.apparmor')}) if request.form.get('raw.apparmor') else False
+    config.update({'security.devlxd': request.form.get('security.devlxd')}) if request.form.get('security.devlxd') else False
+    config.update({'security.protection.shift': request.form.get('security.protection.shift')}) if request.form.get('security.protection.shift') else False
+    config.update({'snapshots.schedule': request.form.get('snapshots.schedule')}) if request.form.get('snapshots.schedule') else False
+    config.update({'snapshots.schedule.stopped': request.form.get('snapshots.schedule.stopped')}) if request.form.get('snapshots.schedule.stopped') else False
+    config.update({'snapshots.pattern': request.form.get('snapshots.pattern')}) if request.form.get('snapshots.pattern') else False
+    config.update({'snapshots.expiry': request.form.get('snapshots.expiry')}) if request.form.get('snapshots.expiry') else False
+
+    #Container only options
     config.update({'limits.cpu.allowance': request.form.get('limits.cpu.allowance')}) if request.form.get('limits.cpu.allowance') else False
     config.update({'limits.cpu.priority': request.form.get('limits.cpu.priority')}) if request.form.get('limits.cpu.priority') else False
-    config.update({'limits.disk.priority': request.form.get('limits.disk.priority')}) if request.form.get('limits.disk.priority') else False
     config.update({'limits.hugepages.64KB': request.form.get('limits.hugepages.64KB')}) if request.form.get('limits.hugepages.64KB') else False
     config.update({'limits.hugepages.1MB': request.form.get('limits.hugepages.1MB')}) if request.form.get('limits.hugepages.1MB') else False
     config.update({'limits.hugepages.2MB': request.form.get('limits.hugepages.2MB')}) if request.form.get('limits.hugepages.2MB') else False
     config.update({'limits.hugepages.1GB': request.form.get('limits.hugepages.1GB')}) if request.form.get('limits.hugepages.1GB') else False
-    config.update({'limits.memory': request.form.get('limits.memory')}) if request.form.get('limits.memory') else False
     config.update({'limits.memory.enforce': request.form.get('limits.memory.enforce')}) if request.form.get('limits.memory.enforce') else False
     config.update({'limits.memory.swap.priority': request.form.get('limits.memory.swap.priority')}) if request.form.get('limits.memory.swap.priority') else False
     config.update({'limits.memory.swap': request.form.get('limits.memory.swap')}) if request.form.get('limits.memory.swap') else False
-    config.update({'limits.network.priority': request.form.get('limits.network.priority')}) if request.form.get('limits.network.priority') else False
     config.update({'limits.processes': request.form.get('limits.processes')}) if request.form.get('limits.processes') else False
-
+    config.update({'linux.kernel_modules': request.form.get('linux.kernel_modules')}) if request.form.get('linux.kernel_modules') else False
     config.update({'migration.incremental.memory': request.form.get('migration.incremental.memory')}) if request.form.get('migration.incremental.memory') else False
     config.update({'migration.incremental.memory.goal': request.form.get('migration.incremental.memory.goal')}) if request.form.get('migration.incremental.memory.goal') else False
     config.update({'migration.incremental.memory.iterations': request.form.get('migration.incremental.memory.iterations')}) if request.form.get('migration.incremental.memory.iterations') else False
-
     config.update({'nvidia.driver.capabilities': request.form.get('nvidia.driver.capabilities')}) if request.form.get('nvidia.driver.capabilities') else False
     config.update({'nvidia.runtime': request.form.get('nvidia.runtime')}) if request.form.get('nvidia.runtime') else False
     config.update({'nvidia.require.cuda': request.form.get('nvidia.require.cuda')}) if request.form.get('nvidia.require.cuda') else False
     config.update({'nvidia.require.driver': request.form.get('nvidia.require.driver')}) if request.form.get('nvidia.require.driver') else False
-
-    config.update({'cluster.evacuate': request.form.get('cluster.evacuate')}) if request.form.get('cluster.evacuate') else False
-    config.update({'linux.kernel_modules': request.form.get('linux.kernel_modules')}) if request.form.get('linux.kernel_modules') else False
-    
-    config.update({'raw.apparmor': request.form.get('raw.apparmor')}) if request.form.get('raw.apparmor') else False
     config.update({'raw.idmap': request.form.get('raw.idmap')}) if request.form.get('raw.idmap') else False
     config.update({'raw.lxc': request.form.get('raw.lxc')}) if request.form.get('raw.lxc') else False
     config.update({'raw.seccomp': request.form.get('raw.seccomp')}) if request.form.get('raw.seccomp') else False
-
     config.update({'security.devlxd': request.form.get('security.devlxd')}) if request.form.get('security.devlxd') else False
     config.update({'security.devlxd.images': request.form.get('security.devlxd.images')}) if request.form.get('security.devlxd.images') else False
     config.update({'security.idmap.base': request.form.get('security.idmap.base')}) if request.form.get('security.idmap.base') else False
@@ -107,7 +110,6 @@ def api_containers_endpoint(endpoint):
     config.update({'security.privileged': request.form.get('security.privileged')}) if request.form.get('security.privileged') else False
     config.update({'security.protection.delete': request.form.get('security.protection.delete')}) if request.form.get('security.protection.delete') else False
     config.update({'security.protection.shift': request.form.get('security.protection.shift')}) if request.form.get('security.protection.shift') else False
-
     config.update({'security.syscalls.allow': request.form.get('security.syscalls.allow')}) if request.form.get('security.syscalls.allow') else False
     config.update({'security.syscalls.deny': request.form.get('security.syscalls.deny')}) if request.form.get('security.syscalls.deny') else False
     config.update({'security.syscalls.deny_compat': request.form.get('security.syscalls.deny_compat')}) if request.form.get('security.syscalls.deny_compat') else False
@@ -120,12 +122,15 @@ def api_containers_endpoint(endpoint):
     config.update({'security.syscalls.intercept.mount.fuse': request.form.get('security.syscalls.intercept.mount.fuse')}) if request.form.get('security.syscalls.intercept.mount.fuse') else False
     config.update({'security.syscalls.intercept.mount.shift': request.form.get('security.syscalls.intercept.mount.shift')}) if request.form.get('security.syscalls.intercept.mount.shift') else False
     config.update({'security.syscalls.intercept.setxattr': request.form.get('security.syscalls.intercept.setxattr')}) if request.form.get('security.syscalls.intercept.setxattr') else False
-
-    config.update({'snapshots.schedule': request.form.get('snapshots.schedule')}) if request.form.get('snapshots.schedule') else False
-    config.update({'snapshots.schedule.stopped': request.form.get('snapshots.schedule.stopped')}) if request.form.get('snapshots.schedule.stopped') else False
-    config.update({'snapshots.pattern': request.form.get('snapshots.pattern')}) if request.form.get('snapshots.pattern') else False
-    config.update({'snapshots.expiry': request.form.get('snapshots.expiry')}) if request.form.get('snapshots.expiry') else False
   
+    #Virtual Machine only options
+    config.update({'limits.memory.hugepages': request.form.get('limits.memory.hugepages')}) if request.form.get('limits.memory.hugepages') else False
+    config.update({'migration.stateful': request.form.get('migration.stateful')}) if request.form.get('migration.stateful') else False
+    config.update({'raw.qemu': request.form.get('raw.qemu')}) if request.form.get('raw.qemu') else False
+    config.update({'raw.qemu.conf': request.form.get('raw.qemu.conf')}) if request.form.get('raw.qemu.conf') else False
+    config.update({'security.agent.metrics': request.form.get('security.agent.metrics')}) if request.form.get('security.agent.metrics') else False
+    config.update({'security.secureboot': request.form.get('security.secureboot')}) if request.form.get('security.secureboot') else False
+
     data.update({'config': config})
     results = requests.post(url, verify=server.ssl_verify, cert=(client_cert, client_key), json=data)
     
@@ -137,7 +142,7 @@ def api_containers_endpoint(endpoint):
     project = request.args.get('project')
     name = request.form.get('name')
     server = Server.query.filter_by(id=id).first()
-    url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/containers/' + name + '?project=' + project
+    url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/instances/' + name + '?project=' + project
     client_cert = get_client_crt()
     client_key = get_client_key()
     results = requests.delete(url, verify=server.ssl_verify, cert=(client_cert, client_key))
@@ -149,12 +154,20 @@ def api_containers_endpoint(endpoint):
     project = request.args.get('project')
     server = Server.query.filter_by(id=id).first()
     recursion = request.args.get('recursion')
+
+    if request.args.get('filter') == "container":
+      filter = "type+eq+container"
+    elif request.args.get('filter') == "virtual-machine":
+      filter = "type+eq+virtual-machine"
+    else:  
+      filter = ""
+
     if recursion == '1':
-      url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/containers?recursion=1&project=' + project
+      url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/instances?filter=' + filter + '&recursion=1&project=' + project
     elif recursion == '2':
-      url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/containers?recursion=2&project=' + project
+      url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/instances?filter=' + filter + '&recursion=2&project=' + project
     else:
-      url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/containers?project=' + project
+      url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/instances?filter=' + filter + '&project=' + project
     client_cert = get_client_crt()
     client_key = get_client_key()
     results = requests.get(url, verify=server.ssl_verify, cert=(client_cert, client_key))
@@ -211,7 +224,7 @@ def api_containers_endpoint(endpoint):
     project = request.args.get('project')
     name = request.form.get('name')
     server = Server.query.filter_by(id=id).first()
-    url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/containers/' + name + '?project=' + project
+    url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/instances/' + name + '?project=' + project
     client_cert = get_client_crt()
     client_key = get_client_key()
     results = requests.get(url, verify=server.ssl_verify, cert=(client_cert, client_key))
@@ -237,7 +250,7 @@ def api_containers_endpoint(endpoint):
     project = request.args.get('project')
     name = request.args.get('name')
     server = Server.query.filter_by(id=id).first()
-    url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/containers/' + name + '?project=' + project
+    url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/instances/' + name + '?project=' + project
     client_cert = get_client_crt()
     client_key = get_client_key()
 

+ 0 - 217
lxconsole/api/virtual_machines.py

@@ -1,217 +0,0 @@
-from flask import jsonify, request
-import json
-import requests
-from lxconsole import db
-from lxconsole.models import Server
-from flask_login import login_required
-from lxconsole.api.access_controls import privilege_check
-
-
-def get_client_crt():
-  return 'certs/client.crt'
-
-def get_client_key():
-  return 'certs/client.key'
-
-@login_required
-def api_virtual_machines_endpoint(endpoint):
-
-  if not privilege_check(endpoint, request.args.get('id')):
-    return jsonify({'data': [], 'metadata':[], 'error': 'not authorized', 'error_code': 403})
-
-
-  if endpoint == 'add_instance':
-    id = request.args.get('id')
-    project = request.args.get('project')
-    server = Server.query.filter_by(id=id).first()
-    location = request.form.get('location')
-    if location == 'none':
-      url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/virtual-machines?project=' + project
-    else:
-      url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/virtual-machines?target=' + location + '&project=' + project
-    client_cert = get_client_crt()
-    client_key = get_client_key()
-
-    if request.form.get('json'):
-      data = request.form.get('json')
-      results = requests.post(url, verify=server.ssl_verify, cert=(client_cert, client_key), data=data)
-      return jsonify(results.json())
-
-    data = {}
-    data.update({'name': request.form.get('name')})
-    data.update({'description': request.form.get('description')})
-    data.update({'location': request.form.get('location')})
-    #data.update({'type': request.form.get('type')})
-    data.update({'instance_type': request.form.get('instance_type')})
-    profiles = []
-    profiles.append(request.form.get('profiles'))
-    data.update({'profiles': profiles})
-
-    source = {}
-    if request.form.get('image') == 'none':
-      source.update({'type': request.form.get('image')})
-      data.update({'source': source})
-    else:
-      source.update({'type': 'image'})
-      source.update({'fingerprint': request.form.get('image')})
-      data.update({'source': source})
-
-    config = {}
-    config.update({'boot.autostart': request.form.get('boot.autostart')}) if request.form.get('boot.autostart') else False
-    config.update({'boot.autostart.delay': request.form.get('boot.autostart.delay')}) if request.form.get('boot.autostart.delay') else False
-    config.update({'boot.autostart.priority': request.form.get('boot.autostart.priority')}) if request.form.get('boot.autostart.priority') else False
-    config.update({'boot.host_shutdown_timeout': request.form.get('boot.host_shutdown_timeout')}) if request.form.get('boot.host_shutdown_timeout') else False
-    config.update({'boot.stop.priority': request.form.get('boot.stop.priority')}) if request.form.get('boot.stop.priority') else False
-
-    config.update({'cloud-init.network-config': request.form.get('cloud-init.network-config')}) if request.form.get('cloud-init.network-config') else False
-    config.update({'cloud-init.user-data': request.form.get('cloud-init.user-data')}) if request.form.get('cloud-init.user-data') else False
-    config.update({'cloud-init.vendor-data': request.form.get('cloud-init.vendor-data')}) if request.form.get('cloud-init.vendor-data') else False
-
-    config.update({'limits.cpu': request.form.get('limits.cpu')}) if request.form.get('limits.cpu') else False
-    config.update({'limits.disk.priority': request.form.get('limits.disk.priority')}) if request.form.get('limits.disk.priority') else False
-    config.update({'limits.memory': request.form.get('limits.memory')}) if request.form.get('limits.memory') else False
-    config.update({'limits.memory.hugepages': request.form.get('limits.memory.hugepages')}) if request.form.get('limits.memory.hugepages') else False
-    config.update({'limits.network.priority': request.form.get('limits.network.priority')}) if request.form.get('limits.network.priority') else False
-
-    config.update({'migration.stateful': request.form.get('migration.stateful')}) if request.form.get('migration.stateful') else False
-
-    config.update({'cluster.evacuate': request.form.get('cluster.evacuate')}) if request.form.get('cluster.evacuate') else False
-
-    config.update({'raw.apparmor': request.form.get('raw.apparmor')}) if request.form.get('raw.apparmor') else False
-    config.update({'raw.qemu': request.form.get('raw.qemu')}) if request.form.get('raw.qemu') else False
-    config.update({'raw.qemu.conf': request.form.get('raw.qemu.conf')}) if request.form.get('raw.qemu.conf') else False
-
-    config.update({'security.devlxd': request.form.get('security.devlxd')}) if request.form.get('security.devlxd') else False
-    config.update({'security.protection.shift': request.form.get('security.protection.shift')}) if request.form.get('security.protection.shift') else False
-    config.update({'security.agent.metrics': request.form.get('security.agent.metrics')}) if request.form.get('security.agent.metrics') else False
-    config.update({'security.secureboot': request.form.get('security.secureboot')}) if request.form.get('security.secureboot') else False
-
-    config.update({'snapshots.schedule': request.form.get('snapshots.schedule')}) if request.form.get('snapshots.schedule') else False
-    config.update({'snapshots.schedule.stopped': request.form.get('snapshots.schedule.stopped')}) if request.form.get('snapshots.schedule.stopped') else False
-    config.update({'snapshots.pattern': request.form.get('snapshots.pattern')}) if request.form.get('snapshots.pattern') else False
-    config.update({'snapshots.expiry': request.form.get('snapshots.expiry')}) if request.form.get('snapshots.expiry') else False
-  
-    data.update({'config': config})
-    results = requests.post(url, verify=server.ssl_verify, cert=(client_cert, client_key), json=data)
-    
-    return jsonify(results.json())
-
-
-  if endpoint == 'delete_instance':
-    id = request.args.get('id')
-    project = request.args.get('project')
-    name = request.form.get('name')
-    server = Server.query.filter_by(id=id).first()
-    url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/virtual-machines/' + name + '?project=' + project
-    client_cert = get_client_crt()
-    client_key = get_client_key()
-    results = requests.delete(url, verify=server.ssl_verify, cert=(client_cert, client_key))
-    return jsonify(results.json())
-
-
-  if endpoint == 'list_instances':
-    id = request.args.get('id')
-    project = request.args.get('project')
-    server = Server.query.filter_by(id=id).first()
-    recursion = request.args.get('recursion')
-    if recursion == '1':
-      url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/virtual-machines?recursion=1&project=' + project
-    elif recursion == '2':
-      url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/virtual-machines?recursion=2&project=' + project
-    else:
-      url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/virtual-machines?project=' + project
-    client_cert = get_client_crt()
-    client_key = get_client_key()
-    results = requests.get(url, verify=server.ssl_verify, cert=(client_cert, client_key))
-    instances = json.dumps(results.json())
-    instances = json.loads(instances)
-    if recursion == '0' or recursion == '1':
-      return jsonify(instances)
-    i = 0
-    for instance in instances['metadata']:
-      instances['metadata'][i]['memory'] = ''
-      instances['metadata'][i]['disk'] = ''
-      instances['metadata'][i]['ipv4_addresses'] = []
-      instances['metadata'][i]['ipv6_addresses'] = []
-
-      if 'state' in instance.keys():
-        
-        # Set memory information if exists
-        if 'memory' in instance['state'].keys():
-          if 'usage' in instance['state']['memory'].keys():
-            memory = instance['state']['memory']['usage']
-            if memory:
-              instances['metadata'][i]['memory'] = memory
-
-        # Set disk information if exists
-        if 'disk' in instance['state'].keys():
-          if 'root' in instance['state']['disk'].keys():
-            if 'usage' in instance['state']['disk']['root'].keys():
-              disk = instance['state']['disk']['root']['usage']
-              if disk:  
-                instances['metadata'][i]['disk'] = disk
-
-        # Set network information if exists
-        if 'network' in instance['state'].keys():
-          networks = instance['state']['network']
-          if networks:
-            instances['metadata'][i]['ipv4_addresses'] = []
-            for network in networks.keys():
-              addresses = networks[network]['addresses']
-              for address in addresses:
-                if address['family'] == 'inet' and address['scope'] == 'global':
-                  instances['metadata'][i]['ipv4_addresses'] += [ address['address'] + ' (' + network + ')' ]
-            instances['metadata'][i]['ipv6_addresses'] = []
-            for network in networks.keys():
-              addresses = networks[network]['addresses']
-              for address in addresses:
-                if address['family'] == 'inet6' and address['scope'] == 'global':
-                  instances['metadata'][i]['ipv6_addresses'] += [ address['address'] + ' (' + network + ')' ]
-      i += 1
-    return jsonify(instances)
-
-
-  if endpoint == 'load_instance':
-    id = request.args.get('id')
-    project = request.args.get('project')
-    name = request.form.get('name')
-    server = Server.query.filter_by(id=id).first()
-    url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/virtual-machines/' + name + '?project=' + project
-    client_cert = get_client_crt()
-    client_key = get_client_key()
-    results = requests.get(url, verify=server.ssl_verify, cert=(client_cert, client_key))
-    return jsonify(results.json())
-
-
-  if endpoint == 'change_instance_state':
-    id = request.args.get('id')
-    project = request.args.get('project')
-    name = request.form.get('name')
-    action = request.form.get('action')
-    server = Server.query.filter_by(id=id).first()
-    url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/instances/' + name + '/state?project=' + project
-    client_cert = get_client_crt()
-    client_key = get_client_key()
-    data = { 'action': action }
-    results = requests.put(url, verify=server.ssl_verify, cert=(client_cert, client_key), json=data)
-    return jsonify(results.json())
-
-
-  if endpoint == 'update_instance':
-    id = request.args.get('id')
-    project = request.args.get('project')
-    name = request.args.get('name')
-    server = Server.query.filter_by(id=id).first()
-    url = 'https://' + server.addr + ':' + str(server.port) + '/1.0/virtual-machines/' + name + '?project=' + project
-    client_cert = get_client_crt()
-    client_key = get_client_key()
-
-    if request.form.get('json'):
-      data = request.form.get('json')
-      results = requests.put(url, verify=server.ssl_verify, cert=(client_cert, client_key), data=data)
-      return jsonify(results.json())
-
-    data = {}
-    data.update({'name': request.form.get('name')})
-    results = requests.post(url, verify=server.ssl_verify, cert=(client_cert, client_key), json=data)
-    return jsonify(results.json())

+ 5 - 21
lxconsole/routes.py

@@ -59,21 +59,16 @@ def cluster_groups():
 def cluster_members():
   return render_template('cluster-members.html', page_title='Cluster Members', page_user_id=current_user.id, page_username=current_user.username,)
 
-@app.route("/container")
-@login_required
-def container():
-  return render_template('container.html', page_title='Container: ', page_user_id=current_user.id, page_username=current_user.username,)
-
-@app.route("/containers")
-@login_required
-def containers():
-  return render_template('containers.html', page_title='Containers', page_user_id=current_user.id, page_username=current_user.username,)
-
 @app.route("/images")
 @login_required
 def images():
   return render_template('images.html', page_title='Images', page_user_id=current_user.id, page_username=current_user.username,)
 
+@app.route("/instance")
+@login_required
+def instance():
+  return render_template('instance.html', page_title='Instance', page_user_id=current_user.id, page_username=current_user.username,)
+
 @app.route("/instances")
 @login_required
 def instances():
@@ -144,17 +139,6 @@ def storage_pools():
 def storage_volumes():
   return render_template('storage-volumes.html', page_title='Storage Volumes', page_user_id=current_user.id, page_username=current_user.username,)
 
-@app.route("/virtual-machine")
-@login_required
-def virtual_machine():
-  return render_template('virtual-machine.html', page_title='Virtual Machine: ', page_user_id=current_user.id, page_username=current_user.username,)
-
-@app.route("/virtual-machines")
-@login_required
-def virtual_machines():
-  return render_template('virtual-machines.html', page_title='Virtual Machines', page_user_id=current_user.id, page_username=current_user.username,)
-
-
 @app.route("/backups/<serverId>/<project>/<instance>/<filename>")
 @login_required
 def backups(serverId, project, instance, filename):

File diff suppressed because it is too large
+ 0 - 0
lxconsole/static/css/bootstrap/bootstrap.min.css.map


+ 6 - 1
lxconsole/static/css/styles.css

@@ -68,7 +68,12 @@ td.details-control {
   color:#007bff ;
 cursor: pointer;
 }
+
 tr.shown td.details-control {
 text-align:center; 
 color:#ff0000 ;
-}
+}
+
+.table-hover tbody tr:hover td, .table-hover tbody tr:hover th {
+  background-color: #fefefe;
+}

+ 4 - 5
lxconsole/static/js/sidebar.js

@@ -53,8 +53,7 @@ function populateNavbarLinks(){
 }
 
 function applySidebarLinks() {
-  $("#containersLinkSidebar").attr("href", "containers?id=" + encodeURI(serverId) + "&project=" + encodeURI(project));
-  $("#virtualMachinesLinkSidebar").attr("href", "virtual-machines?id=" + encodeURI(serverId) + "&project=" + encodeURI(project));
+  $("#instancesLinkSidebar").attr("href", "instances?id=" + encodeURI(serverId) + "&project=" + encodeURI(project));
 
   $("#imagesLinkSidebar").attr("href", "images?id=" + encodeURI(serverId) + "&project=" + encodeURI(project));
   $("#profilesLinkSidebar").attr("href", "profiles?id=" + encodeURI(serverId) + "&project=" + encodeURI(project));
@@ -71,9 +70,9 @@ function applySidebarLinks() {
 }
 
 function  applySidebarStyles() {
-    if (location.pathname == "/containers" || location.pathname == "/container"){
-      $('#containersSpan').css('color','#fff');
-      $('#containersIcon').css('color','#fff');
+    if (location.pathname == "/instances" || location.pathname == "/instance"){
+      $('#instancesSpan').css('color','#fff');
+      $('#instancesIcon').css('color','#fff');
     }
     if (location.pathname == "/images"){
       $('#imagesSpan').css('color','#fff');

+ 6 - 3
lxconsole/templates/access-controls.html

@@ -6,9 +6,9 @@
       <h1>{{ page_title | safe }}</h1>
     </div>
     <div class="col-sm-6">
-      <a class="btn btn-outline-primary float-sm-right mr-4" href="#" data-toggle="modal" data-target="#addModal" title="Add Access Control" aria-hidden="true">
+      <button class="btn btn-outline-primary float-sm-right mr-4" data-bs-toggle="modal" data-bs-target="#addModal" title="Add Access Control" aria-hidden="true">
         <i class="fas fa-plus fa-sm fa-fw"></i> Access Control
-      </a>
+      </button>
     </div>
   </div>
 {% endblock header %}
@@ -59,7 +59,10 @@
           url: "../api/access-controls/list_access_controls",
           dataType: "json",
           dataSrc: "data",
-          contentType: "application/json"
+          contentType: "application/json",
+          error: function (xhr, error, code) {
+            console.log(xhr, code);
+          }
         },
         columns: [
         { title: "Id", data: function (row, type, set) {

+ 6 - 3
lxconsole/templates/certificates.html

@@ -6,9 +6,9 @@
       <h1>{{ page_title | safe }}</h1>
     </div>
     <div class="col-sm-6">
-      <a class="btn btn-outline-primary float-sm-right mr-4" href="#" data-toggle="modal" data-target="#addModal" title="Add Certificate" aria-hidden="true">
+      <button class="btn btn-outline-primary float-sm-right mr-4" data-bs-toggle="modal" data-bs-target="#addModal" title="Add Certificate" aria-hidden="true">
         <i class="fas fa-plus fa-sm fa-fw"></i> Certificate
-      </a>
+      </button>
     </div>
   </div>
 {% endblock header %}
@@ -98,7 +98,10 @@
           url: "../api/certificates/list_certificates?id="+serverId+"&project=" + project + "&recursion=1",
           dataType: "json",
           dataSrc: "metadata",
-          contentType: "application/json"
+          contentType: "application/json",
+          error: function (xhr, error, code) {
+            console.log(xhr, code);
+          }
         },
         columns: [
           { title: "Name", data: function (row, type, set) {

+ 6 - 3
lxconsole/templates/cluster-groups.html

@@ -6,9 +6,9 @@
       <h1>{{ page_title | safe }}</h1>
     </div>
     <div class="col-sm-6">
-      <a class="btn btn-outline-primary float-sm-right mr-4" href="#" data-toggle="modal" data-target="#addModal" title="Add Cluster Group" aria-hidden="true">
+      <button class="btn btn-outline-primary float-sm-right mr-4" data-bs-toggle="modal" data-bs-target="#addModal" title="Add Cluster Group" aria-hidden="true">
         <i class="fas fa-plus fa-sm fa-fw"></i> Cluster Group
-      </a>
+      </button>
     </div>
   </div>
 {% endblock header %}
@@ -98,7 +98,10 @@
           url: "../api/cluster-groups/list_cluster_groups?id="+serverId+"&project=" + project + "&recursion=1",
           dataType: "json",
           dataSrc: "metadata",
-          contentType: "application/json"
+          contentType: "application/json",
+          error: function (xhr, error, code) {
+            console.log(xhr, code);
+          }
         },
         columns: [
           { title: "Name", data: function (row, type, set) {

+ 6 - 3
lxconsole/templates/cluster-members.html

@@ -7,9 +7,9 @@
     </div>
     <!--
     <div class="col-sm-6">
-      <a class="btn btn-outline-primary float-sm-right mr-4" href="#" data-toggle="modal" data-target="#addModal" title="Add Cluster Member" aria-hidden="true">
+      <button class="btn btn-outline-primary float-sm-right mr-4" data-bs-toggle="modal" data-bs-target="#addModal" title="Add Cluster Member" aria-hidden="true">
         <i class="fas fa-plus fa-sm fa-fw"></i> Cluster Member
-      </a>
+      </button>
     </div>
     -->
   </div>
@@ -100,7 +100,10 @@
           url: "../api/cluster-members/list_cluster_members?id="+serverId+"&project=" + project + "&recursion=1",
           dataType: "json",
           dataSrc: "metadata",
-          contentType: "application/json"
+          contentType: "application/json",
+          error: function (xhr, error, code) {
+            console.log(xhr, code);
+          }
         },
         columns: [
           { title: "Server Name", data: function (row, type, set) {

+ 0 - 332
lxconsole/templates/containers.html

@@ -1,332 +0,0 @@
-{% extends "main.html" %}
-
-{% block header %}
-  <div class="row mb-2">
-    <div class="col-sm-6">
-      <h1>{{ page_title | safe }}</h1>
-    </div>
-    <div class="col-sm-6">
-      <a class="btn btn-outline-primary float-sm-right mr-4" href="#" data-toggle="modal" data-target="#addModal" title="Add Container" aria-hidden="true">
-        <i class="fas fa-plus fa-sm fa-fw"></i> Container
-      </a>
-    </div>
-  </div>
-{% endblock header %}
-
-{% block content %}
-  <div class="col-12">
-    <div class="card">
-      <div class="card-header">
-        <h3 class="card-title">Containers</h3>
-        <div class="card-tools">
-          <button type="button" class="btn btn-tool" onclick="reloadPageContent()" title="Refresh">
-          <i class="fas fa-sync"></i>
-          </button>
-        </div>
-      </div>
-      <div class="card-body">
-        <table class="table table-hover" id="myDataTable" width="100%" cellspacing="0">
-        </table>
-      </div>
-    </div>
-  </div>
-{% endblock content %}
-
-{% block modal %}
-  {% include 'modals/containers.html' %}
-{% endblock modal %}
-
-{% block script %}
-  <script>
-    var reloadTime = 10000;
-    const queryString = window.location.search;
-    const urlParams = new URLSearchParams(queryString);
-    const serverId = urlParams.get('id');
-    const project = urlParams.get('project');
-    var editedContainer = ''
-    applySidebarStyles();
-    applySidebarLinks();
-    populateSidebarLinks();
-    populateNavbarLinks();
-
-    function reloadPageContent() {
-      //Clear the automatic page reload
-      clearTimeout(pageReloadTimeout);
-
-      //Reload the datatables content
-      $('#myDataTable').DataTable().ajax.reload(null, false);
-
-      //Set the automatic page reload
-      pageReloadTimeout = setTimeout(() => { reloadPageContent(); }, reloadTime);
-    }
-
-    function loadPageContent(){
-
-      //Display the current project
-      $("#selectedProject").text(project);
-
-      //Populate the Server dropdown
-      $.getJSON("../api/servers/list_servers?id="+serverId, function (data) {
-        data = data.data
-        for (var index = 0; index < data.length; index++) {
-          if (data[index].name == '')
-            optionText = data[index].addr
-          else
-            optionText = data[index].name
-          if (data[index].id == serverId)
-            $('#serverListNav').append('<option value="' + data[index].id + '" selected="selected">' + optionText + '</option>');
-          else
-            $('#serverListNav').append('<option value="' + data[index].id + '">' + optionText + '</option>');
-        }
-      })
-
-      //Populate the Project dropdown
-      $.getJSON("../api/projects/list_projects?id="+serverId+"&project="+project, function (data) {
-        data = data.metadata
-        for (var index = 0; index < data.length; index++) {
-          optionText = data[index].replace('/1.0/projects/','');
-          if (optionText == project)
-            $('#projectListNav').append('<option value="' + optionText + '" selected="selected">' + optionText + '</option>');
-          else
-            $('#projectListNav').append('<option value="' + optionText + '">' + optionText + '</option>');
-        }
-      })
-
-      //Populate the modal Profile dropdown
-      $.getJSON("../api/profiles/list_profiles?id="+serverId+"&project="+project, function (data) {
-        data = data.metadata
-        for (var index = 0; index < data.length; index++) {
-          //When using projects other than default and no recursion, it gets like URL variable with "?"
-          optionText = data[index].split("?")
-          optionText = optionText[0].replace('/1.0/profiles/','');
-          if (optionText == 'default') {
-            $('#containerProfileInput').append('<option value="' + optionText + '" selected="selected">' + optionText + '</option>');
-          }
-          else {
-            $('#containerProfileInput').append('<option value="' + optionText + '">' + optionText + '</option>');
-          }
-        }
-      })
-
-      //Populate the modal Location dropdown
-      $.getJSON("../api/cluster-members/list_cluster_members?id="+serverId+"&project="+project, function (data) {
-        data = data.metadata
-        for (var index = 0; index < data.length; index++) {
-          optionText = data[index].replace('/1.0/cluster/members/','');
-          $('#containerLocationInput').append('<option value="' + optionText + '">' + optionText + '</option>');
-        }
-      })
-      $.getJSON("../api/cluster-groups/list_cluster_groups?id="+serverId+"&project="+project, function (data) {
-        data = data.metadata
-        for (var index = 0; index < data.length; index++) {
-          optionText = data[index].replace('/1.0/cluster/groups/','');
-          $('#containerLocationInput').append('<option value="@' + optionText + '">@' + optionText + '</option>');
-        }
-      })
-
-      //Populate the modal Image dropdown
-      $.getJSON("../api/images/list_images?id="+serverId+"&project="+project+"&recursion=1", function (data) {
-        data = data.metadata
-        for (var index = 0; index < data.length; index++) {
-          // Earlier versions of LXD did not have type property. These only supported container type instances
-          if (data[index].hasOwnProperty('type')) {
-            if(data[index].type == 'container'){
-              $('#containerImageInput').append('<option value="' + data[index].fingerprint + '">' + data[index].properties.description + '</option>');
-            }
-          }
-          else {
-            $('#containerImageInput').append('<option value="' + data[index].fingerprint + '">' + data[index].properties.description + '</option>');
-          }
-        }
-      })
-
-      // Configure Datatable
-      $('#myDataTable').DataTable({
-        ajax: {
-          url: "../api/containers/list_instances?id="+serverId+"&project=" + project + "&recursion=2",
-          dataType: "json",
-          dataSrc: "metadata",
-          contentType: "application/json"
-        },
-        columns: [
-          { title: "Name", data: function (row, type, set) {
-              if (row.hasOwnProperty('name')) {
-                if (row.name)
-                  return '<a href="../container?id=' + serverId + '&project=' + project + '&instance=' + row.name + '">' + row.name + '</a>';
-              }
-              return '-'
-            },
-          },
-          { title: "OS", data: function (row, type, set) {
-              if (row.hasOwnProperty('expanded_config')) {
-                if (row.expanded_config.hasOwnProperty('image.os')) {
-                  if (row.expanded_config['image.os']){
-                    return row.expanded_config['image.os']
-                  }
-                }
-              }
-              return '-'
-            },
-          },
-          { title: "Location", data: function (row, type, set) {
-              if (row.hasOwnProperty('location')) {
-                if (row.location){
-                  return row.location
-                }
-              }
-              return '-'
-            },
-          },
-          { title: "IPv4", data: function (row, type, set) {
-              if (row.hasOwnProperty('ipv4_addresses')) {
-                if (row.ipv4_addresses.length > 0){
-                  return row.ipv4_addresses.join(', <br />')
-                }
-              }
-              return '-'
-            },
-          },
-          { title: "IPv6", data: function (row, type, set) {
-              if (row.hasOwnProperty('ipv6_addresses')) {
-                if (row.ipv6_addresses.length > 0){
-                  return row.ipv6_addresses.join(', <br />')
-                }
-              }
-              return '-'
-            },
-          },
-          { title: "Memory", data: function (row, type, set) {
-              if (row.hasOwnProperty('memory')) {
-                if (row.memory){
-                  if (type === 'display'){
-                    return (row.memory / 1024 / 1024).toFixed(2) + ' MiB'
-                  }
-                  return row.memory
-                }
-              }
-              return '-'
-            },
-          },
-          { title: "Root Disk", data: function (row, type, set) {
-              if (row.hasOwnProperty('disk')) {
-                if (row.disk){
-                  if (type === 'display'){
-                    return (row.disk / 1024 / 1024).toFixed(2) + ' MiB'
-                  }
-                  return row.disk
-                }
-              }
-              return '-'
-            },
-          },
-          { title: "Status", data: function (row, type, set) {
-              if (row.hasOwnProperty('status')) {
-                if (row.status){
-                  return row.status
-                }
-              }
-              return '-'
-            },
-          },
-          { title: "Actions", data: function (row, type, set) {
-              links = ''
-              if (row.hasOwnProperty('name') && row.hasOwnProperty('status')) {
-                if (row.name && row.status){
-                  if (row.status == 'Frozen')
-                    links += '<a href="#" onclick=changeItemState(\''+row.name+'\',\'unfreeze\')><i class="fas fa-pause fa-lg" style="color:#ddd" title="Edit" aria-hidden="true"></i></a>'
-                  else if (row.status == 'Stopped')
-                    links += '<a href="#" onclick=changeItemState(\''+row.name+'\',\'start\')><i class="fas fa-play fa-lg" style="color:#ddd" title="Edit" aria-hidden="true"></i></a>'
-                  else if (row.status == 'Running')
-                    links += '<a href="#" onclick=changeItemState(\''+row.name+'\',\'stop\')><i class="fas fa-stop fa-lg" style="color:#ddd" title="Edit" aria-hidden="true"></i></a>'
-                  links += '&nbsp' + '&nbsp' 
-                  links += '<a href="#" onclick=deleteInstance(\''+row.name+'\')><i class="fas fa-trash-alt fa-lg" style="color:#ddd" title="Delete" aria-hidden="true"></i></a>'
-                }
-              }
-              return links
-            },
-          },
-        ],
-        order: [],
-      });
-
-      //Set reload page content
-      pageReloadTimeout = setTimeout(() => { reloadPageContent(); }, reloadTime);
-
-    }
-
-    // Change state start/stop of instance
-    function changeItemState(name, action){
-      console.log("Info: starting container " + name);
-      $.post("../api/containers/change_instance_state?id=" + serverId + "&project=" + project, { name: name, action: action }, function (data) {
-        console.log(data);
-        if (data.error_code >= 400){
-          alert(data.error);
-        }
-        //Async type
-        setTimeout(() => { reloadPageContent(); }, 2000);
-        operationStatusCheck()
-      });
-    }
-
-    // Add instance
-    function addItem(){
-      console.log("Info: adding new container");
-      data = $('#addForm').serialize();
-      $.post("../api/containers/add_instance?id="+serverId+"&project="+project, data, function (data) {
-        console.log(data);
-        if (data.error_code >= 400){
-          alert(data.error);
-        }
-        //Aync type
-        setTimeout(() => { reloadPageContent(); }, 2000);
-        operationStatusCheck()
-      });
-    }
-
-    // Delete instance
-    function deleteInstance(name){
-      console.log("Info: confirming deletion of container " + name);
-      if (confirm("Are you sure you want to delete container " + name + "?") == true) {
-        console.log("Info: deleting container " + name);
-        $.post("../api/containers/delete_instance?id=" + serverId + "&project=" + project, { name: name }, function (data) {
-          console.log(data);
-          if (data.error_code >= 400){
-            alert(data.error);
-          }
-          //Async type
-          setTimeout(() => { reloadPageContent(); }, 2000);
-          operationStatusCheck()
-        });
-      }
-    }
-
-    // Create instance from JSON
-    function createItemUsingJSON(){
-      var json = $("#jsonCreateInput").val();
-      console.log("Info: adding new instance");
-      $.post("../api/containers/add_instance?id="+serverId+"&project="+project, { json: json },  function (data) {
-        console.log(data);
-        if (data.error_code >= 400){
-          alert(data.error);
-        }
-        //Async type
-        setTimeout(() => { reloadPageContent(); }, 2000);
-        operationStatusCheck()
-      });
-    }
-
-    $(document).ready(function(){
-
-      //If id or project variables are missing redirect to servers page
-      if (!serverId || !project) {
-        window.location.href = 'servers';
-      }
-      else {
-        loadPageContent()
-        operationStatusCheck()
-      }
-      
-    });
-
-  </script>
-{% endblock script %}

+ 6 - 3
lxconsole/templates/groups.html

@@ -6,9 +6,9 @@
       <h1>{{ page_title | safe }}</h1>
     </div>
     <div class="col-sm-6">
-      <a class="btn btn-outline-primary float-sm-right mr-4" href="#" data-toggle="modal" data-target="#addModal" title="Add Group" aria-hidden="true">
+      <button class="btn btn-outline-primary float-sm-right mr-4" data-bs-toggle="modal" data-bs-target="#addModal" title="Add Group" aria-hidden="true">
         <i class="fas fa-plus fa-sm fa-fw"></i> Group
-      </a>
+      </button>
     </div>
   </div>
 {% endblock header %}
@@ -59,7 +59,10 @@
           url: "../api/groups/list_groups",
           dataType: "json",
           dataSrc: "data",
-          contentType: "application/json"
+          contentType: "application/json",
+          error: function (xhr, error, code) {
+            console.log(xhr, code);
+          }
         },
         columns: [
           { title: "Name", data: function (row, type, set) {

+ 5 - 9
lxconsole/templates/head.html

@@ -10,10 +10,11 @@
   <!-- Font Awesome -->
   <link rel="stylesheet" href="../static/plugins/fontawesome-free/css/all.min.css">
 
-  <!-- DataTables -->
-  <link rel="stylesheet" href="../static/plugins/datatables-bs4/css/dataTables.bootstrap4.min.css">
-  <link rel="stylesheet" href="../static/plugins/datatables-responsive/css/responsive.bootstrap4.min.css">
-  <link rel="stylesheet" href="../static/plugins/datatables-buttons/css/buttons.bootstrap4.min.css">
+  <!-- Datatables Bootstrap 5 - https://cdn.datatables.net/1.13.6/css/dataTables.bootstrap5.min.css -->
+  <link rel="stylesheet" href="../static/css/datatables/dataTables.bootstrap5.min.css">
+
+  <!-- Bootstrap 5 - https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/5.2.3/css/bootstrap.min.css -->
+  <link rel="stylesheet" href="../static/css/bootstrap/bootstrap-5.2.3.min.css">
 
   <!-- Xterm.js style -->
   <link rel="stylesheet" href="../static/css/xterm/xterm.css"/>
@@ -24,11 +25,6 @@
   <!-- LXD Dashboard style -->
   <link rel="stylesheet" href="../static/css/styles.css">
 
-  <!-- Bootstrap 5 - https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/5.2.3/css/bootstrap.min.css -->
-  <!-- <link rel="stylesheet" href="../static/css/bootstrap/bootstrap-5.2.3.min.css"> -->
-
-  <!-- Datatables Bootstrap 5 - https://cdn.datatables.net/1.13.6/css/dataTables.bootstrap5.min.css -->
-  <!--<link rel="stylesheet" href="../static/css/datatables/dataTables.bootstrap5.min.css">-->
 
 </head>
 

+ 6 - 3
lxconsole/templates/images.html

@@ -6,9 +6,9 @@
       <h1>{{ page_title | safe }}</h1>
     </div>
     <div class="col-sm-6">
-      <a class="btn btn-outline-primary float-sm-right mr-4" href="#" data-toggle="modal" data-target="#addModal" title="Add Image" aria-hidden="true">
+      <button class="btn btn-outline-primary float-sm-right mr-4" data-bs-toggle="modal" data-bs-target="#addModal" title="Add Image" aria-hidden="true">
         <i class="fas fa-plus fa-sm fa-fw"></i> Image
-      </a>
+      </button>
     </div>
   </div>
 {% endblock header %}
@@ -98,7 +98,10 @@
           url: "../api/images/list_images?id="+serverId + "&project=" + project + "&recursion=1",
           dataType: "json",
           dataSrc: "metadata",
-          contentType: "application/json"
+          contentType: "application/json",
+          error: function (xhr, error, code) {
+            console.log(xhr, code);
+          }
         },
         columns: [
           { title: "Alias", data: function (row, type, set) {

File diff suppressed because it is too large
+ 272 - 200
lxconsole/templates/instance.html


+ 632 - 0
lxconsole/templates/instances.html

@@ -0,0 +1,632 @@
+{% extends "main.html" %}
+
+{% block header %}
+  <div class="row mb-2">
+    <div class="col-sm-6">
+      <h1>{{ page_title | safe }}</h1>
+    </div>
+    <div class="col-sm-6">
+      <button class="btn btn-outline-primary float-sm-right mr-4" data-bs-toggle="modal" data-bs-target="#addModal" title="Add Instance" aria-hidden="true">
+        <i class="fas fa-plus fa-sm fa-fw"></i> Instance
+      </button>
+    </div>
+  </div>
+{% endblock header %}
+
+{% block content %}
+  <div class="col-12">
+    <nav>
+      <div class="nav nav-tabs" id="nav-page-tab" role="tablist">
+        <button class="nav-link active" id="nav-containers-tab" data-bs-toggle="tab" data-bs-target="#nav-containers" type="button" role="tab" aria-controls="nav-containers" aria-selected="true">Containers</button>
+        <button class="nav-link" id="nav-virtual-machines-tab" data-bs-toggle="tab" data-bs-target="#nav-virtual-machines" type="button" role="tab" aria-controls="nav-virtual-machines" aria-selected="false">Virtual-Machines</button>
+      </div>
+    </nav>
+    <div class="tab-content" id="nav-page-content">
+      <div class="tab-pane fade show active" id="nav-containers" role="tabpanel" aria-labelledby="nav-containers-tab">
+        <br />
+        <div class="card">
+          <div class="card-header">
+            <h3 class="card-title">Containers</h3>
+            <div class="card-tools">
+              <button type="button" class="btn btn-tool" onclick="reloadPageContent()" title="Refresh">
+              <i class="fas fa-sync"></i>
+              </button>
+            </div>
+          </div>
+          <div class="card-body">
+            <table class="table table-hover" id="containerDataTable" width="100%" cellspacing="0">
+            </table>
+          </div>
+        </div>
+      </div>
+      <div class="tab-pane fade" id="nav-virtual-machines" role="tabpanel" aria-labelledby="nav-virtual-machines-tab">
+        <br />
+        <div class="card">
+          <div class="card-header">
+            <h3 class="card-title">Virtual Machines</h3>
+            <div class="card-tools">
+              <button type="button" class="btn btn-tool" onclick="reloadPageContent()" title="Refresh">
+              <i class="fas fa-sync"></i>
+              </button>
+            </div>
+          </div>
+          <div class="card-body">
+            <table class="table table-hover" id="virtualMachineDataTable" width="100%" cellspacing="0">
+            </table>
+          </div>
+        </div>
+      </div>
+    </div>
+
+
+  </div>
+{% endblock content %}
+
+{% block modal %}
+  {% include 'modals/instances.html' %}
+{% endblock modal %}
+
+{% block script %}
+  <script>
+    var reloadTime = 10000;
+    const queryString = window.location.search;
+    const urlParams = new URLSearchParams(queryString);
+    const serverId = urlParams.get('id');
+    const project = urlParams.get('project');
+    applySidebarStyles();
+    applySidebarLinks();
+    populateSidebarLinks();
+    populateNavbarLinks();
+
+    function reloadPageContent() {
+      //Clear the automatic page reload
+      clearTimeout(pageReloadTimeout);
+
+      //Reload the datatables content
+      loadContainersTable()
+      loadVirtualMachinesTable()
+
+      //Set the automatic page reload
+      pageReloadTimeout = setTimeout(() => { reloadPageContent(); }, reloadTime);
+    }
+
+    function loadPageContent(){
+
+      //Display the current project
+      $("#selectedProject").text(project);
+
+      //Populate the Server dropdown
+      $.getJSON("../api/servers/list_servers?id="+serverId, function (data) {
+        data = data.data
+        for (var index = 0; index < data.length; index++) {
+          if (data[index].name == '')
+            optionText = data[index].addr
+          else
+            optionText = data[index].name
+          if (data[index].id == serverId)
+            $('#serverListNav').append('<option value="' + data[index].id + '" selected="selected">' + optionText + '</option>');
+          else
+            $('#serverListNav').append('<option value="' + data[index].id + '">' + optionText + '</option>');
+        }
+      })
+
+      //Populate the Project dropdown
+      $.getJSON("../api/projects/list_projects?id="+serverId+"&project="+project, function (data) {
+        data = data.metadata
+        for (var index = 0; index < data.length; index++) {
+          optionText = data[index].replace('/1.0/projects/','');
+          if (optionText == project)
+            $('#projectListNav').append('<option value="' + optionText + '" selected="selected">' + optionText + '</option>');
+          else
+            $('#projectListNav').append('<option value="' + optionText + '">' + optionText + '</option>');
+        }
+      })
+
+      //Populate the modal Profile dropdown
+      $.getJSON("../api/profiles/list_profiles?id="+serverId+"&project="+project, function (data) {
+        data = data.metadata
+        for (var index = 0; index < data.length; index++) {
+          //When using projects other than default and no recursion, it gets like URL variable with "?"
+          optionText = data[index].split("?")
+          optionText = optionText[0].replace('/1.0/profiles/','');
+          if (optionText == 'default') {
+            $('#instanceProfileInput').append('<option value="' + optionText + '" selected="selected">' + optionText + '</option>');
+          }
+          else {
+            $('#instanceProfileInput').append('<option value="' + optionText + '">' + optionText + '</option>');
+          }
+        }
+      })
+
+      //Populate the modal Location dropdown
+      $.getJSON("../api/cluster-members/list_cluster_members?id="+serverId+"&project="+project, function (data) {
+        data = data.metadata
+        for (var index = 0; index < data.length; index++) {
+          optionText = data[index].replace('/1.0/cluster/members/','');
+          $('#instanceLocationInput').append('<option value="' + optionText + '">' + optionText + '</option>');
+        }
+      })
+
+      $.getJSON("../api/cluster-groups/list_cluster_groups?id="+serverId+"&project="+project, function (data) {
+        data = data.metadata
+        for (var index = 0; index < data.length; index++) {
+          optionText = data[index].replace('/1.0/cluster/groups/','');
+          $('#instanceLocationInput').append('<option value="@' + optionText + '">@' + optionText + '</option>');
+        }
+      })
+
+      loadContainersTable()
+      loadVirtualMachinesTable()
+
+      changeInstanceModalTypeOptions()
+
+      //Set reload page content
+      pageReloadTimeout = setTimeout(() => { reloadPageContent(); }, reloadTime);
+
+    }
+
+    function populateContainerImages() {
+      $("#instanceImageInput").empty().append('<option value="none">none</option>');
+      //Populate the modal Image dropdown
+      $.getJSON("../api/images/list_images?id="+serverId+"&project="+project+"&recursion=1", function (data) {
+        data = data.metadata
+        for (var index = 0; index < data.length; index++) {
+          // Earlier versions of LXD did not have type property. These only supported container type instances
+          if (data[index].hasOwnProperty('type')) {
+            if(data[index].type == 'container'){
+              $('#instanceImageInput').append('<option value="' + data[index].fingerprint + '">' + data[index].properties.description + '</option>');
+            }
+          }
+          else {
+            $('#instanceImageInput').append('<option value="' + data[index].fingerprint + '">' + data[index].properties.description + '</option>');
+          }
+        }
+      })
+    }
+
+    function populateVirtualMachineImages() {
+      $("#instanceImageInput").empty().append('<option value="none">none</option>');
+      //Populate the modal Image dropdown
+      $.getJSON("../api/images/list_images?id="+serverId+"&project="+project+"&recursion=1", function (data) {
+        data = data.metadata
+        for (var index = 0; index < data.length; index++) {
+          // Earlier versions of LXD did not have type property. These only supported container type instances
+          if (data[index].hasOwnProperty('type')) {
+            if(data[index].type == 'virtual-machine'){
+              $('#instanceImageInput').append('<option value="' + data[index].fingerprint + '">' + data[index].properties.description + '</option>');
+            }
+          }
+          else {
+            $('#instanceImageInput').append('<option value="' + data[index].fingerprint + '">' + data[index].properties.description + '</option>');
+          }
+        }
+      })
+    }
+
+    function loadContainersTable() {
+      if ( ! $.fn.DataTable.isDataTable( '#containerDataTable' ) ) {
+        // Configure Containers Datatable
+        $('#containerDataTable').DataTable({
+          ajax: {
+            url: "../api/instances/list_instances?id=" + serverId + "&filter=container" + "&project=" + project + "&recursion=2",
+            dataType: "json",
+            dataSrc: "metadata",
+            contentType: "application/json",
+            error: function (xhr, error, code) {
+              console.log(xhr, code);
+            }
+          },
+          columns: [
+            { title: "Name", data: function (row, type, set) {
+                if (row.hasOwnProperty('name')) {
+                  if (row.name)
+                    return '<a href="../instance?id=' + serverId + '&project=' + project + '&instance=' + row.name + '&type=container">' + row.name + '</a>';
+                }
+                return '-'
+              },
+            },
+            { title: "OS", data: function (row, type, set) {
+                if (row.hasOwnProperty('expanded_config')) {
+                  if (row.expanded_config.hasOwnProperty('image.os')) {
+                    if (row.expanded_config['image.os']){
+                      return row.expanded_config['image.os']
+                    }
+                  }
+                }
+                return '-'
+              },
+            },
+            { title: "Location", data: function (row, type, set) {
+                if (row.hasOwnProperty('location')) {
+                  if (row.location){
+                    return row.location
+                  }
+                }
+                return '-'
+              },
+            },
+            { title: "IPv4", data: function (row, type, set) {
+                if (row.hasOwnProperty('ipv4_addresses')) {
+                  if (row.ipv4_addresses.length > 0){
+                    return row.ipv4_addresses.join(', <br />')
+                  }
+                }
+                return '-'
+              },
+            },
+            { title: "IPv6", data: function (row, type, set) {
+                if (row.hasOwnProperty('ipv6_addresses')) {
+                  if (row.ipv6_addresses.length > 0){
+                    return row.ipv6_addresses.join(', <br />')
+                  }
+                }
+                return '-'
+              },
+            },
+            { title: "Memory", data: function (row, type, set) {
+                if (row.hasOwnProperty('memory')) {
+                  if (row.memory){
+                    if (type === 'display'){
+                      return (row.memory / 1024 / 1024).toFixed(2) + ' MiB'
+                    }
+                    return row.memory
+                  }
+                }
+                return '-'
+              },
+            },
+            { title: "Root Disk", data: function (row, type, set) {
+                if (row.hasOwnProperty('disk')) {
+                  if (row.disk){
+                    if (type === 'display'){
+                      return (row.disk / 1024 / 1024).toFixed(2) + ' MiB'
+                    }
+                    return row.disk
+                  }
+                }
+                return '-'
+              },
+            },
+            { title: "Status", data: function (row, type, set) {
+                if (row.hasOwnProperty('status')) {
+                  if (row.status){
+                    return row.status
+                  }
+                }
+                return '-'
+              },
+            },
+            { title: "Actions", data: function (row, type, set) {
+                links = ''
+                if (row.hasOwnProperty('name') && row.hasOwnProperty('status')) {
+                  if (row.name && row.status){
+                    if (row.status == 'Frozen')
+                      links += '<a href="#" onclick=changeItemState(\''+row.name+'\',\'unfreeze\')><i class="fas fa-pause fa-lg" style="color:#ddd" title="Edit" aria-hidden="true"></i></a>'
+                    else if (row.status == 'Stopped')
+                      links += '<a href="#" onclick=changeItemState(\''+row.name+'\',\'start\')><i class="fas fa-play fa-lg" style="color:#ddd" title="Edit" aria-hidden="true"></i></a>'
+                    else if (row.status == 'Running')
+                      links += '<a href="#" onclick=changeItemState(\''+row.name+'\',\'stop\')><i class="fas fa-stop fa-lg" style="color:#ddd" title="Edit" aria-hidden="true"></i></a>'
+                    links += '&nbsp' + '&nbsp' 
+                    links += '<a href="#" onclick=deleteInstance(\''+row.name+'\')><i class="fas fa-trash-alt fa-lg" style="color:#ddd" title="Delete" aria-hidden="true"></i></a>'
+                  }
+                }
+                return links
+              },
+            },
+          ],
+          order: [],
+        });
+      }
+      else {
+        $('#containerDataTable').DataTable().ajax.reload(null, false);
+      }
+    }
+
+    function loadVirtualMachinesTable() {
+      if ( ! $.fn.DataTable.isDataTable( '#virtualMachineDataTable' ) ) {
+        // Configure Datatable
+        $('#virtualMachineDataTable').DataTable({
+          ajax: {
+            url: "../api/instances/list_instances?id=" + serverId + "&filter=virtual-machine" + "&project=" + project + "&recursion=2",
+            dataType: "json",
+            dataSrc: "metadata",
+            contentType: "application/json",
+            error: function (xhr, error, code) {
+              console.log(xhr, code);
+            }
+          },
+          columns: [
+            { title: "Name", data: function (row, type, set) {
+                if (row.hasOwnProperty('name')) {
+                  if (row.name)
+                    return '<a href="../instance?id=' + serverId + '&project=' + project + '&instance=' + row.name + '&type=virtual-machine">' + row.name + '</a>';
+                }
+                return '-'
+              },
+            },
+            { title: "OS", data: function (row, type, set) {
+                if (row.hasOwnProperty('expanded_config')) {
+                  if (row.expanded_config.hasOwnProperty('image.os')) {
+                    if (row.expanded_config['image.os']){
+                      return row.expanded_config['image.os']
+                    }
+                  }
+                }
+                return '-'
+              },
+            },
+            { title: "Location", data: function (row, type, set) {
+                if (row.hasOwnProperty('location')) {
+                  if (row.location){
+                    return row.location
+                  }
+                }
+                return '-'
+              },
+            },
+            { title: "IPv4", data: function (row, type, set) {
+                if (row.hasOwnProperty('ipv4_addresses')) {
+                  if (row.ipv4_addresses.length > 0){
+                    return row.ipv4_addresses.join(', <br />')
+                  }
+                }
+                return '-'
+              },
+            },
+            { title: "IPv6", data: function (row, type, set) {
+                if (row.hasOwnProperty('ipv6_addresses')) {
+                  if (row.ipv6_addresses.length > 0){
+                    return row.ipv6_addresses.join(', <br />')
+                  }
+                }
+                return '-'
+              },
+            },
+            { title: "Memory", data: function (row, type, set) {
+                if (row.hasOwnProperty('memory')) {
+                  if (row.memory){
+                    if (type === 'display'){
+                      return (row.memory / 1024 / 1024).toFixed(2) + ' MiB'
+                    }
+                    return row.memory
+                  }
+                }
+                return '-'
+              },
+            },
+            { title: "Root Disk", data: function (row, type, set) {
+                if (row.hasOwnProperty('disk')) {
+                  if (row.disk){
+                    if (type === 'display'){
+                      return (row.disk / 1024 / 1024).toFixed(2) + ' MiB'
+                    }
+                    return row.disk
+                  }
+                }
+                return '-'
+              },
+            },
+            { title: "Status", data: function (row, type, set) {
+                if (row.hasOwnProperty('status')) {
+                  if (row.status){
+                    return row.status
+                  }
+                }
+                return '-'
+              },
+            },
+            { title: "Actions", data: function (row, type, set) {
+                links = ''
+                if (row.hasOwnProperty('name') && row.hasOwnProperty('status')) {
+                  if (row.name && row.status){
+                    if (row.status == 'Frozen')
+                      links += '<a href="#" onclick=changeItemState(\''+row.name+'\',\'unfreeze\')><i class="fas fa-pause fa-lg" style="color:#ddd" title="Edit" aria-hidden="true"></i></a>'
+                    else if (row.status == 'Stopped')
+                      links += '<a href="#" onclick=changeItemState(\''+row.name+'\',\'start\')><i class="fas fa-play fa-lg" style="color:#ddd" title="Edit" aria-hidden="true"></i></a>'
+                    else if (row.status == 'Running')
+                      links += '<a href="#" onclick=changeItemState(\''+row.name+'\',\'stop\')><i class="fas fa-stop fa-lg" style="color:#ddd" title="Edit" aria-hidden="true"></i></a>'
+                    links += '&nbsp' + '&nbsp' 
+                    links += '<a href="#" onclick=deleteInstance(\''+row.name+'\')><i class="fas fa-trash-alt fa-lg" style="color:#ddd" title="Delete" aria-hidden="true"></i></a>'
+                  }
+                }
+                return links
+              },
+            },
+          ],
+          order: [],
+        });
+      }
+      else {
+        $('#virtualMachineDataTable').DataTable().ajax.reload(null, false);
+      }
+    }
+
+
+    // Change state start/stop of instance
+    function changeItemState(name, action){
+      console.log("Info: starting instance " + name);
+      $.post("../api/instances/change_instance_state?id=" + serverId + "&project=" + project, { name: name, action: action }, function (data) {
+        console.log(data);
+        if (data.error_code >= 400){
+          alert(data.error);
+        }
+        //Async type
+        setTimeout(() => { reloadPageContent(); }, 2000);
+        operationStatusCheck()
+      });
+    }
+
+    // Add instance
+    function addItem(){
+      console.log("Info: adding new instance");
+      data = $('#addForm').serialize();
+      $.post("../api/instances/add_instance?id="+serverId+"&project="+project, data, function (data) {
+        console.log(data);
+        if (data.error_code >= 400){
+          alert(data.error);
+        }
+        //Aync type
+        setTimeout(() => { reloadPageContent(); }, 2000);
+        operationStatusCheck()
+      });
+    }
+
+    // Delete instance
+    function deleteInstance(name){
+      console.log("Info: confirming deletion of instance " + name);
+      if (confirm("Are you sure you want to delete instance " + name + "?") == true) {
+        console.log("Info: deleting instance " + name);
+        $.post("../api/instances/delete_instance?id=" + serverId + "&project=" + project, { name: name }, function (data) {
+          console.log(data);
+          if (data.error_code >= 400){
+            alert(data.error);
+          }
+          //Async type
+          setTimeout(() => { reloadPageContent(); }, 2000);
+          operationStatusCheck()
+        });
+      }
+    }
+
+    // Create instance from JSON
+    function createItemUsingJSON(){
+      var json = $("#jsonCreateInput").val();
+      console.log("Info: adding new instance");
+      $.post("../api/instances/add_instance?id="+serverId+"&project="+project, { json: json },  function (data) {
+        console.log(data);
+        if (data.error_code >= 400){
+          alert(data.error);
+        }
+        //Async type
+        setTimeout(() => { reloadPageContent(); }, 2000);
+        operationStatusCheck()
+      });
+    }
+
+    // Change properties options while adding network device
+    function changeInstanceModalTypeOptions(){
+      var instanceTypeInput = $("#instanceTypeInput").val()
+      if (instanceTypeInput == "container"){
+        populateContainerImages()
+        //Container options
+        $("#limitsCpuAllowance").attr("disabled", false);
+        $("#limitsCpuPriority").attr("disabled", false);
+        $("#limitsHugepages64KB").attr("disabled", false);
+        $("#limitsHugepages1MB").attr("disabled", false);
+        $("#limitsHugepages2MB").attr("disabled", false);
+        $("#limitsHugepages1GB").attr("disabled", false);
+        $("#limitsMemoryEnforce").attr("disabled", false);
+        $("#limitsMemorySwapPriority").attr("disabled", false);
+        $("#limitsMemorySwap").attr("disabled", false);
+        $("#limitsProcesses").attr("disabled", false);
+        $("#linuxKernel_modules").attr("disabled", false);
+        $("#migrationIncrementalMemory").attr("disabled", false);
+        $("#migrationIncrementalMemoryGoal").attr("disabled", false);
+        $("#migrationIncrementalMemoryIterations").attr("disabled", false);
+        $("#nvidiaDriverCapabilities").attr("disabled", false);
+        $("#nvidiaRuntime").attr("disabled", false);
+        $("#nvidiaRequireCuda").attr("disabled", false);
+        $("#nvidiaRequireDriver").attr("disabled", false);
+        $("#rawIdmap").attr("disabled", false);
+        $("#rawLxc").attr("disabled", false);
+        $("#rawSeccomp").attr("disabled", false);
+        $("#securityDevlxd").attr("disabled", false);
+        $("#securityDevlxdImages").attr("disabled", false);
+        $("#securityIdmapBase").attr("disabled", false);
+        $("#securityIdmapIsolated").attr("disabled", false);
+        $("#securityIdmapSize").attr("disabled", false);
+        $("#securityNesting").attr("disabled", false);
+        $("#securityPrivileged").attr("disabled", false);
+        $("#securityProtectionDelete").attr("disabled", false);
+        $("#securityProtectionShift").attr("disabled", false);
+        $("#securitySyscallsAllow").attr("disabled", false);
+        $("#securitySyscallsDeny").attr("disabled", false);
+        $("#securitySyscallsDeny_compat").attr("disabled", false);
+        $("#securitySyscallsDeny_default").attr("disabled", false);
+        $("#securitySyscallsInterceptBpf").attr("disabled", false);
+        $("#securitySyscallsInterceptBpfDevices").attr("disabled", false);
+        $("#securitySyscallsInterceptMknod").attr("disabled", false);
+        $("#securitySyscallsInterceptMount").attr("disabled", false);
+        $("#securitySyscallsInterceptMountAllowed").attr("disabled", false);
+        $("#securitySyscallsInterceptMountFuse").attr("disabled", false);
+        $("#securitySyscallsInterceptMountShift").attr("disabled", false);
+        $("#securitySyscallsInterceptSetxattr").attr("disabled", false);
+        //Virtual-machine options
+        $("#limitsMemoryHugepages").attr("disabled", true); $("#limitsMemoryHugepages").val('');
+        $("#migrationStateful").attr("disabled", true); $("#migrationStateful").val('');
+        $("#rawQemu").attr("disabled", true); $("#rawQemu").val('');
+        $("#rawQemuConf").attr("disabled", true); $("#rawQemuConf").val('');
+        $("#securityAgentMetrics").attr("disabled", true); $("#securityAgentMetrics").val('');
+        $("#securitySecureboot").attr("disabled", true); $("#securitySecureboot").val('');
+      }
+      if (instanceTypeInput == "virtual-machine"){
+        populateVirtualMachineImages()
+        //Container options
+        $("#limitsCpuAllowance").attr("disabled", true); $("#limitsCpuAllowance").val('');
+        $("#limitsCpuPriority").attr("disabled", true); $("#limitsCpuPriority").val('');
+        $("#limitsHugepages64KB").attr("disabled", true); $("#limitsHugepages64KB").val('');
+        $("#limitsHugepages1MB").attr("disabled", true); $("#limitsHugepages1MB").val('');
+        $("#limitsHugepages2MB").attr("disabled", true); $("#limitsHugepages2MB").val('');
+        $("#limitsHugepages1GB").attr("disabled", true); $("#limitsHugepages1GB").val('');
+        $("#limitsMemoryEnforce").attr("disabled", true); $("#limitsMemoryEnforce").val('');
+        $("#limitsMemorySwapPriority").attr("disabled", true); $("#limitsMemorySwapPriority").val('');
+        $("#limitsMemorySwap").attr("disabled", true); $("#limitsMemorySwap").val('');
+        $("#limitsProcesses").attr("disabled", true); $("#limitsProcesses").val('');
+        $("#linuxKernel_modules").attr("disabled", true); $("#linuxKernel_modules").val('');
+        $("#migrationIncrementalMemory").attr("disabled", true); $("#migrationIncrementalMemory").val('');
+        $("#migrationIncrementalMemoryGoal").attr("disabled", true); $("#migrationIncrementalMemoryGoal").val('');
+        $("#migrationIncrementalMemoryIterations").attr("disabled", true); $("#migrationIncrementalMemoryIterations").val('');
+        $("#nvidiaDriverCapabilities").attr("disabled", true); $("#nvidiaDriverCapabilities").val('');
+        $("#nvidiaRuntime").attr("disabled", true); $("#nvidiaRuntime").val('');
+        $("#nvidiaRequireCuda").attr("disabled", true); $("#nvidiaRequireCuda").val('');
+        $("#nvidiaRequireDriver").attr("disabled", true); $("#nvidiaRequireDriver").val('');
+        $("#rawIdmap").attr("disabled", true); $("#rawIdmap").val('');
+        $("#rawLxc").attr("disabled", true); $("#rawLxc").val('');
+        $("#rawSeccomp").attr("disabled", true); $("#rawSeccomp").val('');
+        $("#securityDevlxd").attr("disabled", true); $("#securityDevlxd").val('');
+        $("#securityDevlxdImages").attr("disabled", true); $("#securityDevlxdImages").val('');
+        $("#securityIdmapBase").attr("disabled", true); $("#securityIdmapBase").val('');
+        $("#securityIdmapIsolated").attr("disabled", true); $("#securityIdmapIsolated").val('');
+        $("#securityIdmapSize").attr("disabled", true); $("#securityIdmapSize").val('');
+        $("#securityNesting").attr("disabled", true); $("#securityNesting").val('');
+        $("#securityPrivileged").attr("disabled", true); $("#securityPrivileged").val('');
+        $("#securityProtectionDelete").attr("disabled", true); $("#securityProtectionDelete").val('');
+        $("#securityProtectionShift").attr("disabled", true); $("#securityProtectionShift").val('');
+        $("#securitySyscallsAllow").attr("disabled", true); $("#securitySyscallsAllow").val('');
+        $("#securitySyscallsDeny").attr("disabled", true); $("#securitySyscallsDeny").val('');
+        $("#securitySyscallsDeny_compat").attr("disabled", true); $("#securitySyscallsDeny_compat").val('');
+        $("#securitySyscallsDeny_default").attr("disabled", true); $("#securitySyscallsDeny_default").val('');
+        $("#securitySyscallsInterceptBpf").attr("disabled", true); $("#securitySyscallsInterceptBpf").val('');
+        $("#securitySyscallsInterceptBpfDevices").attr("disabled", true); $("#securitySyscallsInterceptBpfDevices").val('');
+        $("#securitySyscallsInterceptMknod").attr("disabled", true); $("#securitySyscallsInterceptMknod").val('');
+        $("#securitySyscallsInterceptMount").attr("disabled", true); $("#securitySyscallsInterceptMount").val('');
+        $("#securitySyscallsInterceptMountAllowed").attr("disabled", true); $("#securitySyscallsInterceptMountAllowed").val('');
+        $("#securitySyscallsInterceptMountFuse").attr("disabled", true); $("#securitySyscallsInterceptMountFuse").val('');
+        $("#securitySyscallsInterceptMountShift").attr("disabled", true); $("#securitySyscallsInterceptMountShift").val('');
+        $("#securitySyscallsInterceptSetxattr").attr("disabled", true); $("#securitySyscallsInterceptSetxattr").val('');
+        //Virtual-machine options
+        $("#limitsMemoryHugepages").attr("disabled", false);
+        $("#migrationStateful").attr("disabled", false);
+        $("#rawQemu").attr("disabled", false);
+        $("#rawQemuConf").attr("disabled", false);
+        $("#securityAgentMetrics").attr("disabled", false);
+        $("#securitySecureboot").attr("disabled", false);
+      }
+    }
+
+
+    $(document).ready(function(){
+
+      //If id or project variables are missing redirect to servers page
+      if (!serverId || !project) {
+        window.location.href = 'servers';
+      }
+      else {
+        loadPageContent()
+        operationStatusCheck()
+      }
+      
+    });
+
+  </script>
+{% endblock script %}

+ 4 - 1
lxconsole/templates/logs.html

@@ -54,7 +54,10 @@
           url: "../api/logs/list_logs",
           dataType: "json",
           dataSrc: "data",
-          contentType: "application/json"
+          contentType: "application/json",
+          error: function (xhr, error, code) {
+            console.log(xhr, code);
+          }
         },
         columns: [
           { title: "Id", data: function (row, type, set) {

+ 7 - 12
lxconsole/templates/main.html

@@ -3,7 +3,7 @@
 
   {% include 'head.html' %}
   <!-- Add dark-mode class to body for dark theme-->
-  <body class="hold-transition sidebar-mini">
+  <body class="hold-transition sidebar-mini layout-fixed layout-navbar-fixed">
     <script>0</script>
     <div class="wrapper">
 
@@ -40,7 +40,7 @@
 
       <footer class="main-footer">
         <div class="float-right d-none d-sm-block">
-          Version 0.3.0
+          Version 0.4.0
         </div>
         Copyright &copy; 2020-Present <a href="https://penninglabs.com">Penning Labs</a>. All rights reserved.
       </footer>
@@ -51,20 +51,15 @@
     <!-- jQuery - https://code.jquery.com/jquery-3.7.1.js -->
     <script src="../static/js/jquery/jquery-3.7.1.js"></script>
 
+    <!-- Bootstrap 5 - https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/js/bootstrap.bundle.min.js -->
+    <script src="../static/js/bootstrap/bootstrap-5.2.3.bundle.min.js.js"></script>
+
     <!-- jQuery Datatables -   https://cdn.datatables.net/1.13.6/js/jquery.dataTables.min.js -->
-    <!-- <script src="../static/js/datatables/jquery.dataTables-1.13.6.min.js"></script> -->
+    <script src="../static/js/datatables/jquery.dataTables-1.13.6.min.js"></script>
 
     <!-- Datatables Bootstrap 5 - https://cdn.datatables.net/1.13.6/js/dataTables.bootstrap5.min.js -->
-    <!-- <script src="../static/js/datatables/dataTables.bootstrap5.min.js"></script> -->
+    <script src="../static/js/datatables/dataTables.bootstrap5.min.js"></script>
   
-    <!-- Bootstrap 4 -->
-    <script src="../static/plugins/bootstrap/js/bootstrap.bundle.min.js"></script>
-    
-    <!-- DataTables  & Plugins -->
-    <script src="../static/plugins/datatables/jquery.dataTables.min.js"></script>
-    <script src="../static/plugins/datatables-bs4/js/dataTables.bootstrap4.min.js"></script>
-    <script src="../static/plugins/datatables-responsive/js/dataTables.responsive.min.js"></script>
-    <script src="../static/plugins/datatables-responsive/js/responsive.bootstrap4.min.js"></script>
     <script src="../static/plugins/jquery-knob/jquery.knob.min.js"></script>
     
     <!-- AdminLTE App -->

+ 14 - 14
lxconsole/templates/modals/access-controls.html

@@ -4,7 +4,7 @@
     <div class="modal-content">
       <div class="modal-header">
         <h5 class="modal-title" id="exampleModalLabel">Create Access Control</h5>
-        <button class="close" type="button" data-dismiss="modal" aria-label="Close">
+        <button class="close" type="button" data-bs-dismiss="modal" aria-label="Close">
           <span aria-hidden="true">×</span>
         </button>
       </div>
@@ -16,7 +16,7 @@
             <label class="col-3 col-form-label text-right">Group: <span class="text-danger">*</span></label>
             <div class="col-7">
               <div class="form-group">
-                <select id="groupInput" onchange="" class="form-control" name="group_id">
+                <select id="groupInput" onchange="" class="form-select" name="group_id">
                   <option value="">(not set)</option>
                 </select>
               </div>
@@ -30,7 +30,7 @@
             <label class="col-3 col-form-label text-right">Role: <span class="text-danger">*</span></label>
             <div class="col-7">
               <div class="form-group">
-                <select id="roleInput" onchange="" class="form-control" name="role_id">
+                <select id="roleInput" onchange="" class="form-select" name="role_id">
                   <option value="">(not set)</option>
                 </select>
               </div>
@@ -44,7 +44,7 @@
             <label class="col-3 col-form-label text-right">Scope: </label>
             <div class="col-7">
               <div class="form-group">
-                <select id="scopeInput" class="form-control" name="scope">
+                <select id="scopeInput" class="form-select" name="scope">
                   <option value="global">global</option>
                 </select>
               </div>
@@ -58,7 +58,7 @@
             <label class="col-3 col-form-label text-right">Server: </label>
             <div class="col-7">
               <div class="form-group">
-                <select id="serverInput" onchange="" class="form-control" name="server_id">
+                <select id="serverInput" onchange="" class="form-select" name="server_id">
                   <option value="">(not set)</option>
                 </select>
               </div>
@@ -84,8 +84,8 @@
 
       </div> <!-- End Modal Body-->
       <div class="modal-footer">
-        <button class="btn btn-secondary" type="button" data-dismiss="modal">Cancel</button>
-        <a class="btn btn-primary" href="#" onclick="addAccessControl()" data-dismiss="modal">Submit</a>
+        <button class="btn btn-secondary" type="button" data-bs-dismiss="modal">Cancel</button>
+        <a class="btn btn-primary" href="#" onclick="addAccessControl()" data-bs-dismiss="modal">Submit</a>
       </div>
     </div>
   </div>
@@ -98,7 +98,7 @@
     <div class="modal-content">
       <div class="modal-header">
         <h5 class="modal-title" id="exampleModalLabel">Edit Access Control</h5>
-        <button class="close" type="button" data-dismiss="modal" aria-label="Close">
+        <button class="close" type="button" data-bs-dismiss="modal" aria-label="Close">
           <span aria-hidden="true">×</span>
         </button>
       </div>
@@ -110,7 +110,7 @@
             <label class="col-3 col-form-label text-right">Group: <span class="text-danger">*</span></label>
             <div class="col-7">
               <div class="form-group">
-                <select id="groupEditInput" onchange="" class="form-control" name="group_id">
+                <select id="groupEditInput" onchange="" class="form-select" name="group_id">
                   <option value="">(not set)</option>
                 </select>
               </div>
@@ -124,7 +124,7 @@
             <label class="col-3 col-form-label text-right">Role: <span class="text-danger">*</span></label>
             <div class="col-7">
               <div class="form-group">
-                <select id="roleEditInput" onchange="" class="form-control" name="role_id">
+                <select id="roleEditInput" onchange="" class="form-select" name="role_id">
                   <option value="">(not set)</option>
                 </select>
               </div>
@@ -138,7 +138,7 @@
             <label class="col-3 col-form-label text-right">Scope: </label>
             <div class="col-7">
               <div class="form-group">
-                <select id="scopeEditInput" class="form-control" name="scope">
+                <select id="scopeEditInput" class="form-select" name="scope">
                   <option value="global">global</option>
                 </select>
               </div>
@@ -152,7 +152,7 @@
             <label class="col-3 col-form-label text-right">Server: </label>
             <div class="col-7">
               <div class="form-group">
-                <select id="serverEditInput" onchange="" class="form-control" name="server_id">
+                <select id="serverEditInput" onchange="" class="form-select" name="server_id">
                   <option value="">(not set)</option>
                 </select>
               </div>
@@ -179,8 +179,8 @@
 
       </div> <!-- End Modal Body-->
       <div class="modal-footer">
-        <button class="btn btn-secondary" type="button" data-dismiss="modal">Cancel</button>
-        <a class="btn btn-primary" href="#" onclick="updateAccessControl()" data-dismiss="modal">Submit</a>
+        <button class="btn btn-secondary" type="button" data-bs-dismiss="modal">Cancel</button>
+        <a class="btn btn-primary" href="#" onclick="updateAccessControl()" data-bs-dismiss="modal">Submit</a>
       </div>
     </div>
   </div>

+ 10 - 10
lxconsole/templates/modals/certificates.html

@@ -4,17 +4,17 @@
     <div class="modal-content">
         <div class="modal-header">
           <h5 class="modal-title" id="exampleModalLabel">Add Certificate</h5>
-          <button class="close" type="button" data-dismiss="modal" aria-label="Close">
+          <button class="close" type="button" data-bs-dismiss="modal" aria-label="Close">
             <span aria-hidden="true">×</span>
           </button>
         </div>
         <div class="modal-body">
           <ul class="nav nav-tabs" id="myTab" role="tablist">
             <li class="nav-item">
-              <a class="nav-link active" id="form-tab" data-toggle="tab" href="#form" role="tab" aria-controls="form" aria-selected="true">Form</a>
+              <a class="nav-link active" id="form-tab" data-bs-toggle="tab" href="#form" role="tab" aria-controls="form" aria-selected="true">Form</a>
             </li>
             <li class="nav-item">
-              <a class="nav-link" id="json-tab" data-toggle="tab" href="#json" role="tab" aria-controls="json" aria-selected="false">JSON</a>
+              <a class="nav-link" id="json-tab" data-bs-toggle="tab" href="#json" role="tab" aria-controls="json" aria-selected="false">JSON</a>
             </li>
           </ul>
           <div class="tab-content" id="myTabContent">
@@ -58,8 +58,8 @@
                 </div>
               </form>
               <div class="modal-footer">
-                <button class="btn btn-secondary" type="button" data-dismiss="modal">Cancel</button>
-                <a class="btn btn-primary" href="#" onclick="addItem()" data-dismiss="modal">Submit</a>
+                <button class="btn btn-secondary" type="button" data-bs-dismiss="modal">Cancel</button>
+                <a class="btn btn-primary" href="#" onclick="addItem()" data-bs-dismiss="modal">Submit</a>
               </div>
             </div>
             <div class="tab-pane fade" id="json" role="tabpanel" aria-labelledby="json-tab">
@@ -74,8 +74,8 @@
                 </div>
               </div>
               <div class="modal-footer">
-                <button class="btn btn-secondary" type="button" data-dismiss="modal">Cancel</button>
-                <a class="btn btn-primary" href="#" onclick="createItemUsingJSON()" data-dismiss="modal">Submit</a>
+                <button class="btn btn-secondary" type="button" data-bs-dismiss="modal">Cancel</button>
+                <a class="btn btn-primary" href="#" onclick="createItemUsingJSON()" data-bs-dismiss="modal">Submit</a>
               </div>
             </div>
           </div>
@@ -90,7 +90,7 @@
     <div class="modal-content">
         <div class="modal-header">
           <h5 class="modal-title" id="exampleModalLabel">Edit Certificate</h5>
-          <button class="close" type="button" data-dismiss="modal" aria-label="Close">
+          <button class="close" type="button" data-bs-dismiss="modal" aria-label="Close">
             <span aria-hidden="true">×</span>
           </button>
         </div>
@@ -107,8 +107,8 @@
           </div>
         </div>
         <div class="modal-footer">
-          <button class="btn btn-secondary" type="button" data-dismiss="modal">Cancel</button>
-          <a class="btn btn-primary" href="#" onclick="updateItem()" data-dismiss="modal">Submit</a>
+          <button class="btn btn-secondary" type="button" data-bs-dismiss="modal">Cancel</button>
+          <a class="btn btn-primary" href="#" onclick="updateItem()" data-bs-dismiss="modal">Submit</a>
         </div>
     </div>
   </div>

+ 18 - 18
lxconsole/templates/modals/cluster-groups.html

@@ -4,17 +4,17 @@
     <div class="modal-content">
         <div class="modal-header">
           <h5 class="modal-title" id="exampleModalLabel">Add Cluster Group</h5>
-          <button class="close" type="button" data-dismiss="modal" aria-label="Close">
+          <button class="close" type="button" data-bs-dismiss="modal" aria-label="Close">
             <span aria-hidden="true">×</span>
           </button>
         </div>
         <div class="modal-body">
           <ul class="nav nav-tabs" id="myTab" role="tablist">
             <li class="nav-item">
-              <a class="nav-link active" id="form-tab" data-toggle="tab" href="#form" role="tab" aria-controls="form" aria-selected="true">Form</a>
+              <a class="nav-link active" id="form-tab" data-bs-toggle="tab" href="#form" role="tab" aria-controls="form" aria-selected="true">Form</a>
             </li>
             <li class="nav-item">
-              <a class="nav-link" id="json-tab" data-toggle="tab" href="#json" role="tab" aria-controls="json" aria-selected="false">JSON</a>
+              <a class="nav-link" id="json-tab" data-bs-toggle="tab" href="#json" role="tab" aria-controls="json" aria-selected="false">JSON</a>
             </li>
           </ul>
           <div class="tab-content" id="myTabContent">
@@ -47,7 +47,7 @@
                   <label class="col-3 col-form-label text-right">Cluster Members: </label>
                   <div class="col-7">
                     <div class="form-group">
-                      <select id="clusterMembersInput" class="select form-control" multiple name="members">
+                      <select id="clusterMembersInput" class="select form-select" multiple name="members">
                       </select>
                     </div>
                   </div>
@@ -57,8 +57,8 @@
                 </div>
               </form>
               <div class="modal-footer">
-                <button class="btn btn-secondary" type="button" data-dismiss="modal">Cancel</button>
-                <a class="btn btn-primary" href="#" onclick="addItem()" data-dismiss="modal">Submit</a>
+                <button class="btn btn-secondary" type="button" data-bs-dismiss="modal">Cancel</button>
+                <a class="btn btn-primary" href="#" onclick="addItem()" data-bs-dismiss="modal">Submit</a>
               </div>
             </div>
             <div class="tab-pane fade" id="json" role="tabpanel" aria-labelledby="json-tab">
@@ -73,8 +73,8 @@
                 </div>
               </div>
               <div class="modal-footer">
-                <button class="btn btn-secondary" type="button" data-dismiss="modal">Cancel</button>
-                <a class="btn btn-primary" href="#" onclick="createItemUsingJSON()" data-dismiss="modal">Submit</a>
+                <button class="btn btn-secondary" type="button" data-bs-dismiss="modal">Cancel</button>
+                <a class="btn btn-primary" href="#" onclick="createItemUsingJSON()" data-bs-dismiss="modal">Submit</a>
               </div>
             </div>
           </div>
@@ -89,17 +89,17 @@
     <div class="modal-content">
         <div class="modal-header">
           <h5 class="modal-title" id="exampleModalLabel">Edit Cluster Group</h5>
-          <button class="close" type="button" data-dismiss="modal" aria-label="Close">
+          <button class="close" type="button" data-bs-dismiss="modal" aria-label="Close">
             <span aria-hidden="true">×</span>
           </button>
         </div>
         <div class="modal-body">
           <ul class="nav nav-tabs" id="myTab" role="tablist">
             <li class="nav-item">
-              <a class="nav-link active" id="json-edit-tab" data-toggle="tab" href="#json-edit" role="tab" aria-controls="json-edit" aria-selected="false">JSON</a>
+              <a class="nav-link active" id="json-edit-tab" data-bs-toggle="tab" href="#json-edit" role="tab" aria-controls="json-edit" aria-selected="false">JSON</a>
             </li>
             <li class="nav-item">
-              <a class="nav-link" id="rename-edit-tab" data-toggle="tab" href="#rename-edit" role="tab" aria-controls="rename-edit" aria-selected="true">Rename</a>
+              <a class="nav-link" id="rename-edit-tab" data-bs-toggle="tab" href="#rename-edit" role="tab" aria-controls="rename-edit" aria-selected="true">Rename</a>
             </li>
           </ul>
           <div class="tab-content" id="myTabContent">
@@ -116,8 +116,8 @@
                 </div>
               </div>
               <div class="modal-footer">
-                <button class="btn btn-secondary" type="button" data-dismiss="modal">Cancel</button>
-                <a class="btn btn-primary" href="#" onclick="updateItem()" data-dismiss="modal">Submit</a>
+                <button class="btn btn-secondary" type="button" data-bs-dismiss="modal">Cancel</button>
+                <a class="btn btn-primary" href="#" onclick="updateItem()" data-bs-dismiss="modal">Submit</a>
               </div>
             </div>
             <div class="tab-pane fade" id="rename-edit" role="tabpanel" aria-labelledby="rename-edit-tab">
@@ -136,8 +136,8 @@
                 </div>
               </form>
               <div class="modal-footer">
-                <button class="btn btn-secondary" type="button" data-dismiss="modal">Cancel</button>
-                <a class="btn btn-primary" href="#" onclick="renameItem()" data-dismiss="modal">Submit</a>
+                <button class="btn btn-secondary" type="button" data-bs-dismiss="modal">Cancel</button>
+                <a class="btn btn-primary" href="#" onclick="renameItem()" data-bs-dismiss="modal">Submit</a>
               </div>
             </div>
           </div>
@@ -152,7 +152,7 @@
     <div class="modal-content">
       <div class="modal-header">
         <h5 class="modal-title" id="exampleModalLabel">Delete Cluster Group</h5>
-        <button class="close" type="button" data-dismiss="modal" aria-label="Close">
+        <button class="close" type="button" data-bs-dismiss="modal" aria-label="Close">
           <span aria-hidden="true">×</span>
         </button>
       </div>
@@ -163,8 +163,8 @@
         <input type="hidden" id="clusterGroup" class="form-control" name="server_name">
       </div>
       <div class="modal-footer">
-        <button class="btn btn-secondary" type="button" data-dismiss="modal">Cancel</button>
-        <a class="btn btn-primary" href="#" onclick="deleteItem()" data-dismiss="modal">Yes</a>
+        <button class="btn btn-secondary" type="button" data-bs-dismiss="modal">Cancel</button>
+        <a class="btn btn-primary" href="#" onclick="deleteItem()" data-bs-dismiss="modal">Yes</a>
       </div>
     </div>
   </div>

+ 17 - 17
lxconsole/templates/modals/cluster-members.html

@@ -4,17 +4,17 @@
     <div class="modal-content">
         <div class="modal-header">
           <h5 class="modal-title" id="exampleModalLabel">Add Cluster Member</h5>
-          <button class="close" type="button" data-dismiss="modal" aria-label="Close">
+          <button class="close" type="button" data-bs-dismiss="modal" aria-label="Close">
             <span aria-hidden="true">×</span>
           </button>
         </div>
         <div class="modal-body">
           <ul class="nav nav-tabs" id="myTab" role="tablist">
             <li class="nav-item">
-              <a class="nav-link active" id="form-tab" data-toggle="tab" href="#form" role="tab" aria-controls="form" aria-selected="true">Form</a>
+              <a class="nav-link active" id="form-tab" data-bs-toggle="tab" href="#form" role="tab" aria-controls="form" aria-selected="true">Form</a>
             </li>
             <li class="nav-item">
-              <a class="nav-link" id="json-tab" data-toggle="tab" href="#json" role="tab" aria-controls="json" aria-selected="false">JSON</a>
+              <a class="nav-link" id="json-tab" data-bs-toggle="tab" href="#json" role="tab" aria-controls="json" aria-selected="false">JSON</a>
             </li>
           </ul>
           <div class="tab-content" id="myTabContent">
@@ -45,8 +45,8 @@
                 </div>
               </form>
               <div class="modal-footer">
-                <button class="btn btn-secondary" type="button" data-dismiss="modal">Cancel</button>
-                <a class="btn btn-primary" href="#" onclick="addItem()" data-dismiss="modal">Submit</a>
+                <button class="btn btn-secondary" type="button" data-bs-dismiss="modal">Cancel</button>
+                <a class="btn btn-primary" href="#" onclick="addItem()" data-bs-dismiss="modal">Submit</a>
               </div>
             </div>
             <div class="tab-pane fade" id="json" role="tabpanel" aria-labelledby="json-tab">
@@ -61,8 +61,8 @@
                 </div>
               </div>
               <div class="modal-footer">
-                <button class="btn btn-secondary" type="button" data-dismiss="modal">Cancel</button>
-                <a class="btn btn-primary" href="#" onclick="createItemUsingJSON()" data-dismiss="modal">Submit</a>
+                <button class="btn btn-secondary" type="button" data-bs-dismiss="modal">Cancel</button>
+                <a class="btn btn-primary" href="#" onclick="createItemUsingJSON()" data-bs-dismiss="modal">Submit</a>
               </div>
             </div>
           </div>
@@ -77,17 +77,17 @@
     <div class="modal-content">
         <div class="modal-header">
           <h5 class="modal-title" id="exampleModalLabel">Edit Cluster Member</h5>
-          <button class="close" type="button" data-dismiss="modal" aria-label="Close">
+          <button class="close" type="button" data-bs-dismiss="modal" aria-label="Close">
             <span aria-hidden="true">×</span>
           </button>
         </div>
         <div class="modal-body">
           <ul class="nav nav-tabs" id="myTab" role="tablist">
             <li class="nav-item">
-              <a class="nav-link active" id="json-edit-tab" data-toggle="tab" href="#json-edit" role="tab" aria-controls="json-edit" aria-selected="false">JSON</a>
+              <a class="nav-link active" id="json-edit-tab" data-bs-toggle="tab" href="#json-edit" role="tab" aria-controls="json-edit" aria-selected="false">JSON</a>
             </li>
             <li class="nav-item">
-              <a class="nav-link" id="rename-edit-tab" data-toggle="tab" href="#rename-edit" role="tab" aria-controls="rename-edit" aria-selected="true">Rename</a>
+              <a class="nav-link" id="rename-edit-tab" data-bs-toggle="tab" href="#rename-edit" role="tab" aria-controls="rename-edit" aria-selected="true">Rename</a>
             </li>
           </ul>
           <div class="tab-content" id="myTabContent">
@@ -104,8 +104,8 @@
                 </div>
               </div>
               <div class="modal-footer">
-                <button class="btn btn-secondary" type="button" data-dismiss="modal">Cancel</button>
-                <a class="btn btn-primary" href="#" onclick="updateItem()" data-dismiss="modal">Submit</a>
+                <button class="btn btn-secondary" type="button" data-bs-dismiss="modal">Cancel</button>
+                <a class="btn btn-primary" href="#" onclick="updateItem()" data-bs-dismiss="modal">Submit</a>
               </div>
             </div>
             <div class="tab-pane fade" id="rename-edit" role="tabpanel" aria-labelledby="rename-edit-tab">
@@ -125,8 +125,8 @@
                 </div>
               </form>
               <div class="modal-footer">
-                <button class="btn btn-secondary" type="button" data-dismiss="modal">Cancel</button>
-                <a class="btn btn-primary" href="#" onclick="renameItem()" data-dismiss="modal">Submit</a>
+                <button class="btn btn-secondary" type="button" data-bs-dismiss="modal">Cancel</button>
+                <a class="btn btn-primary" href="#" onclick="renameItem()" data-bs-dismiss="modal">Submit</a>
               </div>
             </div>
           </div>
@@ -141,7 +141,7 @@
     <div class="modal-content">
       <div class="modal-header">
         <h5 class="modal-title" id="exampleModalLabel">Delete Cluster Member</h5>
-        <button class="close" type="button" data-dismiss="modal" aria-label="Close">
+        <button class="close" type="button" data-bs-dismiss="modal" aria-label="Close">
           <span aria-hidden="true">×</span>
         </button>
       </div>
@@ -158,8 +158,8 @@
         <input type="hidden" id="clusterMember" class="form-control" name="server_name">
       </div>
       <div class="modal-footer">
-        <button class="btn btn-secondary" type="button" data-dismiss="modal">Cancel</button>
-        <a class="btn btn-primary" href="#" onclick="deleteItem()" data-dismiss="modal">Yes</a>
+        <button class="btn btn-secondary" type="button" data-bs-dismiss="modal">Cancel</button>
+        <a class="btn btn-primary" href="#" onclick="deleteItem()" data-bs-dismiss="modal">Yes</a>
       </div>
     </div>
   </div>

+ 6 - 6
lxconsole/templates/modals/groups.html

@@ -4,7 +4,7 @@
     <div class="modal-content">
       <div class="modal-header">
         <h5 class="modal-title" id="exampleModalLabel">Create Group</h5>
-        <button class="close" type="button" data-dismiss="modal" aria-label="Close">
+        <button class="close" type="button" data-bs-dismiss="modal" aria-label="Close">
           <span aria-hidden="true">×</span>
         </button>
       </div>
@@ -39,8 +39,8 @@
 
       </div> <!-- End Modal Body-->
       <div class="modal-footer">
-        <button class="btn btn-secondary" type="button" data-dismiss="modal">Cancel</button>
-        <a class="btn btn-primary" href="#" onclick="addGroup()" data-dismiss="modal">Submit</a>
+        <button class="btn btn-secondary" type="button" data-bs-dismiss="modal">Cancel</button>
+        <a class="btn btn-primary" href="#" onclick="addGroup()" data-bs-dismiss="modal">Submit</a>
       </div>
     </div>
   </div>
@@ -53,7 +53,7 @@
     <div class="modal-content">
       <div class="modal-header">
         <h5 class="modal-title" id="exampleModalLabel">Edit Group</h5>
-        <button class="close" type="button" data-dismiss="modal" aria-label="Close">
+        <button class="close" type="button" data-bs-dismiss="modal" aria-label="Close">
           <span aria-hidden="true">×</span>
         </button>
       </div>
@@ -89,8 +89,8 @@
 
       </div> <!-- End Modal Body-->
       <div class="modal-footer">
-        <button class="btn btn-secondary" type="button" data-dismiss="modal">Cancel</button>
-        <a class="btn btn-primary" href="#" onclick="updateGroup()" data-dismiss="modal">Submit</a>
+        <button class="btn btn-secondary" type="button" data-bs-dismiss="modal">Cancel</button>
+        <a class="btn btn-primary" href="#" onclick="updateGroup()" data-bs-dismiss="modal">Submit</a>
       </div>
     </div>
   </div>

+ 18 - 18
lxconsole/templates/modals/images.html

@@ -4,17 +4,17 @@
       <div class="modal-content">
         <div class="modal-header">
           <h5 class="modal-title" id="exampleModalLabel">Download Image</h5>
-          <button class="close" type="button" data-dismiss="modal" aria-label="Close">
+          <button class="close" type="button" data-bs-dismiss="modal" aria-label="Close">
             <span aria-hidden="true">×</span>
           </button>
         </div>
         <div class="modal-body">
           <ul class="nav nav-tabs" id="myTab" role="tablist">
             <li class="nav-item">
-              <a class="nav-link active" id="catalog-tab" data-toggle="tab" href="#catalog" role="tab" aria-controls="catalog" aria-selected="true">Catalog</a>
+              <a class="nav-link active" id="catalog-tab" data-bs-toggle="tab" href="#catalog" role="tab" aria-controls="catalog" aria-selected="true">Catalog</a>
             </li>
             <li class="nav-item">
-              <a class="nav-link" id="form-tab" data-toggle="tab" href="#form" role="tab" aria-controls="form" aria-selected="false">Form</a>
+              <a class="nav-link" id="form-tab" data-bs-toggle="tab" href="#form" role="tab" aria-controls="form" aria-selected="false">Form</a>
             </li>
           </ul>
           <div class="tab-content" id="myTabContent">
@@ -24,7 +24,7 @@
                 <label class="col-3 col-form-label text-right">Operating System: </label>
                 <div class="col-7">
                   <div class="form-group">
-                    <select id="operatingSystem" onchange="updateOSVersion()" class="form-control" name="operating_system">
+                    <select id="operatingSystem" onchange="updateOSVersion()" class="form-select" name="operating_system">
                       <option value="">unavailable</option>
                     </select>
                   </div>
@@ -38,7 +38,7 @@
                 <label class="col-3 col-form-label text-right">OS Version: </label>
                 <div class="col-7">
                   <div class="form-group">
-                    <select id="operatingSystemVersion" onchange="" class="form-control" name="version">
+                    <select id="operatingSystemVersion" onchange="" class="form-select" name="version">
                       <option value="">unavailable</option>
                     </select>
                   </div>
@@ -52,7 +52,7 @@
                 <label class="col-3 col-form-label text-right">Image Variant: </label>
                 <div class="col-7">
                   <div class="form-group">
-                    <select id="operatingSystemVariant" onchange="" class="form-control" name="variant">
+                    <select id="operatingSystemVariant" onchange="" class="form-select" name="variant">
                       <option value="">unavailable</option>
                     </select>
                   </div>
@@ -66,7 +66,7 @@
                 <label class="col-3 col-form-label text-right">Image Type: </label>
                 <div class="col-7">
                   <div class="form-group">
-                    <select id="operatingSystemType" onchange="" class="form-control" name="type">
+                    <select id="operatingSystemType" onchange="" class="form-select" name="type">
                       <option value="container">container</option>
                       <option value="virtual-machine">virtual-machine</option>
                     </select>
@@ -78,8 +78,8 @@
               </div>
 
               <div class="modal-footer">
-                <button class="btn btn-secondary" type="button" data-dismiss="modal">Cancel</button>
-                <a class="btn btn-primary" href="#" onclick="addCatalogImage()" data-dismiss="modal">Ok</a>
+                <button class="btn btn-secondary" type="button" data-bs-dismiss="modal">Cancel</button>
+                <a class="btn btn-primary" href="#" onclick="addCatalogImage()" data-bs-dismiss="modal">Ok</a>
               </div>
 
             </div>
@@ -94,13 +94,13 @@
                     </div>
                   </div>
                   <div class="col-1">
-                    <i class="far fa-sm fa-question-circle" data-toggle="tooltip" data-html="true" title='(Required) - Enter in the repository specific name. For example, ubuntu/20.04 would be used for the images repository and simply 20.04 would be used for the ubuntu repositories.'></i>
+                    <i class="far fa-sm fa-question-circle" data-bs-toggle="tooltip" data-html="true" title='(Required) - Enter in the repository specific name. For example, ubuntu/20.04 would be used for the images repository and simply 20.04 would be used for the ubuntu repositories.'></i>
                   </div>
     
                   <label class="col-2 col-form-label text-right">Repository: </label>
                   <div class="col-8">
                     <div class="form-group">
-                      <select id="selectRepoInput" class="form-control" name="simplestreams_id">
+                      <select id="selectRepoInput" class="form-select" name="simplestreams_id">
                       </select>
                     </div>
                   </div>
@@ -111,7 +111,7 @@
                   <label class="col-2 col-form-label text-right">Image Type:</label>
                   <div class="col-8 text-right">
                     <div class="form-group">
-                      <select class="form-control" name="image_type">
+                      <select class="form-select" name="image_type">
                         <option value="container" selected>container</option>
                         <option value="virtual-machine">virtual-machine</option>
                       </select>
@@ -124,14 +124,14 @@
                 </div>
               </form>            
               <div class="modal-footer">
-                <button class="btn btn-secondary" type="button" data-dismiss="modal">Cancel</button>
-                <a class="btn btn-primary" href="#" onclick="addItem()" data-dismiss="modal">Ok</a>
+                <button class="btn btn-secondary" type="button" data-bs-dismiss="modal">Cancel</button>
+                <a class="btn btn-primary" href="#" onclick="addItem()" data-bs-dismiss="modal">Ok</a>
               </div>
             </div>
           </div>
         </div>
         <div class="modal-footer text-center">
-          <!--<a href="#" data-toggle="modal" data-target="#trademarkNotices" title="Download Image" aria-hidden="true">Trademark notices</a>-->
+          <!--<a href="#" data-bs-toggle="modal" data-bs-target="#trademarkNotices" title="Download Image" aria-hidden="true">Trademark notices</a>-->
         </div>
       </div>
     </div>
@@ -143,7 +143,7 @@
       <div class="modal-content">
           <div class="modal-header">
             <h5 class="modal-title" id="exampleModalLabel">Edit Image</h5>
-            <button class="close" type="button" data-dismiss="modal" aria-label="Close">
+            <button class="close" type="button" data-bs-dismiss="modal" aria-label="Close">
               <span aria-hidden="true">×</span>
             </button>
           </div>
@@ -160,8 +160,8 @@
             </div>
           </div>
           <div class="modal-footer">
-            <button class="btn btn-secondary" type="button" data-dismiss="modal">Cancel</button>
-            <a class="btn btn-primary" href="#" onclick="updateImage()" data-dismiss="modal">Submit</a>
+            <button class="btn btn-secondary" type="button" data-bs-dismiss="modal">Cancel</button>
+            <a class="btn btn-primary" href="#" onclick="updateImage()" data-bs-dismiss="modal">Submit</a>
           </div>
       </div>
     </div>

File diff suppressed because it is too large
+ 151 - 137
lxconsole/templates/modals/instance.html


+ 196 - 100
lxconsole/templates/modals/containers.html → lxconsole/templates/modals/instances.html

@@ -3,18 +3,18 @@
   <div class="modal-dialog modal-lg" role="document">
     <div class="modal-content">
         <div class="modal-header">
-          <h5 class="modal-title" id="exampleModalLabel">Create Container</h5>
-          <button class="close" type="button" data-dismiss="modal" aria-label="Close">
+          <h5 class="modal-title" id="exampleModalLabel">Create Instance</h5>
+          <button class="close" type="button" data-bs-dismiss="modal" aria-label="Close">
             <span aria-hidden="true">×</span>
           </button>
         </div>
         <div class="modal-body">
           <ul class="nav nav-tabs" id="myTab" role="tablist">
             <li class="nav-item">
-              <a class="nav-link active" id="form-tab" data-toggle="tab" href="#form" role="tab" aria-controls="form" aria-selected="true">Form</a>
+              <a class="nav-link active" id="form-tab" data-bs-toggle="tab" href="#form" role="tab" aria-controls="form" aria-selected="true">Form</a>
             </li>
             <li class="nav-item">
-              <a class="nav-link" id="json-tab" data-toggle="tab" href="#json" role="tab" aria-controls="json" aria-selected="false">JSON</a>
+              <a class="nav-link" id="json-tab" data-bs-toggle="tab" href="#json" role="tab" aria-controls="json" aria-selected="false">JSON</a>
             </li>
           </ul>
           <div class="tab-content" id="myTabContent">
@@ -30,7 +30,7 @@
                     </div>
                   </div>
                   <div class="col-1">
-                    <i class="far fa-sm fa-question-circle" title='Enter in a name for this container'></i>
+                    <i class="far fa-sm fa-question-circle" title='Enter in a name for this instance'></i>
                   </div>
                 </div>
                 <div class="row">
@@ -41,39 +41,53 @@
                     </div>
                   </div>
                   <div class="col-1">
-                    <i class="far fa-sm fa-question-circle" title='Enter in a description for this container'></i>
+                    <i class="far fa-sm fa-question-circle" title='Enter in a description for this instance'></i>
+                  </div>
+                </div>
+                <div class="row">
+                  <label class="col-3 col-form-label text-right">Type: </label>
+                  <div class="col-7">
+                    <div class="form-group">
+                      <select id="instanceTypeInput" onchange="changeInstanceModalTypeOptions()" class="form-select" name="type">
+                        <option value="container">container</option>
+                        <option value="virtual-machine">virtual-machine</option>
+                      </select>
+                    </div>
+                  </div>
+                  <div class="col-1">
+                    <i class="far fa-sm fa-question-circle" title='Choose either a traditional container or virtual-machine'></i>
                   </div>
                 </div>
                 <div class="row">
                   <label class="col-3 col-form-label text-right">Image: </label>
                   <div class="col-7">
                     <div class="form-group">
-                      <select id="containerImageInput" class="form-control" name="image">
+                      <select id="instanceImageInput" class="form-select" name="image">
                         <option value="none">none</option>
                       </select>
                     </div>
                   </div>
                   <div class="col-1">
-                    <i class="far fa-sm fa-question-circle" title='Select a downloaded image to use to build the container'></i>
+                    <i class="far fa-sm fa-question-circle" title='Select a downloaded image to use to build the instance'></i>
                   </div>
                 </div>
                 <div class="row">
                   <label class="col-3 col-form-label text-right">Profiles: </label>
                   <div class="col-7">
                     <div class="form-group">
-                      <select id="containerProfileInput" class="form-control" name="profiles">
+                      <select id="instanceProfileInput" class="form-select" name="profiles">
                       </select>
                     </div>
                   </div>
                   <div class="col-1">
-                    <i class="far fa-sm fa-question-circle" title='Select the initial profile to attach to this container. Additional profiles can be attached after the container is created. Default: default'></i>
+                    <i class="far fa-sm fa-question-circle" title='Select the initial profile to attach to this instance. Additional profiles can be attached after the instance is created. Default: default'></i>
                   </div>
                 </div>
                 <div class="row">
                   <label class="col-3 col-form-label text-right">Instance Type: </label>
                   <div class="col-7">
                     <div class="form-group">
-                      <select class="form-control" name="instance_type">
+                      <select class="form-select" name="instance_type">
                         <option value="" selected>(not set)</option>
                         <option disabled>--- AWS Instance Types ---</option>
                         <option value="aws:c1.medium">c1.medium</option>
@@ -243,7 +257,7 @@
                     </div>
                   </div>
                   <div class="col-1">
-                    <i class="far fa-sm fa-question-circle" title='Select from a variety of preconfigured container configurations. Default: (not set)'></i>
+                    <i class="far fa-sm fa-question-circle" title='Select from a variety of preconfigured instance configurations. Default: (not set)'></i>
                   </div>
                 </div>
     
@@ -251,28 +265,28 @@
                   <label class="col-3 col-form-label text-right">Location: </label>
                   <div class="col-7">
                     <div class="form-group">
-                      <select id="containerLocationInput" class="form-control" name="location">
+                      <select id="instanceLocationInput" class="form-select" name="location">
                         <option value="none">none</option>
                       </select>
                     </div>
                   </div>
                   <div class="col-1">
-                    <i class="far fa-sm fa-question-circle" title='Select the LXD cluster member or @group to deploy this container on. Default: none'></i>
+                    <i class="far fa-sm fa-question-circle" title='Select the LXD cluster member or @group to deploy this instance on. Default: none'></i>
                   </div>
                 </div>
 
                 <hr class="mb-2">
                 <nav>
                   <div class="nav nav-pills justify-content-center" id="nav-tab" role="tablist">
-                    <a class="nav-link active" id="nav-boot-tab" data-toggle="tab" href="#nav-boot" role="tab" aria-controls="nav-boot" aria-selected="true">Boot</a>
-                    <a class="nav-link" id="nav-cloud-init-tab" data-toggle="tab" href="#nav-cloud-init" role="tab" aria-controls="nav-cloud-init" aria-selected="true">Cloud-init</a>
-                    <a class="nav-link" id="nav-limits-tab" data-toggle="tab" href="#nav-limits" role="tab" aria-controls="nav-limits" aria-selected="false">Limits</a>
-                    <a class="nav-link" id="nav-migration-tab" data-toggle="tab" href="#nav-migration" role="tab" aria-controls="nav-migration" aria-selected="false">Migration</a>
-                    <a class="nav-link" id="nav-nvidia-tab" data-toggle="tab" href="#nav-nvidia" role="tab" aria-controls="nav-nvidia" aria-selected="false">Nvidia</a>
-                    <a class="nav-link" id="nav-other-tab" data-toggle="tab" href="#nav-other" role="tab" aria-controls="nav-other" aria-selected="false">Other</a>
-                    <a class="nav-link" id="nav-raw-tab" data-toggle="tab" href="#nav-raw" role="tab" aria-controls="nav-raw" aria-selected="false">Raw</a>
-                    <a class="nav-link" id="nav-security-tab" data-toggle="tab" href="#nav-security" role="tab" aria-controls="nav-security" aria-selected="false">Security</a>
-                    <a class="nav-link" id="nav-snapshots-tab" data-toggle="tab" href="#nav-snapshots" role="tab" aria-controls="nav-snapshots" aria-selected="false">Snapshots</a>
+                    <a class="nav-link active" id="nav-boot-tab" data-bs-toggle="tab" href="#nav-boot" role="tab" aria-controls="nav-boot" aria-selected="true">Boot</a>
+                    <a class="nav-link" id="nav-cloud-init-tab" data-bs-toggle="tab" href="#nav-cloud-init" role="tab" aria-controls="nav-cloud-init" aria-selected="true">Cloud-init</a>
+                    <a class="nav-link" id="nav-limits-tab" data-bs-toggle="tab" href="#nav-limits" role="tab" aria-controls="nav-limits" aria-selected="false">Limits</a>
+                    <a class="nav-link" id="nav-migration-tab" data-bs-toggle="tab" href="#nav-migration" role="tab" aria-controls="nav-migration" aria-selected="false">Migration</a>
+                    <a class="nav-link" id="nav-nvidia-tab" data-bs-toggle="tab" href="#nav-nvidia" role="tab" aria-controls="nav-nvidia" aria-selected="false">Nvidia</a>
+                    <a class="nav-link" id="nav-other-tab" data-bs-toggle="tab" href="#nav-other" role="tab" aria-controls="nav-other" aria-selected="false">Other</a>
+                    <a class="nav-link" id="nav-raw-tab" data-bs-toggle="tab" href="#nav-raw" role="tab" aria-controls="nav-raw" aria-selected="false">Raw</a>
+                    <a class="nav-link" id="nav-security-tab" data-bs-toggle="tab" href="#nav-security" role="tab" aria-controls="nav-security" aria-selected="false">Security</a>
+                    <a class="nav-link" id="nav-snapshots-tab" data-bs-toggle="tab" href="#nav-snapshots" role="tab" aria-controls="nav-snapshots" aria-selected="false">Snapshots</a>
                   </div>
                 </nav>
                 <hr class="mt-2">
@@ -283,7 +297,7 @@
                       <label class="col-4 col-form-label text-right">Autostart: </label>
                       <div class="col-6">
                         <div class="form-group">
-                          <select class="form-control" name="boot.autostart">
+                          <select class="form-select" name="boot.autostart">
                             <option value="">(not set)</option>
                             <option value="true">true</option>
                             <option value="false">false</option>
@@ -291,7 +305,7 @@
                         </div>
                       </div>
                       <div class="col-1">
-                        <i class="far fa-sm fa-question-circle" title='Select whether to automatically start the container with LXD starts. If not set, defaults to container last state.'></i>
+                        <i class="far fa-sm fa-question-circle" title='Select whether to automatically start the instance when LXD starts. If not set, defaults to instance last state.'></i>
                       </div>
                     </div>
                     <div class="row">
@@ -302,7 +316,7 @@
                         </div>
                       </div>
                       <div class="col-1">
-                        <i class="far fa-sm fa-question-circle" title='Enter in the number of seconds to wait after the container starts to boot up the next container. Default: 0.'></i>
+                        <i class="far fa-sm fa-question-circle" title='Enter in the number of seconds to wait after the instance starts to boot up the next instance. Default: 0.'></i>
                       </div>
                     </div>
                     <div class="row">
@@ -313,7 +327,7 @@
                         </div>
                       </div>
                       <div class="col-1">
-                        <i class="far fa-sm fa-question-circle" title='Enter in a number to determine the order the container boots, higher numbers being first. Default: 0.'></i>
+                        <i class="far fa-sm fa-question-circle" title='Enter in a number to determine the order the instance boots, higher numbers being first. Default: 0.'></i>
                       </div>
                     </div>
                     <div class="row">
@@ -324,7 +338,7 @@
                         </div>
                       </div>
                       <div class="col-1">
-                        <i class="far fa-sm fa-question-circle" title='Enter in a the number of seconds to wait on host shutdown before forcefull shutdown of container. Default: 30.'></i>
+                        <i class="far fa-sm fa-question-circle" title='Enter in a the number of seconds to wait on host shutdown before forcefull shutdown of instance. Default: 30.'></i>
                       </div>
                     </div>
                     <div class="row">
@@ -335,7 +349,7 @@
                         </div>
                       </div>
                       <div class="col-1">
-                        <i class="far fa-sm fa-question-circle" title='Enter in a number to determine the order the container shutsdown, higher numbers being first. Default: 0.'></i>
+                        <i class="far fa-sm fa-question-circle" title='Enter in a number to determine the order the instance shutsdown, higher numbers being first. Default: 0.'></i>
                       </div>
                     </div>
                   </div>
@@ -385,29 +399,29 @@
                         </div>
                       </div>
                       <div class="col-1">
-                        <i class="far fa-sm fa-question-circle" title='Enter in the number or range of CPUs to expose to the container.'></i>
+                        <i class="far fa-sm fa-question-circle" title='Enter in the number or range of CPUs to expose to the instance.'></i>
                       </div>
                     </div>
                     <div class="row">
                       <label class="col-4 col-form-label text-right">CPU Allowance: </label>
                       <div class="col-6">
                         <div class="form-group">
-                          <input type="text" class="form-control" name="limits.cpu.allowance">
+                          <input type="text" class="form-control" id="limitsCpuAllowance" name="limits.cpu.allowance">
                         </div>
                       </div>
                       <div class="col-1">
-                        <i class="far fa-sm fa-question-circle" title='Enter in the amount of Host CPU allowed to the container. This can be a percentage or a chunk of time. For example, 50% or 25ms/100ms. Default: 100%) '></i>
+                        <i class="far fa-sm fa-question-circle" title='Enter in the amount of Host CPU allowed to the instance. This can be a percentage or a chunk of time. For example, 50% or 25ms/100ms. Default: 100%) '></i>
                       </div>
                     </div>
                     <div class="row">
                       <label class="col-4 col-form-label text-right">CPU Priority: </label>
                       <div class="col-6">
                         <div class="form-group">
-                          <input type="number" class="form-control" name="limits.cpu.priority">
+                          <input type="number" class="form-control" id="limitsCpuPriority" name="limits.cpu.priority">
                         </div>
                       </div>
                       <div class="col-1">
-                        <i class="far fa-sm fa-question-circle" title='Enter in an integer between 0 (min) and 10 (max) to schedule the CPU priority compared to other containers. Default: 10.'></i>
+                        <i class="far fa-sm fa-question-circle" title='Enter in an integer between 0 (min) and 10 (max) to schedule the CPU priority compared to other instances. Default: 10.'></i>
                       </div>
                     </div>
                     <div class="row">
@@ -418,14 +432,14 @@
                         </div>
                       </div>
                       <div class="col-1">
-                        <i class="far fa-sm fa-question-circle" title='Enter in an integer between 0 (min) and 10 (max) to schedule disk I/O request priority compared to other containers. Default: 5.'></i>
+                        <i class="far fa-sm fa-question-circle" title='Enter in an integer between 0 (min) and 10 (max) to schedule disk I/O request priority compared to other instances. Default: 5.'></i>
                       </div>
                     </div>
                     <div class="row">
                       <label class="col-4 col-form-label text-right">Hugepages - 64KB: </label>
                       <div class="col-6">
                         <div class="form-group">
-                          <input type="number" class="form-control" name="limits.hugepages.64KB">
+                          <input type="number" class="form-control" id="limitsHugepages64KB" name="limits.hugepages.64KB">
                         </div>
                       </div>
                       <div class="col-1">
@@ -436,7 +450,7 @@
                       <label class="col-4 col-form-label text-right">Hugepages - 1MB: </label>
                       <div class="col-6">
                         <div class="form-group">
-                          <input type="number" class="form-control" name="limits.hugepages.1MB">
+                          <input type="number" class="form-control" id="limitsHugepages1MB" name="limits.hugepages.1MB">
                         </div>
                       </div>
                       <div class="col-1">
@@ -447,7 +461,7 @@
                       <label class="col-4 col-form-label text-right">Hugepages - 2MB: </label>
                       <div class="col-6">
                         <div class="form-group">
-                          <input type="number" class="form-control" name="limits.hugepages.2MB">
+                          <input type="number" class="form-control" id="limitsHugepages2MB" name="limits.hugepages.2MB">
                         </div>
                       </div>
                       <div class="col-1">
@@ -458,7 +472,7 @@
                       <label class="col-4 col-form-label text-right">Hugepages - 1GB: </label>
                       <div class="col-6">
                         <div class="form-group">
-                          <input type="number" class="form-control" name="limits.hugepages.1GB">
+                          <input type="number" class="form-control" id="limitsHugepages1GB" name="limits.hugepages.1GB">
                         </div>
                       </div>
                       <div class="col-1">
@@ -480,7 +494,7 @@
                       <label class="col-4 col-form-label text-right">Memory Enforce: </label>
                       <div class="col-6">
                         <div class="form-group">
-                          <select class="form-control" name="limits.memory.enforce">
+                          <select class="form-select" id="limitsMemoryEnforce" name="limits.memory.enforce">
                             <option value="">(not set)</option>
                             <option value="hard">hard</option>
                             <option value="soft">soft</option>
@@ -491,11 +505,26 @@
                         <i class="far fa-sm fa-question-circle" title="Select whether to put a hard stop on the memory limit or use a soft stop to exceed the limit if extra memory is available. Default: hard."></i>
                       </div>
                     </div>
+                    <div class="row">
+                      <label class="col-4 col-form-label text-right">Memory Hugepages: </label>
+                      <div class="col-6">
+                        <div class="form-group">
+                          <select class="form-select" id="limitsMemoryHugepages" name="limits.memory.hugepages">
+                            <option value="">(not set)</option>
+                            <option value="true">true</option>
+                            <option value="false">false</option>
+                          </select>
+                        </div>
+                      </div>
+                      <div class="col-1">
+                        <i class="far fa-sm fa-question-circle" title="Select whether to back the instance using hugepages rather than regular system memory. Default: false."></i>
+                      </div>
+                    </div>
                     <div class="row">
                       <label class="col-4 col-form-label text-right">Memory Swap: </label>
                       <div class="col-6">
                         <div class="form-group">
-                          <select class="form-control" name="limits.memory.swap">
+                          <select class="form-select" id="limitsMemorySwap" name="limits.memory.swap">
                             <option value="">(not set)</option>
                             <option value="true">true</option>
                             <option value="false">false</option>
@@ -503,18 +532,18 @@
                         </div>
                       </div>
                       <div class="col-1">
-                        <i class="far fa-sm fa-question-circle" title="Select whether to encorage swapping less used pages for the container. Default: true."></i>
+                        <i class="far fa-sm fa-question-circle" title="Select whether to encorage swapping less used pages for the instance. Default: true."></i>
                       </div>
                     </div>
                     <div class="row">
                       <label class="col-4 col-form-label text-right">Memory Swap Priority: </label>
                       <div class="col-6">
                         <div class="form-group">
-                          <input type="number" class="form-control" name="limits.memory.swap.priority">
+                          <input type="number" class="form-control" id="limitsMemorySwapPriority" name="limits.memory.swap.priority">
                         </div>
                       </div>
                       <div class="col-1">
-                        <i class="far fa-sm fa-question-circle" title="Enter in the priority that the container will be less likely to swap to disk, with 10 being the maxium less likeliness. Default 10."></i>
+                        <i class="far fa-sm fa-question-circle" title="Enter in the priority that the instance will be less likely to swap to disk, with 10 being the maxium less likeliness. Default 10."></i>
                       </div>
                     </div>
                     <div class="row">
@@ -525,18 +554,18 @@
                         </div>
                       </div>
                       <div class="col-1">
-                        <i class="far fa-sm fa-question-circle" title="Enter in the priority for the container network when the host is under, with 10 being the priority. Default 0."></i>
+                        <i class="far fa-sm fa-question-circle" title="Enter in the priority for the instance network when the host is under, with 10 being the priority. Default 0."></i>
                       </div>
                     </div>
                     <div class="row">
                       <label class="col-4 col-form-label text-right">Processes: </label>
                       <div class="col-6">
                         <div class="form-group">
-                          <input type="number" class="form-control" name="limits.processes">
+                          <input type="number" class="form-control" id="limitsProcesses" name="limits.processes">
                         </div>
                       </div>
                       <div class="col-1">
-                        <i class="far fa-sm fa-question-circle" title="Enter in the maximum number of processes that can run in an container. Default (not set)."></i>
+                        <i class="far fa-sm fa-question-circle" title="Enter in the maximum number of processes that can run in an instance. Default (not set)."></i>
                       </div>
                     </div>
                   </div>
@@ -546,7 +575,7 @@
                       <label class="col-4 col-form-label text-right">Incremental Memory: </label>
                       <div class="col-6">
                         <div class="form-group">
-                          <select class="form-control" name="migration.incremental.memory">
+                          <select class="form-select" id="migrationIncrementalMemory" name="migration.incremental.memory">
                             <option value="">(not set)</option>
                             <option value="true">true</option>
                             <option value="false">false</option>
@@ -554,29 +583,44 @@
                         </div>
                       </div>
                       <div class="col-1">
-                        <i class="far fa-sm fa-question-circle" title="Select whether to allow incremental memory transfer of the container's memory to reduce downtime. Default: false."></i>
+                        <i class="far fa-sm fa-question-circle" title="Select whether to allow incremental memory transfer of the instance's memory to reduce downtime. Default: false."></i>
                       </div>
                     </div>
                     <div class="row">
                       <label class="col-4 col-form-label text-right">Incremental Memory Goal: </label>
                       <div class="col-6">
                         <div class="form-group">
-                          <input type="number" class="form-control"name="migration.incremental.memory.goal">
+                          <input type="number" class="form-control" id="migrationIncrementalMemoryGoal" name="migration.incremental.memory.goal">
                         </div>
                       </div>
                       <div class="col-1">
-                        <i class="far fa-sm fa-question-circle" title="Enter in the percentage number of memory to have in sync before stopping the container. Default: 70."></i>
+                        <i class="far fa-sm fa-question-circle" title="Enter in the percentage number of memory to have in sync before stopping the instance. Default: 70."></i>
                       </div>
                     </div>
                     <div class="row">
                       <label class="col-4 col-form-label text-right">Incremental Memory Iterations: </label>
                       <div class="col-6">
                         <div class="form-group">
-                          <input type="number" class="form-control" name="migration.incremental.memory.iterations">
+                          <input type="number" class="form-control" id="migrationIncrementalMemoryIterations" name="migration.incremental.memory.iterations">
+                        </div>
+                      </div>
+                      <div class="col-1">
+                        <i class="far fa-sm fa-question-circle" title="Enter in the maximum number of transfer operations to go through before stopping the instance. Default: 10."></i>
+                      </div>
+                    </div>
+                    <div class="row">
+                      <label class="col-4 col-form-label text-right">Stateful: </label>
+                      <div class="col-6">
+                        <div class="form-group">
+                          <select class="form-select" id="migrationStateful" name="migration.stateful">
+                            <option value="">(not set)</option>
+                            <option value="true">true</option>
+                            <option value="false">false</option>
+                          </select>
                         </div>
                       </div>
                       <div class="col-1">
-                        <i class="far fa-sm fa-question-circle" title="Enter in the maximum number of transfer operations to go through before stopping the container. Default: 10."></i>
+                        <i class="far fa-sm fa-question-circle" title="Select whether to allow for stateful stop/start and snapshots. This will prevent the use of some features that are incompatible with it. Default: false."></i>
                       </div>
                     </div>
                   </div>
@@ -586,18 +630,18 @@
                       <label class="col-4 col-form-label text-right">Driver Capabilities: </label>
                       <div class="col-6">
                         <div class="form-group">
-                          <input type="text" class="form-control" name="nvidia.driver.capabilities">
+                          <input type="text" class="form-control" id="nvidiaDriverCapabilities" name="nvidia.driver.capabilities">
                         </div>
                       </div>
                       <div class="col-1">
-                        <i class="far fa-sm fa-question-circle" title="Enter in what driver capabilities the container needs (sets libnvidia-container NVIDIA_DRIVER_CAPABILITIES). Default: compute,utility."></i>
+                        <i class="far fa-sm fa-question-circle" title="Enter in what driver capabilities the instance needs (sets libnvidia-container NVIDIA_DRIVER_CAPABILITIES). Default: compute,utility."></i>
                       </div>
                     </div>
                     <div class="row">
                       <label class="col-4 col-form-label text-right">Runtime: </label>
                       <div class="col-6">
                         <div class="form-group">
-                          <select class="form-control" name="nvidia.runtime">
+                          <select class="form-select" id="nvidiaRuntime" name="nvidia.runtime">
                             <option value="">(not set)</option>
                             <option value="true">true</option>
                             <option value="false">false</option>
@@ -605,14 +649,14 @@
                         </div>
                       </div>
                       <div class="col-1">
-                        <i class="far fa-sm fa-question-circle" title="Select whether to pass the host NVIDIA and CUDA runtime libraries into the container. Default: false."></i>
+                        <i class="far fa-sm fa-question-circle" title="Select whether to pass the host NVIDIA and CUDA runtime libraries into the instance. Default: false."></i>
                       </div>
                     </div>
                     <div class="row">
                       <label class="col-4 col-form-label text-right">Require Cuda: </label>
                       <div class="col-6">
                         <div class="form-group">
-                          <input type="text" class="form-control" name="nvidia.require.cuda">
+                          <input type="text" class="form-control" id="nvidiaRequireCuda" name="nvidia.require.cuda">
                         </div>
                       </div>
                       <div class="col-1">
@@ -623,7 +667,7 @@
                       <label class="col-4 col-form-label text-right">Require Driver: </label>
                       <div class="col-6">
                         <div class="form-group">
-                          <input type="text" class="form-control" name="nvidia.require.driver">
+                          <input type="text" class="form-control" id="nvidiaRequireDriver" name="nvidia.require.driver">
                         </div>
                       </div>
                       <div class="col-1">
@@ -637,7 +681,7 @@
                       <label class="col-4 col-form-label text-right">Cluster Evacuate: </label>
                       <div class="col-6">
                         <div class="form-group">
-                          <select class="form-control" name="cluster.evacuate">
+                          <select class="form-select" name="cluster.evacuate">
                             <option value="">(not set)</option>
                             <option value="auto">auto</option>
                             <option value="migrate">migrate</option>
@@ -646,18 +690,18 @@
                         </div>
                       </div>
                       <div class="col-1">
-                        <i class="far fa-sm fa-question-circle" title='Select what to do when evacuating the container. Default: auto'></i>
+                        <i class="far fa-sm fa-question-circle" title='Select what to do when evacuating the instance. Default: auto'></i>
                       </div>
                     </div>
                     <div class="row">
                       <label class="col-4 col-form-label text-right">Kernel Modules: </label>
                       <div class="col-6">
                         <div class="form-group">
-                          <input type="text" class="form-control" name="linux.kernel_modules">
+                          <input type="text" class="form-control" id="linuxKernel_modules" name="linux.kernel_modules">
                         </div>
                       </div>
                       <div class="col-1">
-                        <i class="far fa-sm fa-question-circle" title="Enter in a comma separated list of kernel modules to load before starting the container. Default (not set)."></i>
+                        <i class="far fa-sm fa-question-circle" title="Enter in a comma separated list of kernel modules to load before starting the instance. Default (not set)."></i>
                       </div>
                     </div>
                   </div>
@@ -678,7 +722,7 @@
                       <label class="col-4 col-form-label text-right">Idmap: </label>
                       <div class="col-6">
                         <div class="form-group">
-                          <input type="text" class="form-control" name="raw.idmap">
+                          <input type="text" class="form-control" id="rawIdmap" name="raw.idmap">
                         </div>
                       </div>
                       <div class="col-1">
@@ -689,7 +733,7 @@
                       <label class="col-4 col-form-label text-right">Lxc: </label>
                       <div class="col-6">
                         <div class="form-group">
-                          <input type="text" class="form-control" name="raw.lxc">
+                          <input type="text" class="form-control" id="rawLxc" name="raw.lxc">
                         </div>
                       </div>
                       <div class="col-1">
@@ -700,21 +744,58 @@
                       <label class="col-4 col-form-label text-right">Seccomp: </label>
                       <div class="col-6">
                         <div class="form-group">
-                          <input type="text" class="form-control" name="raw.seccomp">
+                          <input type="text" class="form-control" id="rawSeccomp" name="raw.seccomp">
                         </div>
                       </div>
                       <div class="col-1">
                         <i class="far fa-sm fa-question-circle" title="Enter in a raw Seccomp configuration. Default: (not set)."></i>
                       </div>
                     </div>
+                    <div class="row">
+                      <label class="col-4 col-form-label text-right">Qemu: </label>
+                      <div class="col-6">
+                        <div class="form-group">
+                          <input type="text" class="form-control" id="rawQemu" name="raw.qemu">
+                        </div>
+                      </div>
+                      <div class="col-1">
+                        <i class="far fa-sm fa-question-circle" title="Enter raw QEMU configuration to be appended to the generated command line. Default: (not set)."></i>
+                      </div>
+                    </div>
+                    <div class="row">
+                      <label class="col-4 col-form-label text-right">Qemu.conf: </label>
+                      <div class="col-6">
+                        <div class="form-group">
+                          <input type="text" class="form-control" id="rawQemuConf" name="raw.qemu.conf">
+                        </div>
+                      </div>
+                      <div class="col-1">
+                        <i class="far fa-sm fa-question-circle" title="Enter in addition/override to the generated qemu.conf file. Default: (not set)."></i>
+                      </div>
+                    </div>
                   </div>
                   <div class="tab-pane fade" id="nav-security" role="tabpanel" aria-labelledby="nav-security-tab">
                     <br>
+                    <div class="row">
+                      <label class="col-4 col-form-label text-right">Agent Metrics: </label>
+                      <div class="col-6">
+                        <div class="form-group">
+                          <select class="form-select" id="securityAgentMetrics" name="security.agent.metrics">
+                            <option value="">(not set)</option>
+                            <option value="true">true</option>
+                            <option value="false">false</option>
+                          </select>
+                        </div>
+                      </div>
+                      <div class="col-1">
+                        <i class="far fa-sm fa-question-circle" title="Select whether the lxd-agent is queried for state information and metrics. Default: true."></i>
+                      </div>
+                    </div>
                     <div class="row">
                       <label class="col-4 col-form-label text-right">Devlxd: </label>
                       <div class="col-6">
                         <div class="form-group">
-                          <select class="form-control" name="security.devlxd">
+                          <select class="form-select" id="securityDevlxd" name="security.devlxd">
                             <option value="">(not set)</option>
                             <option value="true">true</option>
                             <option value="false">false</option>
@@ -722,14 +803,14 @@
                         </div>
                       </div>
                       <div class="col-1">
-                        <i class="far fa-sm fa-question-circle" title="Select whether to control the presence of /dev/lxd in the container. Default: true."></i>
+                        <i class="far fa-sm fa-question-circle" title="Select whether to control the presence of /dev/lxd in the instance. Default: true."></i>
                       </div>
                     </div>
                     <div class="row">
                       <label class="col-4 col-form-label text-right">Devlxd Images: </label>
                       <div class="col-6">
                         <div class="form-group">
-                          <select class="form-control" name="security.devlxd.images">
+                          <select class="form-select" id="securityDevlxdImages" name="security.devlxd.images">
                             <option value="">(not set)</option>
                             <option value="true">true</option>
                             <option value="false">false</option>
@@ -744,7 +825,7 @@
                       <label class="col-4 col-form-label text-right">Idmap Base: </label>
                       <div class="col-6">
                         <div class="form-group">
-                          <input type="number" class="form-control" name="security.idmap.base">
+                          <input type="number" class="form-control" id="securityIdmapBase" name="security.idmap.base">
                         </div>
                       </div>
                       <div class="col-1">
@@ -755,7 +836,7 @@
                       <label class="col-4 col-form-label text-right">Idmap Isolated: </label>
                       <div class="col-6">
                         <div class="form-group">
-                          <select class="form-control" name="security.idmap.isolated">
+                          <select class="form-select" id="securityIdmapIsolated" name="security.idmap.isolated">
                             <option value="">(not set)</option>
                             <option value="true">true</option>
                             <option value="false">false</option>
@@ -763,14 +844,14 @@
                         </div>
                       </div>
                       <div class="col-1">
-                        <i class="far fa-sm fa-question-circle" title="Select whether to use an idmap for the container that is unique amoung containers with isolate enabled. Default: false."></i>
+                        <i class="far fa-sm fa-question-circle" title="Select whether to use an idmap for the instance that is unique amoung instances with isolate enabled. Default: false."></i>
                       </div>
                     </div>
                     <div class="row">
                       <label class="col-4 col-form-label text-right">Idmap Size: </label>
                       <div class="col-6">
                         <div class="form-group">
-                          <input type="number" class="form-control" name="security.idmap.size">
+                          <input type="number" class="form-control" id="securityIdmapSize" name="security.idmap.size">
                         </div>
                       </div>
                       <div class="col-1">
@@ -781,7 +862,7 @@
                       <label class="col-4 col-form-label text-right">Nesting: </label>
                       <div class="col-6">
                         <div class="form-group">
-                          <select class="form-control" name="security.nesting">
+                          <select class="form-select" id="securityNesting" name="security.nesting">
                             <option value="">(not set)</option>
                             <option value="true">true</option>
                             <option value="false">false</option>
@@ -789,14 +870,14 @@
                         </div>
                       </div>
                       <div class="col-1">
-                        <i class="far fa-sm fa-question-circle" title="Select whether to support running LXD inside the container. Default: false."></i>
+                        <i class="far fa-sm fa-question-circle" title="Select whether to support running LXD inside the instance. Default: false."></i>
                       </div>
                     </div>
                     <div class="row">
                       <label class="col-4 col-form-label text-right">Privileged: </label>
                       <div class="col-6">
                         <div class="form-group">
-                          <select class="form-control" name="security.privileged">
+                          <select class="form-select" id="securityPrivileged" name="security.privileged">
                             <option value="">(not set)</option>
                             <option value="true">true</option>
                             <option value="false">false</option>
@@ -804,14 +885,14 @@
                         </div>
                       </div>
                       <div class="col-1">
-                        <i class="far fa-sm fa-question-circle" title="Select whether to run the container in privileged mode. Default: false."></i>
+                        <i class="far fa-sm fa-question-circle" title="Select whether to run the instance in privileged mode. Default: false."></i>
                       </div>
                     </div>
                     <div class="row">
                       <label class="col-4 col-form-label text-right">Protection Delete: </label>
                       <div class="col-6">
                         <div class="form-group">
-                          <select class="form-control" name="security.protection.delete">
+                          <select class="form-select" id="securityProtectionDelete" name="security.protection.delete">
                             <option value="">(not set)</option>
                             <option value="true">true</option>
                             <option value="false">false</option>
@@ -819,14 +900,29 @@
                         </div>
                       </div>
                       <div class="col-1">
-                        <i class="far fa-sm fa-question-circle" title="Select whether to prevent the container from being deleted. Default: false."></i>
+                        <i class="far fa-sm fa-question-circle" title="Select whether to prevent the instance from being deleted. Default: false."></i>
                       </div>
                     </div>
                     <div class="row">
                       <label class="col-4 col-form-label text-right">Protection Shift: </label>
                       <div class="col-6">
                         <div class="form-group">
-                          <select class="form-control" name="security.protection.shift">
+                          <select class="form-select" id="securityProtectionShift" name="security.protection.shift">
+                            <option value="">(not set)</option>
+                            <option value="true">true</option>
+                            <option value="false">false</option>
+                          </select>
+                        </div>
+                      </div>
+                      <div class="col-1">
+                        <i class="far fa-sm fa-question-circle" title="Select whether to prevent the instance filesystem from being uid/gid shifted on startup. Default: false."></i>
+                      </div>
+                    </div>
+                    <div class="row">
+                      <label class="col-4 col-form-label text-right">Secureboot: </label>
+                      <div class="col-6">
+                        <div class="form-group">
+                          <select class="form-select" id="securitySecureboot" name="security.secureboot">
                             <option value="">(not set)</option>
                             <option value="true">true</option>
                             <option value="false">false</option>
@@ -834,14 +930,14 @@
                         </div>
                       </div>
                       <div class="col-1">
-                        <i class="far fa-sm fa-question-circle" title="Select whether to prevent the container filesystem from being uid/gid shifted on startup. Default: false."></i>
+                        <i class="far fa-sm fa-question-circle" title="Select whether whether UEFI secure boot is enabled with the default Microsoft keys. Default: true."></i>
                       </div>
                     </div>
                     <div class="row">
                       <label class="col-4 col-form-label text-right">Syscalls Allow: </label>
                       <div class="col-6">
                         <div class="form-group">
-                          <input type="text" class="form-control" name="security.syscalls.allow">
+                          <input type="text" class="form-control" id="securitySyscallsAllow" name="security.syscalls.allow">
                         </div>
                       </div>
                       <div class="col-1">
@@ -852,7 +948,7 @@
                       <label class="col-4 col-form-label text-right">Syscalls Deny: </label>
                       <div class="col-6">
                         <div class="form-group">
-                          <input type="text" class="form-control" name="security.syscalls.deny">
+                          <input type="text" class="form-control" id="securitySyscallsDeny" name="security.syscalls.deny">
                         </div>
                       </div>
                       <div class="col-1">
@@ -863,7 +959,7 @@
                       <label class="col-4 col-form-label text-right">Syscalls Deny Compat: </label>
                       <div class="col-6">
                         <div class="form-group">
-                          <select class="form-control" name="security.syscalls.deny_compat">
+                          <select class="form-select" id="securitySyscallsDeny_compat" name="security.syscalls.deny_compat">
                             <option value="">(not set)</option>
                             <option value="true">true</option>
                             <option value="false">false</option>
@@ -878,7 +974,7 @@
                       <label class="col-4 col-form-label text-right">Syscalls Deny Default: </label>
                       <div class="col-6">
                         <div class="form-group">
-                          <select class="form-control" name="security.syscalls.deny_default">
+                          <select class="form-select" id="securitySyscallsDeny_default" name="security.syscalls.deny_default">
                             <option value="">(not set)</option>
                             <option value="true">true</option>
                             <option value="false">false</option>
@@ -893,7 +989,7 @@
                       <label class="col-4 col-form-label text-right">Syscalls Intercept Bpf: </label>
                       <div class="col-6">
                         <div class="form-group">
-                          <select class="form-control" name="security.syscalls.intercept.bpf">
+                          <select class="form-select" id="securitySyscallsInterceptBpf" name="security.syscalls.intercept.bpf">
                             <option value="">(not set)</option>
                             <option value="true">true</option>
                             <option value="false">false</option>
@@ -908,7 +1004,7 @@
                       <label class="col-4 col-form-label text-right">Syscalls Intercept Bpf Devices: </label>
                       <div class="col-6">
                         <div class="form-group">
-                          <select class="form-control" name="security.syscalls.intercept.bpf.devices">
+                          <select class="form-select" id="securitySyscallsInterceptBpfDevices" name="security.syscalls.intercept.bpf.devices">
                             <option value="">(not set)</option>
                             <option value="true">true</option>
                             <option value="false">false</option>
@@ -923,7 +1019,7 @@
                       <label class="col-4 col-form-label text-right">Syscalls Intercept Mknod: </label>
                       <div class="col-6">
                         <div class="form-group">
-                          <select class="form-control" name="security.syscalls.intercept.mknod">
+                          <select class="form-select" id="securitySyscallsInterceptMknod" name="security.syscalls.intercept.mknod">
                             <option value="">(not set)</option>
                             <option value="true">true</option>
                             <option value="false">false</option>
@@ -938,7 +1034,7 @@
                       <label class="col-4 col-form-label text-right">Syscalls Intercept Mount: </label>
                       <div class="col-6">
                         <div class="form-group">
-                          <select class="form-control" name="security.syscalls.intercept.mount">
+                          <select class="form-select" id="securitySyscallsInterceptMount" name="security.syscalls.intercept.mount">
                             <option value="">(not set)</option>
                             <option value="true">true</option>
                             <option value="false">false</option>
@@ -953,18 +1049,18 @@
                       <label class="col-4 col-form-label text-right">Syscalls Intercept Mount Allowed: </label>
                       <div class="col-6">
                         <div class="form-group">
-                          <input type="text" class="form-control" name="security.syscalls.intercept.mount.allowed">
+                          <input type="text" class="form-control" id="securitySyscallsInterceptMountAllowed" name="security.syscalls.intercept.mount.allowed">
                         </div>
                       </div>
                       <div class="col-1">
-                        <i class="far fa-sm fa-question-circle" title="Enter in a comma-separated list of filesystems that are safe to mount for processes within the container. Default: (not set)."></i>
+                        <i class="far fa-sm fa-question-circle" title="Enter in a comma-separated list of filesystems that are safe to mount for processes within the instance. Default: (not set)."></i>
                       </div>
                     </div>
                     <div class="row">
                       <label class="col-4 col-form-label text-right">Syscalls Intercept Mount Fuse: </label>
                       <div class="col-6">
                         <div class="form-group">
-                          <input type="text" class="form-control" name="security.syscalls.intercept.mount.fuse">
+                          <input type="text" class="form-control" id="securitySyscallsInterceptMountFuse" name="security.syscalls.intercept.mount.fuse">
                         </div>
                       </div>
                       <div class="col-1">
@@ -975,7 +1071,7 @@
                       <label class="col-4 col-form-label text-right">Syscalls Intercept Mount Shift: </label>
                       <div class="col-6">
                         <div class="form-group">
-                          <select class="form-control" name="security.syscalls.intercept.mount.shift">
+                          <select class="form-select" id="securitySyscallsInterceptMountShift" name="security.syscalls.intercept.mount.shift">
                             <option value="">(not set)</option>
                             <option value="true">true</option>
                             <option value="false">false</option>
@@ -990,7 +1086,7 @@
                       <label class="col-4 col-form-label text-right">Syscalls Intercept Setxattr: </label>
                       <div class="col-6">
                         <div class="form-group">
-                          <select class="form-control" name="security.syscalls.intercept.setxattr">
+                          <select class="form-select" id="securitySyscallsInterceptSetxattr" name="security.syscalls.intercept.setxattr">
                             <option value="">(not set)</option>
                             <option value="true">true</option>
                             <option value="false">false</option>
@@ -1019,7 +1115,7 @@
                       <label class="col-4 col-form-label text-right">Schedule Stopped: </label>
                       <div class="col-6">
                         <div class="form-group">
-                          <select class="form-control" name="snapshots.schedule.stopped">
+                          <select class="form-select" name="snapshots.schedule.stopped">
                             <option value="">(not set)</option>
                             <option value="true">true</option>
                             <option value="false">false</option>
@@ -1027,7 +1123,7 @@
                         </div>
                       </div>
                       <div class="col-1">
-                        <i class="far fa-sm fa-question-circle" title="Select whether stopped containers are to be snapshoted automatically. Default: false."></i>
+                        <i class="far fa-sm fa-question-circle" title="Select whether stopped instances are to be snapshoted automatically. Default: false."></i>
                       </div>
                     </div>
                     <div class="row">
@@ -1058,8 +1154,8 @@
 
               </form>
               <div class="modal-footer">
-                <button class="btn btn-secondary" type="button" data-dismiss="modal">Cancel</button>
-                <a class="btn btn-primary" href="#" onclick="addItem()" data-dismiss="modal">Submit</a>
+                <button class="btn btn-secondary" type="button" data-bs-dismiss="modal">Cancel</button>
+                <a class="btn btn-primary" href="#" onclick="addItem()" data-bs-dismiss="modal">Submit</a>
               </div>
             </div>
             <div class="tab-pane fade" id="json" role="tabpanel" aria-labelledby="json-tab">
@@ -1074,8 +1170,8 @@
                 </div>
               </div>
               <div class="modal-footer">
-                <button class="btn btn-secondary" type="button" data-dismiss="modal">Cancel</button>
-                <a class="btn btn-primary" href="#" onclick="createItemUsingJSON()" data-dismiss="modal">Submit</a>
+                <button class="btn btn-secondary" type="button" data-bs-dismiss="modal">Cancel</button>
+                <a class="btn btn-primary" href="#" onclick="createItemUsingJSON()" data-bs-dismiss="modal">Submit</a>
               </div>
             </div>
           </div>

+ 6 - 6
lxconsole/templates/modals/main.html

@@ -4,7 +4,7 @@
     <div class="modal-content">
       <div class="modal-header">
         <h5 class="modal-title" id="exampleModalLabel">About lxconsole</h5>
-        <button class="close" type="button" data-dismiss="modal" aria-label="Close">
+        <button class="close" type="button" data-bs-dismiss="modal" aria-label="Close">
           <span aria-hidden="true">×</span>
         </button>
       </div>
@@ -13,7 +13,7 @@
           <div class="col-12">
             <p>Lxconsole is an open source management console providing a web-based user interface capable of managing multiple LXD servers from a single location.</p>
             <p>
-              <strong>Version</strong>: <span id="versionNumber">v0.3.0</span> <br />
+              <strong>Version</strong>: <span id="versionNumber">v0.4.0</span> <br />
               <strong>License</strong>: AGPL-3.0 <br />
               <strong>URL</strong>: https://lxconsole.com <br />
             </p>          
@@ -21,7 +21,7 @@
         </div>
       </div>
       <div class="modal-footer">
-        <button class="btn btn-secondary" type="button" data-dismiss="modal">Dismiss</button>
+        <button class="btn btn-secondary" type="button" data-bs-dismiss="modal">Dismiss</button>
       </div>
     </div>
   </div>
@@ -33,7 +33,7 @@
     <div class="modal-content">
       <div class="modal-header">
         <h5 class="modal-title" id="exampleModalLabel">User Account</h5>
-        <button class="close" type="button" data-dismiss="modal" aria-label="Close">
+        <button class="close" type="button" data-bs-dismiss="modal" aria-label="Close">
           <span aria-hidden="true">×</span>
         </button>
       </div>
@@ -103,8 +103,8 @@
 
       </div>
       <div class="modal-footer">
-        <button class="btn btn-secondary" type="button" data-dismiss="modal">Dismiss</button>
-        <a class="btn btn-primary" href="#" onclick="updateAccount()" data-dismiss="modal">Update</a>
+        <button class="btn btn-secondary" type="button" data-bs-dismiss="modal">Dismiss</button>
+        <a class="btn btn-primary" href="#" onclick="updateAccount()" data-bs-dismiss="modal">Update</a>
       </div>
     </div>
   </div>

+ 11 - 11
lxconsole/templates/modals/network-acl.html

@@ -4,17 +4,17 @@
     <div class="modal-content">
         <div class="modal-header">
           <h5 class="modal-title" id="exampleModalLabel">Add Network ACL Rule</h5>
-          <button class="close" type="button" data-dismiss="modal" aria-label="Close">
+          <button class="close" type="button" data-bs-dismiss="modal" aria-label="Close">
             <span aria-hidden="true">×</span>
           </button>
         </div>
         <div class="modal-body">
           <ul class="nav nav-tabs" id="myTab" role="tablist">
             <li class="nav-item">
-              <a class="nav-link active" id="form-tab" data-toggle="tab" href="#form" role="tab" aria-controls="form" aria-selected="true">Form</a>
+              <a class="nav-link active" id="form-tab" data-bs-toggle="tab" href="#form" role="tab" aria-controls="form" aria-selected="true">Form</a>
             </li>
             <li class="nav-item">
-              <a class="nav-link" id="json-tab" data-toggle="tab" href="#json" role="tab" aria-controls="json" aria-selected="false">JSON</a>
+              <a class="nav-link" id="json-tab" data-bs-toggle="tab" href="#json" role="tab" aria-controls="json" aria-selected="false">JSON</a>
             </li>
           </ul>
           <div class="tab-content" id="myTabContent">
@@ -25,7 +25,7 @@
                   <label class="col-3 col-form-label text-right">Type: <span class="text-danger">*</span></label>
                   <div class="col-7">
                     <div class="form-group">
-                      <select onchange="" class="form-control" name="type">
+                      <select onchange="" class="form-select" name="type">
                         <option value="ingress">ingress</option>
                         <option value="egress">egress</option>
                       </select>
@@ -39,7 +39,7 @@
                   <label class="col-3 col-form-label text-right">Action: <span class="text-danger">*</span></label>
                   <div class="col-7">
                     <div class="form-group">
-                      <select onchange="" class="form-control" name="action">
+                      <select onchange="" class="form-select" name="action">
                         <option value="allow">allow</option>
                         <option value="reject">reject</option>
                         <option value="drop">drop</option>
@@ -54,7 +54,7 @@
                   <label class="col-3 col-form-label text-right">State: <span class="text-danger">*</span></label>
                   <div class="col-7">
                     <div class="form-group">
-                      <select onchange="" class="form-control" name="state">
+                      <select onchange="" class="form-select" name="state">
                         <option value="enabled">enabled</option>
                         <option value="disabled">disabled</option>
                         <option value="logged">logged</option>
@@ -102,7 +102,7 @@
                   <label class="col-3 col-form-label text-right">Protocol: </label>
                   <div class="col-7">
                     <div class="form-group">
-                      <select onchange="" class="form-control" name="protocol">
+                      <select onchange="" class="form-select" name="protocol">
                         <option value="">(not set)</option>
                         <option value="icmp4">icmp4</option>
                         <option value="icmp6">icmp6</option>
@@ -161,8 +161,8 @@
                 </div>
               </form>
               <div class="modal-footer">
-                <button class="btn btn-secondary" type="button" data-dismiss="modal">Cancel</button>
-                <a class="btn btn-primary" href="#" onclick="addItem()" data-dismiss="modal">Submit</a>
+                <button class="btn btn-secondary" type="button" data-bs-dismiss="modal">Cancel</button>
+                <a class="btn btn-primary" href="#" onclick="addItem()" data-bs-dismiss="modal">Submit</a>
               </div>
             </div>
             <div class="tab-pane fade" id="json" role="tabpanel" aria-labelledby="json-tab">
@@ -177,8 +177,8 @@
                 </div>
               </div>
               <div class="modal-footer">
-                <button class="btn btn-secondary" type="button" data-dismiss="modal">Cancel</button>
-                <a class="btn btn-primary" href="#" onclick="createItemUsingJSON()" data-dismiss="modal">Submit</a>
+                <button class="btn btn-secondary" type="button" data-bs-dismiss="modal">Cancel</button>
+                <a class="btn btn-primary" href="#" onclick="createItemUsingJSON()" data-bs-dismiss="modal">Submit</a>
               </div>
             </div>
           </div>

+ 13 - 13
lxconsole/templates/modals/network-acls.html

@@ -4,17 +4,17 @@
     <div class="modal-content">
         <div class="modal-header">
           <h5 class="modal-title" id="exampleModalLabel">Add Network ACL</h5>
-          <button class="close" type="button" data-dismiss="modal" aria-label="Close">
+          <button class="close" type="button" data-bs-dismiss="modal" aria-label="Close">
             <span aria-hidden="true">×</span>
           </button>
         </div>
         <div class="modal-body">
           <ul class="nav nav-tabs" id="myTab" role="tablist">
             <li class="nav-item">
-              <a class="nav-link active" id="form-tab" data-toggle="tab" href="#form" role="tab" aria-controls="form" aria-selected="true">Form</a>
+              <a class="nav-link active" id="form-tab" data-bs-toggle="tab" href="#form" role="tab" aria-controls="form" aria-selected="true">Form</a>
             </li>
             <li class="nav-item">
-              <a class="nav-link" id="json-tab" data-toggle="tab" href="#json" role="tab" aria-controls="json" aria-selected="false">JSON</a>
+              <a class="nav-link" id="json-tab" data-bs-toggle="tab" href="#json" role="tab" aria-controls="json" aria-selected="false">JSON</a>
             </li>
           </ul>
           <div class="tab-content" id="myTabContent">
@@ -46,8 +46,8 @@
                 <p class="text-center pt-2">Egress and Ingress rules can be defined once the Network ACL is created.</p>
               </form>
               <div class="modal-footer">
-                <button class="btn btn-secondary" type="button" data-dismiss="modal">Cancel</button>
-                <a class="btn btn-primary" href="#" onclick="addItem()" data-dismiss="modal">Submit</a>
+                <button class="btn btn-secondary" type="button" data-bs-dismiss="modal">Cancel</button>
+                <a class="btn btn-primary" href="#" onclick="addItem()" data-bs-dismiss="modal">Submit</a>
               </div>
             </div>
             <div class="tab-pane fade" id="json" role="tabpanel" aria-labelledby="json-tab">
@@ -62,8 +62,8 @@
                 </div>
               </div>
               <div class="modal-footer">
-                <button class="btn btn-secondary" type="button" data-dismiss="modal">Cancel</button>
-                <a class="btn btn-primary" href="#" onclick="createItemUsingJSON()" data-dismiss="modal">Submit</a>
+                <button class="btn btn-secondary" type="button" data-bs-dismiss="modal">Cancel</button>
+                <a class="btn btn-primary" href="#" onclick="createItemUsingJSON()" data-bs-dismiss="modal">Submit</a>
               </div>
             </div>
           </div>
@@ -78,7 +78,7 @@
     <div class="modal-content">
         <div class="modal-header">
           <h5 class="modal-title" id="exampleModalLabel">Edit Network ACL</h5>
-          <button class="close" type="button" data-dismiss="modal" aria-label="Close">
+          <button class="close" type="button" data-bs-dismiss="modal" aria-label="Close">
             <span aria-hidden="true">×</span>
           </button>
         </div>
@@ -95,8 +95,8 @@
           </div>
         </div>
         <div class="modal-footer">
-          <button class="btn btn-secondary" type="button" data-dismiss="modal">Cancel</button>
-          <a class="btn btn-primary" href="#" onclick="updateItem()" data-dismiss="modal">Submit</a>
+          <button class="btn btn-secondary" type="button" data-bs-dismiss="modal">Cancel</button>
+          <a class="btn btn-primary" href="#" onclick="updateItem()" data-bs-dismiss="modal">Submit</a>
         </div>
     </div>
   </div>
@@ -108,7 +108,7 @@
     <div class="modal-content">
         <div class="modal-header">
           <h5 class="modal-title" id="renameItemModalLabel">Rename Network ACL</h5>
-          <button class="close" type="button" data-dismiss="modal" aria-label="Close">
+          <button class="close" type="button" data-bs-dismiss="modal" aria-label="Close">
             <span aria-hidden="true">×</span>
           </button>
         </div>
@@ -127,8 +127,8 @@
           <input type="hidden" id ="networkACLToRename">
         </div>
         <div class="modal-footer">
-          <button class="btn btn-secondary" type="button" data-dismiss="modal">Cancel</button>
-          <a class="btn btn-primary" href="#" onclick="updateItemName()" data-dismiss="modal">Ok</a>
+          <button class="btn btn-secondary" type="button" data-bs-dismiss="modal">Cancel</button>
+          <a class="btn btn-primary" href="#" onclick="updateItemName()" data-bs-dismiss="modal">Ok</a>
         </div>
     </div>
   </div>

+ 17 - 17
lxconsole/templates/modals/network-zones.html

@@ -4,17 +4,17 @@
     <div class="modal-content">
         <div class="modal-header">
           <h5 class="modal-title" id="exampleModalLabel">Add Network Zone</h5>
-          <button class="close" type="button" data-dismiss="modal" aria-label="Close">
+          <button class="close" type="button" data-bs-dismiss="modal" aria-label="Close">
             <span aria-hidden="true">×</span>
           </button>
         </div>
         <div class="modal-body">
           <ul class="nav nav-tabs" id="myTab" role="tablist">
             <li class="nav-item">
-              <a class="nav-link active" id="form-tab" data-toggle="tab" href="#form" role="tab" aria-controls="form" aria-selected="true">Form</a>
+              <a class="nav-link active" id="form-tab" data-bs-toggle="tab" href="#form" role="tab" aria-controls="form" aria-selected="true">Form</a>
             </li>
             <li class="nav-item">
-              <a class="nav-link" id="json-tab" data-toggle="tab" href="#json" role="tab" aria-controls="json" aria-selected="false">JSON</a>
+              <a class="nav-link" id="json-tab" data-bs-toggle="tab" href="#json" role="tab" aria-controls="json" aria-selected="false">JSON</a>
             </li>
           </ul>
           <div class="tab-content" id="myTabContent">
@@ -46,8 +46,8 @@
 
               </form>
               <div class="modal-footer">
-                <button class="btn btn-secondary" type="button" data-dismiss="modal">Cancel</button>
-                <a class="btn btn-primary" href="#" onclick="addItem()" data-dismiss="modal">Submit</a>
+                <button class="btn btn-secondary" type="button" data-bs-dismiss="modal">Cancel</button>
+                <a class="btn btn-primary" href="#" onclick="addItem()" data-bs-dismiss="modal">Submit</a>
               </div>
             </div>
             <div class="tab-pane fade" id="json" role="tabpanel" aria-labelledby="json-tab">
@@ -62,8 +62,8 @@
                 </div>
               </div>
               <div class="modal-footer">
-                <button class="btn btn-secondary" type="button" data-dismiss="modal">Cancel</button>
-                <a class="btn btn-primary" href="#" onclick="createItemUsingJSON()" data-dismiss="modal">Submit</a>
+                <button class="btn btn-secondary" type="button" data-bs-dismiss="modal">Cancel</button>
+                <a class="btn btn-primary" href="#" onclick="createItemUsingJSON()" data-bs-dismiss="modal">Submit</a>
               </div>
             </div>
           </div>
@@ -78,17 +78,17 @@
     <div class="modal-content">
         <div class="modal-header">
           <h5 class="modal-title" id="exampleModalLabel">Edit Network Zone</h5>
-          <button class="close" type="button" data-dismiss="modal" aria-label="Close">
+          <button class="close" type="button" data-bs-dismiss="modal" aria-label="Close">
             <span aria-hidden="true">×</span>
           </button>
         </div>
         <div class="modal-body">
           <ul class="nav nav-tabs" id="myTab" role="tablist">
             <li class="nav-item">
-              <a class="nav-link active" id="json-edit-tab" data-toggle="tab" href="#json-edit" role="tab" aria-controls="json-edit" aria-selected="false">JSON</a>
+              <a class="nav-link active" id="json-edit-tab" data-bs-toggle="tab" href="#json-edit" role="tab" aria-controls="json-edit" aria-selected="false">JSON</a>
             </li>
             <!-- <li class="nav-item">
-              <a class="nav-link" id="rename-edit-tab" data-toggle="tab" href="#rename-edit" role="tab" aria-controls="rename-edit" aria-selected="true">Rename</a>
+              <a class="nav-link" id="rename-edit-tab" data-bs-toggle="tab" href="#rename-edit" role="tab" aria-controls="rename-edit" aria-selected="true">Rename</a>
             </li> -->
           </ul>
           <div class="tab-content" id="myTabContent">
@@ -105,8 +105,8 @@
                 </div>
               </div>
               <div class="modal-footer">
-                <button class="btn btn-secondary" type="button" data-dismiss="modal">Cancel</button>
-                <a class="btn btn-primary" href="#" onclick="updateItem()" data-dismiss="modal">Submit</a>
+                <button class="btn btn-secondary" type="button" data-bs-dismiss="modal">Cancel</button>
+                <a class="btn btn-primary" href="#" onclick="updateItem()" data-bs-dismiss="modal">Submit</a>
               </div>
             </div>
             <div class="tab-pane fade" id="rename-edit" role="tabpanel" aria-labelledby="rename-edit-tab">
@@ -125,8 +125,8 @@
                 </div>
               </form>
               <div class="modal-footer">
-                <button class="btn btn-secondary" type="button" data-dismiss="modal">Cancel</button>
-                <a class="btn btn-primary" href="#" onclick="renameItem()" data-dismiss="modal">Submit</a>
+                <button class="btn btn-secondary" type="button" data-bs-dismiss="modal">Cancel</button>
+                <a class="btn btn-primary" href="#" onclick="renameItem()" data-bs-dismiss="modal">Submit</a>
               </div>
             </div>
           </div>
@@ -141,7 +141,7 @@
     <div class="modal-content">
       <div class="modal-header">
         <h5 class="modal-title" id="exampleModalLabel">Delete Network Zone</h5>
-        <button class="close" type="button" data-dismiss="modal" aria-label="Close">
+        <button class="close" type="button" data-bs-dismiss="modal" aria-label="Close">
           <span aria-hidden="true">×</span>
         </button>
       </div>
@@ -152,8 +152,8 @@
         <input type="hidden" id="networkZone" class="form-control" name="server_name">
       </div>
       <div class="modal-footer">
-        <button class="btn btn-secondary" type="button" data-dismiss="modal">Cancel</button>
-        <a class="btn btn-primary" href="#" onclick="deleteItem()" data-dismiss="modal">Yes</a>
+        <button class="btn btn-secondary" type="button" data-bs-dismiss="modal">Cancel</button>
+        <a class="btn btn-primary" href="#" onclick="deleteItem()" data-bs-dismiss="modal">Yes</a>
       </div>
     </div>
   </div>

+ 35 - 35
lxconsole/templates/modals/network.html

@@ -4,17 +4,17 @@
     <div class="modal-content">
         <div class="modal-header">
           <h5 class="modal-title" id="exampleModalLabel">Add Network Forward</h5>
-          <button class="close" type="button" data-dismiss="modal" aria-label="Close">
+          <button class="close" type="button" data-bs-dismiss="modal" aria-label="Close">
             <span aria-hidden="true">×</span>
           </button>
         </div>
         <div class="modal-body">
           <ul class="nav nav-tabs" id="myTab" role="tablist">
             <li class="nav-item">
-              <a class="nav-link active" id="add-forward-form-tab" data-toggle="tab" href="#addForwardform" role="tab" aria-controls="add-forward-form-tab" aria-selected="true">Form</a>
+              <a class="nav-link active" id="add-forward-form-tab" data-bs-toggle="tab" href="#addForwardform" role="tab" aria-controls="add-forward-form-tab" aria-selected="true">Form</a>
             </li>
             <li class="nav-item">
-              <a class="nav-link" id="add-forward-json-tab" data-toggle="tab" href="#addForwardJson" role="tab" aria-controls="add-forward-json-tab" aria-selected="false">JSON</a>
+              <a class="nav-link" id="add-forward-json-tab" data-bs-toggle="tab" href="#addForwardJson" role="tab" aria-controls="add-forward-json-tab" aria-selected="false">JSON</a>
             </li>
           </ul>
           <div class="tab-content" id="myTabContent">
@@ -73,7 +73,7 @@
                   <label class="col-3 col-form-label text-right">Protocol: </label>
                   <div class="col-7">
                     <div class="form-group">
-                      <select class="form-control" name="port_protocol">
+                      <select class="form-select" name="port_protocol">
                         <option value="tcp">TCP</option>
                         <option value="udp">UDP</option>
                       </select>
@@ -111,8 +111,8 @@
 
               </form>
               <div class="modal-footer">
-                <button class="btn btn-secondary" type="button" data-dismiss="modal">Cancel</button>
-                <a class="btn btn-primary" href="#" onclick="addItem('forward')" data-dismiss="modal">Submit</a>
+                <button class="btn btn-secondary" type="button" data-bs-dismiss="modal">Cancel</button>
+                <a class="btn btn-primary" href="#" onclick="addItem('forward')" data-bs-dismiss="modal">Submit</a>
               </div>
             </div>
             <div class="tab-pane fade" id="addForwardJson" role="tabpanel" aria-labelledby="json-tab">
@@ -127,8 +127,8 @@
                 </div>
               </div>
               <div class="modal-footer">
-                <button class="btn btn-secondary" type="button" data-dismiss="modal">Cancel</button>
-                <a class="btn btn-primary" href="#" onclick="createItemUsingJSON('forward')" data-dismiss="modal">Submit</a>
+                <button class="btn btn-secondary" type="button" data-bs-dismiss="modal">Cancel</button>
+                <a class="btn btn-primary" href="#" onclick="createItemUsingJSON('forward')" data-bs-dismiss="modal">Submit</a>
               </div>
             </div>
           </div>
@@ -143,17 +143,17 @@
     <div class="modal-content">
         <div class="modal-header">
           <h5 class="modal-title" id="exampleModalLabel">Add Network Load Balancer</h5>
-          <button class="close" type="button" data-dismiss="modal" aria-label="Close">
+          <button class="close" type="button" data-bs-dismiss="modal" aria-label="Close">
             <span aria-hidden="true">×</span>
           </button>
         </div>
         <div class="modal-body">
           <ul class="nav nav-tabs" id="myTab" role="tablist">
             <li class="nav-item">
-              <a class="nav-link active" id="form-tab" data-toggle="tab" href="#form" role="tab" aria-controls="form" aria-selected="true">Form</a>
+              <a class="nav-link active" id="form-tab" data-bs-toggle="tab" href="#form" role="tab" aria-controls="form" aria-selected="true">Form</a>
             </li>
             <li class="nav-item">
-              <a class="nav-link" id="json-tab" data-toggle="tab" href="#json" role="tab" aria-controls="json" aria-selected="false">JSON</a>
+              <a class="nav-link" id="json-tab" data-bs-toggle="tab" href="#json" role="tab" aria-controls="json" aria-selected="false">JSON</a>
             </li>
           </ul>
           <div class="tab-content" id="myTabContent">
@@ -263,7 +263,7 @@
                   <label class="col-3 col-form-label text-right">Protocol: </label>
                   <div class="col-7">
                     <div class="form-group">
-                      <select class="form-control" name="port_protocol">
+                      <select class="form-select" name="port_protocol">
                         <option value="tcp">TCP</option>
                         <option value="udp">UDP</option>
                       </select>
@@ -288,8 +288,8 @@
 
               </form>
               <div class="modal-footer">
-                <button class="btn btn-secondary" type="button" data-dismiss="modal">Cancel</button>
-                <a class="btn btn-primary" href="#" onclick="addItem('load_balancer')" data-dismiss="modal">Submit</a>
+                <button class="btn btn-secondary" type="button" data-bs-dismiss="modal">Cancel</button>
+                <a class="btn btn-primary" href="#" onclick="addItem('load_balancer')" data-bs-dismiss="modal">Submit</a>
               </div>
             </div>
             <div class="tab-pane fade" id="json" role="tabpanel" aria-labelledby="json-tab">
@@ -304,8 +304,8 @@
                 </div>
               </div>
               <div class="modal-footer">
-                <button class="btn btn-secondary" type="button" data-dismiss="modal">Cancel</button>
-                <a class="btn btn-primary" href="#" onclick="createItemUsingJSON('load_balancer')" data-dismiss="modal">Submit</a>
+                <button class="btn btn-secondary" type="button" data-bs-dismiss="modal">Cancel</button>
+                <a class="btn btn-primary" href="#" onclick="createItemUsingJSON('load_balancer')" data-bs-dismiss="modal">Submit</a>
               </div>
             </div>
           </div>
@@ -320,17 +320,17 @@
     <div class="modal-content">
         <div class="modal-header">
           <h5 class="modal-title" id="exampleModalLabel">Add Network Peer</h5>
-          <button class="close" type="button" data-dismiss="modal" aria-label="Close">
+          <button class="close" type="button" data-bs-dismiss="modal" aria-label="Close">
             <span aria-hidden="true">×</span>
           </button>
         </div>
         <div class="modal-body">
           <ul class="nav nav-tabs" id="myTab" role="tablist">
             <li class="nav-item">
-              <a class="nav-link active" id="add-peer-form-tab" data-toggle="tab" href="#addPeerform" role="tab" aria-controls="add-peer-form-tab" aria-selected="true">Form</a>
+              <a class="nav-link active" id="add-peer-form-tab" data-bs-toggle="tab" href="#addPeerform" role="tab" aria-controls="add-peer-form-tab" aria-selected="true">Form</a>
             </li>
             <li class="nav-item">
-              <a class="nav-link" id="add-peer-json-tab" data-toggle="tab" href="#addPeerJson" role="tab" aria-controls="add-peer-json-tab" aria-selected="false">JSON</a>
+              <a class="nav-link" id="add-peer-json-tab" data-bs-toggle="tab" href="#addPeerJson" role="tab" aria-controls="add-peer-json-tab" aria-selected="false">JSON</a>
             </li>
           </ul>
           <div class="tab-content" id="myTabContent">
@@ -384,8 +384,8 @@
 
               </form>
               <div class="modal-footer">
-                <button class="btn btn-secondary" type="button" data-dismiss="modal">Cancel</button>
-                <a class="btn btn-primary" href="#" onclick="addItem('peer')" data-dismiss="modal">Submit</a>
+                <button class="btn btn-secondary" type="button" data-bs-dismiss="modal">Cancel</button>
+                <a class="btn btn-primary" href="#" onclick="addItem('peer')" data-bs-dismiss="modal">Submit</a>
               </div>
             </div>
             <div class="tab-pane fade" id="addPeerJson" role="tabpanel" aria-labelledby="json-tab">
@@ -400,8 +400,8 @@
                 </div>
               </div>
               <div class="modal-footer">
-                <button class="btn btn-secondary" type="button" data-dismiss="modal">Cancel</button>
-                <a class="btn btn-primary" href="#" onclick="createItemUsingJSON('peer')" data-dismiss="modal">Submit</a>
+                <button class="btn btn-secondary" type="button" data-bs-dismiss="modal">Cancel</button>
+                <a class="btn btn-primary" href="#" onclick="createItemUsingJSON('peer')" data-bs-dismiss="modal">Submit</a>
               </div>
             </div>
           </div>
@@ -417,14 +417,14 @@
     <div class="modal-content">
         <div class="modal-header">
           <h5 class="modal-title" id="exampleModalLabel">Edit Network Forward</h5>
-          <button class="close" type="button" data-dismiss="modal" aria-label="Close">
+          <button class="close" type="button" data-bs-dismiss="modal" aria-label="Close">
             <span aria-hidden="true">×</span>
           </button>
         </div>
         <div class="modal-body">
           <ul class="nav nav-tabs" id="myTab" role="tablist">
             <li class="nav-item">
-              <a class="nav-link active" id="json-edit-tab" data-toggle="tab" href="#json-edit" role="tab" aria-controls="json-edit" aria-selected="false">JSON</a>
+              <a class="nav-link active" id="json-edit-tab" data-bs-toggle="tab" href="#json-edit" role="tab" aria-controls="json-edit" aria-selected="false">JSON</a>
             </li>
           </ul>
           <div class="tab-content" id="myTabContent">
@@ -442,8 +442,8 @@
                 </div>
               </div>
               <div class="modal-footer">
-                <button class="btn btn-secondary" type="button" data-dismiss="modal">Cancel</button>
-                <a class="btn btn-primary" href="#" onclick="updateForward()" data-dismiss="modal">Submit</a>
+                <button class="btn btn-secondary" type="button" data-bs-dismiss="modal">Cancel</button>
+                <a class="btn btn-primary" href="#" onclick="updateForward()" data-bs-dismiss="modal">Submit</a>
               </div>
             </div>
           </div>
@@ -458,14 +458,14 @@
     <div class="modal-content">
         <div class="modal-header">
           <h5 class="modal-title" id="exampleModalLabel">Edit Network Load Balancer</h5>
-          <button class="close" type="button" data-dismiss="modal" aria-label="Close">
+          <button class="close" type="button" data-bs-dismiss="modal" aria-label="Close">
             <span aria-hidden="true">×</span>
           </button>
         </div>
         <div class="modal-body">
           <ul class="nav nav-tabs" id="myTab" role="tablist">
             <li class="nav-item">
-              <a class="nav-link active" id="json-edit-tab" data-toggle="tab" href="#json-edit" role="tab" aria-controls="json-edit" aria-selected="false">JSON</a>
+              <a class="nav-link active" id="json-edit-tab" data-bs-toggle="tab" href="#json-edit" role="tab" aria-controls="json-edit" aria-selected="false">JSON</a>
             </li>
           </ul>
           <div class="tab-content" id="myTabContent">
@@ -483,8 +483,8 @@
                 </div>
               </div>
               <div class="modal-footer">
-                <button class="btn btn-secondary" type="button" data-dismiss="modal">Cancel</button>
-                <a class="btn btn-primary" href="#" onclick="updateLoadBalancer()" data-dismiss="modal">Submit</a>
+                <button class="btn btn-secondary" type="button" data-bs-dismiss="modal">Cancel</button>
+                <a class="btn btn-primary" href="#" onclick="updateLoadBalancer()" data-bs-dismiss="modal">Submit</a>
               </div>
             </div>
           </div>
@@ -499,14 +499,14 @@
     <div class="modal-content">
         <div class="modal-header">
           <h5 class="modal-title" id="exampleModalLabel">Edit Network Peer</h5>
-          <button class="close" type="button" data-dismiss="modal" aria-label="Close">
+          <button class="close" type="button" data-bs-dismiss="modal" aria-label="Close">
             <span aria-hidden="true">×</span>
           </button>
         </div>
         <div class="modal-body">
           <ul class="nav nav-tabs" id="myTab" role="tablist">
             <li class="nav-item">
-              <a class="nav-link active" id="json-edit-tab" data-toggle="tab" href="#json-edit" role="tab" aria-controls="json-edit" aria-selected="false">JSON</a>
+              <a class="nav-link active" id="json-edit-tab" data-bs-toggle="tab" href="#json-edit" role="tab" aria-controls="json-edit" aria-selected="false">JSON</a>
             </li>
           </ul>
           <div class="tab-content" id="myTabContent">
@@ -524,8 +524,8 @@
                 </div>
               </div>
               <div class="modal-footer">
-                <button class="btn btn-secondary" type="button" data-dismiss="modal">Cancel</button>
-                <a class="btn btn-primary" href="#" onclick="updatePeer()" data-dismiss="modal">Submit</a>
+                <button class="btn btn-secondary" type="button" data-bs-dismiss="modal">Cancel</button>
+                <a class="btn btn-primary" href="#" onclick="updatePeer()" data-bs-dismiss="modal">Submit</a>
               </div>
             </div>
           </div>

+ 35 - 35
lxconsole/templates/modals/networks.html

@@ -4,17 +4,17 @@
     <div class="modal-content">
         <div class="modal-header">
           <h5 class="modal-title" id="exampleModalLabel">Create Network</h5>
-          <button class="close" type="button" data-dismiss="modal" aria-label="Close">
+          <button class="close" type="button" data-bs-dismiss="modal" aria-label="Close">
             <span aria-hidden="true">×</span>
           </button>
         </div>
         <div class="modal-body">
           <ul class="nav nav-tabs" id="myTab" role="tablist">
             <li class="nav-item">
-              <a class="nav-link active" id="form-tab" data-toggle="tab" href="#form" role="tab" aria-controls="form" aria-selected="true">Form</a>
+              <a class="nav-link active" id="form-tab" data-bs-toggle="tab" href="#form" role="tab" aria-controls="form" aria-selected="true">Form</a>
             </li>
             <li class="nav-item">
-              <a class="nav-link" id="json-tab" data-toggle="tab" href="#json" role="tab" aria-controls="json" aria-selected="false">JSON</a>
+              <a class="nav-link" id="json-tab" data-bs-toggle="tab" href="#json" role="tab" aria-controls="json" aria-selected="false">JSON</a>
             </li>
           </ul>
           <div class="tab-content" id="myTabContent">
@@ -36,7 +36,7 @@
                     <label class="col-3 col-form-label text-right">Network Type: <span class="text-danger">*</span></label>
                     <div class="col-7">
                       <div class="form-group">
-                        <select id="networkTypeInput" onchange="changeNetworkTypeInput()" class="form-control" name="type">
+                        <select id="networkTypeInput" onchange="changeNetworkTypeInput()" class="form-select" name="type">
                           <option value="bridge">bridge</option>
                           <option value="macvlan">macvlan</option>
                           <option value="ovn">ovn</option>
@@ -53,7 +53,7 @@
                     <label class="col-3 col-form-label text-right">Parent: <span class="text-danger">*</span></label>
                     <div class="col-7">
                       <div class="form-group">
-                        <select id="networkParentInput" onchange="" class="form-control" name="parent">
+                        <select id="networkParentInput" onchange="" class="form-select" name="parent">
                         </select>
                       </div>
                     </div>
@@ -65,7 +65,7 @@
                     <label class="col-3 col-form-label text-right">Network: <span class="text-danger">*</span></label>
                     <div class="col-7">
                       <div class="form-group">
-                        <select id="networkNetworkInput" onchange="" class="form-control" name="network">
+                        <select id="networkNetworkInput" onchange="" class="form-select" name="network">
                         </select>
                       </div>
                     </div>
@@ -87,7 +87,7 @@
                   <hr>
                   <div id="accordionConfigurationProperties">
                     <h2>
-                      <button class="btn btn-link collapsed" type="button" data-toggle="collapse" data-target="#configurationProperties" aria-expanded="false" aria-controls="configurationProperties">
+                      <button class="btn btn-link collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#configurationProperties" aria-expanded="false" aria-controls="configurationProperties">
                         Configuration Properties
                       </button>
                     </h2> 
@@ -129,7 +129,7 @@
                         <label class="col-3 col-form-label text-right">Bridge Driver: </label>
                         <div class="col-7">
                           <div class="form-group">
-                            <select onchange="" class="form-control" name="bridge.driver">
+                            <select onchange="" class="form-select" name="bridge.driver">
                               <option value="">(not set)</option>
                               <option value="native">native</option>
                               <option value="openvswitch">openvswitch</option>
@@ -166,7 +166,7 @@
                         <label class="col-3 col-form-label text-right">Bridge Mode: </label>
                         <div class="col-7">
                           <div class="form-group">
-                            <select onchange="" class="form-control" name="bridge.mode">
+                            <select onchange="" class="form-select" name="bridge.mode">
                               <option value="">(not set)</option>
                               <option value="fan">fan</option>
                               <option value="standard">standard</option>
@@ -203,7 +203,7 @@
                         <label class="col-3 col-form-label text-right">DNS Mode: </label>
                         <div class="col-7">
                           <div class="form-group">
-                            <select onchange="" class="form-control" name="dns.mode">
+                            <select onchange="" class="form-select" name="dns.mode">
                               <option value="">(not set)</option>
                               <option value="dynamic">dynamic</option>
                               <option value="managed">managed</option>
@@ -241,7 +241,7 @@
                         <label class="col-3 col-form-label text-right">Fan Type: </label>
                         <div class="col-7">
                           <div class="form-group">
-                            <select onchange="" class="form-control" name="fan.type">
+                            <select onchange="" class="form-select" name="fan.type">
                               <option value="">(not set)</option>
                               <option value="ipip">ipip</option>
                               <option value="vxlan">vxlan</option>
@@ -278,7 +278,7 @@
                         <label class="col-3 col-form-label text-right">IPv4 DHCP: </label>
                         <div class="col-7">
                           <div class="form-group">
-                            <select onchange="" class="form-control" name="ipv4.dhcp">
+                            <select onchange="" class="form-select" name="ipv4.dhcp">
                               <option value="">(not set)</option>
                               <option value="true">true</option>
                               <option value="false">false</option>
@@ -326,7 +326,7 @@
                         <label class="col-3 col-form-label text-right">IPv4 Firewall: </label>
                         <div class="col-7">
                           <div class="form-group">
-                            <select onchange="" class="form-control" name="ipv4.firewall">
+                            <select onchange="" class="form-select" name="ipv4.firewall">
                               <option value="">(not set)</option>
                               <option value="true">true</option>
                               <option value="false">false</option>
@@ -352,7 +352,7 @@
                         <label class="col-3 col-form-label text-right">IPv4 NAT: </label>
                         <div class="col-7">
                           <div class="form-group">
-                            <select onchange="" class="form-control" name="ipv4.nat">
+                            <select onchange="" class="form-select" name="ipv4.nat">
                               <option value="">(not set)</option>
                               <option value="true">true</option>
                               <option value="false">false</option>
@@ -367,7 +367,7 @@
                         <label class="col-3 col-form-label text-right">IPv4 NAT Order: </label>
                         <div class="col-7">
                           <div class="form-group">
-                            <select onchange="" class="form-control" name="ipv4.nat.order">
+                            <select onchange="" class="form-select" name="ipv4.nat.order">
                               <option value="">(not set)</option>
                               <option value="after">after</option>
                               <option value="before">before</option>
@@ -404,7 +404,7 @@
                         <label class="col-3 col-form-label text-right">IPv4 Routes Anycast: </label>
                         <div class="col-7">
                           <div class="form-group">
-                            <select onchange="" class="form-control" name="ipv4.routes.anycast">
+                            <select onchange="" class="form-select" name="ipv4.routes.anycast">
                               <option value="">(not set)</option>
                               <option value="true">true</option>
                               <option value="false">false</option>
@@ -430,7 +430,7 @@
                         <label class="col-3 col-form-label text-right">IPv4 Routing: </label>
                         <div class="col-7">
                           <div class="form-group">
-                            <select onchange="" class="form-control" name="ipv4.routing">
+                            <select onchange="" class="form-select" name="ipv4.routing">
                               <option value="">(not set)</option>
                               <option value="true">true</option>
                               <option value="false">false</option>
@@ -456,7 +456,7 @@
                         <label class="col-3 col-form-label text-right">IPv6 DHCP: </label>
                         <div class="col-7">
                           <div class="form-group">
-                            <select onchange="" class="form-control" name="ipv6.dhcp">
+                            <select onchange="" class="form-select" name="ipv6.dhcp">
                               <option value="">(not set)</option>
                               <option value="true">true</option>
                               <option value="false">false</option>
@@ -493,7 +493,7 @@
                         <label class="col-3 col-form-label text-right">IPv6 DHCP Stateful: </label>
                         <div class="col-7">
                           <div class="form-group">
-                            <select onchange="" class="form-control" name="ipv6.dhcp.stateful">
+                            <select onchange="" class="form-select" name="ipv6.dhcp.stateful">
                               <option value="">(not set)</option>
                               <option value="true">true</option>
                               <option value="false">false</option>
@@ -508,7 +508,7 @@
                         <label class="col-3 col-form-label text-right">IPv6 Firewall: </label>
                         <div class="col-7">
                           <div class="form-group">
-                            <select onchange="" class="form-control" name="ipv6.firewall">
+                            <select onchange="" class="form-select" name="ipv6.firewall">
                               <option value="">(not set)</option>
                               <option value="true">true</option>
                               <option value="false">false</option>
@@ -534,7 +534,7 @@
                         <label class="col-3 col-form-label text-right">IPv6 NAT: </label>
                         <div class="col-7">
                           <div class="form-group">
-                            <select onchange="" class="form-control" name="ipv6.nat">
+                            <select onchange="" class="form-select" name="ipv6.nat">
                               <option value="">(not set)</option>
                               <option value="true">true</option>
                               <option value="false">false</option>
@@ -549,7 +549,7 @@
                         <label class="col-3 col-form-label text-right">IPv6 NAT Order: </label>
                         <div class="col-7">
                           <div class="form-group">
-                            <select onchange="" class="form-control" name="ipv6.nat.order">
+                            <select onchange="" class="form-select" name="ipv6.nat.order">
                               <option value="">(not set)</option>
                               <option value="after">after</option>
                               <option value="before">before</option>
@@ -586,7 +586,7 @@
                         <label class="col-3 col-form-label text-right">IPv6 Routes Anycast: </label>
                         <div class="col-7">
                           <div class="form-group">
-                            <select onchange="" class="form-control" name="ipv6.routes.anycast">
+                            <select onchange="" class="form-select" name="ipv6.routes.anycast">
                               <option value="">(not set)</option>
                               <option value="true">true</option>
                               <option value="false">false</option>
@@ -612,7 +612,7 @@
                         <label class="col-3 col-form-label text-right">IPv6 Routing: </label>
                         <div class="col-7">
                           <div class="form-group">
-                            <select onchange="" class="form-control" name="ipv6.routing">
+                            <select onchange="" class="form-select" name="ipv6.routing">
                               <option value="">(not set)</option>
                               <option value="true">true</option>
                               <option value="false">false</option>
@@ -660,7 +660,7 @@
                         <label class="col-3 col-form-label text-right">OVN Ingress Mode: </label>
                         <div class="col-7">
                           <div class="form-group">
-                            <select onchange="" class="form-control" name="ovn.ingress.mode">
+                            <select onchange="" class="form-select" name="ovn.ingress.mode">
                               <option value="">(not set)</option>
                               <option value="l2proxy">l2proxy</option>
                               <option value="routed">routed</option>
@@ -676,8 +676,8 @@
                 </form>
               </div>
               <div class="modal-footer">
-                <button class="btn btn-secondary" type="button" data-dismiss="modal">Cancel</button>
-                <a class="btn btn-primary" href="#" onclick="addItem()" data-dismiss="modal">Submit</a>
+                <button class="btn btn-secondary" type="button" data-bs-dismiss="modal">Cancel</button>
+                <a class="btn btn-primary" href="#" onclick="addItem()" data-bs-dismiss="modal">Submit</a>
               </div>
             </div>
             <div class="tab-pane fade" id="json" role="tabpanel" aria-labelledby="json-tab">
@@ -692,8 +692,8 @@
                 </div>
               </div>
               <div class="modal-footer">
-                <button class="btn btn-secondary" type="button" data-dismiss="modal">Cancel</button>
-                <a class="btn btn-primary" href="#" onclick="createNetworkUsingJSON()" data-dismiss="modal">Submit</a>
+                <button class="btn btn-secondary" type="button" data-bs-dismiss="modal">Cancel</button>
+                <a class="btn btn-primary" href="#" onclick="createNetworkUsingJSON()" data-bs-dismiss="modal">Submit</a>
               </div>
             </div>
           </div>
@@ -708,7 +708,7 @@
     <div class="modal-content">
         <div class="modal-header">
           <h5 class="modal-title" id="exampleModalLabel">Edit Network</h5>
-          <button class="close" type="button" data-dismiss="modal" aria-label="Close">
+          <button class="close" type="button" data-bs-dismiss="modal" aria-label="Close">
             <span aria-hidden="true">×</span>
           </button>
         </div>
@@ -725,8 +725,8 @@
           </div>
         </div>
         <div class="modal-footer">
-          <button class="btn btn-secondary" type="button" data-dismiss="modal">Cancel</button>
-          <a class="btn btn-primary" href="#" onclick="updateNetwork()" data-dismiss="modal">Submit</a>
+          <button class="btn btn-secondary" type="button" data-bs-dismiss="modal">Cancel</button>
+          <a class="btn btn-primary" href="#" onclick="updateNetwork()" data-bs-dismiss="modal">Submit</a>
         </div>
     </div>
   </div>
@@ -738,7 +738,7 @@
     <div class="modal-content">
         <div class="modal-header">
           <h5 class="modal-title" id="renameNetworkModalLabel">Rename Network</h5>
-          <button class="close" type="button" data-dismiss="modal" aria-label="Close">
+          <button class="close" type="button" data-bs-dismiss="modal" aria-label="Close">
             <span aria-hidden="true">×</span>
           </button>
         </div>
@@ -757,8 +757,8 @@
           <input type="hidden" id ="networkToRename" name="networkToRename">
         </div>
         <div class="modal-footer">
-          <button class="btn btn-secondary" type="button" data-dismiss="modal">Cancel</button>
-          <a class="btn btn-primary" href="#" onclick="updateNetworkName()" data-dismiss="modal">Ok</a>
+          <button class="btn btn-secondary" type="button" data-bs-dismiss="modal">Cancel</button>
+          <a class="btn btn-primary" href="#" onclick="updateNetworkName()" data-bs-dismiss="modal">Ok</a>
         </div>
     </div>
   </div>

+ 2 - 2
lxconsole/templates/modals/operations.html

@@ -4,7 +4,7 @@
     <div class="modal-content">
         <div class="modal-header">
           <h5 class="modal-title" id="exampleModalLabel">View Operation</h5>
-          <button class="close" type="button" data-dismiss="modal" aria-label="Close">
+          <button class="close" type="button" data-bs-dismiss="modal" aria-label="Close">
             <span aria-hidden="true">×</span>
           </button>
         </div>
@@ -21,7 +21,7 @@
           </div>
         </div>
         <div class="modal-footer">
-          <button class="btn btn-secondary" type="button" data-dismiss="modal">Close</button>
+          <button class="btn btn-secondary" type="button" data-bs-dismiss="modal">Close</button>
         </div>
     </div>
   </div>

+ 13 - 13
lxconsole/templates/modals/profiles.html

@@ -4,17 +4,17 @@
       <div class="modal-content">
           <div class="modal-header">
             <h5 class="modal-title" id="exampleModalLabel">Create Profile</h5>
-            <button class="close" type="button" data-dismiss="modal" aria-label="Close">
+            <button class="close" type="button" data-bs-dismiss="modal" aria-label="Close">
               <span aria-hidden="true">×</span>
             </button>
           </div>
           <div class="modal-body">
             <ul class="nav nav-tabs" id="myTab" role="tablist">
               <li class="nav-item">
-                <a class="nav-link active" id="form-tab" data-toggle="tab" href="#form" role="tab" aria-controls="form" aria-selected="true">Form</a>
+                <a class="nav-link active" id="form-tab" data-bs-toggle="tab" href="#form" role="tab" aria-controls="form" aria-selected="true">Form</a>
               </li>
               <li class="nav-item">
-                <a class="nav-link" id="json-tab" data-toggle="tab" href="#json" role="tab" aria-controls="json" aria-selected="false">JSON</a>
+                <a class="nav-link" id="json-tab" data-bs-toggle="tab" href="#json" role="tab" aria-controls="json" aria-selected="false">JSON</a>
               </li>
             </ul>
             <div class="tab-content" id="myTabContent">
@@ -45,8 +45,8 @@
                   </div>
                 </form>
                 <div class="modal-footer">
-                  <button class="btn btn-secondary" type="button" data-dismiss="modal">Cancel</button>
-                  <a class="btn btn-primary" href="#" onclick="addItem()" data-dismiss="modal">Submit</a>
+                  <button class="btn btn-secondary" type="button" data-bs-dismiss="modal">Cancel</button>
+                  <a class="btn btn-primary" href="#" onclick="addItem()" data-bs-dismiss="modal">Submit</a>
                 </div>
               </div>
               <div class="tab-pane fade" id="json" role="tabpanel" aria-labelledby="json-tab">
@@ -61,8 +61,8 @@
                   </div>
                 </div>
                 <div class="modal-footer">
-                  <button class="btn btn-secondary" type="button" data-dismiss="modal">Cancel</button>
-                  <a class="btn btn-primary" href="#" onclick="createItemUsingJSON()" data-dismiss="modal">Submit</a>
+                  <button class="btn btn-secondary" type="button" data-bs-dismiss="modal">Cancel</button>
+                  <a class="btn btn-primary" href="#" onclick="createItemUsingJSON()" data-bs-dismiss="modal">Submit</a>
                 </div>
               </div>
             </div>
@@ -77,7 +77,7 @@
       <div class="modal-content">
           <div class="modal-header">
             <h5 class="modal-title" id="exampleModalLabel">Edit Profile</h5>
-            <button class="close" type="button" data-dismiss="modal" aria-label="Close">
+            <button class="close" type="button" data-bs-dismiss="modal" aria-label="Close">
               <span aria-hidden="true">×</span>
             </button>
           </div>
@@ -94,8 +94,8 @@
             </div>
           </div>
           <div class="modal-footer">
-            <button class="btn btn-secondary" type="button" data-dismiss="modal">Cancel</button>
-            <a class="btn btn-primary" href="#" onclick="updateItem()" data-dismiss="modal">Submit</a>
+            <button class="btn btn-secondary" type="button" data-bs-dismiss="modal">Cancel</button>
+            <a class="btn btn-primary" href="#" onclick="updateItem()" data-bs-dismiss="modal">Submit</a>
           </div>
       </div>
     </div>
@@ -107,7 +107,7 @@
       <div class="modal-content">
           <div class="modal-header">
             <h5 class="modal-title" id="renameItemModalLabel">Rename Profile</h5>
-            <button class="close" type="button" data-dismiss="modal" aria-label="Close">
+            <button class="close" type="button" data-bs-dismiss="modal" aria-label="Close">
               <span aria-hidden="true">×</span>
             </button>
           </div>
@@ -126,8 +126,8 @@
             <input type="hidden" id="profileToRename" name="profileToRename">
           </div>
           <div class="modal-footer">
-            <button class="btn btn-secondary" type="button" data-dismiss="modal">Cancel</button>
-            <a class="btn btn-primary" href="#" onclick="updateItemName()" data-dismiss="modal">Ok</a>
+            <button class="btn btn-secondary" type="button" data-bs-dismiss="modal">Cancel</button>
+            <a class="btn btn-primary" href="#" onclick="updateItemName()" data-bs-dismiss="modal">Ok</a>
           </div>
       </div>
     </div>

+ 40 - 40
lxconsole/templates/modals/projects.html

@@ -4,17 +4,17 @@
       <div class="modal-content">
         <div class="modal-header">
           <h5 class="modal-title" id="exampleModalLabel">Add Project</h5>
-          <button class="close" type="button" data-dismiss="modal" aria-label="Close">
+          <button class="close" type="button" data-bs-dismiss="modal" aria-label="Close">
             <span aria-hidden="true">×</span>
           </button>
         </div>
         <div class="modal-body">
           <ul class="nav nav-tabs" id="myTab" role="tablist">
             <li class="nav-item">
-              <a class="nav-link active" id="form-tab" data-toggle="tab" href="#form" role="tab" aria-controls="form" aria-selected="true">Form</a>
+              <a class="nav-link active" id="form-tab" data-bs-toggle="tab" href="#form" role="tab" aria-controls="form" aria-selected="true">Form</a>
             </li>
             <li class="nav-item">
-              <a class="nav-link" id="json-tab" data-toggle="tab" href="#json" role="tab" aria-controls="json" aria-selected="false">JSON</a>
+              <a class="nav-link" id="json-tab" data-bs-toggle="tab" href="#json" role="tab" aria-controls="json" aria-selected="false">JSON</a>
             </li>
           </ul>
           <div class="tab-content" id="myTabContent">
@@ -47,7 +47,7 @@
                   <label class="col-3 col-form-label text-right">features.images: </label>
                   <div class="col-7">
                     <div class="form-group">
-                      <select onchange="" class="form-control" name="features.images">
+                      <select onchange="" class="form-select" name="features.images">
                         <option value="">(not set)</option>
                         <option value="true">true</option>
                         <option value="false">false</option>
@@ -62,7 +62,7 @@
                   <label class="col-3 col-form-label text-right">features.networks: </label>
                   <div class="col-7">
                     <div class="form-group">
-                      <select onchange="" class="form-control" name="features.networks">
+                      <select onchange="" class="form-select" name="features.networks">
                         <option value="">(not set)</option>
                         <option value="true">true</option>
                         <option value="false">false</option>
@@ -77,7 +77,7 @@
                   <label class="col-3 col-form-label text-right">features.profiles: </label>
                   <div class="col-7">
                     <div class="form-group">
-                      <select onchange="" class="form-control" name="features.profiles">
+                      <select onchange="" class="form-select" name="features.profiles">
                         <option value="">(not set)</option>
                         <option value="true">true</option>
                         <option value="false">false</option>
@@ -92,7 +92,7 @@
                   <label class="col-3 col-form-label text-right">features.storage.volumes: </label>
                   <div class="col-7">
                     <div class="form-group">
-                      <select onchange="" class="form-control" name="features.storage.volumes">
+                      <select onchange="" class="form-select" name="features.storage.volumes">
                         <option value="">(not set)</option>
                         <option value="true">true</option>
                         <option value="false">false</option>
@@ -107,7 +107,7 @@
                   <label class="col-3 col-form-label text-right">features.storage.buckets: </label>
                   <div class="col-7">
                     <div class="form-group">
-                      <select onchange="" class="form-control" name="features.storage.buckets">
+                      <select onchange="" class="form-select" name="features.storage.buckets">
                         <option value="">(not set)</option>
                         <option value="true">true</option>
                         <option value="false">false</option>
@@ -121,7 +121,7 @@
                 <hr>
                 <div id="accordionConfigurationProperties">
                   <h2>
-                    <button class="btn btn-link collapsed" type="button" data-toggle="collapse" data-target="#configurationProperties" aria-expanded="false" aria-controls="configurationProperties">
+                    <button class="btn btn-link collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#configurationProperties" aria-expanded="false" aria-controls="configurationProperties">
                       Additional Configuration Properties
                     </button>
                   </h2> 
@@ -130,7 +130,7 @@
                       <label class="col-4 col-form-label text-right">backups.compression_algorithm: </label>
                       <div class="col-6">
                         <div class="form-group">
-                          <select onchange="" class="form-control" name="features.backups.compression_algorithm">
+                          <select onchange="" class="form-select" name="features.backups.compression_algorithm">
                             <option value="">(not set)</option>
                             <option value="bzip2">bzip2</option>
                             <option value="gzip">gzip</option>
@@ -148,7 +148,7 @@
                       <label class="col-4 col-form-label text-right">images.auto_update_cached: </label>
                       <div class="col-6">
                         <div class="form-group">
-                          <select onchange="" class="form-control" name="features.images.auto_update_cached">
+                          <select onchange="" class="form-select" name="features.images.auto_update_cached">
                             <option value="">(not set)</option>
                             <option value="true">true</option>
                             <option value="false">false</option>
@@ -174,7 +174,7 @@
                       <label class="col-4 col-form-label text-right">images.compression_algorithm: </label>
                       <div class="col-6">
                         <div class="form-group">
-                          <select  onchange="" class="form-control" name="features.images.compression_algorithm">
+                          <select  onchange="" class="form-select" name="features.images.compression_algorithm">
                             <option value="">(not set)</option>
                             <option value="bzip2">bzip2</option>
                             <option value="gzip">gzip</option>
@@ -302,7 +302,7 @@
                       <label class="col-4 col-form-label text-right">restricted: </label>
                       <div class="col-6">
                         <div class="form-group">
-                          <select id="addModalRestrictedInput" onchange="changeRestrictedOptionsDisplay()" class="form-control" name="restricted">
+                          <select id="addModalRestrictedInput" onchange="changeRestrictedOptionsDisplay()" class="form-select" name="restricted">
                             <option value="">(not set)</option>
                             <option value="true">true</option>
                             <option value="false">false</option>
@@ -317,7 +317,7 @@
                       <label class="col-4 col-form-label text-right">restricted.backups: </label>
                       <div class="col-6">
                         <div class="form-group">
-                          <select onchange="" class="form-control" name="restricted.backups">
+                          <select onchange="" class="form-select" name="restricted.backups">
                             <option value="">(not set)</option>
                             <option value="allow">allow</option>
                             <option value="block">block</option>
@@ -332,7 +332,7 @@
                       <label class="col-4 col-form-label text-right">restricted.cluster.target: </label>
                       <div class="col-6">
                         <div class="form-group">
-                          <select onchange="" class="form-control" name="restricted.cluster.target">
+                          <select onchange="" class="form-select" name="restricted.cluster.target">
                             <option value="">(not set)</option>
                             <option value="allow">allow</option>
                             <option value="block">block</option>
@@ -347,7 +347,7 @@
                       <label class="col-4 col-form-label text-right">restricted.containers.lowlevel: </label>
                       <div class="col-6">
                         <div class="form-group">
-                          <select onchange="" class="form-control" name="restricted.containers.lowlevel">
+                          <select onchange="" class="form-select" name="restricted.containers.lowlevel">
                             <option value="">(not set)</option>
                             <option value="allow">allow</option>
                             <option value="block">block</option>
@@ -362,7 +362,7 @@
                       <label class="col-4 col-form-label text-right">restricted.containers.nesting: </label>
                       <div class="col-6">
                         <div class="form-group">
-                          <select onchange="" class="form-control" name="restricted.containers.nesting">
+                          <select onchange="" class="form-select" name="restricted.containers.nesting">
                             <option value="">(not set)</option>
                             <option value="allow">allow</option>
                             <option value="block">block</option>
@@ -377,7 +377,7 @@
                       <label class="col-4 col-form-label text-right">restricted.containers.privilege: </label>
                       <div class="col-6">
                         <div class="form-group">
-                          <select onchange="" class="form-control" name="restricted.containers.privilege">
+                          <select onchange="" class="form-select" name="restricted.containers.privilege">
                             <option value="">(not set)</option>
                             <option value="allow">allow</option>
                             <option value="isolated">isolated</option>
@@ -393,7 +393,7 @@
                       <label class="col-4 col-form-label text-right">restricted.devices.disk: </label>
                       <div class="col-6">
                         <div class="form-group">
-                          <select onchange="" class="form-control" name="restricted.devices.disk">
+                          <select onchange="" class="form-select" name="restricted.devices.disk">
                             <option value="">(not set)</option>
                             <option value="allow">allow</option>
                             <option value="block">block</option>
@@ -409,7 +409,7 @@
                       <label class="col-4 col-form-label text-right">restricted.devices.gpu: </label>
                       <div class="col-6">
                         <div class="form-group">
-                          <select onchange="" class="form-control" name="restricted.devices.gpu">
+                          <select onchange="" class="form-select" name="restricted.devices.gpu">
                             <option value="">(not set)</option>
                             <option value="allow">allow</option>
                             <option value="block">block</option>
@@ -424,7 +424,7 @@
                       <label class="col-4 col-form-label text-right">restricted.devices.infiniband: </label>
                       <div class="col-6">
                         <div class="form-group">
-                          <select onchange="" class="form-control" name="restricted.devices.infiniband">
+                          <select onchange="" class="form-select" name="restricted.devices.infiniband">
                             <option value="">(not set)</option>
                             <option value="allow">allow</option>
                             <option value="block">block</option>
@@ -439,7 +439,7 @@
                       <label class="col-4 col-form-label text-right">restricted.devices.nic: </label>
                       <div class="col-6">
                         <div class="form-group">
-                          <select onchange="" class="form-control" name="restricted.devices.nic">
+                          <select onchange="" class="form-select" name="restricted.devices.nic">
                             <option value="">(not set)</option>
                             <option value="allow">allow</option>
                             <option value="block">block</option>
@@ -455,7 +455,7 @@
                       <label class="col-4 col-form-label text-right">restricted.devices.pci: </label>
                       <div class="col-6">
                         <div class="form-group">
-                          <select onchange="" class="form-control" name="restricted.devices.pci">
+                          <select onchange="" class="form-select" name="restricted.devices.pci">
                             <option value="">(not set)</option>
                             <option value="allow">allow</option>
                             <option value="block">block</option>
@@ -470,7 +470,7 @@
                       <label class="col-4 col-form-label text-right">restricted.devices.proxy: </label>
                       <div class="col-6">
                         <div class="form-group">
-                          <select onchange="" class="form-control" name="restricted.devices.proxy">
+                          <select onchange="" class="form-select" name="restricted.devices.proxy">
                             <option value="">(not set)</option>
                             <option value="allow">allow</option>
                             <option value="block">block</option>
@@ -485,7 +485,7 @@
                       <label class="col-4 col-form-label text-right">restricted.devices.unix-block: </label>
                       <div class="col-6">
                         <div class="form-group">
-                          <select onchange="" class="form-control" name="restricted.devices.unix-block">
+                          <select onchange="" class="form-select" name="restricted.devices.unix-block">
                             <option value="">(not set)</option>
                             <option value="allow">allow</option>
                             <option value="block">block</option>
@@ -500,7 +500,7 @@
                       <label class="col-4 col-form-label text-right">restricted.devices.unix-char: </label>
                       <div class="col-6">
                         <div class="form-group">
-                          <select onchange="" class="form-control" name="restricted.devices.unix-char">
+                          <select onchange="" class="form-select" name="restricted.devices.unix-char">
                             <option value="">(not set)</option>
                             <option value="allow">allow</option>
                             <option value="block">block</option>
@@ -515,7 +515,7 @@
                       <label class="col-4 col-form-label text-right">restricted.devices.unix-hotplug: </label>
                       <div class="col-6">
                         <div class="form-group">
-                          <select onchange="" class="form-control" name="restricted.devices.unix-hotplug">
+                          <select onchange="" class="form-select" name="restricted.devices.unix-hotplug">
                             <option value="">(not set)</option>
                             <option value="allow">allow</option>
                             <option value="block">block</option>
@@ -530,7 +530,7 @@
                       <label class="col-4 col-form-label text-right">restricted.devices.usb: </label>
                       <div class="col-6">
                         <div class="form-group">
-                          <select onchange="" class="form-control" name="restricted.devices.usb">
+                          <select onchange="" class="form-select" name="restricted.devices.usb">
                             <option value="">(not set)</option>
                             <option value="allow">allow</option>
                             <option value="block">block</option>
@@ -567,7 +567,7 @@
                       <label class="col-4 col-form-label text-right">restricted.snapshots: </label>
                       <div class="col-6">
                         <div class="form-group">
-                          <select onchange="" class="form-control" name="restricted.snapshots">
+                          <select onchange="" class="form-select" name="restricted.snapshots">
                             <option value="">(not set)</option>
                             <option value="allow">allow</option>
                             <option value="block">block</option>
@@ -582,7 +582,7 @@
                       <label class="col-4 col-form-label text-right">restricted.virtual-machines.lowlevel: </label>
                       <div class="col-6">
                         <div class="form-group">
-                          <select onchange="" class="form-control" name="restricted.virtual-machines.lowlevel">
+                          <select onchange="" class="form-select" name="restricted.virtual-machines.lowlevel">
                             <option value="">(not set)</option>
                             <option value="allow">allow</option>
                             <option value="block">block</option>
@@ -596,8 +596,8 @@
                   </div>
                 </div>
                 <div class="modal-footer">
-                  <button class="btn btn-secondary" type="button" data-dismiss="modal">Cancel</button>
-                  <a class="btn btn-primary" onclick="addItem()" href="#" data-dismiss="modal">Submit</a>
+                  <button class="btn btn-secondary" type="button" data-bs-dismiss="modal">Cancel</button>
+                  <a class="btn btn-primary" onclick="addItem()" href="#" data-bs-dismiss="modal">Submit</a>
                 </div>
               </form>
             </div>
@@ -613,8 +613,8 @@
                 </div>
               </div>
               <div class="modal-footer">
-                <button class="btn btn-secondary" type="button" data-dismiss="modal">Cancel</button>
-                <a class="btn btn-primary" href="#" onclick="createProjectUsingJSON()" data-dismiss="modal">Submit</a>
+                <button class="btn btn-secondary" type="button" data-bs-dismiss="modal">Cancel</button>
+                <a class="btn btn-primary" href="#" onclick="createProjectUsingJSON()" data-bs-dismiss="modal">Submit</a>
               </div>
             </div>
           </div>
@@ -629,7 +629,7 @@
       <div class="modal-content">
           <div class="modal-header">
             <h5 class="modal-title" id="exampleModalLabel">Edit Project</h5>
-            <button class="close" type="button" data-dismiss="modal" aria-label="Close">
+            <button class="close" type="button" data-bs-dismiss="modal" aria-label="Close">
               <span aria-hidden="true">×</span>
             </button>
           </div>
@@ -646,8 +646,8 @@
             </div>
           </div>
           <div class="modal-footer">
-            <button class="btn btn-secondary" type="button" data-dismiss="modal">Cancel</button>
-            <a class="btn btn-primary" href="#" onclick="updateProject()" data-dismiss="modal">Submit</a>
+            <button class="btn btn-secondary" type="button" data-bs-dismiss="modal">Cancel</button>
+            <a class="btn btn-primary" href="#" onclick="updateProject()" data-bs-dismiss="modal">Submit</a>
           </div>
       </div>
     </div>
@@ -659,7 +659,7 @@
       <div class="modal-content">
           <div class="modal-header">
             <h5 class="modal-title" id="renameProjectModalLabel">Rename Project</h5>
-            <button class="close" type="button" data-dismiss="modal" aria-label="Close">
+            <button class="close" type="button" data-bs-dismiss="modal" aria-label="Close">
               <span aria-hidden="true">×</span>
             </button>
           </div>
@@ -678,8 +678,8 @@
             <input type="hidden" id ="projectToRename" name="projectToRename">
           </div>
           <div class="modal-footer">
-            <button class="btn btn-secondary" type="button" data-dismiss="modal">Cancel</button>
-            <a class="btn btn-primary" href="#" onclick="updateProjectName()" data-dismiss="modal">Ok</a>
+            <button class="btn btn-secondary" type="button" data-bs-dismiss="modal">Cancel</button>
+            <a class="btn btn-primary" href="#" onclick="updateProjectName()" data-bs-dismiss="modal">Ok</a>
           </div>
       </div>
     </div>

+ 4 - 4
lxconsole/templates/modals/roles.html

@@ -4,7 +4,7 @@
     <div class="modal-content">
       <div class="modal-header">
         <h5 class="modal-title" id="exampleModalLabel">Add Role</h5>
-        <button class="close" type="button" data-dismiss="modal" aria-label="Close">
+        <button class="close" type="button" data-bs-dismiss="modal" aria-label="Close">
           <span aria-hidden="true">×</span>
         </button>
       </div>
@@ -14,7 +14,7 @@
           <label class="col-3 col-form-label text-right">Role:</label>
           <div class="col-7 text-right">
             <div class="form-group">
-              <select id="roleIdForAddRoleInput" class="form-control" name="roleIdForAddRoleInput">
+              <select id="roleIdForAddRoleInput" class="form-select" name="roleIdForAddRoleInput">
               </select>
             </div>
           </div>
@@ -27,8 +27,8 @@
 
       </div> <!-- End Modal Body-->
       <div class="modal-footer">
-        <button class="btn btn-secondary" type="button" data-dismiss="modal">Cancel</button>
-        <a class="btn btn-primary" href="#" onclick="addRole()" data-dismiss="modal">Submit</a>
+        <button class="btn btn-secondary" type="button" data-bs-dismiss="modal">Cancel</button>
+        <a class="btn btn-primary" href="#" onclick="addRole()" data-bs-dismiss="modal">Submit</a>
       </div>
     </div>
   </div>

+ 15 - 15
lxconsole/templates/modals/servers.html

@@ -4,7 +4,7 @@
     <div class="modal-content">
       <div class="modal-header">
         <h5 class="modal-title" id="exampleModalLabel">Add LXD Server</h5>
-        <button class="close" type="button" data-dismiss="modal" aria-label="Close">
+        <button class="close" type="button" data-bs-dismiss="modal" aria-label="Close">
           <span aria-hidden="true">×</span>
         </button>
       </div>
@@ -54,7 +54,7 @@
           <label class="col-3 col-form-label text-right">SSL Verify: </label>
           <div class="col-7">
             <div class="form-group">                  
-              <select id="addModalSSLVerifyInput" class="form-control" name="addModalSSLVerifyInput">
+              <select id="addModalSSLVerifyInput" class="form-select" name="addModalSSLVerifyInput">
                 <option value="true">True</option>
                 <option value="false" selected>False</option>
               </select>
@@ -67,8 +67,8 @@
 
       </div> <!-- End Modal Body-->
       <div class="modal-footer">
-        <button class="btn btn-secondary" type="button" data-dismiss="modal">Cancel</button>
-        <a class="btn btn-primary" href="#" onclick="addServer()" data-dismiss="modal">Submit</a>
+        <button class="btn btn-secondary" type="button" data-bs-dismiss="modal">Cancel</button>
+        <a class="btn btn-primary" href="#" onclick="addServer()" data-bs-dismiss="modal">Submit</a>
       </div>
     </div>
   </div>
@@ -80,7 +80,7 @@
     <div class="modal-content">
       <div class="modal-header">
         <h5 class="modal-title" id="exampleModalLabel">Edit Server</h5>
-        <button class="close" type="button" data-dismiss="modal" aria-label="Close">
+        <button class="close" type="button" data-bs-dismiss="modal" aria-label="Close">
           <span aria-hidden="true">×</span>
         </button>
       </div>
@@ -126,7 +126,7 @@
           <label class="col-3 col-form-label text-right">SSL Verify: </label>
           <div class="col-7">
             <div class="form-group">                  
-              <select id="editModalSSLVerifyInput" class="form-control" name="editModalSSLVerifyInput">
+              <select id="editModalSSLVerifyInput" class="form-select" name="editModalSSLVerifyInput">
                 <option value="true">True</option>
                 <option value="false" selected>False</option>
               </select>
@@ -141,8 +141,8 @@
 
       </div> <!-- End Modal Body-->
       <div class="modal-footer">
-        <button class="btn btn-secondary" type="button" data-dismiss="modal">Cancel</button>
-        <a class="btn btn-primary" href="#" onclick="updateServer()" data-dismiss="modal">Submit</a>
+        <button class="btn btn-secondary" type="button" data-bs-dismiss="modal">Cancel</button>
+        <a class="btn btn-primary" href="#" onclick="updateServer()" data-bs-dismiss="modal">Submit</a>
       </div>
     </div>
   </div>
@@ -154,7 +154,7 @@
     <div class="modal-content">
       <div class="modal-header">
         <h5 class="modal-title" id="exampleModalLabel">Instructions</h5>
-        <button class="close" type="button" data-dismiss="modal" aria-label="Close">
+        <button class="close" type="button" data-bs-dismiss="modal" aria-label="Close">
           <span aria-hidden="true">×</span>
         </button>
       </div>
@@ -177,7 +177,7 @@
         </div>
       </div>
       <div class="modal-footer">
-        <button class="btn btn-secondary" type="button" data-dismiss="modal">Dismiss</button>
+        <button class="btn btn-secondary" type="button" data-bs-dismiss="modal">Dismiss</button>
       </div>
     </div>
   </div>
@@ -189,7 +189,7 @@
     <div class="modal-content">
       <div class="modal-header">
         <h5 class="modal-title" id="exampleModalLabel">LXD Client Certificate</h5>
-        <button class="close" type="button" data-dismiss="modal" aria-label="Close">
+        <button class="close" type="button" data-bs-dismiss="modal" aria-label="Close">
           <span aria-hidden="true">×</span>
         </button>
       </div>
@@ -201,7 +201,7 @@
         </div>
       </div>
       <div class="modal-footer">
-        <button class="btn btn-secondary" type="button" data-dismiss="modal">Dismiss</button>
+        <button class="btn btn-secondary" type="button" data-bs-dismiss="modal">Dismiss</button>
       </div>
     </div>
   </div>
@@ -213,14 +213,14 @@
     <div class="modal-content">
       <div class="modal-header">
         <h5 class="modal-title" id="exampleModalLabel">Remove Server</h5>
-        <button class="close" type="button" data-dismiss="modal" aria-label="Close">
+        <button class="close" type="button" data-bs-dismiss="modal" aria-label="Close">
           <span aria-hidden="true">×</span>
         </button>
       </div>
       <div class="modal-body">Are you sure you want to remove this server?</div>
       <div class="modal-footer">
-        <button class="btn btn-secondary" type="button" data-dismiss="modal">Cancel</button>
-        <a class="btn btn-primary" href="#" onclick="deleteServer()" data-dismiss="modal">Yes</a>
+        <button class="btn btn-secondary" type="button" data-bs-dismiss="modal">Cancel</button>
+        <a class="btn btn-primary" href="#" onclick="deleteServer()" data-bs-dismiss="modal">Yes</a>
       </div>
     </div>
   </div>

+ 3 - 3
lxconsole/templates/modals/simplestreams.html

@@ -4,7 +4,7 @@
     <div class="modal-content">
       <div class="modal-header">
         <h5 class="modal-title" id="exampleModalLabel">Add Simplestreams Host</h5>
-        <button class="close" type="button" data-dismiss="modal" aria-label="Close">
+        <button class="close" type="button" data-bs-dismiss="modal" aria-label="Close">
           <span aria-hidden="true">×</span>
         </button>
       </div>
@@ -38,8 +38,8 @@
 
       </div> <!-- End Modal Body-->
       <div class="modal-footer">
-        <button class="btn btn-secondary" type="button" data-dismiss="modal">Cancel</button>
-        <a class="btn btn-primary" href="#" onclick="addItem()" data-dismiss="modal">Submit</a>
+        <button class="btn btn-secondary" type="button" data-bs-dismiss="modal">Cancel</button>
+        <a class="btn btn-primary" href="#" onclick="addItem()" data-bs-dismiss="modal">Submit</a>
       </div>
     </div>
   </div>

+ 21 - 21
lxconsole/templates/modals/storage-pools.html

@@ -4,17 +4,17 @@
     <div class="modal-content">
         <div class="modal-header">
           <h5 class="modal-title" id="exampleModalLabel">Create Storage Pool</h5>
-          <button class="close" type="button" data-dismiss="modal" aria-label="Close">
+          <button class="close" type="button" data-bs-dismiss="modal" aria-label="Close">
             <span aria-hidden="true">×</span>
           </button>
         </div>
         <div class="modal-body">
           <ul class="nav nav-tabs" id="myTab" role="tablist">
             <li class="nav-item">
-              <a class="nav-link active" id="form-tab" data-toggle="tab" href="#form" role="tab" aria-controls="form" aria-selected="true">Form</a>
+              <a class="nav-link active" id="form-tab" data-bs-toggle="tab" href="#form" role="tab" aria-controls="form" aria-selected="true">Form</a>
             </li>
             <li class="nav-item">
-              <a class="nav-link" id="json-tab" data-toggle="tab" href="#json" role="tab" aria-controls="json" aria-selected="false">JSON</a>
+              <a class="nav-link" id="json-tab" data-bs-toggle="tab" href="#json" role="tab" aria-controls="json" aria-selected="false">JSON</a>
             </li>
           </ul>
           <div class="tab-content" id="myTabContent">
@@ -47,7 +47,7 @@
                   <label class="col-3 col-form-label text-right">Driver: <span class="text-danger">*</span></label>
                   <div class="col-7">
                     <div class="form-group">
-                      <select id="storagePoolDriverInput" class="form-control" onclick="changeStoragePoolDriverInput()" name="driver">
+                      <select id="storagePoolDriverInput" class="form-select" onclick="changeStoragePoolDriverInput()" name="driver">
                         <option value="btrfs">btrfs</option>
                         <option value="ceph">ceph</option>
                         <option value="cephfs">cephfs</option>
@@ -86,7 +86,7 @@
                 <hr>
                 <div id="accordionConfigurationProperties">
                   <h2>
-                    <button class="btn btn-link collapsed" type="button" data-toggle="collapse" data-target="#configurationProperties" aria-expanded="false" aria-controls="configurationProperties">
+                    <button class="btn btn-link collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#configurationProperties" aria-expanded="false" aria-controls="configurationProperties">
                       Configuration Properties
                     </button>
                   </h2> 
@@ -118,7 +118,7 @@
                       <label class="col-4 col-form-label text-right">ceph.osd.force_reuse: </label>
                       <div class="col-6">
                         <div class="form-group">
-                          <select onchange="" class="form-control" name="ceph.osd.force_reuse">
+                          <select onchange="" class="form-select" name="ceph.osd.force_reuse">
                             <option value="">(not set)</option>
                             <option value="true">true</option>
                             <option value="false">false</option>
@@ -166,7 +166,7 @@
                       <label class="col-4 col-form-label text-right">ceph.rbd.clone_copy: </label>
                       <div class="col-6">
                         <div class="form-group">
-                          <select onchange="" class="form-control" name="ceph.rbd.clone_copy">
+                          <select onchange="" class="form-select" name="ceph.rbd.clone_copy">
                             <option value="">(not set)</option>
                             <option value="true">true</option>
                             <option value="false">false</option>
@@ -247,7 +247,7 @@
                       <label class="col-4 col-form-label text-right">lvm.use_thinpool: </label>
                       <div class="col-6">
                         <div class="form-group">
-                          <select onchange="" class="form-control" name="lvm.use_thinpool">
+                          <select onchange="" class="form-select" name="lvm.use_thinpool">
                             <option value="">(not set)</option>
                             <option value="true">true</option>
                             <option value="false">false</option>
@@ -273,7 +273,7 @@
                       <label class="col-4 col-form-label text-right">lvm.vg.force_reuse: </label>
                       <div class="col-6">
                         <div class="form-group">
-                          <select onchange="" class="form-control" name="lvm.vg.force_reuse">
+                          <select onchange="" class="form-select" name="lvm.vg.force_reuse">
                             <option value="">(not set)</option>
                             <option value="true">true</option>
                             <option value="false">false</option>
@@ -321,7 +321,7 @@
                       <label class="col-4 col-form-label text-right">rsync.compression: </label>
                       <div class="col-6">
                         <div class="form-group">
-                          <select onchange="" class="form-control" name="rsync.compression">
+                          <select onchange="" class="form-select" name="rsync.compression">
                             <option value="">(not set)</option>
                             <option value="true">true</option>
                             <option value="false">false</option>
@@ -347,7 +347,7 @@
                       <label class="col-4 col-form-label text-right">volatile.pool.pristine: </label>
                       <div class="col-6">
                         <div class="form-group">
-                          <select onchange="" class="form-control" name="volatile.pool.pristine">
+                          <select onchange="" class="form-select" name="volatile.pool.pristine">
                             <option value="">(not set)</option>
                             <option value="true">true</option>
                             <option value="false">false</option>
@@ -395,7 +395,7 @@
                       <label class="col-4 col-form-label text-right">volume.zfs.remove_snapshots: </label>
                       <div class="col-6">
                         <div class="form-group">
-                          <select onchange="" class="form-control" name="volume.zfs.remove_snapshots">
+                          <select onchange="" class="form-select" name="volume.zfs.remove_snapshots">
                             <option value="">(not set)</option>
                             <option value="true">true</option>
                             <option value="false">false</option>
@@ -410,7 +410,7 @@
                       <label class="col-4 col-form-label text-right">volume.zfs.use_refquota: </label>
                       <div class="col-6">
                         <div class="form-group">
-                          <select onchange="" class="form-control" name="volume.zfs.use_refquota ">
+                          <select onchange="" class="form-select" name="volume.zfs.use_refquota ">
                             <option value="">(not set)</option>
                             <option value="true">true</option>
                             <option value="false">false</option>
@@ -425,7 +425,7 @@
                       <label class="col-4 col-form-label text-right">zfs.clone_copy: </label>
                       <div class="col-6">
                         <div class="form-group">
-                          <select onchange="" class="form-control" name="zfs.clone_copy">
+                          <select onchange="" class="form-select" name="zfs.clone_copy">
                             <option value="">(not set)</option>
                             <option value="true">true</option>
                             <option value="false">false</option>
@@ -452,8 +452,8 @@
                 </div>
               </form>
               <div class="modal-footer">
-                <button class="btn btn-secondary" type="button" data-dismiss="modal">Cancel</button>
-                <a class="btn btn-primary" href="#" onclick="addItem()" data-dismiss="modal">Submit</a>
+                <button class="btn btn-secondary" type="button" data-bs-dismiss="modal">Cancel</button>
+                <a class="btn btn-primary" href="#" onclick="addItem()" data-bs-dismiss="modal">Submit</a>
               </div>
             </div>
             <div class="tab-pane fade" id="json" role="tabpanel" aria-labelledby="json-tab">
@@ -468,8 +468,8 @@
                 </div>
               </div>
               <div class="modal-footer">
-                <button class="btn btn-secondary" type="button" data-dismiss="modal">Cancel</button>
-                <a class="btn btn-primary" href="#" onclick="createStoragePoolUsingJSON()" data-dismiss="modal">Submit</a>
+                <button class="btn btn-secondary" type="button" data-bs-dismiss="modal">Cancel</button>
+                <a class="btn btn-primary" href="#" onclick="createStoragePoolUsingJSON()" data-bs-dismiss="modal">Submit</a>
               </div>
             </div>
           </div>
@@ -484,7 +484,7 @@
     <div class="modal-content">
         <div class="modal-header">
           <h5 class="modal-title" id="exampleModalLabel">Edit Storage Pool</h5>
-          <button class="close" type="button" data-dismiss="modal" aria-label="Close">
+          <button class="close" type="button" data-bs-dismiss="modal" aria-label="Close">
             <span aria-hidden="true">×</span>
           </button>
         </div>
@@ -501,8 +501,8 @@
           </div>
         </div>
         <div class="modal-footer">
-          <button class="btn btn-secondary" type="button" data-dismiss="modal">Cancel</button>
-          <a class="btn btn-primary" href="#" onclick="updateStoragePool()" data-dismiss="modal">Submit</a>
+          <button class="btn btn-secondary" type="button" data-bs-dismiss="modal">Cancel</button>
+          <a class="btn btn-primary" href="#" onclick="updateStoragePool()" data-bs-dismiss="modal">Submit</a>
         </div>
     </div>
   </div>

+ 17 - 17
lxconsole/templates/modals/storage-volumes.html

@@ -4,17 +4,17 @@
     <div class="modal-content">
         <div class="modal-header">
           <h5 class="modal-title" id="exampleModalLabel">Create Storage Volume</h5>
-          <button class="close" type="button" data-dismiss="modal" aria-label="Close">
+          <button class="close" type="button" data-bs-dismiss="modal" aria-label="Close">
             <span aria-hidden="true">×</span>
           </button>
         </div>
         <div class="modal-body">
           <ul class="nav nav-tabs" id="myTab" role="tablist">
             <li class="nav-item">
-              <a class="nav-link active" id="form-tab" data-toggle="tab" href="#form" role="tab" aria-controls="form" aria-selected="true">Form</a>
+              <a class="nav-link active" id="form-tab" data-bs-toggle="tab" href="#form" role="tab" aria-controls="form" aria-selected="true">Form</a>
             </li>
             <li class="nav-item">
-              <a class="nav-link" id="json-tab" data-toggle="tab" href="#json" role="tab" aria-controls="json" aria-selected="false">JSON</a>
+              <a class="nav-link" id="json-tab" data-bs-toggle="tab" href="#json" role="tab" aria-controls="json" aria-selected="false">JSON</a>
             </li>
           </ul>
           <div class="tab-content" id="myTabContent">
@@ -47,7 +47,7 @@
                   <label class="col-3 col-form-label text-right">Type: <span class="text-danger">*</span></label>
                   <div class="col-7">
                     <div class="form-group">
-                      <select id="storageVolumeContentTypeInput" class="form-control" name="type">
+                      <select id="storageVolumeContentTypeInput" class="form-select" name="type">
                         <option value="custom" selected>custom</option>
                       </select>
                     </div>
@@ -60,7 +60,7 @@
                   <label class="col-3 col-form-label text-right">Content Type: <span class="text-danger">*</span></label>
                   <div class="col-7">
                     <div class="form-group">
-                      <select id="storageVolumeContentTypeInput" class="form-control" name="content_type">
+                      <select id="storageVolumeContentTypeInput" class="form-select" name="content_type">
                         <option value="block" selected>block</option>
                         <option value="filesystem">filesystem</option>
                       </select>
@@ -84,7 +84,7 @@
                 <hr>
                 <div id="accordionConfigurationProperties">
                   <h2>
-                    <button class="btn btn-link collapsed" type="button" data-toggle="collapse" data-target="#configurationProperties" aria-expanded="false" aria-controls="configurationProperties">
+                    <button class="btn btn-link collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#configurationProperties" aria-expanded="false" aria-controls="configurationProperties">
                       Configuration Properties
                     </button>
                   </h2> 
@@ -115,7 +115,7 @@
                       <label class="col-4 col-form-label text-right">security.shifted: </label>
                       <div class="col-6">
                         <div class="form-group">
-                          <select onchange="" class="form-control" name="security.shifted">
+                          <select onchange="" class="form-select" name="security.shifted">
                             <option value="">(not set)</option>
                             <option value="true">true</option>
                             <option value="false">false</option>
@@ -130,7 +130,7 @@
                       <label class="col-4 col-form-label text-right">security.unmapped: </label>
                       <div class="col-6">
                         <div class="form-group">
-                          <select onchange="" class="form-control" name="security.unmapped">
+                          <select onchange="" class="form-select" name="security.unmapped">
                             <option value="">(not set)</option>
                             <option value="true">true</option>
                             <option value="false">false</option>
@@ -200,7 +200,7 @@
                       <label class="col-4 col-form-label text-right">zfs.remove_snapshots: </label>
                       <div class="col-6">
                         <div class="form-group">
-                          <select onchange="" class="form-control" name="zfs.remove_snapshots">
+                          <select onchange="" class="form-select" name="zfs.remove_snapshots">
                             <option value="">(not set)</option>
                             <option value="true">true</option>
                             <option value="false">false</option>
@@ -215,7 +215,7 @@
                       <label class="col-4 col-form-label text-right">zfs.use_refquota: </label>
                       <div class="col-6">
                         <div class="form-group">
-                          <select onchange="" class="form-control" name="zfs.use_refquota">
+                          <select onchange="" class="form-select" name="zfs.use_refquota">
                             <option value="">(not set)</option>
                             <option value="true">true</option>
                             <option value="false">false</option>
@@ -231,8 +231,8 @@
   
               </form>
               <div class="modal-footer">
-                <button class="btn btn-secondary" type="button" data-dismiss="modal">Cancel</button>
-                <a class="btn btn-primary" href="#" onclick="addItem()" data-dismiss="modal">Submit</a>
+                <button class="btn btn-secondary" type="button" data-bs-dismiss="modal">Cancel</button>
+                <a class="btn btn-primary" href="#" onclick="addItem()" data-bs-dismiss="modal">Submit</a>
               </div>
             </div>
             <div class="tab-pane fade" id="json" role="tabpanel" aria-labelledby="json-tab">
@@ -247,8 +247,8 @@
                 </div>
               </div>
               <div class="modal-footer">
-                <button class="btn btn-secondary" type="button" data-dismiss="modal">Cancel</button>
-                <a class="btn btn-primary" href="#" onclick="createStorageVolumeUsingJSON()" data-dismiss="modal">Submit</a>
+                <button class="btn btn-secondary" type="button" data-bs-dismiss="modal">Cancel</button>
+                <a class="btn btn-primary" href="#" onclick="createStorageVolumeUsingJSON()" data-bs-dismiss="modal">Submit</a>
               </div>
             </div>
           </div>
@@ -263,7 +263,7 @@
     <div class="modal-content">
         <div class="modal-header">
           <h5 class="modal-title" id="exampleModalLabel">Edit Storage Volume</h5>
-          <button class="close" type="button" data-dismiss="modal" aria-label="Close">
+          <button class="close" type="button" data-bs-dismiss="modal" aria-label="Close">
             <span aria-hidden="true">×</span>
           </button>
         </div>
@@ -280,8 +280,8 @@
           </div>
         </div>
         <div class="modal-footer">
-          <button class="btn btn-secondary" type="button" data-dismiss="modal">Cancel</button>
-          <a class="btn btn-primary" href="#" onclick="updateStorageVolume()" data-dismiss="modal">Submit</a>
+          <button class="btn btn-secondary" type="button" data-bs-dismiss="modal">Cancel</button>
+          <a class="btn btn-primary" href="#" onclick="updateStorageVolume()" data-bs-dismiss="modal">Submit</a>
         </div>
     </div>
   </div>

+ 17 - 17
lxconsole/templates/modals/users.html

@@ -4,7 +4,7 @@
     <div class="modal-content">
       <div class="modal-header">
         <h5 class="modal-title" id="exampleModalLabel">Create User</h5>
-        <button class="close" type="button" data-dismiss="modal" aria-label="Close">
+        <button class="close" type="button" data-bs-dismiss="modal" aria-label="Close">
           <span aria-hidden="true">×</span>
         </button>
       </div>
@@ -75,7 +75,7 @@
             <label class="col-3 col-form-label text-right">Group: </label>
             <div class="col-7">
               <div class="form-group">
-                <select id="groupInput" class="form-control" required="required"  name="group_id">
+                <select id="groupInput" class="form-select" required="required"  name="group_id">
                   <option value="4">Auditor</option>
                 </select>
               </div>
@@ -89,8 +89,8 @@
 
       </div> <!-- End Modal Body-->
       <div class="modal-footer">
-        <button class="btn btn-secondary" type="button" data-dismiss="modal">Cancel</button>
-        <a class="btn btn-primary" href="#" onclick="addUser()" data-dismiss="modal">Submit</a>
+        <button class="btn btn-secondary" type="button" data-bs-dismiss="modal">Cancel</button>
+        <a class="btn btn-primary" href="#" onclick="addUser()" data-bs-dismiss="modal">Submit</a>
       </div>
     </div>
   </div>
@@ -102,20 +102,20 @@
     <div class="modal-content">
         <div class="modal-header">
           <h5 class="modal-title" id="exampleModalLabel">Edit User</h5>
-          <button class="close" type="button" data-dismiss="modal" aria-label="Close">
+          <button class="close" type="button" data-bs-dismiss="modal" aria-label="Close">
             <span aria-hidden="true">×</span>
           </button>
         </div>
         <div class="modal-body">
           <ul class="nav nav-tabs" id="myTab" role="tablist">
             <li class="nav-item">
-              <a class="nav-link active" id="user-tab" data-toggle="tab" href="#user-profile" role="tab" aria-controls="user-profile" aria-selected="true">Profile</a>
+              <a class="nav-link active" id="user-tab" data-bs-toggle="tab" href="#user-profile" role="tab" aria-controls="user-profile" aria-selected="true">Profile</a>
             </li>
             <li class="nav-item">
-              <a class="nav-link" id="group-tab" data-toggle="tab" href="#user-group" role="tab" aria-controls="user-group" aria-selected="false">Groups</a>
+              <a class="nav-link" id="group-tab" data-bs-toggle="tab" href="#user-group" role="tab" aria-controls="user-group" aria-selected="false">Groups</a>
             </li>
             <li class="nav-item">
-              <a class="nav-link" id="password-tab" data-toggle="tab" href="#user-password" role="tab" aria-controls="user-password" aria-selected="false">Password</a>
+              <a class="nav-link" id="password-tab" data-bs-toggle="tab" href="#user-password" role="tab" aria-controls="user-password" aria-selected="false">Password</a>
             </li>
           </ul>
           <div class="tab-content" id="myTabContent">
@@ -175,8 +175,8 @@
                 <input type="hidden" id="idEditInput" name="id">
               </form>
               <div class="modal-footer">
-                <button class="btn btn-secondary" type="button" data-dismiss="modal">Cancel</button>
-                <a class="btn btn-primary" href="#" onclick="updateUser()" data-dismiss="modal">Update Profile</a>
+                <button class="btn btn-secondary" type="button" data-bs-dismiss="modal">Cancel</button>
+                <a class="btn btn-primary" href="#" onclick="updateUser()" data-bs-dismiss="modal">Update Profile</a>
               </div>
             </div>
 
@@ -188,7 +188,7 @@
                   <label class="col-3 col-form-label text-right">Action: </label>
                   <div class="col-7">
                     <div class="form-group">
-                      <select id="actionEditInput" onchange="changeActionInput()" class="form-control" required="required"  name="action">
+                      <select id="actionEditInput" onchange="changeActionInput()" class="form-select" required="required"  name="action">
                         <option value="add">Add</option>
                         <option value="remove">Remove</option>
                       </select>
@@ -203,7 +203,7 @@
                   <label class="col-3 col-form-label text-right">Group: </label>
                   <div class="col-7">
                     <div class="form-group">
-                      <select id="addGroupEditInput" class="form-control" required="required"  name="add_group">
+                      <select id="addGroupEditInput" class="form-select" required="required"  name="add_group">
                       </select>
                     </div>
                   </div>
@@ -216,7 +216,7 @@
                   <label class="col-3 col-form-label text-right">Group: </label>
                   <div class="col-7">
                     <div class="form-group">
-                      <select id="removeGroupEditInput" class="form-control" required="required"  name="remove_group">
+                      <select id="removeGroupEditInput" class="form-select" required="required"  name="remove_group">
                       </select>
                     </div>
                   </div>
@@ -229,8 +229,8 @@
               </form>
 
               <div class="modal-footer">
-                <button class="btn btn-secondary" type="button" data-dismiss="modal">Cancel</button>
-                <a class="btn btn-primary" href="#" onclick="updateUserGroup()" data-dismiss="modal">Update Group</a>
+                <button class="btn btn-secondary" type="button" data-bs-dismiss="modal">Cancel</button>
+                <a class="btn btn-primary" href="#" onclick="updateUserGroup()" data-bs-dismiss="modal">Update Group</a>
               </div>
             </div>
 
@@ -265,8 +265,8 @@
               </form>
 
               <div class="modal-footer">
-                <button class="btn btn-secondary" type="button" data-dismiss="modal">Cancel</button>
-                <a class="btn btn-primary" href="#" onclick="updateUserPassword()" data-dismiss="modal">Update Password</a>
+                <button class="btn btn-secondary" type="button" data-bs-dismiss="modal">Cancel</button>
+                <a class="btn btn-primary" href="#" onclick="updateUserPassword()" data-bs-dismiss="modal">Update Password</a>
               </div>
             </div>
 

+ 0 - 2361
lxconsole/templates/modals/virtual-machine.html

@@ -1,2361 +0,0 @@
-
-  <!-- New Snapshot Modal-->
-  <div class="modal fade" id="createSnapshotModal" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel" aria-hidden="true">
-    <div class="modal-dialog" role="document">
-      <div class="modal-content">
-          <div class="modal-header">
-            <h5 class="modal-title" id="exampleModalLabel">Create Snapshot</h5>
-            <button class="close" type="button" data-dismiss="modal" aria-label="Close">
-              <span aria-hidden="true">×</span>
-            </button>
-          </div>
-          <div class="modal-body">
-            <div class="row">
-              <label class="col-3 col-form-label text-right">Name: </label>
-              <div class="col-7">
-                <div class="form-group">
-                  <input type="text" id="snapshotName" class="form-control" placeholder="" name="snapshot">
-                </div>
-              </div>
-              <div class="col-1">
-                <i class="far fa-sm fa-question-circle" title='Enter a unique name to identify this snapshot. If a name is not provided it will be autogenerated.'></i>
-              </div>
-            </div>
-            <div class="row">
-              <label class="col-3 col-form-label text-right">Stateful:</label>
-              <div class="col-7 text-right">
-                <div class="form-group">
-                  <select id="snapshotStateful" class="form-control" name="snapshotStateful">
-                    <option value="false" selected>false</option>
-                    <option value="true">true</option>
-                  </select>
-                </div>
-              </div>
-              <div class="col-1">
-                <i class="far fa-sm fa-question-circle" title='Select whether or not to create a stateful snapshot. Default: false'></i>
-              </div>
-            </div>
-          </div>
-          <div class="modal-footer">
-            <button class="btn btn-secondary" type="button" data-dismiss="modal">Cancel</button>
-            <a class="btn btn-primary" href="#" onclick="createSnapshot()" data-dismiss="modal">Submit</a>
-          </div>
-      </div>
-    </div>
-  </div>
-
-  <!-- Rename Instance Modal-->
-  <div class="modal fade" id="renameInstanceModal" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel" aria-hidden="true">
-    <div class="modal-dialog" role="document">
-      <div class="modal-content">
-          <div class="modal-header">
-            <h5 class="modal-title" id="exampleModalLabel">Rename Instance</h5>
-            <button class="close" type="button" data-dismiss="modal" aria-label="Close">
-              <span aria-hidden="true">×</span>
-            </button>
-          </div>
-          <div class="modal-body">
-            <div class="row">
-              <label class="col-3 col-form-label text-right">Name: <span class="text-danger">*</span></label>
-              <div class="col-7">
-                <div class="form-group">
-                  <input type="text" id="renameName" class="form-control" placeholder="">
-                </div>
-              </div>
-              <div class="col-1">
-                <i class="far fa-sm fa-question-circle" title='(Required) - Enter in a new name for this instance.'></i>
-              </div>
-            </div>
-          </div>
-          <div class="modal-footer">
-            <button class="btn btn-secondary" type="button" data-dismiss="modal">Cancel</button>
-            <a class="btn btn-primary" href="#" onclick="renameInstance()" data-dismiss="modal">Submit</a>
-          </div>
-      </div>
-    </div>
-  </div>
-
-  <!-- Migrate Instance Modal-->
-  <div class="modal fade" id="migrateInstanceModal" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel" aria-hidden="true">
-    <div class="modal-dialog" role="document">
-      <div class="modal-content">
-          <div class="modal-header">
-            <h5 class="modal-title" id="exampleModalLabel">Migrate Instance</h5>
-            <button class="close" type="button" data-dismiss="modal" aria-label="Close">
-              <span aria-hidden="true">×</span>
-            </button>
-          </div>
-          <div class="modal-body">
-            <div class="row">
-              <label class="col-3 col-form-label text-right">Server: <span class="text-danger">*</span></label>
-              <div class="col-7">
-                <div class="form-group">
-                  <select id="selectClusterInput" class="form-control" name="cluster">
-                  </select>
-                </div>
-              </div>
-              <div class="col-1">
-                <i class="far fa-sm fa-question-circle" title='Select the cluster member to migrate this instance to.'></i>
-              </div>
-            </div>
-          </div>
-          <div class="modal-footer">
-            <button class="btn btn-secondary" type="button" data-dismiss="modal">Cancel</button>
-            <a class="btn btn-primary" href="#" onclick="migrateInstance()" data-dismiss="modal">Submit</a>
-          </div>
-      </div>
-    </div>
-  </div>
-
-  <!-- Copy Instance Modal-->
-  <div class="modal fade" id="copyInstanceModal" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel" aria-hidden="true">
-    <div class="modal-dialog" role="document">
-      <div class="modal-content">
-          <div class="modal-header">
-            <h5 class="modal-title" id="exampleModalLabel">Copy Instance</h5>
-            <button class="close" type="button" data-dismiss="modal" aria-label="Close">
-              <span aria-hidden="true">×</span>
-            </button>
-          </div>
-          <div class="modal-body">
-            <div class="row">
-              <label class="col-3 col-form-label text-right">Name: <span class="text-danger">*</span></label>
-              <div class="col-7">
-                <div class="form-group">
-                  <input type="text" id="copyName" class="form-control" placeholder="" name="copy">
-                </div>
-              </div>
-              <div class="col-1">
-                <i class="far fa-sm fa-question-circle" title='Enter in the name of the new copied instance.'></i>
-              </div>
-            </div>
-          </div>
-          <div class="modal-footer">
-            <button class="btn btn-secondary" type="button" data-dismiss="modal">Cancel</button>
-            <a class="btn btn-primary" href="#" onclick="copyInstance()" data-dismiss="modal">Submit</a>
-          </div>
-      </div>
-    </div>
-  </div>
-
-  <!-- Create Instance from Snapshot Modal-->
-  <div class="modal fade" id="createSnapshotInstanceModal" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel" aria-hidden="true">
-    <div class="modal-dialog" role="document">
-      <div class="modal-content">
-          <div class="modal-header">
-            <h5 class="modal-title" id="exampleModalLabel">Create Instance from Snapshot</h5>
-            <button class="close" type="button" data-dismiss="modal" aria-label="Close">
-              <span aria-hidden="true">×</span>
-            </button>
-          </div>
-          <div class="modal-body">
-            <div class="row">
-              <label class="col-3 col-form-label text-right">Name: <span class="text-danger">*</span></label>
-              <div class="col-7">
-                <div class="form-group">
-                  <input type="text" id="instanceNameForSnapshotCreate" class="form-control" placeholder="" name="copysnap">
-                  <input type="hidden" id="snapNameForSnapshotCreate">
-                </div>
-              </div>
-              <div class="col-1">
-                <i class="far fa-sm fa-question-circle" title='Enter in a name for the new instance.'></i>
-              </div>
-            </div>
-          </div>
-          <div class="modal-footer">
-            <button class="btn btn-secondary" type="button" data-dismiss="modal">Cancel</button>
-            <a class="btn btn-primary" href="#" onclick="createSnapshotInstance()" data-dismiss="modal">Submit</a>
-          </div>
-      </div>
-    </div>
-  </div>
-
-  <!-- Publish Image from Snapshot Modal-->
-  <div class="modal fade" id="publishSnapshotModal" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel" aria-hidden="true">
-    <div class="modal-dialog" role="document">
-      <div class="modal-content">
-          <div class="modal-header">
-            <h5 class="modal-title" id="exampleModalLabel">Publish Image from Snapshot</h5>
-            <button class="close" type="button" data-dismiss="modal" aria-label="Close">
-              <span aria-hidden="true">×</span>
-            </button>
-          </div>
-          <div class="modal-body">
-            <div class="row">
-              <label class="col-3 col-form-label text-right">Description: </label>
-              <div class="col-7">
-                <div class="form-group">
-                  <input type="text" id="publishSnapshotDescriptionInput" class="form-control" placeholder="" name="description">
-                </div>
-              </div>
-              <div class="col-1">
-                <i class="far fa-sm fa-question-circle" title='Enter in a description for the new image.'></i>
-              </div>
-            </div>
-            <div class="row">
-              <label class="col-3 col-form-label text-right">OS: </label>
-              <div class="col-7">
-                <div class="form-group">
-                  <input type="text" id="publishSnapshotOsInput" class="form-control" placeholder="" name="os">
-                </div>
-              </div>
-              <div class="col-1">
-                <i class="far fa-sm fa-question-circle" title='Enter in the operating system name for the new image.'></i>
-              </div>
-            </div>
-            <div class="row">
-              <label class="col-3 col-form-label text-right">Release: </label>
-              <div class="col-7">
-                <div class="form-group">
-                  <input type="text" id="publishSnapshotReleaseInput" class="form-control" placeholder="" name="release">
-                </div>
-              </div>
-              <div class="col-1">
-                <i class="far fa-sm fa-question-circle" title='Enter in the release version for the new image.'></i>
-              </div>
-            </div>
-            <div class="row">
-              <label class="col-3 col-form-label text-right">Public:</label>
-              <div class="col-7">
-                <div class="form-group">
-                  <select id="publishSnapshotPublicInput" class="form-control" name="public">
-                    <option value="false" selected>false</option>
-                    <option value="true">true</option>
-                  </select>
-                </div>
-              </div>
-              <div class="col-1">
-                <i class="far fa-sm fa-question-circle" title='Select whether or not this image is public. Default: false'></i>
-              </div>
-            </div>
-            <input type="hidden" id="publishSnapshotHiddenName">
-          </div>
-          <div class="modal-footer">
-            <button class="btn btn-secondary" type="button" data-dismiss="modal">Cancel</button>
-            <a class="btn btn-primary" href="#" onclick="publishSnapshot()" data-dismiss="modal">Submit</a>
-          </div>
-      </div>
-    </div>
-  </div>
-
-  <!-- Backup Instance Modal-->
-  <div class="modal fade" id="backupInstanceModal" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel" aria-hidden="true">
-    <div class="modal-dialog" role="document">
-      <div class="modal-content">
-          <div class="modal-header">
-            <h5 class="modal-title" id="exampleModalLabel">Backup Instance</h5>
-            <button class="close" type="button" data-dismiss="modal" aria-label="Close">
-              <span aria-hidden="true">×</span>
-            </button>
-          </div>
-          <div class="modal-body">
-            <div class="row">
-              <label class="col-3 col-form-label text-right">Name:</label>
-              <div class="col-7">
-                <div class="form-group">
-                  <input type="text" id="backupName" class="form-control" placeholder="" name="backupName">
-                </div>
-              </div>
-              <div class="col-1">
-                <i class="far fa-sm fa-question-circle" title='Enter in the name of the backup. A file extension will be appended to this name.'></i>
-              </div>
-            </div>
-            <div class="row">
-              <label class="col-3 col-form-label text-right">Instance Only:</label>
-              <div class="col-7 text-right">
-                <div class="form-group">
-                  <select id="backupInstanceOnly" class="form-control" name="backupInstanceOnly">
-                    <option value="false" selected>false</option>
-                    <option value="true">true</option>
-                  </select>
-                </div>
-              </div>
-              <div class="col-1">
-                <i class="far fa-sm fa-question-circle" title='Select whether or not to backup just the instance itself. Default: false'></i>
-              </div>
-            </div>
-            <div class="row">
-              <label class="col-3 col-form-label text-right">Optimized Storage:</label>
-              <div class="col-7 text-right">
-                <div class="form-group">
-                  <select id="backupOptimizedStorage" class="form-control" name="backupOptimizedStorage">
-                    <option value="false" selected>false</option>
-                    <option value="true">true</option>
-                  </select>
-                </div>
-              </div>
-              <div class="col-1">
-                <i class="far fa-sm fa-question-circle" title='Select whether or not to optimize storage size. Default: false'></i>
-              </div>
-            </div>
-            <div class="row">
-              <label class="col-3 col-form-label text-right">Compression:</label>
-              <div class="col-7">
-                <div class="form-group">
-                  <select id="backupCompressionAlgorithm" class="form-control" name="backupCompressionAlgorithm">
-                    <option value="bzip2">bzip2</option>
-                    <option value="gzip" selected>gzip</option>
-                    <option value="lzma">lzma</option>
-                    <option value="none">none</option>
-                    <option value="xz">xz</option>
-                    <option value="zstd">zstd</option>
-                  </select>
-                </div>
-              </div>
-              <div class="col-1">
-                <i class="far fa-sm fa-question-circle" title='Select which compression algorithm to use. Default: gzip'></i>
-              </div>
-            </div>
-          </div>
-          <div class="modal-footer">
-            <button class="btn btn-secondary" type="button" data-dismiss="modal">Cancel</button>
-            <a class="btn btn-primary" href="#" onclick="createBackup()" data-dismiss="modal">Submit</a>
-          </div>
-      </div>
-    </div>
-  </div>
-  
-  <!-- Delete Instance Modal-->
-  <div class="modal fade" id="deleteInstanceModal" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel" aria-hidden="true">
-    <div class="modal-dialog" role="document">
-      <div class="modal-content">
-        <div class="modal-header">
-          <h5 class="modal-title" id="exampleModalLabel">Delete Instance</h5>
-          <button class="close" type="button" data-dismiss="modal" aria-label="Close">
-            <span aria-hidden="true">×</span>
-          </button>
-        </div>
-        <div class="modal-body">Are you sure you want to delete this instance?</div>
-        <div class="modal-footer">
-          <button class="btn btn-secondary" type="button" data-dismiss="modal">Cancel</button>
-          <a class="btn btn-primary" href="#" onclick="deleteInstance()" data-dismiss="modal">Yes</a>
-        </div>
-      </div>
-    </div>
-  </div>
-
-  <!-- Attach Profile Modal-->
-  <div class="modal fade" id="attachProfileModal" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel" aria-hidden="true">
-    <div class="modal-dialog" role="document">
-      <div class="modal-content">
-          <div class="modal-header">
-            <h5 class="modal-title" id="exampleModalLabel">Attach Profile</h5>
-            <button class="close" type="button" data-dismiss="modal" aria-label="Close">
-              <span aria-hidden="true">×</span>
-            </button>
-          </div>
-          <div class="modal-body">
-            <div class="row">
-              <label class="col-3 col-form-label text-right">Profile:</label>
-              <div class="col-7">
-                <div class="form-group">
-                  <select id="selectProfileInput" class="form-control" name="profile">
-                  </select>
-                </div>
-              </div>
-              <div class="col-1">
-                <i class="far fa-sm fa-question-circle" title='Select an existing profile to attach to this instance.'></i>
-              </div>
-            </div>
-          </div>
-          <div class="modal-footer">
-            <button class="btn btn-secondary" type="button" data-dismiss="modal">Cancel</button>
-            <a class="btn btn-primary" href="#" onclick="attachProfile()" data-dismiss="modal">Submit</a>
-          </div>
-      </div>
-    </div>
-  </div>
-
-  <!-- Detach Profile Modal-->
-  <div class="modal fade" id="detachProfileModal" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel" aria-hidden="true">
-    <div class="modal-dialog" role="document">
-      <div class="modal-content">
-          <div class="modal-header">
-            <h5 class="modal-title" id="exampleModalLabel">Detach Profile</h5>
-            <button class="close" type="button" data-dismiss="modal" aria-label="Close">
-              <span aria-hidden="true">×</span>
-            </button>
-          </div>
-          <div class="modal-body">
-            <div class="row">
-              <label class="col-3 col-form-label text-right">Profile:</label>
-              <div class="col-7">
-                <div class="form-group">
-                  <select id="selectDetachProfileInput" class="form-control" name="profile">
-                  </select>
-                </div>
-              </div>
-              <div class="col-1">
-                <i class="far fa-sm fa-question-circle" title='Select an existing profile to detach from this instance.'></i>
-              </div>
-            </div>
-          </div>
-          <div class="modal-footer">
-            <button class="btn btn-secondary" type="button" data-dismiss="modal">Cancel</button>
-            <a class="btn btn-primary" href="#" onclick="detachProfile()" data-dismiss="modal">Submit</a>
-          </div>
-      </div>
-    </div>
-  </div>
-
-  <!-- Add Disk Device Modal-->
-  <div class="modal fade" id="addDiskDeviceModal" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel" aria-hidden="true">
-    <div class="modal-dialog modal-lg" role="document">
-      <div class="modal-content">
-          <div class="modal-header">
-            <h5 class="modal-title" id="exampleModalLabel">Add Disk Device</h5>
-            <button class="close" type="button" data-dismiss="modal" aria-label="Close">
-              <span aria-hidden="true">×</span>
-            </button>
-          </div>
-          <div class="modal-body">
-            <div class="row">
-              <label class="col-3 col-form-label text-right">Device Name: <span class="text-danger">*</span></label>
-              <div class="col-7">
-                <div class="form-group">
-                  <input type="text" id="diskNameInput" class="form-control" placeholder="" name="diskNameInput">
-                </div>
-              </div>
-              <div class="col-1">
-                <i class="far fa-sm fa-question-circle" title='(Required) - Enter a unique name to identify this instance device.'></i>
-              </div>
-            </div>
-            <div class="row">
-              <label class="col-3 col-form-label text-right">Pool:</label>
-              <div class="col-7">
-                <div class="form-group">
-                  <select id="diskPoolInput" onchange="changeStorageVolumeInput()" class="form-control" name="diskPoolInput">
-                    <option value="">(not set)</option>
-                  </select>
-                </div>
-              </div>
-              <div class="col-1">
-                <i class="far fa-sm fa-question-circle" title='For LXD managed storage volumes, select the storage pool where the source storage volume is located.'></i>
-              </div>
-            </div>
-            <div class="row">
-              <label class="col-3 col-form-label text-right">Source: <span class="text-danger">*</span></label>
-              <div class="col-7">
-                <div class="form-group">
-                  <input type="text" id="diskSourceInput" class="form-control" placeholder="" name="diskSourceInput">
-                  <select style="display:none;" id="diskSourceSelectInput" class="form-control" name="diskSourceSelectInput">
-                    <option value="">(not set)</option>
-                  </select>
-                </div>
-              </div>
-              <div class="col-1">
-                <i class="far fa-sm fa-question-circle" title='(Required) - Select the storage volume or enter the filepath of the storage device.'></i>
-              </div>
-            </div>
-            <div class="row">
-              <label class="col-3 col-form-label text-right">Path: <span class="text-danger">*</span></label>
-              <div class="col-7">
-                <div class="form-group">
-                  <input type="text" id="diskPathInput" class="form-control" placeholder="" name="diskPathInput">
-                </div>
-              </div>
-              <div class="col-1">
-                <i class="far fa-sm fa-question-circle" title='(Required) - Enter a filepath for where this disk will be mounted within the instance. For example, /mnt/vol1'></i>
-              </div>
-            </div>
-
-            <hr>
-
-            <div id="accordionDiskProperties">
-              <h2>
-                <button class="btn btn-link collapsed" type="button" data-toggle="collapse" data-target="#additionalDiskProperties" aria-expanded="false" aria-controls="additionalDiskProperties">
-                  Additional Properties
-                </button>
-              </h2> 
-              <div id="additionalDiskProperties" class="collapse" aria-labelledby="additionalDiskProperties">
-                <div class="row">
-                  <label class="col-3 col-form-label text-right">Limits.Read:</label>
-                  <div class="col-7">
-                    <div class="form-group">
-                      <input type="text" id="diskLimitsReadInput" class="form-control" placeholder="" name="diskLimitsReadInput">
-                    </div>
-                  </div>
-                  <div class="col-1">
-                    <i class="far fa-sm fa-question-circle" title='Enter in the I/O limit. Be sure to include the suffix. Default: (not set)'></i>
-                  </div>
-                </div>
-                <div class="row">
-                  <label class="col-3 col-form-label text-right">Limits.Write:</label>
-                  <div class="col-7">
-                    <div class="form-group">
-                      <input type="text" id="diskLimitsWriteInput" class="form-control" placeholder="" name="diskLimitsWriteInput">
-                    </div>
-                  </div>
-                  <div class="col-1">
-                    <i class="far fa-sm fa-question-circle" title='Enter in the I/O limit. Be sure to inlude the suffix. Default: (not set)'></i>
-                  </div>
-                </div>
-                <div class="row">
-                  <label class="col-3 col-form-label text-right">Limits.Max:</label>
-                  <div class="col-7">
-                    <div class="form-group">
-                      <input type="text" id="diskLimitsMaxInput" class="form-control" placeholder="" name="diskLimitsMaxInput">
-                    </div>
-                  </div>
-                  <div class="col-1">
-                    <i class="far fa-sm fa-question-circle" title='Enter in the I/O limit. Be sure to inlude the suffix. Default: (not set)'></i>
-                  </div>
-                </div>
-                <div class="row">
-                  <label class="col-3 col-form-label text-right">Required:</label>
-                  <div class="col-7">
-                    <div class="form-group">
-                      <select id="diskRequiredInput" onchange="" class="form-control" name="diskRequiredInput">
-                        <option value="">(not set)</option>
-                        <option value="true">true</option>
-                        <option value="false">false</option>
-                      </select>
-                    </div>
-                  </div>
-                  <div class="col-1">
-                    <i class="far fa-sm fa-question-circle" title="Select whether to fail if the source disk doesn't exist. Default: true"></i>
-                  </div>
-                </div>
-                <div class="row">
-                  <label class="col-3 col-form-label text-right">Read Only:</label>
-                  <div class="col-7">
-                    <div class="form-group">
-                      <select id="diskReadOnlyInput" onchange="" class="form-control" name="diskReadOnlyInput">
-                        <option value="">(not set)</option>
-                        <option value="true">true</option>
-                        <option value="false">false</option>
-                      </select>
-                    </div>
-                  </div>
-                  <div class="col-1">
-                    <i class="far fa-sm fa-question-circle" title="Select whether to make the mount disk read-only or not. Default: false"></i>
-                  </div>
-                </div>
-                <div class="row">
-                  <label class="col-3 col-form-label text-right">Size:</label>
-                  <div class="col-7">
-                    <div class="form-group">
-                      <input type="text" id="diskSizeInput" class="form-control" placeholder="" name="diskSizeInput">
-                    </div>
-                  </div>
-                  <div class="col-1">
-                    <i class="far fa-sm fa-question-circle" title='Enter in the disk size in bytes. Be sure to include the suffix. This is only supported for the rootfs (/). Default: (not set)'></i>
-                  </div>
-                </div>
-                <div class="row">
-                  <label class="col-3 col-form-label text-right">Size.State:</label>
-                  <div class="col-7">
-                    <div class="form-group">
-                      <input type="text" id="diskSizeStateInput" class="form-control" placeholder="" name="diskSizeStateInput">
-                    </div>
-                  </div>
-                  <div class="col-1">
-                    <i class="far fa-sm fa-question-circle" title='Enter in the size of the filesystem volume used for saving runtime state in virtual machines. Be sure to inlude the suffix. Default: (not set)'></i>
-                  </div>
-                </div>
-                <div class="row">
-                  <label class="col-3 col-form-label text-right">Recursive:</label>
-                  <div class="col-7">
-                    <div class="form-group">
-                      <select id="diskRecursiveInput" onchange="" class="form-control" name="diskRecursiveInput">
-                        <option value="">(not set)</option>
-                        <option value="true">true</option>
-                        <option value="false">false</option>
-                      </select>
-                    </div>
-                  </div>
-                  <div class="col-1">
-                    <i class="far fa-sm fa-question-circle" title="Select whether or not to recursively mount the source path. Default: false"></i>
-                  </div>
-                </div>
-                <div class="row">
-                  <label class="col-3 col-form-label text-right">Propagation:</label>
-                  <div class="col-7">
-                    <div class="form-group">
-                      <select id="diskPropagationInput" onchange="" class="form-control" name="diskPropagationInput">
-                        <option value="">(not set)</option>
-                        <option value="private">private</option>
-                        <option value="rprivate">rprivate</option>
-                        <option value="rshared">rshared</option>
-                        <option value="rslave">rslave</option>
-                        <option value="runbindable">runbindable</option>
-                        <option value="shared">shared</option>
-                        <option value="slave">slave</option>
-                        <option value="unbindable">unbindable</option>
-                      </select>
-                    </div>
-                  </div>
-                  <div class="col-1">
-                    <i class="far fa-sm fa-question-circle" title='Select how a bind-mount is shared between the instance and the host. Default: private'></i>
-                  </div>
-                </div>
-                <div class="row">
-                  <label class="col-3 col-form-label text-right">Shift:</label>
-                  <div class="col-7">
-                    <div class="form-group">
-                      <select id="diskShiftInput" onchange="" class="form-control" name="diskShiftInput">
-                        <option value="">(not set)</option>
-                        <option value="true">true</option>
-                        <option value="false">false</option>
-                      </select>
-                    </div>
-                  </div>
-                  <div class="col-1">
-                    <i class="far fa-sm fa-question-circle" title="Select wheter to setup a shifting overlay to translate the source uid/gid to match the instance. Default: false"></i>
-                  </div>
-                </div>
-                <div class="row">
-                  <label class="col-3 col-form-label text-right">Raw Mount Options:</label>
-                  <div class="col-7">
-                    <div class="form-group">
-                      <input type="text" id="diskRawMountOptionsInput" class="form-control" placeholder="" name="diskRawMountOptionsInput">
-                    </div>
-                  </div>
-                  <div class="col-1">
-                    <i class="far fa-sm fa-question-circle" title='Enter in filesystem specific mount options. Default: (not set)'></i>
-                  </div>
-                </div>
-                <div class="row">
-                  <label class="col-3 col-form-label text-right">Ceph User Name:</label>
-                  <div class="col-7">
-                    <div class="form-group">
-                      <input type="text" id="diskCephUserNameInput" class="form-control" placeholder="" name="diskCephUserNameInput">
-                    </div>
-                  </div>
-                  <div class="col-1">
-                    <i class="far fa-sm fa-question-circle" title='Used if the source is ceph or cephfs. Enter a ceph user_name. Default: admin'></i>
-                  </div>
-                </div>
-                <div class="row">
-                  <label class="col-3 col-form-label text-right">Ceph Cluster Name:</label>
-                  <div class="col-7">
-                    <div class="form-group">
-                      <input type="text" id="diskCephClusterNameInput" class="form-control" placeholder="" name="diskCephClusterNameInput">
-                    </div>
-                  </div>
-                  <div class="col-1">
-                    <i class="far fa-sm fa-question-circle" title='Used if the source is ceph or cephfs. Enter a ceph cluster_name. Default: ceph'></i>
-                  </div>
-                </div>
-                <div class="row">
-                  <label class="col-3 col-form-label text-right">Boot Priority:</label>
-                  <div class="col-7">
-                    <div class="form-group">
-                      <input type="number" id="diskBootPriorityInput" class="form-control" placeholder="" name="diskBootPriorityInput">
-                    </div>
-                  </div>
-                  <div class="col-1">
-                    <i class="far fa-sm fa-question-circle" title='Enter in a boot priority number for VMs (highest numbers boot first). Default: (not set)'></i>
-                  </div>
-                </div>
-              </div>
-
-            </div>
-
-          </div>
-          <div class="modal-footer">
-            <button class="btn btn-secondary" type="button" data-dismiss="modal">Cancel</button>
-            <a class="btn btn-primary" href="#" onclick="addInstanceDiskDevice()" data-dismiss="modal">Submit</a>
-          </div>
-      </div>
-    </div>
-  </div>
-
-  <!-- Add GPU Device Modal-->
-  <div class="modal fade" id="addGPUDeviceModal" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel" aria-hidden="true">
-    <div class="modal-dialog modal-lg" role="document">
-      <div class="modal-content">
-          <div class="modal-header">
-            <h5 class="modal-title" id="exampleModalLabel">Add GPU Device</h5>
-            <button class="close" type="button" data-dismiss="modal" aria-label="Close">
-              <span aria-hidden="true">×</span>
-            </button>
-          </div>
-          <div class="modal-body">
-            <div class="row">
-              <label class="col-3 col-form-label text-right">Device Name: <span class="text-danger">*</span></label>
-              <div class="col-7">
-                <div class="form-group">
-                  <input type="text" id="gpuDeviceNameInput" class="form-control" placeholder="" name="gpuDeviceNameInput">
-                </div>
-              </div>
-              <div class="col-1">
-                <i class="far fa-sm fa-question-circle" title='(Required) - Enter a unique name to identify this instance device'></i>
-              </div>
-            </div>
-            <div class="row">
-              <label class="col-3 col-form-label text-right">GPU Type:</label>
-              <div class="col-7">
-                <div class="form-group">
-                  <select id="gpuTypeInput" class="form-control" name="gpuTypeInput">
-                    <option value="">(not set)</option>
-                    <option value="physical">physical</option>
-                    <option value="mig">mig</option>
-                  </select>
-                </div>
-              </div>
-              <div class="col-1">
-                <i class="far fa-sm fa-question-circle" title='Select which GPU type to use. Default: physical'></i>
-              </div>
-            </div>
-            <div class="row">
-              <label class="col-3 col-form-label text-right">Vendor Id:</label>
-              <div class="col-7">
-                <div class="form-group">
-                  <input type="text" id="gpuVendoridInput" class="form-control" placeholder="" name="gpuVendoridInput">
-                </div>
-              </div>
-              <div class="col-1">
-                <i class="far fa-sm fa-question-circle" title='Enter in the vendor id of the GPU device'></i>
-              </div>
-            </div>
-            <div class="row">
-              <label class="col-3 col-form-label text-right">Product Id: <span class="text-danger">*</span></label>
-              <div class="col-7">
-                <div class="form-group">
-                  <input type="text" id="gpuProductidInput" class="form-control" placeholder="" name="gpuProductidInput">
-                </div>
-              </div>
-              <div class="col-1">
-                <i class="far fa-sm fa-question-circle" title='Enter in the product id of the GPU device'></i>
-              </div>
-            </div>
-            <div class="row">
-              <label class="col-3 col-form-label text-right">MIG CI: <span class="text-danger">*</span></label>
-              <div class="col-7">
-                <div class="form-group">
-                  <input type="number" id="gpuMigCiInput" class="form-control" placeholder="" name="gpuMigCiInput">
-                </div>
-              </div>
-              <div class="col-1">
-                <i class="far fa-sm fa-question-circle" title='Enter in the existing MIG compute instance ID. Default: (not set)'></i>
-              </div>
-            </div>
-            <div class="row">
-              <label class="col-3 col-form-label text-right">MIG GI: <span class="text-danger">*</span></label>
-              <div class="col-7">
-                <div class="form-group">
-                  <input type="number" id="gpuMigGiInput" class="form-control" placeholder="" name="gpuMigGiInput">
-                </div>
-              </div>
-              <div class="col-1">
-                <i class="far fa-sm fa-question-circle" title='Enter in the existing MIG GPU instance ID. Default: (not set)'></i>
-              </div>
-            </div>
-
-            <hr>
-
-            <div id="accordionProxyProperties">
-              <h2>
-                <button class="btn btn-link collapsed" type="button" data-toggle="collapse" data-target="#additionalProxyProperties" aria-expanded="false" aria-controls="additionalProxyProperties">
-                  Additional Properties
-                </button>
-              </h2> 
-              <div id="additionalProxyProperties" class="collapse" aria-labelledby="additionalProxyProperties">
-
-                <div class="row">
-                  <label class="col-3 col-form-label text-right">ID:</label>
-                  <div class="col-7">
-                    <div class="form-group">
-                      <input type="text" id="gpuIdInput" class="form-control" placeholder="" name="gpuIdInput">
-                    </div>
-                  </div>
-                  <div class="col-1">
-                    <i class="far fa-sm fa-question-circle" title='Enter in the card ID of the GPU. Default: (not set)'></i>
-                  </div>
-                </div>
-                <div class="row">
-                  <label class="col-3 col-form-label text-right">PCI:</label>
-                  <div class="col-7">
-                    <div class="form-group">
-                      <input type="text" id="gpuPciInput" class="form-control" placeholder="" name="gpuPciInput">
-                    </div>
-                  </div>
-                  <div class="col-1">
-                    <i class="far fa-sm fa-question-circle" title='Enter in the PCI address of the GPU. Default: (not set)'></i>
-                  </div>
-                </div>
-                <div class="row">
-                  <label class="col-3 col-form-label text-right">UID:</label>
-                  <div class="col-7">
-                    <div class="form-group">
-                      <input type="number" id="gpuUidInput" class="form-control" placeholder="" name="gpuUidInput">
-                    </div>
-                  </div>
-                  <div class="col-1">
-                    <i class="far fa-sm fa-question-circle" title='Enter in the UID number of the device owner. Default: 0'></i>
-                  </div>
-                </div>
-                <div class="row">
-                  <label class="col-3 col-form-label text-right">GID:</label>
-                  <div class="col-7">
-                    <div class="form-group">
-                      <input type="number" id="gpuGidInput" class="form-control" placeholder="" name="gpuGidInput">
-                    </div>
-                  </div>
-                  <div class="col-1">
-                    <i class="far fa-sm fa-question-circle" title='Enter in the GID number of the device owner. Default: 0'></i>
-                  </div>
-                </div>
-                <div class="row">
-                  <label class="col-3 col-form-label text-right">Mode:</label>
-                  <div class="col-7">
-                    <div class="form-group">
-                      <input type="number" id="gpuModeInput" class="form-control" placeholder="" name="gpuModeInput">
-                    </div>
-                  </div>
-                  <div class="col-1">
-                    <i class="far fa-sm fa-question-circle" title='Enter in the permissions mode for the device in the instance. Default: 0600'></i>
-                  </div>
-                </div>
-
-              </div>
-            </div>
-
-          </div>
-          <div class="modal-footer">
-            <button class="btn btn-secondary" type="button" data-dismiss="modal">Cancel</button>
-            <a class="btn btn-primary" href="#" onclick="addInstanceGPUDevice()" data-dismiss="modal">Submit</a>
-          </div>
-      </div>
-    </div>
-  </div>
-
-  <!-- Add Network Device Modal-->
-  <div class="modal fade" id="addNetworkDeviceModal" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel" aria-hidden="true">
-    <div class="modal-dialog modal-lg" role="document">
-      <div class="modal-content">
-          <div class="modal-header">
-            <h5 class="modal-title" id="exampleModalLabel">Add Network Device</h5>
-            <button class="close" type="button" data-dismiss="modal" aria-label="Close">
-              <span aria-hidden="true">×</span>
-            </button>
-          </div>
-          <div class="modal-body">
-            <div class="row">
-              <label class="col-3 col-form-label text-right">Device Name: <span class="text-danger">*</span></label>
-              <div class="col-7">
-                <div class="form-group">
-                  <input type="text" id="networkNameInput" class="form-control" placeholder="" name="networkNameInput">
-                </div>
-              </div>
-              <div class="col-1">
-                <i class="far fa-sm fa-question-circle" title='(Required) - Enter a unique name to identify this instance device.'></i>
-              </div>
-            </div>
-            <div class="row">
-              <label class="col-3 col-form-label text-right">Property Set: <span class="text-danger">*</span></label>
-              <div class="col-7">
-                <div class="form-group">
-                  <select id="networkPropertySetInput" onchange="changePropertySetInput()" onchange="" class="form-control" name="networkPropertySetInput">
-                    <option value="network">network</option>
-                    <option value="nictype">nictype</option>
-                  </select>
-                </div>
-              </div>
-              <div class="col-1">
-                <i class="far fa-sm fa-question-circle" title='Select "network" to link to an existing LXD managed network or "nictype" to define your network.'></i>
-              </div>
-            </div>
-            <div class="row" id="networkNicTypeRow" style="display: none;">
-              <label class="col-3 col-form-label text-right">NIC Type: <span class="text-danger">*</span></label>
-              <div class="col-7">
-                <div class="form-group">
-                  <select id="networkNicTypeInput" onchange="changeNicTypeInput()" onchange="" class="form-control" name="networkNicTypeInput">
-                    <option value="">(not set)</option>
-                    <option value="bridged">bridged</option>
-                    <option value="ipvlan">ipvlan</option>
-                    <option value="macvlan">macvlan</option>
-                    <option value="p2p">p2p</option>
-                    <option value="physical">physical</option>
-                    <option value="routed">routed</option>
-                    <option value="sriov">sriov</option>
-                  </select>
-                </div>
-              </div>
-              <div class="col-1">
-                <i class="far fa-sm fa-question-circle" title='Select the network device type. Bridged devices use an existing bridge on the host. MacVlan devices setup a device based on an existing parent but using a different MAC address. P2P devices create a virtual device pair. Physical devices create a straight passthrough from the host interface. An sriov device passes a virtual function of an SR-IOV enabled network into the instance.'></i>
-              </div>
-            </div>
-            <div class="row" id="networkParentTypeRow">
-              <label class="col-3 col-form-label text-right">Parent Type: <span class="text-danger">*</span></label>
-              <div class="col-7">
-                <div class="form-group">
-                  <select id="networkParentTypeInput" onchange="changeParentTypeInput()" class="form-control" name="networkParentTypeInput">
-                    <option value="">(not set)</option>
-                    <option value="bridge">bridge</option>
-                    <option value="macvlan">macvlan</option>
-                    <option value="ovn">ovn</option>
-                    <option value="sriov">sriov</option>
-                  </select>
-                </div>
-              </div>
-              <div class="col-1">
-                <i class="far fa-sm fa-question-circle" title='Select the network type of the parent device.'></i>
-              </div>
-            </div>
-            <div class="row" id="networkParentRow" style="display: none;">
-              <label class="col-3 col-form-label text-right">Parent: <span class="text-danger">*</span></label>
-              <div class="col-7">
-                <div class="form-group">
-                  <select id="networkParentInput" class="form-control" name="networkParentInput">
-                    <option value="">(not set)</option>
-                  </select>
-                </div>
-              </div>
-              <div class="col-1">
-                <i class="far fa-sm fa-question-circle" title='(Required) - Select the parent network device from the host'></i>
-              </div>
-            </div>
-            <div class="row" id="networkNetworkRow">
-              <label class="col-3 col-form-label text-right">Network: <span class="text-danger">*</span></label>
-              <div class="col-7">
-                <div class="form-group">
-                  <select id="networkNetworkInput" class="form-control" name="networkNetworkInput">
-                    <option value="">(not set)</option>
-                  </select>
-                </div>
-              </div>
-              <div class="col-1">
-                <i class="far fa-sm fa-question-circle" title='(Required) - Select the LXD network to link this device to.'></i>
-              </div>
-            </div>
-            <div class="row" id="networkInterfaceNameRow">
-              <label class="col-3 col-form-label text-right">Interface Name:</label>
-              <div class="col-7">
-                <div class="form-group">
-                  <input type="text" id="networkInterfaceNameInput" class="form-control" placeholder="" name="networkInterfaceNameInput">
-                </div>
-              </div>
-              <div class="col-1">
-                <i class="far fa-sm fa-question-circle" title='Enter in a name for the interface inside the instance. Default: (kernel assigned)'></i>
-              </div>
-            </div>
-
-            <hr>
-
-            <div id="accordionNetworkProperties">
-              <h2>
-                <button class="btn btn-link collapsed" type="button" data-toggle="collapse" data-target="#additionalNetworkProperties" aria-expanded="false" aria-controls="additionalNetworkProperties">
-                  Additional Properties
-                </button>
-              </h2> 
-              <div id="additionalNetworkProperties" class="collapse" aria-labelledby="additionalNetworkProperties">
-                <div class="row" id="networkMtuRow" style="display: none;">
-                  <label class="col-3 col-form-label text-right">MTU:</label>
-                  <div class="col-7">
-                    <div class="form-group">
-                      <input type="number" id="networkMtuInput" class="form-control" placeholder="" name="networkMtuInput">
-                    </div>
-                  </div>
-                  <div class="col-1">
-                    <i class="far fa-sm fa-question-circle" title='The MTU of the new interface. Default: (inherited from parent)'></i>
-                  </div>
-                </div>
-                <div class="row" id="networkModeRow" style="display: none;">
-                  <label class="col-3 col-form-label text-right">Mode:</label>
-                  <div class="col-7">
-                    <div class="form-group">
-                      <select id="networkModeInput" onchange="" class="form-control" name="networkModeInput">
-                        <option value="">(not set)</option>
-                        <option value="l2">l2</option>
-                        <option value="l3s">l3s</option>
-                      </select>
-                    </div>
-                  </div>
-                  <div class="col-1">
-                    <i class="far fa-sm fa-question-circle" title='Select the IPVLAN mode. Default: (l3s)'></i>
-                  </div>
-                </div>
-                <div class="row" id="networkHwaddrRow" style="display: none;">
-                  <label class="col-3 col-form-label text-right">HWADDR:</label>
-                  <div class="col-7">
-                    <div class="form-group">
-                      <input type="text" id="networkHwaddrInput" class="form-control" placeholder="" name="networkHwaddrInput">
-                    </div>
-                  </div>
-                  <div class="col-1">
-                    <i class="far fa-sm fa-question-circle" title='Enter in a MAC address for the interface. Default: (randomly assigned)'></i>
-                  </div>
-                </div>
-                <div class="row" id="networkHostNameRow" style="display: none;">
-                  <label class="col-3 col-form-label text-right">Host Name:</label>
-                  <div class="col-7">
-                    <div class="form-group">
-                      <input type="text" id="networkHostNameInput" class="form-control" placeholder="" name="networkHostNameInput">
-                    </div>
-                  </div>
-                  <div class="col-1">
-                    <i class="far fa-sm fa-question-circle" title='Enter in the name of the interface inside the host. Default: (randomly assigned)'></i>
-                  </div>
-                </div>
-                <div class="row" id="networkLimitsIngressRow" style="display: none;">
-                  <label class="col-3 col-form-label text-right">Limits.Ingress:</label>
-                  <div class="col-7">
-                    <div class="form-group">
-                      <input type="text" id="networkLimitsIngressInput" class="form-control" placeholder="" name="networkLimitsIngressInput">
-                    </div>
-                  </div>
-                  <div class="col-1">
-                    <i class="far fa-sm fa-question-circle" title='Enter in the I/O limit for incoming traffic. Be sure to include the suffix. Default: (not set)'></i>
-                  </div>
-                </div>
-                <div class="row" id="networkLimitsEgressRow" style="display: none;">
-                  <label class="col-3 col-form-label text-right">Limits.Egress:</label>
-                  <div class="col-7">
-                    <div class="form-group">
-                      <input type="text" id="networkLimitsEgressInput" class="form-control" placeholder="" name="networkLimitsEgressInput">
-                    </div>
-                  </div>
-                  <div class="col-1">
-                    <i class="far fa-sm fa-question-circle" title='Enter in the I/O limit for outgoing traffic. Be sure to include the suffix. Default: (not set)'></i>
-                  </div>
-                </div>
-                <div class="row" id="networkLimitsMaxRow" style="display: none;">
-                  <label class="col-3 col-form-label text-right">Limits.Max:</label>
-                  <div class="col-7">
-                    <div class="form-group">
-                      <input type="text" id="networkLimitsMaxInput" class="form-control" placeholder="" name="networkLimitsMaxInput">
-                    </div>
-                  </div>
-                  <div class="col-1">
-                    <i class="far fa-sm fa-question-circle" title='Enter in the I/O limit. Be sure to inluce the suffix. Default: (not set)'></i>
-                  </div>
-                </div>
-                <div class="row" id="networkIpv4AddressRow" style="display: none;">
-                  <label class="col-3 col-form-label text-right">IPv4 Address:</label>
-                  <div class="col-7">
-                    <div class="form-group">
-                      <input type="text" id="networkIpv4AddressInput" class="form-control" placeholder="" name="networkIpv4AddressInput">
-                    </div>
-                  </div>
-                  <div class="col-1">
-                    <i class="far fa-sm fa-question-circle" title='Enter in an IPv4 address to assign to the instance through DHCP. Default: (not set)'></i>
-                  </div>
-                </div>
-                <div class="row" id="networkIpv4GatewayRow" style="display: none;">
-                  <label class="col-3 col-form-label text-right">IPv4 Gateway:</label>
-                  <div class="col-7">
-                    <div class="form-group">
-                      <input type="text" id="networkIpv4GatewayInput" class="form-control" placeholder="" name="networkIpv4GatewayInput">
-                    </div>
-                  </div>
-                  <div class="col-1">
-                    <i class="far fa-sm fa-question-circle" title='If using l3s mode, enter either "auto" or "none for using an automatic default gateway. If using l2 mode, enter in the address of the gateway. Default: (auto)'></i>
-                  </div>
-                </div>
-                <div class="row" id="networkIpv4HostTableRow" style="display: none;">
-                  <label class="col-3 col-form-label text-right">IPv4 Host Table:</label>
-                  <div class="col-7">
-                    <div class="form-group">
-                      <input type="number" id="networkIpv4HostTableInput" class="form-control" placeholder="" name="networkIpv4HostTableInput">
-                    </div>
-                  </div>
-                  <div class="col-1">
-                    <i class="far fa-sm fa-question-circle" title='Enter in a custom policy routing table ID to add IPv4 static routes to. Default: (not set)'></i>
-                  </div>
-                </div>
-                <div class="row" id="networkIpv4HostAddressRow" style="display: none;">
-                  <label class="col-3 col-form-label text-right">IPv4 Host Address:</label>
-                  <div class="col-7">
-                    <div class="form-group">
-                      <input type="number" id="networkIpv4HostAddressInput" class="form-control" placeholder="" name="networkIpv4HostAddressInput">
-                    </div>
-                  </div>
-                  <div class="col-1">
-                    <i class="far fa-sm fa-question-circle" title='Enter in the IPv4 address to add to the host-side veth interface. Default: (169.254.0.1)'></i>
-                  </div>
-                </div>
-                <div class="row" id="networkIpv4RoutesRow" style="display: none;">
-                  <label class="col-3 col-form-label text-right">IPv4 Routes:</label>
-                  <div class="col-7">
-                    <div class="form-group">
-                      <input type="text" id="networkIpv4RoutesInput" class="form-control" placeholder="" name="networkIpv4RoutesInput">
-                    </div>
-                  </div>
-                  <div class="col-1">
-                    <i class="far fa-sm fa-question-circle" title='Enter in a comma seperated list of IPv4 static routes. Default: (not set)'></i>
-                  </div>
-                </div>
-                <div class="row" id="networkIpv4RoutesExternalRow" style="display: none;">
-                  <label class="col-3 col-form-label text-right">IPv4 Routes External:</label>
-                  <div class="col-7">
-                    <div class="form-group">
-                      <input type="text" id="networkIpv4RoutesExternalInput" class="form-control" placeholder="" name="networkIpv4RoutesExternalInput">
-                    </div>
-                  </div>
-                  <div class="col-1">
-                    <i class="far fa-sm fa-question-circle" title='Enter in a comma seperated list of static routes to route to the NIC and publish on the uplink. Default: (not set)'></i>
-                  </div>
-                </div>
-                <div class="row" id="networkIpv6AddressRow" style="display: none;">
-                  <label class="col-3 col-form-label text-right">IPv6 Address:</label>
-                  <div class="col-7">
-                    <div class="form-group">
-                      <input type="text" id="networkIpv6AddressInput" class="form-control" placeholder="" name="networkIpv6AddressInput">
-                    </div>
-                  </div>
-                  <div class="col-1">
-                    <i class="far fa-sm fa-question-circle" title='Enter in an IPv6 address to assign to the instance through DHCP. Default: (not set)'></i>
-                  </div>
-                </div>
-                <div class="row" id="networkIpv6GatewayRow" style="display: none;">
-                  <label class="col-3 col-form-label text-right">IPv6 Gateway:</label>
-                  <div class="col-7">
-                    <div class="form-group">
-                      <input type="text" id="networkIpv6GatewayInput" class="form-control" placeholder="" name="networkIpv6GatewayInput">
-                    </div>
-                  </div>
-                  <div class="col-1">
-                    <i class="far fa-sm fa-question-circle" title='If using l3s mode, enter either "auto" or "none for using an automatic default gateway. If using l2 mode, enter in the address of the gateway. Default: (auto or not set)'></i>
-                  </div>
-                </div>
-                <div class="row" id="networkIpv6HostTableRow" style="display: none;">
-                  <label class="col-3 col-form-label text-right">IPv6 Host Table:</label>
-                  <div class="col-7">
-                    <div class="form-group">
-                      <input type="number" id="networkIpv6HostTableInput" class="form-control" placeholder="" name="networkIpv6HostTableInput">
-                    </div>
-                  </div>
-                  <div class="col-1">
-                    <i class="far fa-sm fa-question-circle" title='Enter in a custom policy routing table ID to add IPv4 static routes to. Default: (not set)'></i>
-                  </div>
-                </div>
-                <div class="row" id="networkIpv6HostAddressRow" style="display: none;">
-                  <label class="col-3 col-form-label text-right">IPv6 Host Address:</label>
-                  <div class="col-7">
-                    <div class="form-group">
-                      <input type="number" id="networkIpv6HostAddressInput" class="form-control" placeholder="" name="networkIpv6HostAddressInput">
-                    </div>
-                  </div>
-                  <div class="col-1">
-                    <i class="far fa-sm fa-question-circle" title='Enter in the IPv6 address to add to the host-side veth interface. Default: (fe80::1)'></i>
-                  </div>
-                </div>
-                <div class="row" id="networkIpv6RoutesRow" style="display: none;">
-                  <label class="col-3 col-form-label text-right">IPv6 Routes:</label>
-                  <div class="col-7">
-                    <div class="form-group">
-                      <input type="text" id="networkIpv6RoutesInput" class="form-control" placeholder="" name="networkIpv6RoutesInput">
-                    </div>
-                  </div>
-                  <div class="col-1">
-                    <i class="far fa-sm fa-question-circle" title='Enter in a comma seperated list of IPv4 static routes. Default: (not set)'></i>
-                  </div>
-                </div>
-                <div class="row" id="networkIpv6RoutesExternalRow" style="display: none;">
-                  <label class="col-3 col-form-label text-right">IPv6 Routes External:</label>
-                  <div class="col-7">
-                    <div class="form-group">
-                      <input type="text" id="networkIpv6RoutesExternalInput" class="form-control" placeholder="" name="networkIpv6RoutesExternalInput">
-                    </div>
-                  </div>
-                  <div class="col-1">
-                    <i class="far fa-sm fa-question-circle" title='Enter in a comma seperated list of static routes to route to the NIC and publish on the uplink. Default: (not set)'></i>
-                  </div>
-                </div>
-                <div class="row" id="networkSecurityMacFilteringRow" style="display: none;">
-                  <label class="col-3 col-form-label text-right">Security.MAC.Filtering:</label>
-                  <div class="col-7">
-                    <div class="form-group">
-                      <select id="networkSecurityMacFilteringInput" onchange="" class="form-control" name="networkSecurityMacFilteringInput">
-                        <option value="">(not set)</option>
-                        <option value="true">true</option>
-                        <option value="false">false</option>
-                      </select>
-                    </div>
-                  </div>
-                  <div class="col-1">
-                    <i class="far fa-sm fa-question-circle" title="Select wheter to prevent the instance from spoofing another's MAC address. Default: false"></i>
-                  </div>
-                </div>
-                <div class="row" id="networkSecurityIpv4FilteringRow" style="display: none;">
-                  <label class="col-3 col-form-label text-right">Security.IPv4.Filtering:</label>
-                  <div class="col-7">
-                    <div class="form-group">
-                      <select id="networkSecurityIpv4FilteringInput" onchange="" class="form-control" name="networkSecurityIpv4FilteringInput">
-                        <option value="">(not set)</option>
-                        <option value="true">true</option>
-                        <option value="false">false</option>
-                      </select>
-                    </div>
-                  </div>
-                  <div class="col-1">
-                    <i class="far fa-sm fa-question-circle" title="Select wheter to prevent the instance from spoofing another's IPv4 address (enables mac_filtering). Default: false"></i>
-                  </div>
-                </div>
-                <div class="row" id="networkSecurityIpv6FilteringRow" style="display: none;">
-                  <label class="col-3 col-form-label text-right">Security.IPv6.Filtering:</label>
-                  <div class="col-7">
-                    <div class="form-group">
-                      <select id="networkSecurityIpv6FilteringInput" onchange="" class="form-control" name="networkSecurityIpv6FilteringInput">
-                        <option value="">(not set)</option>
-                        <option value="true">true</option>
-                        <option value="false">false</option>
-                      </select>
-                    </div>
-                  </div>
-                  <div class="col-1">
-                    <i class="far fa-sm fa-question-circle" title="Select wheter to prevent the instance from spoofing another's IPv6 address (enables mac_filtering). Default: false"></i>
-                  </div>
-                </div>
-                <div class="row" id="networkMaasSubnetIpv4Row" style="display: none;">
-                  <label class="col-3 col-form-label text-right">MAAS Subnet IPv4:</label>
-                  <div class="col-7">
-                    <div class="form-group">
-                      <input type="text" id="networkMaasSubnetIpv4Input" class="form-control" placeholder="" name="networkMaasSubnetIpv4Input">
-                    </div>
-                  </div>
-                  <div class="col-1">
-                    <i class="far fa-sm fa-question-circle" title="Enter in the MAAS IPv4 subnet to register the instance in. Default: (not set)"></i>
-                  </div>
-                </div>
-                <div class="row" id="networkMaasSubnetIpv6Row" style="display: none;">
-                  <label class="col-3 col-form-label text-right">MAAS Subnet IPv6:</label>
-                  <div class="col-7">
-                    <div class="form-group">
-                      <input type="text" id="networkMaasSubnetIpv6Input" class="form-control" placeholder="" name="networkMaasSubnetIpv6Input">
-                    </div>
-                  </div>
-                  <div class="col-1">
-                    <i class="far fa-sm fa-question-circle" title="Enter in the MAAS IPv6 subnet to register the instance in. Default: (not set)"></i>
-                  </div>
-                </div>
-                <div class="row" id="networkBootPriorityRow" style="display: none;">
-                  <label class="col-3 col-form-label text-right">Boot Priority:</label>
-                  <div class="col-7">
-                    <div class="form-group">
-                      <input type="number" id="networkBootPriorityInput" class="form-control" placeholder="" name="networkBootPriorityInput">
-                    </div>
-                  </div>
-                  <div class="col-1">
-                    <i class="far fa-sm fa-question-circle" title="Enter in a boot priority number for VMs (highest number boots first). Default: (not set)"></i>
-                  </div>
-                </div>
-                <div class="row" id="networkVlanRow" style="display: none;">
-                  <label class="col-3 col-form-label text-right">VLAN:</label>
-                  <div class="col-7">
-                    <div class="form-group">
-                      <input type="number" id="networkVlanInput" class="form-control" placeholder="" name="networkVlanInput">
-                    </div>
-                  </div>
-                  <div class="col-1">
-                    <i class="far fa-sm fa-question-circle" title='Enter in a VLAN ID to use for untagged traffic. Enter "none" to remove the port from the default VLAN. Default: (not set)'></i>
-                  </div>
-                </div>
-                <div class="row" id="networkVlanTaggedRow" style="display: none;">
-                  <label class="col-3 col-form-label text-right">VLAN Tagged:</label>
-                  <div class="col-7">
-                    <div class="form-group">
-                      <input type="text" id="networkVlanTaggedInput" class="form-control" placeholder="" name="networkVlanTaggedInput">
-                    </div>
-                  </div>
-                  <div class="col-1">
-                    <i class="far fa-sm fa-question-circle" title="Enter in a comma seperated list of VLAN IDs to join. Default: (not set)"></i>
-                  </div>
-                </div>
-                <div class="row" id="networkSecurityPortIsolationRow" style="display: none;">
-                  <label class="col-3 col-form-label text-right">Security Port Isolation:</label>
-                  <div class="col-7">
-                    <div class="form-group">
-                      <select id="networkSecurityPortIsolationInput" onchange="" class="form-control" name="networkSecurityPortIsolationInput">
-                        <option value="">(not set)</option>
-                        <option value="true">true</option>
-                        <option value="false">false</option>
-                      </select>
-                    </div>
-                  </div>
-                  <div class="col-1">
-                    <i class="far fa-sm fa-question-circle" title="Select whether to prevent the NIC from communicating with other port isolated NICs in the network. Default: false"></i>
-                  </div>
-                </div>
-                <div class="row" id="networkGvrpRow" style="display: none;">
-                  <label class="col-3 col-form-label text-right">GVRP:</label>
-                  <div class="col-7">
-                    <div class="form-group">
-                      <select id="networkGvrpInput" onchange="" class="form-control" name="networkGvrpInput">
-                        <option value="">(not set)</option>
-                        <option value="true">true</option>
-                        <option value="false">false</option>
-                      </select>
-                    </div>
-                  </div>
-                  <div class="col-1">
-                    <i class="far fa-sm fa-question-circle" title="Select whether to register the VLAN using the GARP VLAN Registration Protocol. Default: false"></i>
-                  </div>
-                </div>
-                <div class="row" id="networkSecurityAclsRow" style="display: none;">
-                  <label class="col-3 col-form-label text-right">Security ACLs:</label>
-                  <div class="col-7">
-                    <div class="form-group">
-                      <input type="text" id="networkSecurityAclsInput" class="form-control" placeholder="" name="networkSecurityAclsInput">
-                    </div>
-                  </div>
-                  <div class="col-1">
-                    <i class="far fa-sm fa-question-circle" title="Enter in a comma separated list of Network ACLs. Default: (not set)"></i>
-                  </div>
-                </div>
-                <div class="row" id="networkSecurityAclsDefaultIngressActionRow" style="display: none;">
-                  <label class="col-3 col-form-label text-right">Security ACLs Default Ingress Action:</label>
-                  <div class="col-7">
-                    <div class="form-group">
-                      <select id="networkSecurityAclsDefaultIngressActionInput" onchange="" class="form-control" name="networkSecurityAclsDefaultIngressActionInput">
-                        <option value="">(not set)</option>
-                        <option value="allow">allow</option>
-                        <option value="reject">reject</option>
-                        <option value="drop">drop</option>
-                      </select>
-                    </div>
-                  </div>
-                  <div class="col-1">
-                    <i class="far fa-sm fa-question-circle" title="Select an action to use for ingress traffic without any matching ACL rules. Default: (reject)"></i>
-                  </div>
-                </div>
-                <div class="row" id="networkSecurityAclsDefaultEgressActionRow" style="display: none;">
-                  <label class="col-3 col-form-label text-right">Security ACLs Default Egress Action:</label>
-                  <div class="col-7">
-                    <div class="form-group">
-                      <select id="networkSecurityAclsDefaultEgressActionInput" onchange="" class="form-control" name="networkSecurityAclsDefaultEgressActionInput">
-                        <option value="">(not set)</option>
-                        <option value="allow">allow</option>
-                        <option value="reject">reject</option>
-                        <option value="drop">drop</option>
-                      </select>
-                    </div>
-                  </div>
-                  <div class="col-1">
-                    <i class="far fa-sm fa-question-circle" title="Select an action to use for egress traffic without any matching ACL rules. Default: (reject)"></i>
-                  </div>
-                </div>
-                <div class="row" id="networkSecurityAclsDefaultIngressLoggedRow" style="display: none;">
-                  <label class="col-3 col-form-label text-right">Security ACLs Default Ingress Logged:</label>
-                  <div class="col-7">
-                    <div class="form-group">
-                      <select id="networkSecurityAclsDefaultIngressLoggedInput" onchange="" class="form-control" name="networkSecurityAclsDefaultIngressLoggedInput">
-                        <option value="">(not set)</option>
-                        <option value="true">true</option>
-                        <option value="false">false</option>
-                      </select>
-                    </div>
-                  </div>
-                  <div class="col-1">
-                    <i class="far fa-sm fa-question-circle" title="Select whether to log ingress traffic without any matching ACL rules. Default: (false)"></i>
-                  </div>
-                </div>
-                <div class="row" id="networkSecurityAclsDefaultEgressLoggedRow" style="display: none;">
-                  <label class="col-3 col-form-label text-right">Security ACLs Default Egress Logged:</label>
-                  <div class="col-7">
-                    <div class="form-group">
-                      <select id="networkSecurityAclsDefaultEgressLoggedInput" onchange="" class="form-control" name="networkSecurityAclsDefaultEgressLoggedInput">
-                        <option value="">(not set)</option>
-                        <option value="true">true</option>
-                        <option value="false">false</option>
-                      </select>
-                    </div>
-                  </div>
-                  <div class="col-1">
-                    <i class="far fa-sm fa-question-circle" title="Select whether to log egress traffic without any matching ACL rules. Default: (false)"></i>
-                  </div>
-                </div>
-              </div>
-
-            </div>
-
-          </div>
-          <div class="modal-footer">
-            <button class="btn btn-secondary" type="button" data-dismiss="modal">Cancel</button>
-            <a class="btn btn-primary" href="#" onclick="addNetworkDevice()" data-dismiss="modal">Submit</a>
-          </div>
-      </div>
-    </div>
-  </div>
-
-  <!-- Add Proxy Device Modal-->
-  <div class="modal fade" id="addProxyDeviceModal" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel" aria-hidden="true">
-    <div class="modal-dialog modal-lg" role="document">
-      <div class="modal-content">
-          <div class="modal-header">
-            <h5 class="modal-title" id="exampleModalLabel">Add Proxy Device</h5>
-            <button class="close" type="button" data-dismiss="modal" aria-label="Close">
-              <span aria-hidden="true">×</span>
-            </button>
-          </div>
-          <div class="modal-body">
-            <div class="row">
-              <label class="col-3 col-form-label text-right">Device Name: <span class="text-danger">*</span></label>
-              <div class="col-7">
-                <div class="form-group">
-                  <input type="text" id="proxyDeviceNameInput" class="form-control" placeholder="" name="proxyDeviceNameInput">
-                </div>
-              </div>
-              <div class="col-1">
-                <i class="far fa-sm fa-question-circle" title='(Required) - Enter a unique name to identify this instance device'></i>
-              </div>
-            </div>
-            <div class="row">
-              <label class="col-3 col-form-label text-right">Listen: <span class="text-danger">*</span></label>
-              <div class="col-7">
-                <div class="form-group">
-                  <input type="text" id="proxyListenInput" class="form-control" placeholder="" name="proxyListenInput">
-                </div>
-              </div>
-              <div class="col-1">
-                <i class="far fa-sm fa-question-circle" title='(Required) - Enter in the connection type, address, and port to bind and listen to, using the format <type>:<addr>:<port>[-<port>][,<port>]. For example, tcp:0.0.0.0:8080'></i>
-              </div>
-            </div>
-            <div class="row">
-              <label class="col-3 col-form-label text-right">Connect: <span class="text-danger">*</span></label>
-              <div class="col-7">
-                <div class="form-group">
-                  <input type="text" id="proxyConnectInput" class="form-control" placeholder="" name="proxyConnectInput">
-                </div>
-              </div>
-              <div class="col-1">
-                <i class="far fa-sm fa-question-circle" title='(Required) - Enter in the connection type, address, and port to connect to, using the format <type>:<addr>:<port>[-<port>][,<port>]. For example, tcp:127.0.0.1:8080'></i>
-              </div>
-            </div>
-
-            <hr>
-
-            <div id="accordionProxyProperties">
-              <h2>
-                <button class="btn btn-link collapsed" type="button" data-toggle="collapse" data-target="#additionalProxyProperties" aria-expanded="false" aria-controls="additionalProxyProperties">
-                  Additional Properties
-                </button>
-              </h2> 
-              <div id="additionalProxyProperties" class="collapse" aria-labelledby="additionalProxyProperties">
-                <div class="row">
-                  <label class="col-3 col-form-label text-right">Bind:</label>
-                  <div class="col-7">
-                    <div class="form-group">
-                      <select id="proxyBindInput" onchange="" class="form-control" name="proxyBindInput">
-                        <option value="">(not set)</option>
-                        <option value="host">host</option>
-                        <option value="instance">instance</option>
-                      </select>
-                    </div>
-                  </div>
-                  <div class="col-1">
-                    <i class="far fa-sm fa-question-circle" title='Select which side to bind on. Default: host'></i>
-                  </div>
-                </div>
-                <div class="row">
-                  <label class="col-3 col-form-label text-right">UID:</label>
-                  <div class="col-7">
-                    <div class="form-group">
-                      <input type="number" id="proxyUidInput" class="form-control" placeholder="" name="proxyUidInput">
-                    </div>
-                  </div>
-                  <div class="col-1">
-                    <i class="far fa-sm fa-question-circle" title='Enter in the UID number of the owner to the listening Unix socket. Default: 0'></i>
-                  </div>
-                </div>
-                <div class="row">
-                  <label class="col-3 col-form-label text-right">GID:</label>
-                  <div class="col-7">
-                    <div class="form-group">
-                      <input type="number" id="proxyGidInput" class="form-control" placeholder="" name="proxyGidInput">
-                    </div>
-                  </div>
-                  <div class="col-1">
-                    <i class="far fa-sm fa-question-circle" title='Enter in the GID number of the owner ot the listening Unix socket. Default: 0'></i>
-                  </div>
-                </div>
-                <div class="row">
-                  <label class="col-3 col-form-label text-right">Mode:</label>
-                  <div class="col-7">
-                    <div class="form-group">
-                      <input type="number" id="proxyModeInput" class="form-control" placeholder="" name="proxyModeInput">
-                    </div>
-                  </div>
-                  <div class="col-1">
-                    <i class="far fa-sm fa-question-circle" title='Enter in the permissions mode for the listening Unix socket. Default: 0644'></i>
-                  </div>
-                </div>
-                <div class="row">
-                  <label class="col-3 col-form-label text-right">NAT:</label>
-                  <div class="col-7">
-                    <div class="form-group">
-                      <select id="proxyNatInput" onchange="" class="form-control" name="proxyNatInput">
-                        <option value="">(not set)</option>
-                        <option value="true">true</option>
-                        <option value="false">false</option>
-                      </select>
-                    </div>
-                  </div>
-                  <div class="col-1">
-                    <i class="far fa-sm fa-question-circle" title='Select whether or not to optimize proxying via NAT. Default: false'></i>
-                  </div>
-                </div>
-                <div class="row">
-                  <label class="col-3 col-form-label text-right">Proxy Protocol:</label>
-                  <div class="col-7">
-                    <div class="form-group">
-                      <select id="proxyProxyProtocolInput" onchange="" class="form-control" name="proxyProxyProtocolInput">
-                        <option value="">(not set)</option>
-                        <option value="true">true</option>
-                        <option value="false">false</option>
-                      </select>
-                    </div>
-                  </div>
-                  <div class="col-1">
-                    <i class="far fa-sm fa-question-circle" title='Select whether to use the HAProxy PROXY protocol to when sending information. Default: false'></i>
-                  </div>
-                </div>
-                <div class="row">
-                  <label class="col-3 col-form-label text-right">Security UID:</label>
-                  <div class="col-7">
-                    <div class="form-group">
-                      <input type="number" id="proxySecurityUidInput" class="form-control" placeholder="" name="proxySecurityUidInput">
-                    </div>
-                  </div>
-                  <div class="col-1">
-                    <i class="far fa-sm fa-question-circle" title='Enter in the UID for security privileges. Default: 0'></i>
-                  </div>
-                </div>
-                <div class="row">
-                  <label class="col-3 col-form-label text-right">Security GID:</label>
-                  <div class="col-7">
-                    <div class="form-group">
-                      <input type="number" id="proxySecurityGidInput" class="form-control" placeholder="" name="proxySecurityGidInput">
-                    </div>
-                  </div>
-                  <div class="col-1">
-                    <i class="far fa-sm fa-question-circle" title='Enter in the GID for security privileges. Default: 0'></i>
-                  </div>
-                </div>
-              </div>
-            </div>
-
-          </div>
-          <div class="modal-footer">
-            <button class="btn btn-secondary" type="button" data-dismiss="modal">Cancel</button>
-            <a class="btn btn-primary" href="#" onclick="addInstanceProxyDevice()" data-dismiss="modal">Submit</a>
-          </div>
-      </div>
-    </div>
-  </div>
-
-  <!-- Add Unix Device Modal-->
-  <div class="modal fade" id="addUnixDeviceModal" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel" aria-hidden="true">
-    <div class="modal-dialog modal-lg" role="document">
-      <div class="modal-content">
-          <div class="modal-header">
-            <h5 class="modal-title" id="exampleModalLabel">Add Unix Device</h5>
-            <button class="close" type="button" data-dismiss="modal" aria-label="Close">
-              <span aria-hidden="true">×</span>
-            </button>
-          </div>
-          <div class="modal-body">
-            <div class="row">
-              <label class="col-3 col-form-label text-right">Device Name: <span class="text-danger">*</span></label>
-              <div class="col-7">
-                <div class="form-group">
-                  <input type="text" id="unixDeviceNameInput" class="form-control" placeholder="" name="unixDeviceNameInput">
-                </div>
-              </div>
-              <div class="col-1">
-                <i class="far fa-sm fa-question-circle" title='(Required) - Enter a unique name to identify this instance device'></i>
-              </div>
-            </div>
-            <div class="row">
-              <label class="col-3 col-form-label text-right">Type: <span class="text-danger">*</span></label>
-              <div class="col-7">
-                <div class="form-group">
-                  <select id="unixTypeInput" class="form-control" name="unixTypeInput">
-                    <option value="unix-block">unix-block</option>
-                    <option value="unix-char">unix-char</option>
-                  </select>
-                </div>
-              </div>
-              <div class="col-1">
-                <i class="far fa-sm fa-question-circle" title='Select which Unix type to use'></i>
-              </div>
-            </div>
-            <div class="row">
-              <label class="col-3 col-form-label text-right">Source: <span class="text-danger">*</span></label>
-              <div class="col-7">
-                <div class="form-group">
-                  <input type="text" id="unixSourceInput" class="form-control" placeholder="" name="unixSourceInput">
-                </div>
-              </div>
-              <div class="col-1">
-                <i class="far fa-sm fa-question-circle" title='Enter in source filepath on the host'></i>
-              </div>
-            </div>
-            <div class="row">
-              <label class="col-3 col-form-label text-right">Path: <span class="text-danger">*</span></label>
-              <div class="col-7">
-                <div class="form-group">
-                  <input type="text" id="unixPathInput" class="form-control" placeholder="" name="unixPathInput">
-                </div>
-              </div>
-              <div class="col-1">
-                <i class="far fa-sm fa-question-circle" title='Enter in the filepath inside the instance'></i>
-              </div>
-            </div>
-
-            <hr>
-
-            <div id="accordionProxyProperties">
-              <h2>
-                <button class="btn btn-link collapsed" type="button" data-toggle="collapse" data-target="#additionalProxyProperties" aria-expanded="false" aria-controls="additionalProxyProperties">
-                  Additional Properties
-                </button>
-              </h2> 
-              <div id="additionalProxyProperties" class="collapse" aria-labelledby="additionalProxyProperties">
-                <div class="row">
-                  <label class="col-3 col-form-label text-right">Major:</label>
-                  <div class="col-7">
-                    <div class="form-group">
-                      <input type="number" id="unixMajorInput" class="form-control" placeholder="" name="unixMajorInput">
-                    </div>
-                  </div>
-                  <div class="col-1">
-                    <i class="far fa-sm fa-question-circle" title='Enter in the device major number'></i>
-                  </div>
-                </div>
-                <div class="row">
-                  <label class="col-3 col-form-label text-right">Minor:</label>
-                  <div class="col-7">
-                    <div class="form-group">
-                      <input type="number" id="unixMinorInput" class="form-control" placeholder="" name="unixMinorInput">
-                    </div>
-                  </div>
-                  <div class="col-1">
-                    <i class="far fa-sm fa-question-circle" title='Enter in the device minor number'></i>
-                  </div>
-                </div>
-                <div class="row">
-                  <label class="col-3 col-form-label text-right">UID:</label>
-                  <div class="col-7">
-                    <div class="form-group">
-                      <input type="number" id="unixUidInput" class="form-control" placeholder="" name="unixUidInput">
-                    </div>
-                  </div>
-                  <div class="col-1">
-                    <i class="far fa-sm fa-question-circle" title='Enter in the UID number of the device owner in the instance. Default: 0'></i>
-                  </div>
-                </div>
-                <div class="row">
-                  <label class="col-3 col-form-label text-right">GID:</label>
-                  <div class="col-7">
-                    <div class="form-group">
-                      <input type="number" id="unixGidInput" class="form-control" placeholder="" name="unixGidInput">
-                    </div>
-                  </div>
-                  <div class="col-1">
-                    <i class="far fa-sm fa-question-circle" title='Enter in the GID number of the device owner in the instance. Default: 0'></i>
-                  </div>
-                </div>
-                <div class="row">
-                  <label class="col-3 col-form-label text-right">Mode:</label>
-                  <div class="col-7">
-                    <div class="form-group">
-                      <input type="number" id="unixModeInput" class="form-control" placeholder="" name="unixModeInput">
-                    </div>
-                  </div>
-                  <div class="col-1">
-                    <i class="far fa-sm fa-question-circle" title='Enter in the permissions mode for the listening Unix socket. Default: 0660'></i>
-                  </div>
-                </div>
-                <div class="row">
-                  <label class="col-3 col-form-label text-right">Required:</label>
-                  <div class="col-7">
-                    <div class="form-group">
-                      <select id="unixRequiredInput" class="form-control" name="unixRequiredInput">
-                        <option value="">(not set)</option>
-                        <option value="true">True</option>
-                        <option value="false">False</option>
-                      </select>
-                    </div>
-                  </div>
-                  <div class="col-1">
-                    <i class="far fa-sm fa-question-circle" title='Select whether or not this device is required to start the instance. Default: true'></i>
-                  </div>
-                </div>
-
-              </div>
-            </div>
-
-          </div>
-          <div class="modal-footer">
-            <button class="btn btn-secondary" type="button" data-dismiss="modal">Cancel</button>
-            <a class="btn btn-primary" href="#" onclick="addInstanceUnixDevice()" data-dismiss="modal">Submit</a>
-          </div>
-      </div>
-    </div>
-  </div>
-
-  <!-- Add USB Device Modal-->
-  <div class="modal fade" id="addUSBDeviceModal" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel" aria-hidden="true">
-    <div class="modal-dialog modal-lg" role="document">
-      <div class="modal-content">
-          <div class="modal-header">
-            <h5 class="modal-title" id="exampleModalLabel">Add USB Device</h5>
-            <button class="close" type="button" data-dismiss="modal" aria-label="Close">
-              <span aria-hidden="true">×</span>
-            </button>
-          </div>
-          <div class="modal-body">
-            <div class="row">
-              <label class="col-3 col-form-label text-right">Device Name: <span class="text-danger">*</span></label>
-              <div class="col-7">
-                <div class="form-group">
-                  <input type="text" id="usbDeviceNameInput" class="form-control" placeholder="" name="usbDeviceNameInput">
-                </div>
-              </div>
-              <div class="col-1">
-                <i class="far fa-sm fa-question-circle" title='(Required) - Enter a unique name to identify this instance device'></i>
-              </div>
-            </div>
-            <div class="row">
-              <label class="col-3 col-form-label text-right">Vendor Id: <span class="text-danger">*</span></label>
-              <div class="col-7">
-                <div class="form-group">
-                  <input type="text" id="usbVendoridInput" class="form-control" placeholder="" name="usbVendoridInput">
-                </div>
-              </div>
-              <div class="col-1">
-                <i class="far fa-sm fa-question-circle" title='Enter in the vendor id of the usb device'></i>
-              </div>
-            </div>
-            <div class="row">
-              <label class="col-3 col-form-label text-right">Product Id: <span class="text-danger">*</span></label>
-              <div class="col-7">
-                <div class="form-group">
-                  <input type="text" id="usbProductidInput" class="form-control" placeholder="" name="usbProductidInput">
-                </div>
-              </div>
-              <div class="col-1">
-                <i class="far fa-sm fa-question-circle" title='Enter in the product id of the usb device'></i>
-              </div>
-            </div>
-
-            <hr>
-
-            <div id="accordionProxyProperties">
-              <h2>
-                <button class="btn btn-link collapsed" type="button" data-toggle="collapse" data-target="#additionalProxyProperties" aria-expanded="false" aria-controls="additionalProxyProperties">
-                  Additional Properties
-                </button>
-              </h2> 
-              <div id="additionalProxyProperties" class="collapse" aria-labelledby="additionalProxyProperties">
-
-                <div class="row">
-                  <label class="col-3 col-form-label text-right">UID:</label>
-                  <div class="col-7">
-                    <div class="form-group">
-                      <input type="number" id="usbUidInput" class="form-control" placeholder="" name="usbUidInput">
-                    </div>
-                  </div>
-                  <div class="col-1">
-                    <i class="far fa-sm fa-question-circle" title='Enter in the UID number of the owner to the listening Unix socket. Default: 0'></i>
-                  </div>
-                </div>
-                <div class="row">
-                  <label class="col-3 col-form-label text-right">GID:</label>
-                  <div class="col-7">
-                    <div class="form-group">
-                      <input type="number" id="usbGidInput" class="form-control" placeholder="" name="usbGidInput">
-                    </div>
-                  </div>
-                  <div class="col-1">
-                    <i class="far fa-sm fa-question-circle" title='Enter in the GID number of the owner ot the listening Unix socket. Default: 0'></i>
-                  </div>
-                </div>
-                <div class="row">
-                  <label class="col-3 col-form-label text-right">Mode:</label>
-                  <div class="col-7">
-                    <div class="form-group">
-                      <input type="number" id="usbModeInput" class="form-control" placeholder="" name="usbModeInput">
-                    </div>
-                  </div>
-                  <div class="col-1">
-                    <i class="far fa-sm fa-question-circle" title='Enter in the permissions mode for the listening Unix socket. Default: 0644'></i>
-                  </div>
-                </div>
-
-              </div>
-            </div>
-
-          </div>
-          <div class="modal-footer">
-            <button class="btn btn-secondary" type="button" data-dismiss="modal">Cancel</button>
-            <a class="btn btn-primary" href="#" onclick="addInstanceUSBDevice()" data-dismiss="modal">Submit</a>
-          </div>
-      </div>
-    </div>
-  </div>
-
-  <!-- Publish Instance Modal-->
-  <div class="modal fade" id="publishInstanceModal" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel" aria-hidden="true">
-    <div class="modal-dialog" role="document">
-      <div class="modal-content">
-          <div class="modal-header">
-            <h5 class="modal-title" id="exampleModalLabel">Publish Image from Instance</h5>
-            <button class="close" type="button" data-dismiss="modal" aria-label="Close">
-              <span aria-hidden="true">×</span>
-            </button>
-          </div>
-          <div class="modal-body">
-            <div class="row">
-              <label class="col-3 col-form-label text-right">Description: </label>
-              <div class="col-7">
-                <div class="form-group">
-                  <input type="text" id="publishInstanceDescriptionInput" class="form-control" placeholder="" name="description">
-                </div>
-              </div>
-              <div class="col-1">
-                <i class="far fa-sm fa-question-circle" title='Enter in a description for the new image.'></i>
-              </div>
-            </div>
-            <div class="row">
-              <label class="col-3 col-form-label text-right">OS: </label>
-              <div class="col-7">
-                <div class="form-group">
-                  <input type="text" id="publishInstanceOsInput" class="form-control" placeholder="" name="os">
-                </div>
-              </div>
-              <div class="col-1">
-                <i class="far fa-sm fa-question-circle" title='Enter in the operating system name for the new image.'></i>
-              </div>
-            </div>
-            <div class="row">
-              <label class="col-3 col-form-label text-right">Release: </label>
-              <div class="col-7">
-                <div class="form-group">
-                  <input type="text" id="publishInstanceReleaseInput" class="form-control" placeholder="" name="release">
-                </div>
-              </div>
-              <div class="col-1">
-                <i class="far fa-sm fa-question-circle" title='Enter in the release version for the new image.'></i>
-              </div>
-            </div>
-            <div class="row">
-              <label class="col-3 col-form-label text-right">Public:</label>
-              <div class="col-7">
-                <div class="form-group">
-                  <select id="publishInstancePublicInput" class="form-control" name="public">
-                    <option value="false" selected>false</option>
-                    <option value="true">true</option>
-                  </select>
-                </div>
-              </div>
-              <div class="col-1">
-                <i class="far fa-sm fa-question-circle" title='Select whether or not this image is public. Default: false'></i>
-              </div>
-            </div>
-          </div>
-          <div class="modal-footer">
-            <button class="btn btn-secondary" type="button" data-dismiss="modal">Cancel</button>
-            <a class="btn btn-primary" href="#" onclick="publishInstance()" data-dismiss="modal">Submit</a>
-          </div>
-      </div>
-    </div>
-  </div>
-
-  <!-- Load Log Modal-->
-  <div class="modal fade" id="loadLogModal" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel" aria-hidden="true">
-    <div class="modal-dialog modal-lg" role="document">
-      <div class="modal-content">
-          <div class="modal-header">
-            <h5 class="modal-title" id="exampleModalLabel">Log Contents</h5>
-            <button class="close" type="button" data-dismiss="modal" aria-label="Close">
-              <span aria-hidden="true">×</span>
-            </button>
-          </div>
-          <div class="modal-body">
-            <div class="row">
-              <label class="col-12 col-form-label" id="logNameInput"></label>
-              <div class="col-12">
-                <div class="form-group text-right">
-                  <pre>
-                    <textarea name="log_data" class="form-control" id="logDataInput" rows="16" ></textarea>
-                  </pre>
-                </div>
-              </div>
-            </div>
-          </div>
-          <div class="modal-footer">
-            <button class="btn btn-secondary" type="button" data-dismiss="modal">Close</button>
-          </div>
-      </div>
-    </div>
-  </div>
-
-  <!-- Edit Modal-->
-  <div class="modal fade" id="editModal" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel" aria-hidden="true">
-    <div class="modal-dialog modal-xl" role="document">
-      <div class="modal-content">
-          <div class="modal-header">
-            <h5 class="modal-title" id="exampleModalLabel">Edit Virtual Machine</h5>
-            <button class="close" type="button" data-dismiss="modal" aria-label="Close">
-              <span aria-hidden="true">×</span>
-            </button>
-          </div>
-          <div class="modal-body">
-            <ul class="nav nav-tabs" id="myTab" role="tablist">
-              <li class="nav-item">
-                <a class="nav-link active" id="form-tab" data-toggle="tab" href="#form" role="tab" aria-controls="form" aria-selected="true">Form</a>
-              </li>
-              <li class="nav-item">
-                <a class="nav-link" id="json-tab" data-toggle="tab" href="#json" role="tab" aria-controls="json" aria-selected="false">JSON</a>
-              </li>
-            </ul>
-            <div class="tab-content" id="myTabContent">
-              
-              <div class="tab-pane fade show active" id="form" role="tabpanel" aria-labelledby="form-tab">
-                <br />
-                <form id="editForm">
-                  <div class="row">
-                    <label class="col-3 col-form-label text-right">Description: </label>
-                    <div class="col-7">
-                      <div class="form-group">
-                        <input type="text" id="virtualMachineDescriptionInput" class="form-control" required="required" name="description">
-                      </div>
-                    </div>
-                    <div class="col-1">
-                      <i class="far fa-sm fa-question-circle" title='Enter in a description for this virtual machine'></i>
-                    </div>
-                  </div>
-                  <hr>
-                  <nav>
-                    <div class="nav nav-pills justify-content-center" id="nav-tab" role="tablist">
-                      <a class="nav-link active" id="nav-boot-tab" data-toggle="tab" href="#nav-boot" role="tab" aria-controls="nav-boot" aria-selected="true">Boot</a>
-                      <a class="nav-link" id="nav-cloud-init-tab" data-toggle="tab" href="#nav-cloud-init" role="tab" aria-controls="nav-cloud-init" aria-selected="true">Cloud-init</a>
-                      <a class="nav-link" id="nav-limits-tab" data-toggle="tab" href="#nav-limits" role="tab" aria-controls="nav-limits" aria-selected="false">Limits</a>
-                      <a class="nav-link" id="nav-migration-tab" data-toggle="tab" href="#nav-migration" role="tab" aria-controls="nav-migration" aria-selected="false">Migration</a>
-                      <a class="nav-link" id="nav-other-tab" data-toggle="tab" href="#nav-other" role="tab" aria-controls="nav-other" aria-selected="false">Other</a>
-                      <a class="nav-link" id="nav-raw-tab" data-toggle="tab" href="#nav-raw" role="tab" aria-controls="nav-raw" aria-selected="false">Raw</a>
-                      <a class="nav-link" id="nav-security-tab" data-toggle="tab" href="#nav-security" role="tab" aria-controls="nav-security" aria-selected="false">Security</a>
-                      <a class="nav-link" id="nav-snapshots-config-tab" data-toggle="tab" href="#nav-snapshots-config" role="tab" aria-controls="nav-snapshots-config" aria-selected="false">Snapshots</a>
-                    </div>
-                  </nav>
-                  <hr class="mt-2">
-                  <div class="tab-content" id="nav-tabContent">
-                    <div class="tab-pane fade show active" id="nav-boot" role="tabpanel" aria-labelledby="nav-boot-tab">
-                      <br>
-                      <div class="row">
-                        <label class="col-4 col-form-label text-right">Autostart: </label>
-                        <div class="col-6">
-                          <div class="form-group">
-                            <select id="boot.autostart" onchange="" class="form-control" name="boot.autostart">
-                              <option value="">(not set)</option>
-                              <option value="true">true</option>
-                              <option value="false">false</option>
-                            </select>
-                          </div>
-                        </div>
-                        <div class="col-1">
-                          <i class="far fa-sm fa-question-circle" title='Select whether to automatically start the virtualMachine with LXD starts. If not set, defaults to virtual machine last state.'></i>
-                        </div>
-                      </div>
-                      <div class="row">
-                        <label class="col-4 col-form-label text-right">Autostart Delay: </label>
-                        <div class="col-6">
-                          <div class="form-group">
-                            <input type="number" id="virtualMachineBootAutostartDelayInput" class="form-control" placeholder="" name="boot.autostart.delay">
-                          </div>
-                        </div>
-                        <div class="col-1">
-                          <i class="far fa-sm fa-question-circle" title='Enter in the number of seconds to wait after the virtual machine starts to boot up the next virtual machine. Default: 0.'></i>
-                        </div>
-                      </div>
-                      <div class="row">
-                        <label class="col-4 col-form-label text-right">Autostart Priority: </label>
-                        <div class="col-6">
-                          <div class="form-group">
-                            <input type="number" id="virtualMachineBootAutostartPriorityInput" class="form-control" placeholder="" name="boot.autostart.priority">
-                          </div>
-                        </div>
-                        <div class="col-1">
-                          <i class="far fa-sm fa-question-circle" title='Enter in a number to determine the order the virtual machine boots, higher numbers being first. Default: 0.'></i>
-                        </div>
-                      </div>
-                      <div class="row">
-                        <label class="col-4 col-form-label text-right">Host Shutdown Timeout: </label>
-                        <div class="col-6">
-                          <div class="form-group">
-                            <input type="number" id="virtualMachineBootHostShutdownTimeoutInput" class="form-control" placeholder="" name="boot.host_shutdown_timeout">
-                          </div>
-                        </div>
-                        <div class="col-1">
-                          <i class="far fa-sm fa-question-circle" title='Enter in a the number of seconds to wait on host shutdown before forcefull shutdown of virtual machine. Default: 30.'></i>
-                        </div>
-                      </div>
-                      <div class="row">
-                        <label class="col-4 col-form-label text-right">Stop Priority: </label>
-                        <div class="col-6">
-                          <div class="form-group">
-                            <input type="number" id="virtualMachineBootStopPriorityInput" class="form-control" placeholder="" name="boot.stop.priority">
-                          </div>
-                        </div>
-                        <div class="col-1">
-                          <i class="far fa-sm fa-question-circle" title='Enter in a number to determine the order the virtual machine shutsdown, higher numbers being first. Default: 0.'></i>
-                        </div>
-                      </div>
-                    </div>
-                    <div class="tab-pane fade" id="nav-cloud-init" role="tabpanel" aria-labelledby="nav-cloud-init-tab">
-                      <br>
-                      <div class="row">
-                        <label class="col-4 col-form-label text-right">Network Config: </label>
-                        <div class="col-6">
-                          <div class="form-group">
-                            <textarea class="form-control" name="cloud-init.network-config"></textarea>
-                          </div>
-                        </div>
-                        <div class="col-1">
-                          <i class="far fa-sm fa-question-circle" title='Support for this option depends on the instance image. Enter in network configuration. Default: not set.'></i>
-                        </div>
-                      </div>
-                      <div class="row">
-                        <label class="col-4 col-form-label text-right">User Data: </label>
-                        <div class="col-6">
-                          <div class="form-group">
-                            <textarea class="form-control" name="cloud-init.user-data"></textarea>
-                          </div>
-                        </div>
-                        <div class="col-1">
-                          <i class="far fa-sm fa-question-circle" title='Support for this option depends on the instance image. Enter in user data configuration. If both cloud-init.user-data and cloud-init.vendor-data exist, the contents of both are merged. Default: not set.'></i>
-                        </div>
-                      </div>
-                      <div class="row">
-                        <label class="col-4 col-form-label text-right">Vendor Data: </label>
-                        <div class="col-6">
-                          <div class="form-group">
-                            <textarea class="form-control" name="cloud-init.vendor-data"></textarea>
-                          </div>
-                        </div>
-                        <div class="col-1">
-                          <i class="far fa-sm fa-question-circle" title='Support for this option depends on the instance image. Enter in vendor data configuration. If both cloud-init.user-data and cloud-init.vendor-data exist, the contents of both are merged. Default: not set.'></i>
-                        </div>
-                      </div>
-                    </div>
-                    <div class="tab-pane fade" id="nav-limits" role="tabpanel" aria-labelledby="nav-limits-tab">
-                      <br>
-                      <div class="row">
-                        <label class="col-4 col-form-label text-right">CPU: </label>
-                        <div class="col-6">
-                          <div class="form-group">
-                            <input type="text" id="virtualMachineLimitsCpuInput" class="form-control" placeholder="" name="limits.cpu">
-                          </div>
-                        </div>
-                        <div class="col-1">
-                          <i class="far fa-sm fa-question-circle" title='Enter in the number or range of CPUs to expose to the virtual machine.'></i>
-                        </div>
-                      </div>
-                      <div class="row">
-                        <label class="col-4 col-form-label text-right">Disk Priority: </label>
-                        <div class="col-6">
-                          <div class="form-group">
-                            <input type="number" id="virtualMachineLimitsDiskPriorityInput" class="form-control" placeholder="" name="limits.disk.priority">
-                          </div>
-                        </div>
-                        <div class="col-1">
-                          <i class="far fa-sm fa-question-circle" title='Enter in an integer between 0 (min) and 10 (max) to schedule disk I/O request priority compared to other virtual machines. Default: 5.'></i>
-                        </div>
-                      </div>
-                      <div class="row">
-                        <label class="col-4 col-form-label text-right">Memory: </label>
-                        <div class="col-6">
-                          <div class="form-group">
-                            <input type="text" id="virtualMachineLimitsMemoryInput" class="form-control" placeholder="" name="limits.memory">
-                          </div>
-                        </div>
-                        <div class="col-1">
-                          <i class="far fa-sm fa-question-circle" title="Enter in a percentage of the host's memory or enter in a fixed value of bytes."></i>
-                        </div>
-                      </div>
-                      <div class="row">
-                        <label class="col-4 col-form-label text-right">Memory Hugepages: </label>
-                        <div class="col-6">
-                          <div class="form-group">
-                            <select class="form-control" name="limits.memory.hugepages">
-                              <option value="">(not set)</option>
-                              <option value="true">true</option>
-                              <option value="false">false</option>
-                            </select>
-                          </div>
-                        </div>
-                        <div class="col-1">
-                          <i class="far fa-sm fa-question-circle" title="Select whether to back the instance using hugepages rather than regular system memory. Default: false."></i>
-                        </div>
-                      </div>
-                      <div class="row">
-                        <label class="col-4 col-form-label text-right">Network Priority: </label>
-                        <div class="col-6">
-                          <div class="form-group">
-                            <input type="number" id="virtualMachineLimitsNetworkPriorityInput" class="form-control" placeholder="" name="limits.network.priority">
-                          </div>
-                        </div>
-                        <div class="col-1">
-                          <i class="far fa-sm fa-question-circle" title="Enter in the priority for the virtual machine network when the host is under, with 10 being the priority. Default 0."></i>
-                        </div>
-                      </div>
-                    </div>
-                    <div class="tab-pane fade" id="nav-migration" role="tabpanel" aria-labelledby="nav-migration-tab">
-                      <br>
-                      <div class="row">
-                        <label class="col-4 col-form-label text-right">Stateful: </label>
-                        <div class="col-6">
-                          <div class="form-group">
-                            <select class="form-control" name="migration.stateful">
-                              <option value="">(not set)</option>
-                              <option value="true">true</option>
-                              <option value="false">false</option>
-                            </select>
-                          </div>
-                        </div>
-                        <div class="col-1">
-                          <i class="far fa-sm fa-question-circle" title="Select whether to allow for stateful stop/start and snapshots. This will prevent the use of some features that are incompatible with it. Default: false."></i>
-                        </div>
-                      </div>
-                      <div class="row">
-                        <label class="col-4 col-form-label text-right">Incremental Memory Goal: </label>
-                        <div class="col-6">
-                          <div class="form-group">
-                            <input type="number" id="virtualMachineMigrationIncrementalMemoryGoalInput" class="form-control" placeholder="" name="migration.incremental.memory.goal">
-                          </div>
-                        </div>
-                        <div class="col-1">
-                          <i class="far fa-sm fa-question-circle" title="Enter in the percentage number of memory to have in sync before stopping the virtual machine. Default: 70."></i>
-                        </div>
-                      </div>
-                      <div class="row">
-                        <label class="col-4 col-form-label text-right">Incremental Memory Iterations: </label>
-                        <div class="col-6">
-                          <div class="form-group">
-                            <input type="number" id="virtualMachineMigrationIncrementalMemoryIterationsInput" class="form-control" placeholder="" name="migration.incremental.memory.iterations">
-                          </div>
-                        </div>
-                        <div class="col-1">
-                          <i class="far fa-sm fa-question-circle" title="Enter in the maximum number of transfer operations to go through before stopping the virtual machine. Default: 10."></i>
-                        </div>
-                      </div>
-                    </div>
-                    <div class="tab-pane fade" id="nav-other" role="tabpanel" aria-labelledby="nav-other-tab">
-                      <br>
-                      <div class="row">
-                        <label class="col-4 col-form-label text-right">Cluster Evacuate: </label>
-                        <div class="col-6">
-                          <div class="form-group">
-                            <select id="virtualMachineClusterEvacuateInput" onchange="" class="form-control" name="cluster.evacuate">
-                              <option value="">(not set)</option>
-                              <option value="auto">auto</option>
-                              <option value="migrate">migrate</option>
-                              <option value="stop">stop</option>
-                            </select>
-                          </div>
-                        </div>
-                        <div class="col-1">
-                          <i class="far fa-sm fa-question-circle" title='Select what to do when evacuating the virtual machine. Default: auto'></i>
-                        </div>
-                      </div>
-                    </div>
-                    <div class="tab-pane fade" id="nav-raw" role="tabpanel" aria-labelledby="nav-raw-tab">
-                      <br>
-                      <div class="row">
-                        <label class="col-4 col-form-label text-right">Apparmor: </label>
-                        <div class="col-6">
-                          <div class="form-group">
-                            <input type="text" id="virtualMachineRawApparmorInput" class="form-control" placeholder="" name="raw.apparmor">
-                          </div>
-                        </div>
-                        <div class="col-1">
-                          <i class="far fa-sm fa-question-circle" title="Enter in apparmor profile entries to be appended to the profile. Default: (not set)."></i>
-                        </div>
-                      </div>
-                      <div class="row">
-                        <label class="col-4 col-form-label text-right">Qemu: </label>
-                        <div class="col-6">
-                          <div class="form-group">
-                            <input type="text" class="form-control" name="raw.qemu">
-                          </div>
-                        </div>
-                        <div class="col-1">
-                          <i class="far fa-sm fa-question-circle" title="Enter raw QEMU configuration to be appended to the generated command line. Default: (not set)."></i>
-                        </div>
-                      </div>
-                      <div class="row">
-                        <label class="col-4 col-form-label text-right">Qemu.conf: </label>
-                        <div class="col-6">
-                          <div class="form-group">
-                            <input type="text" class="form-control" name="raw.qemu.conf">
-                          </div>
-                        </div>
-                        <div class="col-1">
-                          <i class="far fa-sm fa-question-circle" title="Enter in addition/override to the generated qemu.conf file. Default: (not set)."></i>
-                        </div>
-                      </div>
-                    </div>
-                    <div class="tab-pane fade" id="nav-security" role="tabpanel" aria-labelledby="nav-security-tab">
-                      <br>
-                      <div class="row">
-                        <label class="col-4 col-form-label text-right">Devlxd: </label>
-                        <div class="col-6">
-                          <div class="form-group">
-                            <select id="virtualMachineSecurityDevLxdInput" onchange="" class="form-control" name="security.devlxd">
-                              <option value="">(not set)</option>
-                              <option value="true">true</option>
-                              <option value="false">false</option>
-                            </select>
-                          </div>
-                        </div>
-                        <div class="col-1">
-                          <i class="far fa-sm fa-question-circle" title="Select whether to control the presence of /dev/lxd in the virtual machine. Default: true."></i>
-                        </div>
-                      </div>
-                      <div class="row">
-                        <label class="col-4 col-form-label text-right">Protection Delete: </label>
-                        <div class="col-6">
-                          <div class="form-group">
-                            <select class="form-control" name="security.protection.delete">
-                              <option value="">(not set)</option>
-                              <option value="true">true</option>
-                              <option value="false">false</option>
-                            </select>
-                          </div>
-                        </div>
-                        <div class="col-1">
-                          <i class="far fa-sm fa-question-circle" title="Select whether to prevent the instance from being deleted. Default: false."></i>
-                        </div>
-                      </div>
-                      <div class="row">
-                        <label class="col-4 col-form-label text-right">Agent Metrics: </label>
-                        <div class="col-6">
-                          <div class="form-group">
-                            <select class="form-control" name="security.agent.metrics">
-                              <option value="">(not set)</option>
-                              <option value="true">true</option>
-                              <option value="false">false</option>
-                            </select>
-                          </div>
-                        </div>
-                        <div class="col-1">
-                          <i class="far fa-sm fa-question-circle" title="Select whether the lxd-agent is queried for state information and metrics. Default: true."></i>
-                        </div>
-                      </div>
-                      <div class="row">
-                        <label class="col-4 col-form-label text-right">Secureboot: </label>
-                        <div class="col-6">
-                          <div class="form-group">
-                            <select class="form-control" name="security.secureboot">
-                              <option value="">(not set)</option>
-                              <option value="true">true</option>
-                              <option value="false">false</option>
-                            </select>
-                          </div>
-                        </div>
-                        <div class="col-1">
-                          <i class="far fa-sm fa-question-circle" title="Select whether whether UEFI secure boot is enabled with the default Microsoft keys. Default: true."></i>
-                        </div>
-                      </div>
-                    </div>
-                    <div class="tab-pane fade" id="nav-snapshots-config" role="tabpanel" aria-labelledby="nav-snapshots-config-tab">
-                      <br>
-                      <div class="row">
-                        <label class="col-4 col-form-label text-right">Schedule: </label>
-                        <div class="col-6">
-                          <div class="form-group">
-                            <input type="text" id="virtualMachineSnapshotsScheduleInput" class="form-control" placeholder="" name="snapshots.schedule">
-                          </div>
-                        </div>
-                        <div class="col-1">
-                          <i class="far fa-sm fa-question-circle" title="Enter in a cron expression (<minute> <hour> <dom> <month> <dow>), or a comma separated list of schedule aliases <@hourly> <@daily> <@midnight> <@weekly> <@monthly> <@annually> <@yearly> <@startup>. Default: (not set)."></i>
-                        </div>
-                      </div>
-                      <div class="row">
-                        <label class="col-4 col-form-label text-right">Schedule Stopped: </label>
-                        <div class="col-6">
-                          <div class="form-group">
-                            <select id="virtualMachineSnapshotsScheduleStoppedInput" onchange="" class="form-control" name="snapshots.schedule.stopped">
-                              <option value="">(not set)</option>
-                              <option value="true">true</option>
-                              <option value="false">false</option>
-                            </select>
-                          </div>
-                        </div>
-                        <div class="col-1">
-                          <i class="far fa-sm fa-question-circle" title="Select whether stopped virtual machines are to be snapshoted automatically. Default: false."></i>
-                        </div>
-                      </div>
-                      <div class="row">
-                        <label class="col-4 col-form-label text-right">Pattern: </label>
-                        <div class="col-6">
-                          <div class="form-group">
-                            <input type="text" id="virtualMachineSnapshotsPatternInput" class="form-control" placeholder="" name="snapshots.pattern">
-                          </div>
-                        </div>
-                        <div class="col-1">
-                          <i class="far fa-sm fa-question-circle" title="Enter in a pongo2 template string representing the snapshot name. Default: snap%d."></i>
-                        </div>
-                      </div>
-                      <div class="row">
-                        <label class="col-4 col-form-label text-right">Expiry: </label>
-                        <div class="col-6">
-                          <div class="form-group">
-                            <input type="text" id="virtualMachineSnapshotsExpiryInput" class="form-control" placeholder="" name="snapshots.expiry">
-                          </div>
-                        </div>
-                        <div class="col-1">
-                          <i class="far fa-sm fa-question-circle" title="Enter in time controls when snapshots are to be deleted (expects expressions like 1M 2H 3d 4w 5m 6y). Default: (not set)."></i>
-                        </div>
-                      </div>
-                      
-                    </div>
-                  </div>
-                </form>
-                <div class="modal-footer">
-                  <button class="btn btn-secondary" type="button" data-dismiss="modal">Cancel</button>
-                  <a class="btn btn-primary" href="#" id="editFormSubmit" onclick="updateInstanceForm()" data-dismiss="modal">Submit</a>
-                </div>
-              </div>
-             
-              <div class="tab-pane fade" id="json" role="tabpanel" aria-labelledby="json-tab">
-                <br />
-                <div class="row">
-                  <label class="col-12 col-form-label" id="instanceNameEditInput"></label>
-                  <div class="col-12">
-                    <div class="form-group text-right">
-                      <pre>
-                        <textarea name="json" class="form-control" id="jsonEditInput" rows="16" placeholder="Enter JSON data"></textarea>
-                      </pre>
-                    </div>
-                  </div>
-                </div>
-                <div class="modal-footer">
-                  <button class="btn btn-secondary" type="button" data-dismiss="modal">Cancel</button>
-                  <a class="btn btn-primary" href="#" onclick="updateInstanceJson()" data-dismiss="modal">Save</a>
-                </div>
-              </div>
-            </div>
-          </div>
-      </div>
-    </div>
-  </div>
-
-
-    <!-- Web Socket Connection Error Modal-->
-    <div class="modal fade" id="webSocketConnectionErrorModal" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel" aria-hidden="true">
-      <div class="modal-dialog" role="document">
-        <div class="modal-content">
-          <div class="modal-header">
-            <h5 class="modal-title" id="exampleModalLabel">WebSocket Connection Error</h5>
-            <button class="close" type="button" data-dismiss="modal" aria-label="Close">
-              <span aria-hidden="true">×</span>
-            </button>
-          </div>
-          <div class="modal-body">
-            <div class="row">
-              <div class="col-12">
-                <div id="webSocketConnectionError"></div>
-              </div>
-            </div>
-          </div>
-          <div class="modal-footer">
-            <button class="btn btn-secondary" type="button" data-dismiss="modal">Dismiss</button>
-          </div>
-        </div>
-      </div>
-    </div>

+ 0 - 655
lxconsole/templates/modals/virtual-machines.html

@@ -1,655 +0,0 @@
-<!-- Add Modal-->
-<div class="modal fade" id="addModal" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel" aria-hidden="true">
-  <div class="modal-dialog modal-lg" role="document">
-    <div class="modal-content">
-        <div class="modal-header">
-          <h5 class="modal-title" id="exampleModalLabel">Create Virtual Machine</h5>
-          <button class="close" type="button" data-dismiss="modal" aria-label="Close">
-            <span aria-hidden="true">×</span>
-          </button>
-        </div>
-        <div class="modal-body">
-          <ul class="nav nav-tabs" id="myTab" role="tablist">
-            <li class="nav-item">
-              <a class="nav-link active" id="form-tab" data-toggle="tab" href="#form" role="tab" aria-controls="form" aria-selected="true">Form</a>
-            </li>
-            <li class="nav-item">
-              <a class="nav-link" id="json-tab" data-toggle="tab" href="#json" role="tab" aria-controls="json" aria-selected="false">JSON</a>
-            </li>
-          </ul>
-          <div class="tab-content" id="myTabContent">
-            <div class="tab-pane fade show active" id="form" role="tabpanel" aria-labelledby="form-tab">
-              <br />
-              <form id="addForm">
-
-                <div class="row">
-                  <label class="col-3 col-form-label text-right">Name: <span class="text-danger">*</span> </label>
-                  <div class="col-7">
-                    <div class="form-group">
-                      <input type="text" class="form-control" required="required" name="name">
-                    </div>
-                  </div>
-                  <div class="col-1">
-                    <i class="far fa-sm fa-question-circle" title='Enter in a name for this instance'></i>
-                  </div>
-                </div>
-                <div class="row">
-                  <label class="col-3 col-form-label text-right">Description: </label>
-                  <div class="col-7">
-                    <div class="form-group">
-                      <input type="text" class="form-control" required="required" name="description">
-                    </div>
-                  </div>
-                  <div class="col-1">
-                    <i class="far fa-sm fa-question-circle" title='Enter in a description for this instance'></i>
-                  </div>
-                </div>
-                <div class="row">
-                  <label class="col-3 col-form-label text-right">Image: </label>
-                  <div class="col-7">
-                    <div class="form-group">
-                      <select id="virtualMachineImageInput" class="form-control" name="image">
-                        <option value="none">none</option>
-                      </select>
-                    </div>
-                  </div>
-                  <div class="col-1">
-                    <i class="far fa-sm fa-question-circle" title='Select a downloaded image to use to build the instance'></i>
-                  </div>
-                </div>
-                <div class="row">
-                  <label class="col-3 col-form-label text-right">Profiles: </label>
-                  <div class="col-7">
-                    <div class="form-group">
-                      <select id="virtualMachineProfileInput" class="form-control" name="profiles">
-                      </select>
-                    </div>
-                  </div>
-                  <div class="col-1">
-                    <i class="far fa-sm fa-question-circle" title='Select the initial profile to attach to this instance. Additional profiles can be attached after the instance is created. Default: default'></i>
-                  </div>
-                </div>
-                <div class="row">
-                  <label class="col-3 col-form-label text-right">Instance Type: </label>
-                  <div class="col-7">
-                    <div class="form-group">
-                      <select class="form-control" name="instance_type">
-                        <option value="" selected>(not set)</option>
-                        <option disabled>--- AWS Instance Types ---</option>
-                        <option value="aws:c1.medium">c1.medium</option>
-                        <option value="aws:c1.xlarge">c1.xlarge</option>
-                        <option value="aws:c3.2xlarge">c3.2xlarge</option>
-                        <option value="aws:c3.4xlarge">c3.4xlarge</option>
-                        <option value="aws:c3.8xlarge">c3.8xlarge</option>
-                        <option value="aws:c3.large">c3.large</option>
-                        <option value="aws:c3.xlarge">c3.xlarge</option>
-                        <option value="aws:c4.2xlarge">c4.2xlarge</option>
-                        <option value="aws:c4.4xlarge">c4.4xlarge</option>
-                        <option value="aws:c4.8xlarge">c4.8xlarge</option>
-                        <option value="aws:c4.large">c4.large</option>
-                        <option value="aws:c4.xlarge">c4.xlarge</option>
-                        <option value="aws:c5.large">c5.large</option>
-                        <option value="aws:c5.xlarge">c5.xlarge</option>
-                        <option value="aws:c5.2xlarge">c5.2xlarge</option>
-                        <option value="aws:c5.4xlarge">c5.4xlarge</option>
-                        <option value="aws:c5.9xlarge">c5.9xlarge</option>
-                        <option value="aws:c5.18xlarge">c5.18xlarge</option>
-                        <option value="aws:cc2.8xlarge">cc2.8xlarge</option>
-                        <option value="aws:cg1.4xlarge">cg1.4xlarge</option>
-                        <option value="aws:cr1.8xlarge">cr1.8xlarge</option>
-                        <option value="aws:d2.xlarge">d2.xlarge</option>
-                        <option value="aws:d2.2xlarge">d2.2xlarge</option>
-                        <option value="aws:d2.4xlarge">d2.4xlarge</option>
-                        <option value="aws:d2.8xlarge">d2.8xlarge</option>
-                        <option value="aws:f1.2xlarge">f1.2xlarge</option>
-                        <option value="aws:f1.16xlarge">f1.16xlarge</option>
-                        <option value="aws:g2.2xlarge">g2.2xlarge</option>
-                        <option value="aws:g2.8xlarge">g2.8xlarge</option>
-                        <option value="aws:g3.4xlarge">g3.4xlarge</option>
-                        <option value="aws:g3.8xlarge">g3.8xlarge</option>
-                        <option value="aws:g3.16xlarge">g3.16xlarge</option>
-                        <option value="aws:hi1.4xlarge">hi1.4xlarge</option>
-                        <option value="aws:hs1.8xlarge">hs1.8xlarge</option>
-                        <option value="aws:i2.xlarge">i2.xlarge</option>
-                        <option value="aws:i2.2xlarge">i2.2xlarge</option>
-                        <option value="aws:i2.4xlarge">i2.4xlarge</option>
-                        <option value="aws:i2.8xlarge">i2.8xlarge</option>
-                        <option value="aws:i3.large">i3.large</option>
-                        <option value="aws:i3.xlarge">i3.xlarge</option>
-                        <option value="aws:i3.2xlarge">i3.2xlarge</option>
-                        <option value="aws:i3.4xlarge">i3.4xlarge</option>
-                        <option value="aws:i3.8xlarge">i3.8xlarge</option>
-                        <option value="aws:i3.16xlarge">i3.16xlarge</option>
-                        <option value="aws:m1.small">m1.small</option>
-                        <option value="aws:m1.medium">m1.medium</option>
-                        <option value="aws:m1.large">m1.large</option>
-                        <option value="aws:m1.xlarge">m1.xlarge</option>
-                        <option value="aws:m2.xlarge">m2.xlarge</option>
-                        <option value="aws:m2.2xlarge">m2.2xlarge</option>
-                        <option value="aws:m2.4xlarge">m2.4xlarge</option>
-                        <option value="aws:m3.medium">m3.medium</option>
-                        <option value="aws:m3.large">m3.large</option>
-                        <option value="aws:m3.xlarge">m3.xlarge</option>
-                        <option value="aws:m3.2xlarge">m3.2xlarge</option>
-                        <option value="aws:m4.large">m4.large</option>
-                        <option value="aws:m4.xlarge">m4.xlarge</option>
-                        <option value="aws:m4.2xlarge">m4.2xlarge</option>
-                        <option value="aws:m4.4xlarge">m4.4xlarge</option>
-                        <option value="aws:m4.10xlarge">m4.10xlarge</option>
-                        <option value="aws:m4.16xlarge">m4.16xlarge</option>
-                        <option value="aws:p2.xlarge">p2.xlarge</option>
-                        <option value="aws:p2.8xlarge">p2.8xlarge</option>
-                        <option value="aws:p2.16xlarge">p2.16xlarge</option>
-                        <option value="aws:r3.large">r3.large</option>
-                        <option value="aws:r3.xlarge">r3.xlarge</option>
-                        <option value="aws:r3.2xlarge">r3.2xlarge</option>
-                        <option value="aws:r3.4xlarge">r3.4xlarge</option>
-                        <option value="aws:r3.8xlarge">r3.8xlarge</option>
-                        <option value="aws:r4.large">r4.large</option>
-                        <option value="aws:r4.xlarge">r4.xlarge</option>
-                        <option value="aws:r4.2xlarge">r4.2xlarge</option>
-                        <option value="aws:r4.4xlarge">r4.4xlarge</option>
-                        <option value="aws:r4.8xlarge">r4.8xlarge</option>
-                        <option value="aws:r4.16xlarge">r4.16xlarge</option>
-                        <option value="aws:t1.micro">t1.micro</option>
-                        <option value="aws:t2.nano">t2.nano</option>
-                        <option value="aws:t2.micro">t2.micro</option>
-                        <option value="aws:t2.small">t2.small</option>
-                        <option value="aws:t2.medium">t2.medium</option>
-                        <option value="aws:t2.large">t2.large</option>
-                        <option value="aws:t2.xlarge">t2.xlarge</option>
-                        <option value="aws:t2.2xlarge">t2.2xlarge</option>
-                        <option value="aws:t3.nano">t3.nano</option>
-                        <option value="aws:t3.micro">t3.micro</option>
-                        <option value="aws:t3.small">t3.small</option>
-                        <option value="aws:t3.medium">t3.medium</option>
-                        <option value="aws:t3.large">t3.large</option>
-                        <option value="aws:t3.xlarge">t3.xlarge</option>
-                        <option value="aws:t3.2xlarge">t3.2xlarge</option>
-                        <option value="aws:x1.16xlarge">x1.16xlarge</option>
-                        <option value="aws:x1.32xlarge">x1.32xlarge</option>
-                        <option disabled>--- Azure Instance Types ---</option>
-                        <option value="azure:A5">A5</option>
-                        <option value="azure:A6">A6</option>
-                        <option value="azure:A7">A7</option>
-                        <option value="azure:A8">A8</option>
-                        <option value="azure:A9">A9</option>
-                        <option value="azure:A10">A10</option>
-                        <option value="azure:A11">A11</option>
-                        <option value="azure:ExtraSmall">ExtraSmall</option>
-                        <option value="azure:Small">Small</option>
-                        <option value="azure:Medium">Medium</option>
-                        <option value="azure:Large">Large</option>
-                        <option value="azure:ExtraLarge">ExtraLarge</option>
-                        <option value="azure:Standard_A1_v2">Standard_A1_v2</option>
-                        <option value="azure:Standard_A2m_v2">Standard_A2m_v2</option>
-                        <option value="azure:Standard_A2_v2">Standard_A2_v2</option>
-                        <option value="azure:Standard_A4m_v2">Standard_A4m_v2</option>
-                        <option value="azure:Standard_A4_v2">Standard_A4_v2</option>
-                        <option value="azure:Standard_A8m_v2">Standard_A8m_v2</option>
-                        <option value="azure:Standard_A8_v2">Standard_A8_v2</option>
-                        <option value="azure:Standard_D1">Standard_D1</option>
-                        <option value="azure:Standard_D1_v2">Standard_D1_v2</option>
-                        <option value="azure:Standard_D2">Standard_D2</option>
-                        <option value="azure:Standard_D2_v2">Standard_D2_v2</option>
-                        <option value="azure:Standard_D3">Standard_D3</option>
-                        <option value="azure:Standard_D3_v2">Standard_D3_v2</option>
-                        <option value="azure:Standard_D4">Standard_D4</option>
-                        <option value="azure:Standard_D4_v2">Standard_D4_v2</option>
-                        <option value="azure:Standard_D5_v2">Standard_D5_v2</option>
-                        <option value="azure:Standard_D11">Standard_D11</option>
-                        <option value="azure:Standard_D11_v2">Standard_D11_v2</option>
-                        <option value="azure:Standard_D12">Standard_D12</option>
-                        <option value="azure:Standard_D12_v2">Standard_D12_v2</option>
-                        <option value="azure:Standard_D13">Standard_D13</option>
-                        <option value="azure:Standard_D13_v2">Standard_D13_v2</option>
-                        <option value="azure:Standard_D14">Standard_D14</option>
-                        <option value="azure:Standard_D14_v2">Standard_D14_v2</option>
-                        <option value="azure:Standard_D15_v2">Standard_D15_v2</option>
-                        <option value="azure:Standard_G1">Standard_G1</option>
-                        <option value="azure:Standard_G2">Standard_G2</option>
-                        <option value="azure:Standard_G3">Standard_G3</option>
-                        <option value="azure:Standard_G4">Standard_G4</option>
-                        <option value="azure:Standard_G5">Standard_G5</option>
-                        <option value="azure:Standard_H8">Standard_H8</option>
-                        <option value="azure:Standard_H8m">Standard_H8m</option>
-                        <option value="azure:Standard_H16">Standard_H16</option>
-                        <option value="azure:Standard_H16m">Standard_H16m</option>
-                        <option value="azure:Standard_H16mr">Standard_H16mr</option>
-                        <option value="azure:Standard_H16r">Standard_H16r</option>
-                        <option disabled>--- GCE Instance Types ---</option>
-                        <option value="gce:f1-micro">f1-micro</option>
-                        <option value="gce:g1-small">g1-small</option>
-                        <option value="gce:n1-highcpu-2">n1-highcpu-2</option>
-                        <option value="gce:n1-highcpu-4">n1-highcpu-4</option>
-                        <option value="gce:n1-highcpu-8">n1-highcpu-8</option>
-                        <option value="gce:n1-highcpu-16">n1-highcpu-16</option>
-                        <option value="gce:n1-highcpu-32">n1-highcpu-32</option>
-                        <option value="gce:n1-highcpu-64">n1-highcpu-64</option>
-                        <option value="gce:n1-highmem-2">n1-highmem-2</option>
-                        <option value="gce:n1-highmem-4">n1-highmem-4</option>
-                        <option value="gce:n1-highmem-8">n1-highmem-8</option>
-                        <option value="gce:n1-highmem-16">n1-highmem-16</option>
-                        <option value="gce:n1-highmem-32">n1-highmem-32</option>
-                        <option value="gce:n1-highmem-64">n1-highmem-64</option>
-                        <option value="gce:n1-standard-1">n1-standard-1</option>
-                        <option value="gce:n1-standard-2">n1-standard-2</option>
-                        <option value="gce:n1-standard-4">n1-standard-4</option>
-                        <option value="gce:n1-standard-8">n1-standard-8</option>
-                        <option value="gce:n1-standard-16">n1-standard-16</option>
-                        <option value="gce:n1-standard-32">n1-standard-32</option>
-                        <option value="gce:n1-standard-64">n1-standard-64</option>
-                      </select>
-                    </div>
-                  </div>
-                  <div class="col-1">
-                    <i class="far fa-sm fa-question-circle" title='Select from a variety of preconfigured instance configurations. Default: (not set)'></i>
-                  </div>
-                </div>
-    
-                <div class="row">
-                  <label class="col-3 col-form-label text-right">Location: </label>
-                  <div class="col-7">
-                    <div class="form-group">
-                      <select id="virtualMachineLocationInput" class="form-control" name="location">
-                        <option value="none">none</option>
-                      </select>
-                    </div>
-                  </div>
-                  <div class="col-1">
-                    <i class="far fa-sm fa-question-circle" title='Select the LXD cluster member or @group to deploy this virtual machine on. Default: none'></i>
-                  </div>
-                </div>
-                
-                <hr class="mb-2">
-                <nav>
-                  <div class="nav nav-pills justify-content-center" id="nav-tab" role="tablist">
-                    <a class="nav-link active" id="nav-boot-tab" data-toggle="tab" href="#nav-boot" role="tab" aria-controls="nav-boot" aria-selected="true">Boot</a>
-                    <a class="nav-link" id="nav-cloud-init-tab" data-toggle="tab" href="#nav-cloud-init" role="tab" aria-controls="nav-cloud-init" aria-selected="true">Cloud-init</a>
-                    <a class="nav-link" id="nav-limits-tab" data-toggle="tab" href="#nav-limits" role="tab" aria-controls="nav-limits" aria-selected="false">Limits</a>
-                    <a class="nav-link" id="nav-migration-tab" data-toggle="tab" href="#nav-migration" role="tab" aria-controls="nav-migration" aria-selected="false">Migration</a>
-                    <a class="nav-link" id="nav-other-tab" data-toggle="tab" href="#nav-other" role="tab" aria-controls="nav-other" aria-selected="false">Other</a>
-                    <a class="nav-link" id="nav-raw-tab" data-toggle="tab" href="#nav-raw" role="tab" aria-controls="nav-raw" aria-selected="false">Raw</a>
-                    <a class="nav-link" id="nav-security-tab" data-toggle="tab" href="#nav-security" role="tab" aria-controls="nav-security" aria-selected="false">Security</a>
-                    <a class="nav-link" id="nav-snapshots-tab" data-toggle="tab" href="#nav-snapshots" role="tab" aria-controls="nav-snapshots" aria-selected="false">Snapshots</a>
-                  </div>
-                </nav>
-                <hr class="mt-2">
-                <div class="tab-content" id="nav-tabContent">
-                  <div class="tab-pane fade show active" id="nav-boot" role="tabpanel" aria-labelledby="nav-boot-tab">
-                    <br>
-                    <div class="row">
-                      <label class="col-4 col-form-label text-right">Autostart: </label>
-                      <div class="col-6">
-                        <div class="form-group">
-                          <select class="form-control" name="boot.autostart">
-                            <option value="">(not set)</option>
-                            <option value="true">true</option>
-                            <option value="false">false</option>
-                          </select>
-                        </div>
-                      </div>
-                      <div class="col-1">
-                        <i class="far fa-sm fa-question-circle" title='Select whether to automatically start the instance with LXD starts. If not set, defaults to instance last state.'></i>
-                      </div>
-                    </div>
-                    <div class="row">
-                      <label class="col-4 col-form-label text-right">Autostart Delay: </label>
-                      <div class="col-6">
-                        <div class="form-group">
-                          <input type="number" class="form-control" name="boot.autostart.delay">
-                        </div>
-                      </div>
-                      <div class="col-1">
-                        <i class="far fa-sm fa-question-circle" title='Enter in the number of seconds to wait after the instance starts to boot up the next instance. Default: 0.'></i>
-                      </div>
-                    </div>
-                    <div class="row">
-                      <label class="col-4 col-form-label text-right">Autostart Priority: </label>
-                      <div class="col-6">
-                        <div class="form-group">
-                          <input type="number" class="form-control" name="boot.autostart.priority">
-                        </div>
-                      </div>
-                      <div class="col-1">
-                        <i class="far fa-sm fa-question-circle" title='Enter in a number to determine the order the instance boots, higher numbers being first. Default: 0.'></i>
-                      </div>
-                    </div>
-                    <div class="row">
-                      <label class="col-4 col-form-label text-right">Host Shutdown Timeout: </label>
-                      <div class="col-6">
-                        <div class="form-group">
-                          <input type="number" class="form-control" name="boot.host_shutdown_timeout">
-                        </div>
-                      </div>
-                      <div class="col-1">
-                        <i class="far fa-sm fa-question-circle" title='Enter in a the number of seconds to wait on host shutdown before forcefull shutdown of instance. Default: 30.'></i>
-                      </div>
-                    </div>
-                    <div class="row">
-                      <label class="col-4 col-form-label text-right">Stop Priority: </label>
-                      <div class="col-6">
-                        <div class="form-group">
-                          <input type="number" class="form-control" name="boot.stop.priority">
-                        </div>
-                      </div>
-                      <div class="col-1">
-                        <i class="far fa-sm fa-question-circle" title='Enter in a number to determine the order the instance shutsdown, higher numbers being first. Default: 0.'></i>
-                      </div>
-                    </div>
-                  </div>
-                  <div class="tab-pane fade" id="nav-cloud-init" role="tabpanel" aria-labelledby="nav-cloud-init-tab">
-                    <br>
-                    <div class="row">
-                      <label class="col-4 col-form-label text-right">Network Config: </label>
-                      <div class="col-6">
-                        <div class="form-group">
-                          <textarea class="form-control" name="cloud-init.network-config"></textarea>
-                        </div>
-                      </div>
-                      <div class="col-1">
-                        <i class="far fa-sm fa-question-circle" title='Support for this option depends on the instance image. Enter in network configuration. Default: not set.'></i>
-                      </div>
-                    </div>
-                    <div class="row">
-                      <label class="col-4 col-form-label text-right">User Data: </label>
-                      <div class="col-6">
-                        <div class="form-group">
-                          <textarea class="form-control" name="cloud-init.user-data"></textarea>
-                        </div>
-                      </div>
-                      <div class="col-1">
-                        <i class="far fa-sm fa-question-circle" title='Support for this option depends on the instance image. Enter in user data configuration. If both cloud-init.user-data and cloud-init.vendor-data exist, the contents of both are merged. Default: not set.'></i>
-                      </div>
-                    </div>
-                    <div class="row">
-                      <label class="col-4 col-form-label text-right">Vendor Data: </label>
-                      <div class="col-6">
-                        <div class="form-group">
-                          <textarea class="form-control" name="cloud-init.vendor-data"></textarea>
-                        </div>
-                      </div>
-                      <div class="col-1">
-                        <i class="far fa-sm fa-question-circle" title='Support for this option depends on the instance image. Enter in vendor data configuration. If both cloud-init.user-data and cloud-init.vendor-data exist, the contents of both are merged. Default: not set.'></i>
-                      </div>
-                    </div>
-                  </div>
-                  <div class="tab-pane fade" id="nav-limits" role="tabpanel" aria-labelledby="nav-limits-tab">
-                    <br>
-                    <div class="row">
-                      <label class="col-4 col-form-label text-right">CPU: </label>
-                      <div class="col-6">
-                        <div class="form-group">
-                          <input type="text" class="form-control" name="limits.cpu">
-                        </div>
-                      </div>
-                      <div class="col-1">
-                        <i class="far fa-sm fa-question-circle" title='Enter in the number or range of CPUs to expose to the instance.'></i>
-                      </div>
-                    </div>
-                    <div class="row">
-                      <label class="col-4 col-form-label text-right">Disk Priority: </label>
-                      <div class="col-6">
-                        <div class="form-group">
-                          <input type="number" class="form-control" name="limits.disk.priority">
-                        </div>
-                      </div>
-                      <div class="col-1">
-                        <i class="far fa-sm fa-question-circle" title='Enter in an integer between 0 (min) and 10 (max) to schedule disk I/O request priority compared to other instances. Default: 5.'></i>
-                      </div>
-                    </div>
-                    <div class="row">
-                      <label class="col-4 col-form-label text-right">Memory: </label>
-                      <div class="col-6">
-                        <div class="form-group">
-                          <input type="text" class="form-control" name="limits.memory">
-                        </div>
-                      </div>
-                      <div class="col-1">
-                        <i class="far fa-sm fa-question-circle" title="Enter in a percentage of the host's memory or enter in a fixed value of bytes."></i>
-                      </div>
-                    </div>
-                    <div class="row">
-                      <label class="col-4 col-form-label text-right">Memory Hugepages: </label>
-                      <div class="col-6">
-                        <div class="form-group">
-                          <select class="form-control" name="limits.memory.hugepages">
-                            <option value="">(not set)</option>
-                            <option value="true">true</option>
-                            <option value="false">false</option>
-                          </select>
-                        </div>
-                      </div>
-                      <div class="col-1">
-                        <i class="far fa-sm fa-question-circle" title="Select whether to back the instance using hugepages rather than regular system memory. Default: false."></i>
-                      </div>
-                    </div>
-                    <div class="row">
-                      <label class="col-4 col-form-label text-right">Network Priority: </label>
-                      <div class="col-6">
-                        <div class="form-group">
-                          <input type="number" class="form-control" name="limits.network.priority">
-                        </div>
-                      </div>
-                      <div class="col-1">
-                        <i class="far fa-sm fa-question-circle" title="Enter in the priority for the instance network when the host is under, with 10 being the priority. Default 0."></i>
-                      </div>
-                    </div>
-                  </div>
-                  <div class="tab-pane fade" id="nav-migration" role="tabpanel" aria-labelledby="nav-migration-tab">
-                    <br>
-                    <div class="row">
-                      <label class="col-4 col-form-label text-right">Stateful: </label>
-                      <div class="col-6">
-                        <div class="form-group">
-                          <select class="form-control" name="migration.stateful">
-                            <option value="">(not set)</option>
-                            <option value="true">true</option>
-                            <option value="false">false</option>
-                          </select>
-                        </div>
-                      </div>
-                      <div class="col-1">
-                        <i class="far fa-sm fa-question-circle" title="Select whether to allow for stateful stop/start and snapshots. This will prevent the use of some features that are incompatible with it. Default: false."></i>
-                      </div>
-                    </div>
-                  </div>
-                  <div class="tab-pane fade" id="nav-other" role="tabpanel" aria-labelledby="nav-other-tab">
-                    <br>
-                    <div class="row">
-                      <label class="col-4 col-form-label text-right">Cluster Evacuate: </label>
-                      <div class="col-6">
-                        <div class="form-group">
-                          <select class="form-control" name="cluster.evacuate">
-                            <option value="">(not set)</option>
-                            <option value="auto">auto</option>
-                            <option value="migrate">migrate</option>
-                            <option value="stop">stop</option>
-                          </select>
-                        </div>
-                      </div>
-                      <div class="col-1">
-                        <i class="far fa-sm fa-question-circle" title='Select what to do when evacuating the instance. Default: auto'></i>
-                      </div>
-                    </div>
-                  </div>
-                  <div class="tab-pane fade" id="nav-raw" role="tabpanel" aria-labelledby="nav-raw-tab">
-                    <br>
-                    <div class="row">
-                      <label class="col-4 col-form-label text-right">Apparmor: </label>
-                      <div class="col-6">
-                        <div class="form-group">
-                          <input type="text" class="form-control" name="raw.apparmor">
-                        </div>
-                      </div>
-                      <div class="col-1">
-                        <i class="far fa-sm fa-question-circle" title="Enter in apparmor profile entries to be appended to the profile. Default: (not set)."></i>
-                      </div>
-                    </div>
-                    <div class="row">
-                      <label class="col-4 col-form-label text-right">Qemu: </label>
-                      <div class="col-6">
-                        <div class="form-group">
-                          <input type="text" class="form-control" name="raw.qemu">
-                        </div>
-                      </div>
-                      <div class="col-1">
-                        <i class="far fa-sm fa-question-circle" title="Enter raw QEMU configuration to be appended to the generated command line. Default: (not set)."></i>
-                      </div>
-                    </div>
-                    <div class="row">
-                      <label class="col-4 col-form-label text-right">Qemu.conf: </label>
-                      <div class="col-6">
-                        <div class="form-group">
-                          <input type="text" class="form-control" name="raw.qemu.conf">
-                        </div>
-                      </div>
-                      <div class="col-1">
-                        <i class="far fa-sm fa-question-circle" title="Enter in addition/override to the generated qemu.conf file. Default: (not set)."></i>
-                      </div>
-                    </div>
-                  </div>
-                  <div class="tab-pane fade" id="nav-security" role="tabpanel" aria-labelledby="nav-security-tab">
-                    <br>
-                    <div class="row">
-                      <label class="col-4 col-form-label text-right">Devlxd: </label>
-                      <div class="col-6">
-                        <div class="form-group">
-                          <select class="form-control" name="security.devlxd">
-                            <option value="">(not set)</option>
-                            <option value="true">true</option>
-                            <option value="false">false</option>
-                          </select>
-                        </div>
-                      </div>
-                      <div class="col-1">
-                        <i class="far fa-sm fa-question-circle" title="Select whether to control the presence of /dev/lxd in the instance. Default: true."></i>
-                      </div>
-                    </div>
-                    <div class="row">
-                      <label class="col-4 col-form-label text-right">Protection Delete: </label>
-                      <div class="col-6">
-                        <div class="form-group">
-                          <select class="form-control" name="security.protection.delete">
-                            <option value="">(not set)</option>
-                            <option value="true">true</option>
-                            <option value="false">false</option>
-                          </select>
-                        </div>
-                      </div>
-                      <div class="col-1">
-                        <i class="far fa-sm fa-question-circle" title="Select whether to prevent the instance from being deleted. Default: false."></i>
-                      </div>
-                    </div>
-                    <div class="row">
-                      <label class="col-4 col-form-label text-right">Agent Metrics: </label>
-                      <div class="col-6">
-                        <div class="form-group">
-                          <select class="form-control" name="security.agent.metrics">
-                            <option value="">(not set)</option>
-                            <option value="true">true</option>
-                            <option value="false">false</option>
-                          </select>
-                        </div>
-                      </div>
-                      <div class="col-1">
-                        <i class="far fa-sm fa-question-circle" title="Select whether the lxd-agent is queried for state information and metrics. Default: true."></i>
-                      </div>
-                    </div>
-                    <div class="row">
-                      <label class="col-4 col-form-label text-right">Secureboot: </label>
-                      <div class="col-6">
-                        <div class="form-group">
-                          <select class="form-control" name="security.secureboot">
-                            <option value="">(not set)</option>
-                            <option value="true">true</option>
-                            <option value="false">false</option>
-                          </select>
-                        </div>
-                      </div>
-                      <div class="col-1">
-                        <i class="far fa-sm fa-question-circle" title="Select whether whether UEFI secure boot is enabled with the default Microsoft keys. Default: true."></i>
-                      </div>
-                    </div>
-                  </div>
-                  <div class="tab-pane fade" id="nav-snapshots" role="tabpanel" aria-labelledby="nav-snapshots-tab">
-                    <br>
-                    <div class="row">
-                      <label class="col-4 col-form-label text-right">Schedule: </label>
-                      <div class="col-6">
-                        <div class="form-group">
-                          <input type="text" class="form-control" name="snapshots.schedule">
-                        </div>
-                      </div>
-                      <div class="col-1">
-                        <i class="far fa-sm fa-question-circle" title="Enter in a cron expression (<minute> <hour> <dom> <month> <dow>), or a comma separated list of schedule aliases <@hourly> <@daily> <@midnight> <@weekly> <@monthly> <@annually> <@yearly> <@startup>. Default: (not set)."></i>
-                      </div>
-                    </div>
-                    <div class="row">
-                      <label class="col-4 col-form-label text-right">Schedule Stopped: </label>
-                      <div class="col-6">
-                        <div class="form-group">
-                          <select class="form-control" name="snapshots.schedule.stopped">
-                            <option value="">(not set)</option>
-                            <option value="true">true</option>
-                            <option value="false">false</option>
-                          </select>
-                        </div>
-                      </div>
-                      <div class="col-1">
-                        <i class="far fa-sm fa-question-circle" title="Select whether stopped instances are to be snapshoted automatically. Default: false."></i>
-                      </div>
-                    </div>
-                    <div class="row">
-                      <label class="col-4 col-form-label text-right">Pattern: </label>
-                      <div class="col-6">
-                        <div class="form-group">
-                          <input type="text" class="form-control" name="snapshots.pattern'">
-                        </div>
-                      </div>
-                      <div class="col-1">
-                        <i class="far fa-sm fa-question-circle" title="Enter in a pongo2 template string representing the snapshot name. Default: snap%d."></i>
-                      </div>
-                    </div>
-                    <div class="row">
-                      <label class="col-4 col-form-label text-right">Expiry: </label>
-                      <div class="col-6">
-                        <div class="form-group">
-                          <input type="text" class="form-control" name="snapshots.expiry">
-                        </div>
-                      </div>
-                      <div class="col-1">
-                        <i class="far fa-sm fa-question-circle" title="Enter in time controls when snapshots are to be deleted (expects expressions like 1M 2H 3d 4w 5m 6y). Default: (not set)."></i>
-                      </div>
-                    </div>
-                    
-                  </div>
-                </div>
-
-              </form>
-              <div class="modal-footer">
-                <button class="btn btn-secondary" type="button" data-dismiss="modal">Cancel</button>
-                <a class="btn btn-primary" href="#" onclick="addItem()" data-dismiss="modal">Submit</a>
-              </div>
-            </div>
-            <div class="tab-pane fade" id="json" role="tabpanel" aria-labelledby="json-tab">
-              <br />
-              <div class="row">
-                <div class="col-12">
-                  <div class="form-group text-right">
-                    <pre>
-                      <textarea name="json" class="form-control" id="jsonCreateInput" rows="16" placeholder="Enter JSON data"></textarea>
-                    </pre>
-                  </div>
-                </div>
-              </div>
-              <div class="modal-footer">
-                <button class="btn btn-secondary" type="button" data-dismiss="modal">Cancel</button>
-                <a class="btn btn-primary" href="#" onclick="createItemUsingJSON()" data-dismiss="modal">Submit</a>
-              </div>
-            </div>
-          </div>
-        </div>
-    </div>
-  </div>
-</div>

+ 6 - 6
lxconsole/templates/navbar.html

@@ -20,7 +20,7 @@
       </li>
       <li id="serverNavbarSelect" class="nav-item" style="display: none;">
         <div class="input-group">
-          <select class="form-control" id="serverListNav" style="width:150px;" onchange="changeServer(this.value)">
+          <select class="form-select" id="serverListNav" style="width:150px;" onchange="changeServer(this.value)">
           </select>
         </div>
       </li>
@@ -31,19 +31,19 @@
       </li>
       <li id="projectNavbarSelect" class="nav-item" style="display: none;">
         <div class="input-group">
-          <select class="form-control" id="projectListNav" style="width:150px;" onchange="changeProject(this.value)">
+          <select class="form-select" id="projectListNav" style="width:150px;" onchange="changeProject(this.value)">
           </select>
         </div>
       </li>
 
       <!-- Nav Item - User Information -->
-      <li class="nav-item dropdown">
-        <a class="nav-link" href="#" id="userDropdown" data-toggle="dropdown" aria-expanded="false">
+      <li class="nav-item dropdown border-start ml-3">
+        <a class="nav-link" href="#" id="userDropdown" data-bs-toggle="dropdown" aria-expanded="false">
           <i class="fas fa-user-circle"></i>
           <span id="username">{{ page_username }}</span>
         </a>
         <!-- Dropdown - User Information -->
-        <div class="dropdown-menu dropdown-menu-right" aria-labelledby="userDropdown">
+        <div class="dropdown-menu dropdown-menu-end" aria-labelledby="userDropdown">
           <a class="dropdown-item" href="#" onclick="loadAccountModal()">
             <i class="fas fa-user-circle fa-sm fa-fw mr-2"></i>
             Account
@@ -68,7 +68,7 @@
             <i class="fas fa-history fa-sm fa-fw mr-2"></i>
             Logs
           </a> -->
-          <a class="dropdown-item" href="#" data-toggle="modal" data-target="#aboutModal">
+          <a class="dropdown-item" href="#" data-bs-toggle="modal" data-bs-target="#aboutModal">
             <i class="fas fa-info-circle fa-sm fa-fw mr-2"></i>
             About
           </a>

+ 12 - 6
lxconsole/templates/network-acl.html

@@ -6,9 +6,9 @@
       <h1>{{ page_title | safe }}</h1>
     </div>
     <div class="col-sm-6">
-      <a class="btn btn-outline-primary float-sm-right mr-4" href="#" data-toggle="modal" data-target="#addModal" title="Add Network ACL Rule" aria-hidden="true">
+      <button class="btn btn-outline-primary float-sm-right mr-4" data-bs-toggle="modal" data-bs-target="#addModal" title="Add Network ACL Rule" aria-hidden="true">
         <i class="fas fa-plus fa-sm fa-fw"></i> Network ACL Rule
-      </a>
+      </button>
     </div>
   </div>
 {% endblock header %}
@@ -17,10 +17,10 @@
   <div class="col-12">
     <ul class="nav nav-tabs" id="myTab" role="tablist">
       <li class="nav-item">
-        <a class="nav-link active" id="ingress-tab" data-toggle="tab" href="#ingress" role="tab" aria-controls="ingress" aria-selected="true">Ingress</a>
+        <a class="nav-link active" id="ingress-tab" data-bs-toggle="tab" href="#ingress" role="tab" aria-controls="ingress" aria-selected="true">Ingress</a>
       </li>
       <li class="nav-item">
-        <a class="nav-link" id="egress-tab" data-toggle="tab" href="#egress" role="tab" aria-controls="egress" aria-selected="false">Egress</a>
+        <a class="nav-link" id="egress-tab" data-bs-toggle="tab" href="#egress" role="tab" aria-controls="egress" aria-selected="false">Egress</a>
       </li>
     </ul>
 
@@ -136,7 +136,10 @@
           url: "../api/network-acl/list_network_acls?id="+serverId+"&project=" + project + "&acl=" + acl,
           dataType: "json",
           dataSrc: "metadata.ingress",
-          contentType: "application/json"
+          contentType: "application/json",
+          error: function (xhr, error, code) {
+            console.log(xhr, code);
+          }
         },
         columns: [
           { title: "Index", data: function (row, type, set) {
@@ -237,7 +240,10 @@
           url: "../api/network-acl/list_network_acls?id="+serverId+"&project=" + project + "&acl=" + acl,
           dataType: "json",
           dataSrc: "metadata.egress",
-          contentType: "application/json"
+          contentType: "application/json",
+          error: function (xhr, error, code) {
+            console.log(xhr, code);
+          }
         },
         columns: [
           { title: "Index", data: function (row, type, set) {

+ 6 - 3
lxconsole/templates/network-acls.html

@@ -6,9 +6,9 @@
       <h1>{{ page_title | safe }}</h1>
     </div>
     <div class="col-sm-6">
-      <a class="btn btn-outline-primary float-sm-right mr-4" href="#" data-toggle="modal" data-target="#addModal" title="Add Network ACL" aria-hidden="true">
+      <button class="btn btn-outline-primary float-sm-right mr-4" data-bs-toggle="modal" data-bs-target="#addModal" title="Add Network ACL" aria-hidden="true">
         <i class="fas fa-plus fa-sm fa-fw"></i> Network ACL
-      </a>
+      </button>
     </div>
   </div>
 {% endblock header %}
@@ -98,7 +98,10 @@
           url: "../api/network-acls/list_network_acls?id="+serverId+"&project=" + project + "&recursion=1",
           dataType: "json",
           dataSrc: "metadata",
-          contentType: "application/json"
+          contentType: "application/json",
+          error: function (xhr, error, code) {
+            console.log(xhr, code);
+          }
         },
         columns: [
           { title: "Name", data: function (row, type, set) {

+ 6 - 3
lxconsole/templates/network-zones.html

@@ -6,9 +6,9 @@
       <h1>{{ page_title | safe }}</h1>
     </div>
     <div class="col-sm-6">
-      <a class="btn btn-outline-primary float-sm-right mr-4" href="#" data-toggle="modal" data-target="#addModal" title="Add Network Zone" aria-hidden="true">
+      <button class="btn btn-outline-primary float-sm-right mr-4" data-bs-toggle="modal" data-bs-target="#addModal" title="Add Network Zone" aria-hidden="true">
         <i class="fas fa-plus fa-sm fa-fw"></i> Network Zone
-      </a>
+      </button>
     </div>
   </div>
 {% endblock header %}
@@ -98,7 +98,10 @@
           url: "../api/network-zones/list_network_zones?id="+serverId+"&project=" + project + "&recursion=1",
           dataType: "json",
           dataSrc: "metadata",
-          contentType: "application/json"
+          contentType: "application/json",
+          error: function (xhr, error, code) {
+            console.log(xhr, code);
+          }
         },
         columns: [
           { title: "Name", data: function (row, type, set) {

+ 31 - 20
lxconsole/templates/network.html

@@ -6,14 +6,13 @@
       <h1>{{ page_title | safe }} <span id="network_title"></span></h1>
     </div>
     <div class="col-sm-6">
-
-      <a class="btn btn-outline-primary dropdown-toggle float-sm-right ml-2 mr-4" href="#" role="button" id="dropdownMenuLink" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false" title="Actions">
+      <button class="btn btn-outline-primary dropdown-toggle float-sm-right ml-2 mr-4" type="button" id="dropdownMenuLink" data-bs-toggle="dropdown" aria-expanded="false" title="Actions">
         Network Actions
-      </a>
+      </button>
       <div class="dropdown-menu dropdown-menu-right shadow animated--fade-in" aria-labelledby="dropdownMenuLink">
-        <a class="dropdown-item text-primary" href="#" data-toggle="modal" data-target="#addLoadBalancerModal" id="addLoadBalancer"><i class="fas fa-save fa-sm fa-fw mr-2"></i>Add Load Balancer</a>
-        <a class="dropdown-item text-primary" href="#" data-toggle="modal" data-target="#addForwardModal" id="addForward"><i class="fas fa-save fa-sm fa-fw mr-2"></i>Add Forward</a>
-        <a class="dropdown-item text-primary" href="#" data-toggle="modal" data-target="#addPeerModal" id="addPeer"><i class="fas fa-save fa-sm fa-fw mr-2"></i>Add Peer</a>
+        <a class="dropdown-item text-primary" href="#" data-bs-toggle="modal" data-bs-target="#addLoadBalancerModal" id="addLoadBalancer"><i class="fas fa-save fa-sm fa-fw mr-2"></i>Add Load Balancer</a>
+        <a class="dropdown-item text-primary" href="#" data-bs-toggle="modal" data-bs-target="#addForwardModal" id="addForward"><i class="fas fa-save fa-sm fa-fw mr-2"></i>Add Forward</a>
+        <a class="dropdown-item text-primary" href="#" data-bs-toggle="modal" data-bs-target="#addPeerModal" id="addPeer"><i class="fas fa-save fa-sm fa-fw mr-2"></i>Add Peer</a>
       </div>
 
     </div>
@@ -25,10 +24,10 @@
 
     <nav>
       <div class="nav nav-tabs" id="nav-page-tab" role="tablist">
-        <a class="nav-item nav-link active" id="nav-home-tab" data-toggle="tab" href="#nav-home" role="tab" aria-controls="nav-home" aria-selected="true">Home</a>
-        <a class="nav-item nav-link" id="nav-forwards-tab" data-toggle="tab" href="#nav-forwards" role="tab" aria-controls="nav-forwards" aria-selected="false">Forwards</a>
-        <a class="nav-item nav-link" id="nav-load-balancers-tab" data-toggle="tab" href="#nav-load-balancers" role="tab" aria-controls="nav-load-balancers" aria-selected="false">Load Balancers</a>
-        <a class="nav-item nav-link" id="nav-peers-tab" data-toggle="tab" href="#nav-peers" role="tab" aria-controls="nav-peers" aria-selected="false">Peers</a>
+        <button class="nav-link active" id="nav-home-tab" data-bs-toggle="tab" data-bs-target="#nav-home" type="button" role="tab" aria-controls="nav-home" aria-selected="true">Home</button>
+        <button class="nav-link" id="nav-forwards-tab" data-bs-toggle="tab" data-bs-target="#nav-forwards" type="button" role="tab" aria-controls="nav-forwards" aria-selected="false">Forwards</button>
+        <button class="nav-link" id="nav-load-balancers-tab" data-bs-toggle="tab" data-bs-target="#nav-load-balancers" type="button" role="tab" aria-controls="nav-load-balancers" aria-selected="false">Load Balancers</button>
+        <button class="nav-link" id="nav-peers-tab" data-bs-toggle="tab" data-bs-target="#nav-peers" type="button" role="tab" aria-controls="nav-peers" aria-selected="false">Peers</button>
       </div>
     </nav>
     <div class="tab-content" id="nav-page-content">
@@ -142,11 +141,11 @@
               </h3>
               <div class="card-tools">
                 <button type="button" class="btn btn-tool" data-card-widget="collapse"><i class="fas fa-minus"></i></button>
-                <button type="button" class="btn btn-tool" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
+                <button type="button" class="btn btn-tool" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
                   <i class="fa fa-bars"></i>
                 </button>
                 <div class="dropdown-menu dropdown-menu-right">
-                  <a href="#" class="dropdown-item" data-toggle="modal" data-target="#addForwardModal" title="Create Forward">Create Forward</a>
+                  <a href="#" class="dropdown-item" data-bs-toggle="modal" data-bs-target="#addForwardModal" title="Create Forward">Create Forward</a>
                 </div>
               </div>
             </div>
@@ -171,11 +170,11 @@
               </h3>
               <div class="card-tools">
                 <button type="button" class="btn btn-tool" data-card-widget="collapse"><i class="fas fa-minus"></i></button>
-                <button type="button" class="btn btn-tool" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
+                <button type="button" class="btn btn-tool" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
                   <i class="fa fa-bars"></i>
                 </button>
                 <div class="dropdown-menu dropdown-menu-right">
-                  <a href="#" class="dropdown-item" data-toggle="modal" data-target="#addLoadBalancerModal" title="Create Load Balancer">Create Load Balancer</a>
+                  <a href="#" class="dropdown-item" data-bs-toggle="modal" data-bs-target="#addLoadBalancerModal" title="Create Load Balancer">Create Load Balancer</a>
                 </div>
               </div>
             </div>
@@ -200,11 +199,11 @@
               </h3>
               <div class="card-tools">
                 <button type="button" class="btn btn-tool" data-card-widget="collapse"><i class="fas fa-plus"></i></button>
-                <button type="button" class="btn btn-tool" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
+                <button type="button" class="btn btn-tool" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
                   <i class="fa fa-bars"></i>
                 </button>
                 <div class="dropdown-menu dropdown-menu-right">
-                  <a href="#" class="dropdown-item" data-toggle="modal" data-target="#addPeerModal" title="Create Peer">Create Peer</a>
+                  <a href="#" class="dropdown-item" data-bs-toggle="modal" data-bs-target="#addPeerModal" title="Create Peer">Create Peer</a>
                 </div>
               </div>
             </div>
@@ -351,7 +350,10 @@
             url: "../api/network/list_network_leases?id="+serverId+"&project="+project+"&name="+network,
             dataType: "json",
             dataSrc: "metadata",
-            contentType: "application/json"
+            contentType: "application/json",
+            error: function (xhr, error, code) {
+              console.log(xhr, code);
+            }
           },
           rowId: 'id',
           stateSave: true,
@@ -413,7 +415,10 @@
               url: "../api/network/list_network_load_balancers?id="+serverId+"&project="+project+"&name="+network+"&recursion=1",
               dataType: "json",
               dataSrc: "metadata",
-              contentType: "application/json"
+              contentType: "application/json",
+              error: function (xhr, error, code) {
+                console.log(xhr, code);
+              }
             },
             stateSave: true,
             columns: [
@@ -470,7 +475,10 @@
               url: "../api/network/list_network_forwards?id="+serverId+"&project="+project+"&name="+network+"&recursion=1",
               dataType: "json",
               dataSrc: "metadata",
-              contentType: "application/json"
+              contentType: "application/json",
+              error: function (xhr, error, code) {
+                console.log(xhr, code);
+              }
             },
             stateSave: true,
             columns: [
@@ -527,7 +535,10 @@
             url: "../api/network/list_network_peers?id="+serverId+"&project="+project+"&name="+network+"&recursion=1",
             dataType: "json",
             dataSrc: "metadata",
-            contentType: "application/json"
+            contentType: "application/json",
+            error: function (xhr, error, code) {
+              console.log(xhr, code);
+            }
           },
           rowId: 'id',
           stateSave: true,

+ 6 - 3
lxconsole/templates/networks.html

@@ -6,9 +6,9 @@
     <h1>{{ page_title | safe }}</h1>
   </div>
   <div class="col-sm-6">
-    <a class="btn btn-outline-primary float-sm-right mr-4" href="#" data-toggle="modal" data-target="#addModal" title="Add Network" aria-hidden="true">
+    <button class="btn btn-outline-primary float-sm-right mr-4" data-bs-toggle="modal" data-bs-target="#addModal" title="Add Network" aria-hidden="true">
       <i class="fas fa-plus fa-sm fa-fw"></i> Network
-    </a>
+    </button>
   </div>
 </div>
 {% endblock header %}
@@ -98,7 +98,10 @@
           url: "../api/networks/list_networks?id="+serverId+"&project=" + project + "&recursion=1",
           dataType: "json",
           dataSrc: "metadata",
-          contentType: "application/json"
+          contentType: "application/json",
+          error: function (xhr, error, code) {
+            console.log(xhr, code);
+          }
         },
         columns: [
           { title: "Name", data: function (row, type, set) {

+ 4 - 1
lxconsole/templates/operations.html

@@ -94,7 +94,10 @@
           url: "../api/operations/list_operations?id="+serverId+"&project=" + project + "&recursion=1",
           dataType: "json",
           dataSrc: "metadata.running",
-          contentType: "application/json"
+          contentType: "application/json",
+          error: function (xhr, error, code) {
+            console.log(xhr, code);
+          }
         },
         columns: [
           { title: "ID", data: function (row, type, set) {

+ 6 - 3
lxconsole/templates/profiles.html

@@ -6,9 +6,9 @@
       <h1>{{ page_title | safe }}</h1>
     </div>
     <div class="col-sm-6">
-      <a class="btn btn-outline-primary float-sm-right mr-4" href="#" data-toggle="modal" data-target="#addModal" title="Add Profile" aria-hidden="true">
+      <button class="btn btn-outline-primary float-sm-right mr-4" data-bs-toggle="modal" data-bs-target="#addModal" title="Add Profile" aria-hidden="true">
         <i class="fas fa-plus fa-sm fa-fw"></i> Profile
-      </a>
+      </button>
     </div>
   </div>
 {% endblock header %}
@@ -98,7 +98,10 @@
           url: "../api/profiles/list_profiles?id="+serverId+"&project=" + project + "&recursion=1",
           dataType: "json",
           dataSrc: "metadata",
-          contentType: "application/json"
+          contentType: "application/json",
+          error: function (xhr, error, code) {
+            console.log(xhr, code);
+          }
         },
         columns: [
           { title: "Name", data: function (row, type, set) {

+ 6 - 3
lxconsole/templates/projects.html

@@ -6,9 +6,9 @@
       <h1>{{ page_title | safe }}</h1>
     </div>
     <div class="col-sm-6">
-      <a class="btn btn-outline-primary float-sm-right mr-4" href="#" data-toggle="modal" data-target="#addModal" title="Add Project" aria-hidden="true">
+      <button class="btn btn-outline-primary float-sm-right mr-4" data-bs-toggle="modal" data-bs-target="#addModal" title="Add Project" aria-hidden="true">
         <i class="fas fa-plus fa-sm fa-fw"></i> Project
-      </a>
+      </button>
     </div>
   </div>
 {% endblock header %}
@@ -98,7 +98,10 @@
           url: "../api/projects/list_projects?id="+serverId+"&project="+project+"&recursion=1",
           dataType: "json",
           dataSrc: "metadata",
-          contentType: "application/json"
+          contentType: "application/json",
+          error: function (xhr, error, code) {
+            console.log(xhr, code);
+          }
         },
         columns: [
           { title: "Name", data: function (row, type, set) {

+ 6 - 3
lxconsole/templates/roles.html

@@ -7,9 +7,9 @@
       <h1>{{ page_title | safe }}</h1>
     </div>
     <div class="col-sm-6">
-      <a class="btn btn-outline-primary float-sm-right mr-4" href="#" data-toggle="modal" data-target="#addModal" title="Add Role" aria-hidden="true">
+      <button class="btn btn-outline-primary float-sm-right mr-4" data-bs-toggle="modal" data-bs-target="#addModal" title="Add Role" aria-hidden="true">
         <i class="fas fa-plus fa-sm fa-fw"></i> Role
-      </a>
+      </button>
     </div>
   </div>
 -->
@@ -61,7 +61,10 @@
           url: "../api/roles/list_roles",
           dataType: "json",
           dataSrc: "data",
-          contentType: "application/json"
+          contentType: "application/json",
+          error: function (xhr, error, code) {
+            console.log(xhr, code);
+          }
         },
         columns: [
           { title: "Name", data: function (row, type, set) {

+ 4 - 5
lxconsole/templates/server.html

@@ -9,7 +9,6 @@
   <div class="col-12 mt-n3">
     <div class="row">
 
-
       <div class="col-md-3 col-sm-6 col-12">
         <div class="info-box">
           <a href="#" class="stretched-link" id="containersLink"></a>
@@ -404,7 +403,7 @@
       });
 
       //Load Containers Info
-      $.getJSON("../api/containers/list_instances?id="+encodeURI(serverId)+'&project='+encodeURI(project)+'&recursion=1', function (data) {
+      $.getJSON("../api/instances/list_instances?id="+encodeURI(serverId)+'&project='+encodeURI(project)+'&filter=container'+'&recursion=1', function (data) {
         data = data.metadata;
         
         running_containers = 0
@@ -430,7 +429,7 @@
       });
 
       // Load Virtual Machine Info
-      $.getJSON("../api/virtual-machines/list_instances?id="+encodeURI(serverId)+'&project='+encodeURI(project)+'&recursion=1', function (data) {
+      $.getJSON("../api/instances/list_instances?id="+encodeURI(serverId)+'&project='+encodeURI(project)+'&filter=virtual-machine'+'&recursion=1', function (data) {
         data = data.metadata;
         
         running_virtual_machines = 0
@@ -516,8 +515,8 @@
       });
 
       //Set hyperlink references for cards
-      $("#containersLink").attr("href", "containers?id="+serverId+"&project="+project)
-      $("#virtualMachinesLink").attr("href", "virtual-machines?id="+serverId+"&project="+project)
+      $("#containersLink").attr("href", "instances?id="+serverId+"&project="+project)
+      $("#virtualMachinesLink").attr("href", "instances?id="+serverId+"&project="+project)
       $("#clusterMembersLink").attr("href", "cluster-members?id="+serverId+"&project="+project)
       $("#imagesLink").attr("href", "images?id="+serverId+"&project="+project)
       $("#profilesLink").attr("href", "profiles?id="+serverId+"&project="+project)

+ 6 - 3
lxconsole/templates/servers.html

@@ -6,9 +6,9 @@
       <h1>{{ page_title | safe }}</h1>
     </div>
     <div class="col-sm-6">
-      <a class="btn btn-outline-primary float-sm-right mr-4" href="#" data-toggle="modal" data-target="#addModal" title="Add Server" aria-hidden="true">
+      <button class="btn btn-outline-primary float-sm-right mr-4" data-bs-toggle="modal" data-bs-target="#addModal" title="Add Server" aria-hidden="true">
         <i class="fas fa-plus fa-sm fa-fw"></i> Server
-      </a>
+      </button>
     </div>
   </div>
 {% endblock header %}
@@ -59,7 +59,10 @@
           url: "../api/servers/list_servers",
           dataType: "json",
           dataSrc: "data",
-          contentType: "application/json"
+          contentType: "application/json",
+          error: function (xhr, error, code) {
+            console.log(xhr, code);
+          }
         },
         columns: [
           { title: "Name", data: function (row, type, set) {

+ 4 - 12
lxconsole/templates/sidebar.html

@@ -40,18 +40,10 @@
 
         <ul id="instanceSidebarLinks" class="nav nav-pills nav-sidebar flex-column user-panel py-2" style="display: none;" data-widget="treeview" role="menu" data-accordion="false">
           <li class="nav-item">
-            <a class="nav-link" id="containersLinkSidebar" href="containers">
-              <i id="containersIcon" class="nav-icon fas fa-cube"></i>
-              <p id="containersSpan">
-                Containers
-              </p>
-            </a>
-          </li>
-          <li class="nav-item">
-            <a class="nav-link" id="virtualMachinesLinkSidebar" href="virtual-machines">
-              <i id="virtualMachinesIcon" class="nav-icon fas fa-cube"></i>
-              <p id="virtualMachinesSpan">
-                Virtual Machines
+            <a class="nav-link" id="instancesLinkSidebar" href="instances">
+              <i id="instancesIcon" class="nav-icon fas fa-cube"></i>
+              <p id="instancesSpan">
+                Instances
               </p>
             </a>
           </li>

+ 6 - 3
lxconsole/templates/simplestreams.html

@@ -6,9 +6,9 @@
       <h1>{{ page_title | safe }}</h1>
     </div>
     <div class="col-sm-6">
-      <a class="btn btn-outline-primary float-sm-right mr-4" href="#" data-toggle="modal" data-target="#addModal" title="Add Simplestreams Repository" aria-hidden="true">
+      <button class="btn btn-outline-primary float-sm-right mr-4" data-bs-toggle="modal" data-bs-target="#addModal" title="Add Simplestreams Repository" aria-hidden="true">
         <i class="fas fa-plus fa-sm fa-fw"></i> Simplestreams Repository
-      </a>
+      </button>
     </div>
   </div>
 {% endblock header %}
@@ -97,7 +97,10 @@
           url: "../api/simplestreams/list_simplestreams",
           dataType: "json",
           dataSrc: "data",
-          contentType: "application/json"
+          contentType: "application/json",
+          error: function (xhr, error, code) {
+            console.log(xhr, code);
+          }
         },
         columns: [
           { title: "URL", data: function (row, type, set) {

+ 6 - 3
lxconsole/templates/storage-pools.html

@@ -6,9 +6,9 @@
       <h1>{{ page_title | safe }}</h1>
     </div>
     <div class="col-sm-6">
-      <a class="btn btn-outline-primary float-sm-right mr-4" href="#" data-toggle="modal" data-target="#addModal" title="Add Storage Pool" aria-hidden="true">
+      <button class="btn btn-outline-primary float-sm-right mr-4" data-bs-toggle="modal" data-bs-target="#addModal" title="Add Storage Pool" aria-hidden="true">
         <i class="fas fa-plus fa-sm fa-fw"></i> Storage Pool
-      </a>
+      </button>
     </div>
   </div>
 {% endblock header %}
@@ -98,7 +98,10 @@
           url: "../api/storage-pools/list_storage_pools?id="+serverId+"&project=" + project + "&recursion=1",
           dataType: "json",
           dataSrc: "metadata",
-          contentType: "application/json"
+          contentType: "application/json",
+          error: function (xhr, error, code) {
+            console.log(xhr, code);
+          }
         },
         columns: [
           { title: "Name", data: function (row, type, set) {

+ 6 - 3
lxconsole/templates/storage-volumes.html

@@ -6,9 +6,9 @@
       <h1>{{ page_title | safe }}</h1>
     </div>
     <div class="col-sm-6">
-      <a class="btn btn-outline-primary float-sm-right mr-4" href="#" data-toggle="modal" data-target="#addModal" title="Add Storage Volume" aria-hidden="true">
+      <button class="btn btn-outline-primary float-sm-right mr-4" data-tbs-oggle="modal" data-bs-target="#addModal" title="Add Storage Volume" aria-hidden="true">
         <i class="fas fa-plus fa-sm fa-fw"></i> Storage Volume
-      </a>
+      </button>
     </div>
   </div>
 {% endblock header %}
@@ -106,7 +106,10 @@
           url: "../api/storage-volumes/list_storage_volumes?id="+serverId+"&project=" + project + "&recursion=1" + "&pool=" + pool,
           dataType: "json",
           dataSrc: "metadata",
-          contentType: "application/json"
+          contentType: "application/json",
+          error: function (xhr, error, code) {
+            console.log(xhr, code);
+          }
         },
         columns: [
           { title: "Name", data: function (row, type, set) {

+ 6 - 3
lxconsole/templates/users.html

@@ -6,9 +6,9 @@
       <h1>{{ page_title | safe }}</h1>
     </div>
     <div class="col-sm-6">
-      <a class="btn btn-outline-primary float-sm-right mr-4" href="#" data-toggle="modal" data-target="#addModal" title="Add User" aria-hidden="true">
+      <button class="btn btn-outline-primary float-sm-right mr-4" data-bs-toggle="modal" data-bs-target="#addModal" title="Add User" aria-hidden="true">
         <i class="fas fa-plus fa-sm fa-fw"></i> User
-      </a>
+      </button>
     </div>
   </div>
 {% endblock header %}
@@ -59,7 +59,10 @@
           url: "../api/users/list_users",
           dataType: "json",
           dataSrc: "data",
-          contentType: "application/json"
+          contentType: "application/json",
+          error: function (xhr, error, code) {
+            console.log(xhr, code);
+          }
         },
         columns: [
           { title: "Username", data: function (row, type, set) {

+ 0 - 2965
lxconsole/templates/virtual-machine.html

@@ -1,2965 +0,0 @@
-{% extends "main.html" %}
-
-{% block header %}
-  <div class="row mb-2">
-    <div class="col-sm-6">
-      <h1>{{ page_title | safe }} <span id="instance_title"></span></h1>
-    </div>
-    <div class="col-sm-6">
-      <a class="btn btn-outline-primary dropdown-toggle float-sm-right ml-2 mr-4" href="#" role="button" id="dropdownMenuLink" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false" title="Actions">
-        Instance Actions
-      </a>
-      <div class="dropdown-menu dropdown-menu-right shadow animated--fade-in" aria-labelledby="dropdownMenuLink">
-        <!--<div class="dropdown-header">Options:</div>-->
-        <a class="dropdown-item text-primary" style="display: none;" onclick="changeItemState(instance, 'start')" id="startLink"><i class="fas fa-play fa-sm fa-fw mr-2"></i>Start</a>
-        <a class="dropdown-item text-primary" style="display: none;" onclick="changeItemState(instance, 'stop')" id="stopLink"><i class="fas fa-stop fa-sm fa-fw mr-2"></i>Stop</a>
-        <a class="dropdown-item text-primary" style="display: none;" onclick="changeItemState(instance, 'unfreeze')" id="unfreezeLink"><i class="fas fa-pause fa-sm fa-fw mr-2"></i>UnFreeze</a>
-        <div class="dropdown-divider"></div> 
-        <a class="dropdown-item" onclick="editInstance()" id="editInstanceOption"><i class="fas fa-edit fa-sm fa-fw mr-2"></i>Edit</a>
-        <a class="dropdown-item" onclick="changeItemState(instance, 'restart')" id="restartInstanceOption"><i class="fas fa-redo fa-sm fa-fw mr-2"></i>Restart</a>
-        <a class="dropdown-item" onclick="changeItemState(instance, 'stop', true)" id="stopInstanceForcefullyOption"><i class="fas fa-plug fa-sm fa-fw mr-2"></i>Force Stop</a>
-        <a class="dropdown-item" onclick="changeItemState(instance, 'freeze')" id="freezeInstanceOption"><i class="fas fa-pause fa-sm fa-fw mr-2"></i>Freeze</a>
-        <a class="dropdown-item" href="#" data-toggle="modal" data-target="#createSnapshotModal" id="snapshotInstanceOption"><i class="fas fa-clone fa-sm fa-fw mr-2"></i>Snapshot</a>
-        <a class="dropdown-item" onclick="loadAttachProfileModal()" id="attachProfileOption"><i class="fas fa-address-card fa-sm fa-fw mr-2"></i>Attach Profile</a>
-        <a class="dropdown-item" onclick="loadDetachProfileModal()" id="detachProfileOption"><i class="fas fa-address-card fa-sm fa-fw mr-2"></i>Detach Profile</a>
-        <a class="dropdown-item" href="#" data-toggle="modal" data-target="#renameInstanceModal" id="renameInstanceOption"><i class="fas fa-edit fa-sm fa-fw mr-2"></i>Rename</a>
-        <a class="dropdown-item" href="#" data-toggle="modal" data-target="#copyInstanceModal" id="copyInstanceOption"><i class="fas fa-copy fa-sm fa-fw mr-2"></i>Copy</a>
-        <a class="dropdown-item" onclick="loadMigrateInstanceModal()" id="migrateInstanceOption"><i class="fas fa-suitcase fa-sm fa-fw mr-2"></i>Migrate</a>
-        <a class="dropdown-item text-primary" href="#" data-toggle="modal" data-target="#backupInstanceModal" id="backupInstanceOption"><i class="fas fa-save fa-sm fa-fw mr-2"></i>Backup</a>
-        <a class="dropdown-item" href="#" data-toggle="modal" data-target="#publishInstanceModal" id="publishInstanceOption"><i class="fas fa-box-open fa-sm fa-fw mr-2"></i>Publish</a>
-        <a class="dropdown-item" onclick="deleteInstance()" id="deleteInstanceOption"><i class="fas fa-trash-alt fa-sm fa-fw mr-2"></i>Delete</a>
-      </div>
-
-      <a class="btn btn-outline-primary float-sm-right" href="#" role="button" id="startLinkButton" onclick="changeItemState(instance, 'start')" style="display:none;" title="Start">
-        <i class="fas fa-play fa-fw"></i>
-      </a>
-      <a class="btn btn-outline-primary float-sm-right" href="#" role="button" id="stopLinkButton" onclick="changeItemState(instance, 'stop')" style="display:none;" title="Stop">
-        <i class="fas fa-stop fa-fw"></i>
-      </a>
-      <a class="btn btn-outline-primary float-sm-right" href="#" role="button" id="unfreezeLinkButton" onclick="changeItemState(instance, 'unfreeze')" style="display:none;" title="UnFreeze">
-        <i class="fas fa-pause fa-fw"></i>
-      </a>
-
-    </div>
-  </div>
-{% endblock header %}
-
-{% block content %}
-  <div class="col-12">
-    <nav>
-      <div class="nav nav-tabs" id="nav-page-tab" role="tablist">
-        <a class="nav-item nav-link active" id="nav-home-tab" data-toggle="tab" href="#nav-home" role="tab" aria-controls="nav-home" aria-selected="true">Home</a>
-        <a class="nav-item nav-link" id="nav-configuration-tab" data-toggle="tab" href="#nav-configuration" role="tab" aria-controls="nav-configuration" aria-selected="false">Configuration</a>
-        <a class="nav-item nav-link" id="nav-devices-tab" data-toggle="tab" href="#nav-devices" role="tab" aria-controls="nav-devices" aria-selected="false">Devices</a>
-        <a class="nav-item nav-link" id="nav-console-tab" data-toggle="tab" href="#nav-console" role="tab" aria-controls="nav-console" aria-selected="false">Console</a>
-        <a class="nav-item nav-link" id="nav-exec-tab" data-toggle="tab" href="#nav-exec" role="tab" aria-controls="nav-exec" aria-selected="false">Exec</a>
-      </div>
-    </nav>
-    <div class="tab-content" id="nav-page-content">
-      <div class="tab-pane fade show active" id="nav-home" role="tabpanel" aria-labelledby="nav-home-tab">
-        <br />
-        <div class="row">
-          <div class="col-9">
-      
-            <!-- Interfaces Card-->
-            <div class="card" id="interfacesCard">
-              <div class="card-header">
-                <h3 class="card-title text-primary">
-                    Interfaces
-                </h3>
-              </div>
-              <div class="card-body">
-                <div class="table-responsive">
-                  <table class="table table-hover" id="interfaceTableList" width="100%" cellspacing="0">
-                  </table>
-                </div>
-              </div>
-            </div>
-    
-            <!-- Snapshots Card-->
-            <div class="card" id="snapshotsCard">
-              <div class="card-header">
-                <h3 class="card-title text-primary">
-                  Snapshots
-                </h3>
-                <div class="card-tools">
-                  <button type="button" class="btn btn-tool" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
-                    <i class="fa fa-bars"></i>
-                  </button>
-                  <div class="dropdown-menu dropdown-menu-right">
-                    <a href="#" class="dropdown-item" data-toggle="modal" data-target="#createSnapshotModal" title="Create Snapshot">Create Snapshot</a>
-                  </div>
-                </div>
-              </div>
-              <div class="card-body">
-                <div class="table-responsive">
-                  <table class="table table-hover" id="snapshotTableList" width="100%" cellspacing="0">
-                  </table>
-                </div>
-              </div>
-            </div>
-    
-            <!-- Backups Card-->
-            <div class="card" id="backupsCard">
-              <div class="card-header">
-                <h3 class="card-title text-primary">
-                  Backups
-                </h3>
-                <div class="card-tools">
-                  <button type="button" class="btn btn-tool" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
-                    <i class="fa fa-bars"></i>
-                  </button>
-                  <div class="dropdown-menu dropdown-menu-right">
-                    <a href="#" class="dropdown-item" data-toggle="modal" data-target="#backupInstanceModal" title="Create Backup">Create Backup</a>
-                  </div>
-                </div>
-              </div>
-              <div class="card-body">
-                <div class="table-responsive">
-                  <table class="table table-hover" id="backupTableList" width="100%" cellspacing="0">
-                  </table>
-                </div>
-              </div>
-            </div>
-        
-            <!-- Logs Card-->
-            <div class="card" id="logsCard">
-              <div class="card-header">
-                <h3 class="card-title text-primary">
-                  Logs
-                </h3>
-              </div>
-              <div class="card-body">
-                <div class="table-responsive">
-                  <table class="table table-hover" id="logTableList" width="100%" cellspacing="0">
-                  </table>
-                </div>
-              </div>
-            </div>
-    
-          </div>
-
-          <div class="col-3">    
-            <div class="accordion" id="accordionExample">
-      
-              <!-- General Data Card-->
-              <div class="card">
-                <div class="card-header">
-                  <h3 class="card-title text-primary" data-card-widget="collapse">
-                    General Data
-                  </h3>
-                  <div class="card-tools">
-                    <button type="button" class="btn btn-tool" data-card-widget="collapse"><i class="fas fa-minus"></i></button>
-                  </div>
-                </div>
-                <div class="card-body">
-                  <div class="d-flex justify-content-between">
-                    <div>CPU</div>
-                    <div><span id="cpuPercentage">0</span>%</div>
-                  </div>
-                  <div class="progress">
-                    <div class="progress-bar bg-primary" id="cpuPercentageBar" role="progressbar" style="width: 0%" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100"></div>
-                  </div>
-                  <br />
-                  <div class="d-flex justify-content-between">
-                    <div>Memory</div>
-                    <div><span id="memPercentage">0</span>%</div>
-                  </div>
-                  <div class="progress">
-                    <div class="progress-bar bg-primary" id="memPercentageBar" role="progressbar" style="width: 0%" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100"></div>
-                  </div>
-                  <br /><br />
-                  <table class="table table-sm h6">
-                    <tr><td class="pr-3">Status:</td> <td><span id="status"></span></td></tr>
-                    <tr><td class="pr-3">Profiles:</td> <td><span id="profiles"></span></td></tr>
-                    <tr><td class="pr-3">Image:</td> <td><span id="image"></span></td></tr>
-                    <tr><td class="pr-3">Location:</td> <td><span id="location"></span></td></tr>
-                    <tr><td class="pr-3">Created:</td> <td><span id="created"></span></td></tr>
-                    <tr><td class="pr-3">CPU:</td> <td><span id="cpu"></span></td></tr>
-                    <tr><td class="pr-3">Memory:</td> <td><span id="memory"></span></td></tr>
-                    <tr><td class="pr-3">Swap:</td> <td><span id="swap"></span></td></tr>
-                    <tr><td class="pr-3">PID:</td> <td><span id="pid"></span></td></tr>
-                    <tr><td class="pr-3">Processes:</td> <td><span id="processes"></span></td></tr>
-                  </table>
-                </div>
-              </div>
-            
-            </div>
-          </div>
-
-        </div>
-      </div>
-      <div class="tab-pane fade" id="nav-configuration" role="tabpanel" aria-labelledby="nav-configuration-tab">
-        <br />
-        <div class="row">
-
-          <div class="col-auto border-right pr-4 mr-4 ml-4">
-            <div class="nav flex-column nav-pills" id="v-pills-tab" role="tablist" aria-orientation="vertical">
-              <a class="nav-link active" id="v-pills-boot-configuration-tab" data-toggle="pill" href="#v-pills-boot-configuration" role="tab" aria-controls="v-pills-boot-configuration" aria-selected="true">Boot</a>
-              <a class="nav-link" id="v-pills-cloud-init-configuration-tab" data-toggle="pill" href="#v-pills-cloud-init-configuration" role="tab" aria-controls="v-pills-cloud-init-configuration" aria-selected="false">Cloud-init</a>
-              <a class="nav-link" id="v-pills-limits-configuration-tab" data-toggle="pill" href="#v-pills-limits-configuration" role="tab" aria-controls="v-pills-limits-configuration" aria-selected="false">Limits</a>
-              <a class="nav-link" id="v-pills-migration-configuration-tab" data-toggle="pill" href="#v-pills-migration-configuration" role="tab" aria-controls="v-pills-migration-configuration" aria-selected="false">Migration</a>
-              <a class="nav-link" id="v-pills-other-configuration-tab" data-toggle="pill" href="#v-pills-other-configuration" role="tab" aria-controls="v-pills-other-configuration" aria-selected="false">Other</a>
-              <a class="nav-link" id="v-pills-raw-configuration-tab" data-toggle="pill" href="#v-pills-raw-configuration" role="tab" aria-controls="v-pills-raw-configuration" aria-selected="false">Raw</a>
-              <a class="nav-link" id="v-pills-security-configuration-tab" data-toggle="pill" href="#v-pills-security-configuration" role="tab" aria-controls="v-pills-security-configuration" aria-selected="false">Security</a>
-              <a class="nav-link" id="v-pills-snapshots-configuration-tab" data-toggle="pill" href="#v-pills-snapshot-configuration" role="tab" aria-controls="v-pills-snapshot-configuration" aria-selected="false">Snapshot</a>
-            </div>
-          </div>
-          <div class="col">
-            <div class="tab-content" id="v-pills-configurationContent">
-
-              <div class="tab-pane fade show active" id="v-pills-boot-configuration" role="tabpanel" aria-labelledby="v-pills-boot-configuration-tab">
-                <!-- Boot Configuration Card-->
-                <table class="table w-auto">
-                  <tr><td class="pr-3">Autostart:</td> <td><span id="bootAutostart"></span></td></tr>
-                  <tr><td class="pr-3">Autostart Delay:</td> <td><span id="bootAutostartDelay"></span></td></tr>
-                  <tr><td class="pr-3">Autostart Priority:</td> <td><span id="bootAutostartPriority"></span></td></tr>
-                  <tr><td class="pr-3">Host Shutdown Timeout:</td> <td><span id="bootHostShutdownTimeout"></span></td></tr>
-                  <tr><td class="pr-3">Stop Priority:</td> <td><span id="bootStopPriority"></span></td></tr>
-                </table>
-              </div>
-
-              <div class="tab-pane fade" id="v-pills-cloud-init-configuration" role="tabpanel" aria-labelledby="v-pills-cloud-init-configuration-tab">
-                <!-- Cloud-init Configuration Card-->
-                <table class="table w-auto">
-                  <tr><td class="pr-3">Network-Config:</td> <td><span id="cloudInitNetworkConfig"></span></td></tr>
-                  <tr><td class="pr-3">User-Data:</td> <td><span id="cloudInitUserData"></span></td></tr>
-                  <tr><td class="pr-3">Vendor-Data:</td> <td><span id="cloudInitVendorData"></span></td></tr>
-                </table>
-              </div>
-
-              <div class="tab-pane fade" id="v-pills-limits-configuration" role="tabpanel" aria-labelledby="v-pills-limits-configuration-tab">
-                <!-- Limits Configuration Card-->
-                <table class="table w-auto">
-                  <tr><td class="pr-3">CPU:</td> <td><span id="limitsCpu"></span></td></tr>
-                  <tr><td class="pr-3">Disk Priority:</td> <td><span id="limitsDiskPriority"></span></td></tr>
-                  <tr><td class="pr-3">Memory:</td> <td><span id="limitsMemory"></span></td></tr>
-                  <tr><td class="pr-3">Memory Hugepages:</td> <td><span id="limitsMemoryHugepages"></span></td></tr>
-                  <tr><td class="pr-3">Network Priority:</td> <td><span id="limitsNetworkPriority"></span></td></tr>
-                </table>
-              </div>
-
-              <div class="tab-pane fade" id="v-pills-migration-configuration" role="tabpanel" aria-labelledby="v-pills-migration-configuration-tab">
-                <!-- Migration Configuration Card-->
-                <table class="table w-auto">
-                  <tr><td class="pr-3">Stateful:</td> <td><span id="migrationStateful"></span></td></tr>
-                </table>
-              </div>
-
-              <div class="tab-pane fade" id="v-pills-other-configuration" role="tabpanel" aria-labelledby="v-pills-other-configuration-tab">
-                <!-- Other Configuration Card-->
-                <table class="table w-auto">
-                  <tr><td class="pr-3">Cluster Evacuate:</td> <td><span id="clusterEvacuate"></span></td></tr>
-                </table>
-              </div>
-
-              <div class="tab-pane fade" id="v-pills-raw-configuration" role="tabpanel" aria-labelledby="v-pills-raw-configuration-tab">
-                <!-- Raw Configuration Card-->
-                <table class="table w-auto">
-                  <tr><td class="pr-3">Apparmor:</td> <td><span id="rawApparmor"></span></td></tr>
-                  <tr><td class="pr-3">Qemu:</td> <td><span id="rawQemu"></span></td></tr>
-                  <tr><td class="pr-3">Qemu.conf:</td> <td><span id="rawQemuConf"></span></td></tr>
-                </table>
-              </div>
-
-              <div class="tab-pane fade" id="v-pills-security-configuration" role="tabpanel" aria-labelledby="v-pills-security-configuration-tab">
-                <!-- Security Configuration Card-->
-                <table class="table w-auto">
-                  <tr><td class="pr-3">Devlxd:</td> <td><span id="securityDevLxd"></span></td></tr>
-                  <tr><td class="pr-3">Protection Delete:</td> <td><span id="securityProtectionDelete"></span></td></tr>
-                  <tr><td class="pr-3">Agent Metrics:</td> <td><span id="securityAgentMetrics"></span></td></tr>
-                  <tr><td class="pr-3">Secureboot:</td> <td><span id="securitySecureboot"></span></td></tr>
-                </table>
-              </div>
-
-              <div class="tab-pane fade" id="v-pills-snapshot-configuration" role="tabpanel" aria-labelledby="v-pills-snapshot-configuration-tab">
-                <!-- Snapshot Configuration Card-->
-                <table class="table w-auto">
-                  <tr><td class="pr-3">Schedule:</td> <td><span id="snapshotsSchedule"></span></td></tr>
-                  <tr><td class="pr-3">Schedule Stopped:</td> <td><span id="snapshotsScheduleStopped"></span></td></tr>
-                  <tr><td class="pr-3">Pattern:</td> <td><span id="snapshotsPattern"></span></td></tr>
-                  <tr><td class="pr-3">Expiry:</td> <td><span id="snapshotsExpiry"></span></td></tr>
-                </table>
-              </div>
-          
-            </div>
-          </div>
-
-        </div>
-      </div>
-      <div class="tab-pane fade" id="nav-devices" role="tabpanel" aria-labelledby="nav-devices-tab">
-        <br />
-        <div class="row">
-
-          <div class="col-auto border-right pr-4 mr-4 ml-4">
-            <div class="nav flex-column nav-pills" id="v-pills-tab" role="tablist" aria-orientation="vertical">
-              <a class="nav-link active" id="v-pills-disk-devices-tab" data-toggle="pill" href="#v-pills-disk-devices" role="tab" aria-controls="v-pills-disk-devices" aria-selected="true">Disk</a>
-              <a class="nav-link" id="v-pills-gpu-devices-tab" data-toggle="pill" href="#v-pills-gpu-devices" role="tab" aria-controls="v-pills-gpu-devices" aria-selected="false">GPU</a>
-              <a class="nav-link" id="v-pills-network-devices-tab" data-toggle="pill" href="#v-pills-network-devices" role="tab" aria-controls="v-pills-network-devices" aria-selected="false">Network</a>
-              <a class="nav-link" id="v-pills-proxy-devices-tab" data-toggle="pill" href="#v-pills-proxy-devices" role="tab" aria-controls="v-pills-proxy-devices" aria-selected="false">Proxy</a>
-              <a class="nav-link" id="v-pills-usb-devices-tab" data-toggle="pill" href="#v-pills-usb-devices" role="tab" aria-controls="v-pills-usb-devices" aria-selected="false">USB</a>
-            </div>
-          </div>
-          <div class="col">
-
-            <div class="tab-content" id="v-pills-deviceContent">
-
-              <div class="tab-pane fade show active" id="v-pills-disk-devices" role="tabpanel" aria-labelledby="v-pills-disk-devices-tab">
-                <!-- Disk Devices Card-->
-                <div class="card" id="diskDevicesCard">
-                  <div class="card-header">
-                    <h3 class="card-title text-primary">
-                      Disk Devices
-                    </h3>
-                    <div class="card-tools">
-                      <button type="button" class="btn btn-tool" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
-                        <i class="fa fa-bars"></i>
-                      </button>
-                      <div class="dropdown-menu dropdown-menu-right">
-                        <a class="dropdown-item" onclick="loadAddDiskDeviceModal()" title="Add Disk Device">Add Disk Device</a>
-                      </div>
-                    </div>
-                  </div>
-                  <div class="card-body">
-                    <div class="table-responsive">
-                      <table class="table table-hover" id="diskDeviceTableList" width="100%" cellspacing="0">
-                      </table>
-                    </div>
-                  </div>
-                </div>
-              </div>
-
-              <div class="tab-pane fade" id="v-pills-gpu-devices" role="tabpanel" aria-labelledby="v-pills-gpu-devices-tab">
-                <!-- GPU Devices Card-->
-                <div class="card" id="gpuDevicesCard">
-                  <div class="card-header">
-                    <h3 class="card-title text-primary">
-                      GPU Devices
-                    </h3>
-                    <div class="card-tools">
-                      <button type="button" class="btn btn-tool" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
-                        <i class="fa fa-bars"></i>
-                      </button>
-                      <div class="dropdown-menu dropdown-menu-right">
-                        <a href="#" class="dropdown-item" data-toggle="modal" data-target="#addGPUDeviceModal" title="Add GPU Device">Add GPU Device</a>
-                      </div>
-                    </div>
-                  </div>
-                  <div class="card-body">
-                    <div class="table-responsive">
-                      <table class="table table-hover" id="gpuDeviceTableList" width="100%" cellspacing="0">
-                      </table>
-                    </div>
-                  </div>
-                </div>
-              </div>
-
-              <div class="tab-pane fade" id="v-pills-network-devices" role="tabpanel" aria-labelledby="v-pills-network-devices-tab">
-                <!-- Network Devices Card-->
-                <div class="card" id="networkDevicesCard">
-                  <div class="card-header">
-                    <h3 class="card-title text-primary">
-                      Network Devices
-                    </h3>
-                    <div class="card-tools">
-                      <button type="button" class="btn btn-tool" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
-                        <i class="fa fa-bars"></i>
-                      </button>
-                      <div class="dropdown-menu dropdown-menu-right">
-                        <a class="dropdown-item" onclick="loadAddNetworkDeviceModal()" title="Add Network Device">Add Network Device</a>
-                      </div>
-                    </div>
-                  </div>
-                  <div class="card-body">
-                    <div class="table-responsive">
-                      <table class="table table-hover" id="networkDeviceTableList" width="100%" cellspacing="0">
-                      </table>
-                    </div>
-                  </div>
-                </div>
-              </div>
-
-              <div class="tab-pane fade" id="v-pills-proxy-devices" role="tabpanel" aria-labelledby="v-pills-proxy-devices-tab">
-                <!-- Proxy Devices Card-->
-                <div class="card" id="proxyDevicesCard">
-                  <div class="card-header">
-                    <h3 class="card-title text-primary">
-                      Proxy Devices
-                    </h3>
-                    <div class="card-tools">
-                      <button type="button" class="btn btn-tool" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
-                        <i class="fa fa-bars"></i>
-                      </button>
-                      <div class="dropdown-menu dropdown-menu-right">
-                        <a href="#" class="dropdown-item" data-toggle="modal" data-target="#addProxyDeviceModal" title="Add Proxy Device">Add Proxy Device</a>
-                      </div>
-                    </div>
-                  </div>
-                  <div class="card-body">
-                    <div class="table-responsive">
-                      <table class="table table-hover" id="proxyDeviceTableList" width="100%" cellspacing="0">
-                      </table>
-                    </div>
-                  </div>
-                </div>
-              </div>
-
-              <div class="tab-pane fade" id="v-pills-usb-devices" role="tabpanel" aria-labelledby="v-pills-usb-devices-tab">
-                <!-- USB Devices Card-->
-                <div class="card" id="usbDevicesCard">
-                  <div class="card-header">
-                    <h3 class="card-title text-primary">
-                      USB Devices
-                    </h3>
-                    <div class="card-tools">
-                      <button type="button" class="btn btn-tool" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
-                        <i class="fa fa-bars"></i>
-                      </button>
-                      <div class="dropdown-menu dropdown-menu-right">
-                        <a href="#" class="dropdown-item" data-toggle="modal" data-target="#addUSBDeviceModal" title="Add USB Device">Add USB Device</a>
-                      </div>
-                    </div>
-                  </div>
-                  <div class="card-body">
-                    <div class="table-responsive">
-                      <table class="table table-hover" id="usbDeviceTableList" width="100%" cellspacing="0">
-                      </table>
-                    </div>
-                  </div>
-                </div>
-              </div>
-          
-            </div>
-          </div>
-
-        </div>
-
-      </div>
-      <div class="tab-pane fade" id="nav-console" role="tabpanel" aria-labelledby="nav-console-tab">
-        <br />
-        <!-- Console Card -->
-        <div class="card">
-          <div class="card-header">
-            <h3 class="card-title text-primary">Console</h3>
-            <div class="card-tools">
-              <div class="dropdown no-arrow">
-                <button type="button btn-tool" class="dropdown-toggle mr-2 btn btn-sm btn-outline-primary" id="startConsoleButton" title="Start Console Terminal" onclick="establishInstanceWebSocketConsoleConnection()">Start Console</button>
-                <button type="button btn-tool" class="dropdown-toggle mr-2 btn btn-sm btn-outline-primary" id="stopConsoleButton" style="display: none;"  title="Stop Console Terminal" onclick="closeWebSocketConsoleConnection()">Stop Console</button>
-              </div>
-            </div>
-          </div>
-          <div class="card-body">
-            <div id="terminal-console"></div>
-          </div>
-        </div>
-        <!-- Console Card  -->
-      </div>
-      <div class="tab-pane fade" id="nav-exec" role="tabpanel" aria-labelledby="nav-exec-tab">
-        <br />
-        <!-- Exec Card -->
-        <div class="card">
-          <div class="card-header">
-            <h3 class="card-title text-primary">Exec</h3>
-            <div class="card-tools">
-              <div class="dropdown no-arrow">
-                <button type="button btn-tool" class="dropdown-toggle mr-2 btn btn-sm btn-outline-primary" id="startExecButton" title="Start Exec Terminal" onclick="establishInstanceWebSocketExecConnection()">Start Exec</button>
-                <button type="button btn-tool" class="dropdown-toggle mr-2 btn btn-sm btn-outline-primary"  style="display: none;" id="stopExecButton" title="Stop Exec Terminal" onclick="closeWebSocketExecConnection()">Stop Exec</button>
-                <select id="execShellInput" class="dropdown-toggle mr-2 btn btn-sm btn-tool" name="execShellInput">
-                  <option value="bash" selected>/bin/bash</option>
-                  <option value="sh">/bin/sh</option>
-                </select>
-              </div>
-            </div>
-          </div>
-          <div class="card-body">
-            <div id="terminal-exec"></div>
-          </div>
-        </div>
-        <!-- Exec Card  -->
-      </div>
-    </div>
-  </div>
-{% endblock content %}
-
-{% block modal %}
-  {% include 'modals/virtual-machine.html' %}
-{% endblock modal %}
-
-{% block script %}
-
-  <!-- xterm -->
-  <script src="../static/js/xterm/xterm.js"></script> 
-
-  <script>
-    
-    var reloadTime = 10000;
-    const queryString = window.location.search;
-    const urlParams = new URLSearchParams(queryString);
-    const serverId = urlParams.get('id');
-    const project = urlParams.get('project');
-    const instance = urlParams.get('instance');
-    var target_location 
-    var server_name
-    var server_clustered
-    var editedContainer
-    var execControlSocket
-    var execDataSocket
-    var resizeTimer
-    populateSidebarLinks();
-    populateNavbarLinks();
-
-    //Initialize xterm for Exec
-    const execTerminal = new Terminal({
-      cursorBlink: "block",
-      fontSize: 15,
-      convertEol: true,
-      rendererType: 'dom',
-      cols: parseInt(($("#page-container").width() - 40) / 9),
-      rows: 35
-    });
-
-    //Initialize xterm for Console
-    const consoleTerminal = new Terminal({
-      cursorBlink: "block",
-      fontSize: 15,
-      convertEol: true,
-      rendererType: 'dom',
-      cols: parseInt(($("#page-container").width() - 40) / 9),
-      rows: 35
-    });
-
-    // Resize the terminal and websocket connection on element resize
-    function terminalResize() {
-      execTerminal.resize(parseInt(($("#page-container").width() - 40) / 9), 35);
-      consoleTerminal.resize(parseInt(($("#page-container").width() - 40) / 9), 35);
-
-      resize_command = {
-        command: "window-resize",
-        args: {
-          width: parseInt(($("#page-container").width() - 40) / 9).toString(),
-          height: "35"
-        },
-      }
-      
-      if (typeof execControlSocket == 'object')
-        execControlSocket.send(convertString2ArrayBuffer(JSON.stringify(resize_command)))
-      if (typeof consoleControlSocket == 'object')
-        consoleControlSocket.send(convertString2ArrayBuffer(JSON.stringify(resize_command)))
-    }
-    
-    // Listen for console and exec terminal size changes on page resize
-    $(window).resize(function(){
-      // Using a Timeout to prevent rapid resize calls and improve performance
-      clearTimeout(resizeTimer)
-      resizeTimer = setTimeout(() => { terminalResize(); }, 500);
-    })
-
-    // Listen for console and exec terminal size changes on toggled sidebar
-    try {
-      ro = new ResizeObserver(() => {
-        // Using a Timeout to prevent rapid resize calls and improve performance
-        clearTimeout(resizeTimer)
-        resizeTimer = setTimeout(() => { terminalResize(); }, 500);
-      }).observe(document.getElementById("terminal-exec"))
-    } catch (error) {
-      console.log(error);
-    }    
-
-    applySidebarStyles();
-    applySidebarLinks();
-
-
-    function reloadPageContent() {
-  
-      //Clear the automatic page reload
-      clearTimeout(pageReloadTimeout);
-
-      //Load Instance Data and Configuration
-      loadInstanceData()
-      
-      //Load Instance State Data and Configuration
-      loadInstanceStateData()
-
-      //Reload the HOME tab tables if active
-      if ($('#nav-home-tab').hasClass('active')) {
-        loadInterfaceTable()
-        loadSnapshotsTable()
-        loadBackupsTable()
-        loadLogsTable()
-      }
-
-      //Reload the DEVICES tab tables if active
-      if ($('#nav-devices-tab').hasClass('active')) {
-        loadDiskDevicesTable()
-        loadGpuDevicesTable()
-        loadNetworkDevicesTable()
-        loadProxyDevicesTable()
-        loadUsbDevicesTable()
-      }
-
-      //Reload CPU Percentage
-      loadCpuPercentage()
-
-      //Reload Memory Percentage
-      loadMemoryPercentage()
-      
-      //Set the automatic page reload
-      pageReloadTimeout = setTimeout(() => { reloadPageContent(); }, reloadTime);
-    }
-
-    function loadPageContent(){
-      
-      //Populate the Server dropdown
-      $.getJSON("../api/servers/list_servers?id="+serverId, function (data) {
-        data = data.data
-        for (var index = 0; index < data.length; index++) {
-          if (data[index].name == '')
-            optionText = data[index].addr
-          else
-            optionText = data[index].name
-          if (data[index].id == serverId){
-            $('#serverListNav').append('<option value="' + data[index].id + '" selected="selected">' + optionText + '</option>');
-          }
-          else
-            $('#serverListNav').append('<option value="' + data[index].id + '">' + optionText + '</option>');
-        }
-      })
-
-      //Populate the Project dropdown
-      $.getJSON("../api/projects/list_projects?id="+serverId+"&project="+project, function (data) {
-        data = data.metadata
-        for (var index = 0; index < data.length; index++) {
-          optionText = data[index].replace('/1.0/projects/','');
-          if (optionText == project)
-            $('#projectListNav').append('<option value="' + optionText + '" selected="selected">' + optionText + '</option>');
-          else
-            $('#projectListNav').append('<option value="' + optionText + '">' + optionText + '</option>');
-        }
-      })
-
-      //Load Instance Data and Configuration
-      loadInstanceData()
-
-      //Load Instance State Data and Configuration
-      loadInstanceStateData()
-
-      //Load CPU Percentage
-      loadCpuPercentage()
-
-      //Load Home Tab Tables
-      loadInterfaceTable()
-      loadSnapshotsTable()
-      loadBackupsTable()
-      loadLogsTable()
-
-      //Load Memory Percentage
-      loadMemoryPercentage()
-      
-      //Setup new data listener for Exec terminal
-      execTerminal.onData( (data) => {
-        if (execDataSocket.readyState === 1) {
-          execDataSocket.send(convertString2ArrayBuffer(data))
-        }
-      });
-
-      //Setup new data listener for Console terminal
-      consoleTerminal.onData( (data) => {
-        if (consoleDataSocket.readyState === 1) {
-          consoleDataSocket.send(convertString2ArrayBuffer(data))
-        }
-      });
-
-      //Open Exec terminal
-      execTerminal.open(document.getElementById("terminal-exec"));
-
-      //Open Console terminal
-      consoleTerminal.open(document.getElementById("terminal-console"));
-
-      //Set reload page content
-      pageReloadTimeout = setTimeout(() => { reloadPageContent(); }, reloadTime);
-
-    }
-
-    function loadCpuPercentage() {
-      $.get("../api/virtual-machine/get_instance_cpu_percentage?id="+serverId+"&project="+project+"&name="+instance, function (data) {
-        percentage = parseFloat(data.percentage).toFixed(2);
-        $('#cpuPercentage').text(percentage)
-        $('#cpuPercentageBar').css('width', percentage + '%');
-        $('#cpuPercentageBar').attr('aria-valuenow', percentage + '%');
-        if (percentage > 90.00)
-          $('#cpuPercentageBar').attr('class', 'progress-bar bg-danger');
-        else
-          $('#cpuPercentageBar').attr('class', 'progress-bar bg-primary');
-      });
-    }
-
-    function loadMemoryPercentage() {
-      $.get("../api/virtual-machine/get_instance_memory_percentage?id="+serverId+"&project="+project+"&name="+instance, function (data) {
-        percentage = parseFloat(data.percentage).toFixed(2);
-        $('#memPercentage').text(percentage)
-        $('#memPercentageBar').css('width', percentage + '%');
-        $('#memPercentageBar').attr('aria-valuenow', percentage + '%');
-        if (percentage > 90.00)
-          $('#memPercentageBar').attr('class', 'progress-bar bg-danger');
-        else
-          $('#memPercentageBar').attr('class', 'progress-bar bg-primary');
-      });
-    }
-
-    function loadInstanceData() {
-      $.get("../api/virtual-machine/get_instance?id="+serverId+"&project="+project+"&name="+instance+"&recursion=1", function (data) {
-        data = data.metadata;
-        dataConfig = data.config;
-        target_location = data.location
-
-        $.getJSON("../api/server/get_server_info?id="+encodeURI(serverId)+'&project='+encodeURI(project), function (data) {
-          data = data.metadata.environment;
-          server_name = data.server_name
-          server_clustered = data.server_clustered 
-          if (data.server_clustered && data.server_name != target_location) {
-            $('#startExecButton').prop('disabled', true);
-            $('#startConsoleButton').prop('disabled', true);
-            consoleTerminal.write("\r\n--- This instance is located on a differenct host within the cluster. Console is unavailable  --- \r\n");
-            execTerminal.write("\r\n--- This instance is located on a differenct host within the cluster. Exec is unavailable  --- \r\n");
-          }
-        });
-
-        $("#name").text(data.name);
-        if (data.hasOwnProperty('description')) { $("#description").text(data.description); }
-        $("#status").text(data.status);
-        $("#profiles").text(data.profiles.join(', '));
-        if (dataConfig.hasOwnProperty('image.description')) { $("#image").text(dataConfig["image.description"]); }
-        $("#location").text(data.location);
-        $("#created").text(data.created_at.substring(0,10));
-
-        if (dataConfig.hasOwnProperty('boot.autostart')) { $("#bootAutostart").text(dataConfig['boot.autostart']); } else { $("#bootAutostart").text("-"); }
-        if (dataConfig.hasOwnProperty('boot.autostart.delay')) { $("#bootAutostartDelay").text(dataConfig['boot.autostart.delay']); } else { $("#bootAutostartDelay").text("-"); }
-        if (dataConfig.hasOwnProperty('boot.autostart.priority')) { $("#bootAutostartPriority").text(dataConfig['boot.autostart.priority']); } else { $("#bootAutostartPriority").text("-"); }
-        if (dataConfig.hasOwnProperty('boot.host_shutdown_timeout')) { $("#bootHostShutdownTimeout").text(dataConfig['boot.host_shutdown_timeout']); } else { $("#bootHostShutdownTimeout").text("-"); }
-        if (dataConfig.hasOwnProperty('boot.stop.priority')) { $("#bootStopPriority").text(dataConfig['boot.stop.priority']); } else { $("#bootStopPriority").text("-"); }
-
-        if (dataConfig.hasOwnProperty('cloud-init.network-config')) { $("#cloudInitNetworkConfig").text(dataConfig['cloud-init.network-config']); } else { $("#cloudInitNetworkConfig").text("-"); }
-        if (dataConfig.hasOwnProperty('cloud-init.user-data')) { $("#cloudInitUserData").text(dataConfig['cloud-init.user-data']); } else { $("#cloudInitUserData").text("-"); }
-        if (dataConfig.hasOwnProperty('cloud-init.vendor-data')) { $("#cloudInitVendorData").text(dataConfig['cloud-init.vendor-data']); } else { $("#cloudInitVendorData").text("-"); }
-
-        if (dataConfig.hasOwnProperty('cluster.evacuate')) { $("#clusterEvacuate").text(dataConfig['cluster.evacuate']); } else { $("#clusterEvacuate").text("-"); }
-
-        if (dataConfig.hasOwnProperty('limits.cpu')) { $("#limitsCpu").text(dataConfig['limits.cpu']); } else { $("#limitsCpu").text("-"); }
-        if (dataConfig.hasOwnProperty('limits.disk.priority')) { $("#limitsDiskPriority").text(dataConfig['limits.disk.priority']); } else { $("#limitsDiskPriority").text("-"); }
-        if (dataConfig.hasOwnProperty('limits.memory')) { $("#limitsMemory").text(dataConfig['limits.memory']); } else { $("#limitsMemory").text("-"); }
-        if (dataConfig.hasOwnProperty('limits.memory.hugepages')) { $("#limitsMemoryHugepages").text(dataConfig['limits.memory.hugepages']); } else { $("#limitsMemoryHugepages").text("-"); }
-        if (dataConfig.hasOwnProperty('limits.network.priority')) { $("#limitsNetworkPriority").text(dataConfig['limits.network.priority']); } else { $("#limitsNetworkPriority").text("-"); }
-
-        if (dataConfig.hasOwnProperty('migration.stateful')) { $("#migrationStateful").text(dataConfig['migration.stateful']); } else { $("#migrationStateful").text("-"); }
-
-        if (dataConfig.hasOwnProperty('raw.apparmor')) { $("#rawApparmor").text(dataConfig['raw.apparmor']); } else { $("#rawApparmor").text("-"); }
-        if (dataConfig.hasOwnProperty('raw.qemu')) { $("#rawQemu").text(dataConfig['raw.qemu']); } else { $("#rawQemu").text("-"); }
-        if (dataConfig.hasOwnProperty('raw.qemu.conf')) { $("#rawQemuConf").text(dataConfig['raw.qemu.conf']); } else { $("#rawQemuConf").text("-"); }
-
-        if (dataConfig.hasOwnProperty('security.devlxd')) { $("#securityDevLxd").text(dataConfig['security.devlxd']); } else { $("#securityDevLxd").text("-"); }
-        if (dataConfig.hasOwnProperty('security.protection.delete')) { $("#securityProtectionDelete").text(dataConfig['security.protection.delete']); } else { $("#securityProtectionDelete").text("-"); }
-        if (dataConfig.hasOwnProperty('security.agent.metrics')) { $("#securityAgentMetrics").text(dataConfig['security.agent.metrics']); } else { $("#securityAgentMetrics").text("-"); }
-        if (dataConfig.hasOwnProperty('security.secureboot')) { $("#securitySecureboot").text(dataConfig['security.secureboot']); } else { $("#securitySecureboot").text("-"); }
-
-        if (dataConfig.hasOwnProperty('snapshots.schedule')) { $("#snapshotsSchedule").text(dataConfig['snapshots.schedule']); } else { $("#snapshotsSchedule").text("-"); }
-        if (dataConfig.hasOwnProperty('snapshots.schedule.stopped')) { $("#snapshotsScheduleStopped").text(dataConfig['snapshots.schedule.stopped']); } else { $("#snapshotsScheduleStopped").text("-"); }
-        if (dataConfig.hasOwnProperty('snapshots.pattern')) { $("#snapshotsPattern").text(dataConfig['snapshots.pattern']); } else { $("#snapshotsPattern").text("-"); }
-        if (dataConfig.hasOwnProperty('snapshots.expiry')) { $("#snapshotsExpiry").text(dataConfig['snapshots.expiry']); } else { $("#snapshotsExpiry").text("-"); }
-
-      });
-
-      
-    }
-
-    function loadInstanceStateData() {
-      $.get("../api/virtual-machine/get_instance_state?id="+serverId+"&project="+project+"&name="+instance+"&recursion=1", function (data) {
-        data = data.metadata;
-        displayMenuOptions(data)
-        $("#cpu").text(parseFloat(parseInt(data.cpu.usage) / 1000000).toFixed(2)  + ' ms')
-        $("#memory").text(parseFloat(parseInt(data.memory.usage) / 1024 / 1024 / 1024).toFixed(2)  + ' GiB')
-        $("#swap").text(parseFloat(parseInt(data.memory.swap_usage) / 1024 / 1024 / 1024).toFixed(2)  + ' GiB')
-        $("#pid").text(data.pid)
-        $("#processes").text(data.processes)
-
-      });
-    }
-
-    // ********************* HOME TAB TABLES **************************
-    function loadInterfaceTable(){
-      if ( ! $.fn.DataTable.isDataTable( '#interfaceTableList' ) ) {
-        //Load Interfaces Table
-        $('#interfaceTableList').DataTable({
-          ajax: {
-            url: "../api/virtual-machine/get_instance_interfaces?id="+serverId+"&project="+project+"&name="+instance+"&recursion=1",
-            dataType: "json",
-            dataSrc: "data",
-            contentType: "application/json"
-          },
-          columns: [
-            { title: "Name", data: function (row, type, set) {
-                if (row.hasOwnProperty('name')) {
-                  if (row.name)
-                    return row.name
-                }
-                return '-'
-              },
-            },
-            { title: "HW Addr", data: function (row, type, set) {
-                if (row.hasOwnProperty('hwaddr')) {
-                  if (row.hwaddr)
-                    return row.hwaddr
-                }
-                return '-'
-              },
-            },
-            { title: "IPv4", data: function (row, type, set) {
-                if (row.hasOwnProperty('ipv4_addresses')) {
-                  if (row.ipv4_addresses.length > 0)
-                    return row.ipv4_addresses.join(', <br />')
-                }
-                return '-'
-              },
-            },
-            { title: "IPv6", data: function (row, type, set) {
-                if (row.hasOwnProperty('ipv6_addresses')) {
-                  if (row.ipv6_addresses.length > 0)
-                    return row.ipv6_addresses.join(', <br />')
-                }
-                return '-'
-              },
-            },
-            { title: "State", data: function (row, type, set) {
-                if (row.hasOwnProperty('state')) {
-                  if (row.state)
-                    return row.state
-                }
-                return '-'
-              },
-            },
-          ],
-          order: [],
-        });
-      }
-      else {
-        $('#interfaceTableList').DataTable().ajax.reload(null, false);
-      }
-    }
-
-    function loadSnapshotsTable() {
-      if ( ! $.fn.DataTable.isDataTable( '#snapshotTableList' ) ) {
-        //Load Snapshots Table
-        $('#snapshotTableList').DataTable({
-          ajax: {
-            url: "../api/virtual-machine/list_instance_snapshots?id="+serverId+"&project="+project+"&name="+instance+"&recursion=1",
-            dataType: "json",
-            dataSrc: "metadata",
-            contentType: "application/json"
-          },
-          columns: [
-            { title: "Name", data: function (row, type, set) {
-                if (row.hasOwnProperty('name')) {
-                  if (row.name)
-                    return row.name
-                }
-                return '-'
-              },
-            },
-            { title: "Stateful", data: function (row, type, set) {
-                if (row.hasOwnProperty('stateful')) {
-                  // Boolean field
-                  return row.stateful
-                }
-                return '-'
-              },
-            },
-            { title: "Size", data: function (row, type, set) {
-                if (row.hasOwnProperty('size')) {
-                  if (row.size){
-                    if (type === 'display') {
-                      return (row.size / 1024 / 1024).toFixed(2) + ' MiB'
-                    }
-                    return row.size
-                  }
-                }
-                return '-'
-              },
-            },
-            { title: "Created", data: function (row, type, set) {
-                if (row.hasOwnProperty('created_at')) {
-                  if (row.created_at)
-                    return row.created_at
-                }
-                return '-'
-              },
-            },
-            { title: "Expires", data: function (row, type, set) {
-                if (row.hasOwnProperty('expires_at')) {
-                  if (row.expires_at)
-                    if (row.expires_at == '0001-01-01T00:00:00Z')
-                      return 'never'
-                    return row.expires_at
-                }
-                return '-'
-              },
-            },
-            { title: "Actions", data: function (row, type, set) {
-                links = ''
-                if (row.hasOwnProperty('name')) {
-                  links += '<a onclick=restoreInstanceSnapshot(\''+row.name+'\')><i class="fas fa-window-restore fa-lg" style="color:#ddd" title="Restore Snapshot" aria-hidden="true"></i></a>'
-                  links += '&nbsp' + '&nbsp' 
-                  links += '<a onclick=loadCreateInstanceFromSnapshotModal(\''+row.name+'\')><i class="fas fa-cube fa-lg" style="color:#ddd" title="Create Instance" aria-hidden="true"></i></a>'
-                  links += '&nbsp' + '&nbsp'
-                  links += '<a onclick=loadPublishImageFromSnapshotModal(\''+row.name+'\')><i class="fas fa-box-open fa-lg" style="color:#ddd" title="Publish Image" aria-hidden="true"></i></a>'
-                  links += '&nbsp' + '&nbsp' 
-                  links += '<a onclick=deleteSnapshot(\''+row.name+'\')><i class="fas fa-trash-alt fa-lg" style="color:#ddd" title="Delete" aria-hidden="true"></i></a>'
-                }
-                return links
-              },
-            },
-          ],
-          order: [],
-        });
-      }
-      else {
-        $('#snapshotTableList').DataTable().ajax.reload(null, false);
-      }
-    }
-
-    function loadBackupsTable() {
-      if ( ! $.fn.DataTable.isDataTable( '#backupTableList' ) ) {
-        //Load Backups Table
-        $('#backupTableList').DataTable({
-          ajax: {
-            url: "../api/virtual-machine/list_instance_backups?id="+serverId+"&project="+project+"&name="+instance+"&recursion=1",
-            dataType: "json",
-            dataSrc: "metadata",
-            contentType: "application/json"
-          },
-          columns: [
-            { title: "Name", data: function (row, type, set) {
-                if (row.hasOwnProperty('name')) {
-                  if (row.name) {
-                    if (row.backup_file_exists)
-                      return '<a href="backups/' + serverId + '/' + project + '/' + instance + '/' + row.name + '">' + row.name + '</a>'
-                    return row.name
-                  }
-                }
-                return '-'
-              },
-            },
-            { title: "Instance Only", data: function (row, type, set) {
-                if (row.hasOwnProperty('instance_only')) {
-                  // Boolean field
-                  return row.instance_only
-                }
-                return '-'
-              },
-            },
-            { title: "Optimized Storage", data: function (row, type, set) {
-                if (row.hasOwnProperty('optimized_storage')) {
-                  // Boolean field
-                  return row.optimized_storage
-                }
-                return '-'
-              },
-            },
-
-            { title: "Created", data: function (row, type, set) {
-                if (row.hasOwnProperty('created_at')) {
-                  if (row.created_at)
-                    return row.created_at
-                }
-                return '-'
-              },
-            },
-            { title: "Expires", data: function (row, type, set) {
-                if (row.hasOwnProperty('expires_at')) {
-                  if (row.expires_at) {
-                    if (row.expires_at == '0000-12-31T19:03:58-04:56')
-                      return 'never'
-                    return row.expires_at
-                  }
-                }
-                return '-'
-              },
-            },
-            { title: "File Size", data: function (row, type, set) {
-                if (row.hasOwnProperty('backup_file_exists') && row.hasOwnProperty('backup_file_size')) {
-                  if (row.backup_file_exists && row.backup_file_size){
-                    if (type === 'display') {
-                      size = row.backup_file_size / 1024 / 1024
-                      return size.toFixed(2) + ' MiB'
-                    }
-                    return row.backup_file_exists
-                  }
-                }
-                return '-'
-              },
-            },
-            { title: "Actions", data: function (row, type, set) {
-                links = ''
-                if (row.hasOwnProperty('name')) {
-                  if (row.hasOwnProperty('backup_file_exists')) {
-                    if (row.backup_file_exists)
-                      links += '<a><i class="fas fa-file-export fa-lg" style="color:#f1f1f1" title="Export Backup" aria-hidden="true"></i></a>'
-                    else 
-                      links += '<a onclick=exportBackup(\''+row.name+'\')><i class="fas fa-file-export fa-lg" style="color:#ddd" title="Export Backup" aria-hidden="true"></i></a>'
-                    links += '&nbsp' + '&nbsp' 
-                  }
-                  links += '<a onclick=deleteBackup(\''+row.name+'\')><i class="fas fa-trash-alt fa-lg" style="color:#ddd" title="Delete" aria-hidden="true"></i></a>'
-                }
-                return links
-              },
-            },
-          ],
-          order: [],
-        });
-      }
-      else {
-        $('#backupTableList').DataTable().ajax.reload(null, false);
-      }
-    }
-
-    function loadLogsTable() {
-      if ( ! $.fn.DataTable.isDataTable( '#logTableList' ) ) {
-        //Load Logs Table
-        $('#logTableList').DataTable({
-          ajax: {
-            url: "../api/virtual-machine/list_instance_logs?id="+serverId+"&project="+project+"&name="+instance+"&recursion=1",
-            dataType: "json",
-            dataSrc: "metadata",
-            contentType: "application/json"
-          },
-          columns: [
-            { title: "Log", data: function (row, type, set) {
-                if (row)
-                  return row
-                else
-                  return '-'
-              },
-            },
-            { title: "Actions", data: function (row, type, set) {
-              links = '<a onclick=displayLog(\''+row+'\')><i class="fas fa-file fa-lg" style="color:#ddd" title="Display Log" aria-hidden="true"></i></a>'
-              links += '&nbsp' + '&nbsp' 
-              links += '<a onclick=deleteLog(\''+row+'\')><i class="fas fa-trash-alt fa-lg" style="color:#ddd" title="Delete" aria-hidden="true"></i></a>'
-              return links
-              },
-            },
-          ],
-          order: [],
-        });
-      }
-      else {
-        $('#logTableList').DataTable().ajax.reload(null, false);
-      }
-    }
-
-    // Load/Reload the Home tab content when selected
-    $('#nav-home-tab').on('show.bs.tab', function () {
-      loadInterfaceTable()
-      loadSnapshotsTable()
-      loadBackupsTable()
-      loadLogsTable()
-    })
-
-    // ********************* DEVICES TAB TABLES **************************
-    function loadDiskDevicesTable() {
-      if ( ! $.fn.DataTable.isDataTable( '#diskDeviceTableList' ) ) {
-        //Load Disk Devices Table
-        $('#diskDeviceTableList').DataTable({
-          ajax: {
-            url: "../api/virtual-machine/get_instance_disk_devices?id="+serverId+"&project="+project+"&name="+instance+"&recursion=1",
-            dataType: "json",
-            dataSrc: "data",
-            contentType: "application/json"
-          },
-          columns: [
-            { title: "Device", data: function (row, type, set) {
-                if (row.hasOwnProperty('device')) {
-                  if (row.device)
-                    return row.device
-                }
-                return '-'
-              },
-            },
-            { title: "Path", data: function (row, type, set) {
-                if (row.hasOwnProperty('path')) {
-                  if (row.path)
-                    return row.path
-                }
-                return '-'
-              },
-            },
-            { title: "Pool", data: function (row, type, set) {
-                if (row.hasOwnProperty('pool')) {
-                  if (row.pool)
-                    return row.pool
-                }
-                return '-'
-              },
-            },
-            { title: "Usage", data: function (row, type, set) {
-                if (row.hasOwnProperty('usage')) {
-                  if (row.usage) {
-                    if (type === 'display')
-                      return (row.usage / 1024 / 1024).toFixed(2) + ' MiB'
-                    return row.usage
-                  }
-                }
-                return '-'
-              },
-            },
-            { title: "Actions", data: function (row, type, set) {
-              links = ''
-              if (row.hasOwnProperty('device')) {
-                links = '<a onclick=delete_device(\''+row.device+'\')><i class="fas fa-trash-alt fa-lg" style="color:#ddd" title="Delete" aria-hidden="true"></i></a>'
-              }
-              return links
-              },
-            },
-          ],
-          order: [],
-        });
-      }
-      else {
-        $('#diskDeviceTableList').DataTable().ajax.reload(null, false);
-      }
-    }
-
-    function loadGpuDevicesTable() {
-      if ( ! $.fn.DataTable.isDataTable( '#gpuDeviceTableList' ) ) {
-        //Load GPU Devices Table
-        $('#gpuDeviceTableList').DataTable({
-          ajax: {
-            url: "../api/virtual-machine/get_instance_gpu_devices?id="+serverId+"&project="+project+"&name="+instance+"&recursion=1",
-            dataType: "json",
-            dataSrc: "data",
-            contentType: "application/json"
-          },
-          columns: [
-          { title: "Device", data: function (row, type, set) {
-                if (row.hasOwnProperty('device')) {
-                  if (row.device)
-                    return row.device
-                }
-                return '-'
-              },
-            },
-            { title: "Vendor ID", data: function (row, type, set) {
-                if (row.hasOwnProperty('vendorid')) {
-                  if (row.vendorid)
-                    return row.vendorid
-                }
-                return '-'
-              },
-            },
-            { title: "Product ID", data: function (row, type, set) {
-                if (row.hasOwnProperty('productid')) {
-                  if (row.productid)
-                    return row.productid
-                }
-                return '-'
-              },
-            },
-            { title: "ID", data: function (row, type, set) {
-                if (row.hasOwnProperty('id')) {
-                  if (row.id)
-                    return row.id
-                }
-                return '-'
-              },
-            },
-            { title: "PCI", data: function (row, type, set) {
-                if (row.hasOwnProperty('pci')) {
-                  if (row.pci)
-                    return row.pci
-                }
-                return '-'
-              },
-            },
-            { title: "Type", data: function (row, type, set) {
-                if (row.hasOwnProperty('type')) {
-                  if (row.type)
-                    return row.type
-                }
-                return '-'
-              },
-            },
-            { title: "Actions", data: function (row, type, set) {
-              links = ''
-              if (row.hasOwnProperty('device')) {
-                links = '<a onclick=delete_device(\''+row.device+'\')><i class="fas fa-trash-alt fa-lg" style="color:#ddd" title="Delete" aria-hidden="true"></i></a>'
-              }
-              return links
-              },
-            },
-          ],
-          order: [],
-        });
-      }
-      else {
-        $('#gpuDeviceTableList').DataTable().ajax.reload(null, false);
-      }
-    }
-
-    function loadNetworkDevicesTable() {
-      if ( ! $.fn.DataTable.isDataTable( '#networkDeviceTableList' ) ) {
-        //Load Network Devices Table
-        $('#networkDeviceTableList').DataTable({
-          ajax: {
-            url: "../api/virtual-machine/get_instance_network_devices?id="+serverId+"&project="+project+"&name="+instance+"&recursion=1",
-            dataType: "json",
-            dataSrc: "data",
-            contentType: "application/json"
-          },
-          columns: [
-            { title: "Device", data: function (row, type, set) {
-                if (row.hasOwnProperty('device')) {
-                  if (row.device)
-                    return row.device
-                }
-                return '-'
-              },
-            },
-            { title: "NIC Type", data: function (row, type, set) {
-                if (row.hasOwnProperty('nictype')) {
-                  if (row.nictype)
-                    return row.nictype
-                }
-                return '-'
-              },
-            },
-            { title: "Parent Interface", data: function (row, type, set) {
-                if (row.hasOwnProperty('parent')) {
-                  if (row.parent)
-                    return row.parent
-                }
-                return '-'
-              },
-            },
-            { title: "Network", data: function (row, type, set) {
-                if (row.hasOwnProperty('network')) {
-                  if (row.network)
-                    return row.network
-                }
-                return '-'
-              },
-            },
-            { title: "Interface Name", data: function (row, type, set) {
-                if (row.hasOwnProperty('name')) {
-                  if (row.name)
-                    return row.name
-                }
-                return '-'
-              },
-            },
-            { title: "Actions", data: function (row, type, set) {
-              links = ''
-              if (row.hasOwnProperty('device')) {
-                links = '<a onclick=delete_device(\''+row.device+'\')><i class="fas fa-trash-alt fa-lg" style="color:#ddd" title="Delete" aria-hidden="true"></i></a>'
-              }
-              return links
-              },
-            },
-          ],
-          order: [],
-        });
-      }
-      else {
-        $('#networkDeviceTableList').DataTable().ajax.reload(null, false);
-      }
-    }
-
-    function loadProxyDevicesTable() {
-      if ( ! $.fn.DataTable.isDataTable( '#proxyDeviceTableList' ) ) {
-        //Load Proxy Devices Table
-        $('#proxyDeviceTableList').DataTable({
-          ajax: {
-            url: "../api/virtual-machine/get_instance_proxy_devices?id="+serverId+"&project="+project+"&name="+instance+"&recursion=1",
-            dataType: "json",
-            dataSrc: "data",
-            contentType: "application/json"
-          },
-          columns: [
-            { title: "Device", data: function (row, type, set) {
-                if (row.hasOwnProperty('device')) {
-                  if (row.device)
-                    return row.device
-                }
-                return '-'
-              },
-            },
-            { title: "Connect", data: function (row, type, set) {
-                if (row.hasOwnProperty('connect')) {
-                  if (row.connect)
-                    return row.connect
-                }
-                return '-'
-              },
-            },
-            { title: "Listen", data: function (row, type, set) {
-                if (row.hasOwnProperty('listen')) {
-                  if (row.listen)
-                    return row.listen
-                }
-                return '-'
-              },
-            },
-            { title: "Type", data: function (row, type, set) {
-                if (row.hasOwnProperty('type')) {
-                  if (row.type)
-                    return row.type
-                }
-                return '-'
-              },
-            },
-            { title: "Actions", data: function (row, type, set) {
-              links = ''
-              if (row.hasOwnProperty('device')) {
-                links = '<a onclick=delete_device(\''+row.device+'\')><i class="fas fa-trash-alt fa-lg" style="color:#ddd" title="Delete" aria-hidden="true"></i></a>'
-              }
-              return links
-              },
-            },
-          ],
-          order: [],
-        });
-      }
-      else {
-        $('#proxyDeviceTableList').DataTable().ajax.reload(null, false);
-      }
-    }
-
-    function loadUsbDevicesTable() {
-      if ( ! $.fn.DataTable.isDataTable( '#usbDeviceTableList' ) ) {
-        //Load USB Devices Table
-        $('#usbDeviceTableList').DataTable({
-          ajax: {
-            url: "../api/virtual-machine/get_instance_usb_devices?id="+serverId+"&project="+project+"&name="+instance+"&recursion=1",
-            dataType: "json",
-            dataSrc: "data",
-            contentType: "application/json"
-          },
-          columns: [
-            { title: "Device", data: function (row, type, set) {
-                if (row.hasOwnProperty('device')) {
-                  if (row.device)
-                    return row.device
-                }
-                return '-'
-              },
-            },
-            { title: "Vendor ID", data: function (row, type, set) {
-                if (row.hasOwnProperty('vendorid')) {
-                  if (row.vendorid)
-                    return row.vendorid
-                }
-                return '-'
-              },
-            },
-            { title: "Product ID", data: function (row, type, set) {
-                if (row.hasOwnProperty('productid')) {
-                  if (row.productid)
-                    return row.productid
-                }
-                return '-'
-              },
-            },
-            { title: "Mode", data: function (row, type, set) {
-                if (row.hasOwnProperty('mode')) {
-                  if (row.mode)
-                    return row.mode
-                }
-                return '-'
-              },
-            },
-            { title: "Required", data: function (row, type, set) {
-                if (row.hasOwnProperty('required')) {
-                  if (row.required)
-                    return row.required
-                }
-                return '-'
-              },
-            },
-            { title: "Type", data: function (row, type, set) {
-                if (row.hasOwnProperty('type')) {
-                  if (row.type)
-                    return row.type
-                }
-                return '-'
-              },
-            },
-            { title: "Actions", data: function (row, type, set) {
-              lins = ''
-              if (row.hasOwnProperty('device')) {
-                links = '<a onclick=delete_device(\''+row.device+'\')><i class="fas fa-trash-alt fa-lg" style="color:#ddd" title="Delete" aria-hidden="true"></i></a>'
-              }
-              return links
-              },
-            },
-          ],
-          order: [],
-        });
-      }
-      else {
-        $('#usbDeviceTableList').DataTable().ajax.reload(null, false);
-      }
-    }
-
-    // Load/Reload the Devices tab content when selected
-    $('#nav-devices-tab').on('show.bs.tab', function () {
-      loadDiskDevicesTable()
-      loadGpuDevicesTable()
-      loadNetworkDevicesTable()
-      loadProxyDevicesTable()
-      loadUsbDevicesTable()
-    })
-
-    // Load the Disk Devices table when selected
-    $('#v-pills-disk-devices-tab').on('show.bs.tab', function () {
-      loadDiskDevicesTable()
-    })
-
-    // Load the GPU Devices table when selected
-    $('#v-pills-gpu-devices-tab').on('show.bs.tab', function () {
-      loadGpuDevicesTable()
-    })
-
-    // Load the Network Devices table when selected
-    $('#v-pills-network-devices-tab').on('show.bs.tab', function () {
-      loadNetworkDevicesTable()
-    })
-
-    // Load the Proxy Devices table when selected
-    $('#v-pills-proxy-devices-tab').on('show.bs.tab', function () {
-      loadProxyDevicesTable()
-    })
-
-    // Load the USB Devices table when selected
-    $('#v-pills-usb-devices-tab').on('show.bs.tab', function () {
-      loadUsbDevicesTable()
-    })
-
-
-
-    // Loads the attachProfile modal and populates dynamic form options
-    function loadAttachProfileModal(){
-      //Reset and populate the Attach profile modal profile dropdown
-      $("#selectProfileInput").empty().append('<option value="">(not set)</option>');
-      $.getJSON("../api/profiles/list_profiles?id="+serverId+"&project="+project, function (data) {
-        data = data.metadata
-        for (var index = 0; index < data.length; index++) {
-          //When using projects other than default and no recursion, it gets like URL variable with "?"
-          optionText = data[index].split("?")
-          optionText = optionText[0].replace('/1.0/profiles/','');
-          $('#selectProfileInput').append('<option value="' + optionText + '">' + optionText + '</option>');
-        }
-        //Show modal
-        $("#attachProfileModal").modal('show');
-      })
-    }
-
-    // Loads the detachProfile modal and populates dynamic form options
-    function loadDetachProfileModal(){
-      //Reset and populate the Detach profile modal profile dropdown
-      $("#selectDetachProfileInput").empty().append('<option value="">(not set)</option>');
-      $.getJSON("../api/virtual-machine/get_instance?id="+serverId+"&project="+project+"&name="+instance+"&recursion=1", function (data) {
-        data = data.metadata
-        for (var index = 0; index < data.profiles.length; index++) {
-          optionText = data.profiles[index];
-          $('#selectDetachProfileInput').append('<option value="' + optionText + '">' + optionText + '</option>');
-        }
-        //Show modal
-        $("#detachProfileModal").modal('show');
-      })
-    }
-
-    // Loads the addNetworkDevice modal and populates dynamic form options
-    function loadAddNetworkDeviceModal(){
-
-      //Reset and populate the modal Network Device's Network dropdown
-      $("#networkNetworkInput").empty().append('<option value="">(not set)</option>');
-      $.getJSON("../api/networks/list_network_managed_devices?id="+serverId+"&project="+project, function (data) {
-        for (var index = 0; index < data.length; index++) {
-          optionText = data[index];
-          $('#networkNetworkInput').append('<option value="' + optionText + '">' + optionText + '</option>');
-        }
-        //Set correct options
-        changeParentTypeInput();
-
-        //Show modal
-        $("#addNetworkDeviceModal").modal('show');
-      })
-
-      //Reset and populate the modal Network Device's Parent Network dropdown
-      $("#networkParentInput").empty().append('<option value="">(not set)</option>');
-      $.getJSON("../api/networks/list_networks?id="+serverId+"&project="+project, function (data) {
-        data = data.metadata
-        for (var index = 0; index < data.length; index++) {
-          optionText = data[index].replace('/1.0/networks/','');
-          $('#networkParentInput').append('<option value="' + optionText + '">' + optionText + '</option>');
-        }
-      })
-
-    }
-    
-    // Loads the addDiskDevice modal and populates dynamic form options
-    function loadAddDiskDeviceModal(){
-      //Reset and populate the modal Disk Device's Storage Pools dropdown
-      $("#diskPoolInput").empty().append('<option value="">(not set)</option>');
-      $.getJSON("../api/storage-pools/list_storage_pools?id="+serverId+"&project="+project, function (data) {
-        data = data.metadata
-        for (var index = 0; index < data.length; index++) {
-          optionText = data[index].replace('/1.0/storage-pools/','');
-          $('#diskPoolInput').append('<option value="' + optionText + '">' + optionText + '</option>');
-        }
-        //Show modal
-        $("#addDiskDeviceModal").modal('show');
-      })
-    }
-
-    // Loads thes migrateInstanceModal and populates dynamic form options
-    function loadMigrateInstanceModal(){
-      //Reset and populate the modal Server dropdown
-      $("#selectClusterInput").empty().append('<option value="">(not set)</option>');
-      $.getJSON("../api/cluster-members/list_cluster_members?id="+serverId+"&project="+project, function (data) {
-        data = data.metadata
-        for (var index = 0; index < data.length; index++) {
-          optionText = data[index].replace('/1.0/cluster/members/','');
-          $('#selectClusterInput').append('<option value="' + optionText + '">' + optionText + '</option>');
-        }
-        //Show modal
-        $("#migrateInstanceModal").modal('show');
-      })
-    }
-
-    // Create snapshot from modal data
-    function createSnapshot(){
-      var snapshotName = $("#snapshotName").val();
-      var snapshotStateful = $("#snapshotStateful").val();
-      console.log("Info: creating snapshot " + snapshotName);
-      $.post("../api/virtual-machine/create_instance_snapshot?id="+serverId+"&project="+project+"&instance="+instance, { name: snapshotName, stateful: snapshotStateful},  function (data) {
-        console.log(data);
-        if (data.error_code >= 400){
-          alert(data.error);
-        }
-        //Async type
-        setTimeout(() => { reloadPageContent(); }, 2000);
-        operationStatusCheck()
-      });
-    }
-
-    // Create instance from snapshot
-    function createSnapshotInstance(){
-      var copyName = $("#instanceNameForSnapshotCreate").val();
-      var snapName = $("#snapNameForSnapshotCreate").val();
-      console.log("Info: creating snapshot " + snapshotName);
-      $.post("../api/virtual-machine/create_instance_snapshot_instance?id="+serverId+"&project="+project+"&instance="+instance+"&location="+target_location, { name: copyName, snapshot: snapName },  function (data) {
-        console.log(data);
-        if (data.error_code >= 400){
-          alert(data.error);
-        }
-        //Async type
-        setTimeout(() => { reloadPageContent(); }, 2000);
-        operationStatusCheck()
-      });
-    }
-
-    // Load the create instance from snapshot modal
-    function loadCreateInstanceFromSnapshotModal(snap){
-      $("#snapNameForSnapshotCreate").val(snap);
-      $("#createSnapshotInstanceModal").modal('show');
-    } 
-
-    // Restore an instance from snapshot
-    function restoreInstanceSnapshot(snapshotName){
-      console.log("Info: restoring snapshot " + snapshotName + " to instance " + instance);
-      $.post("../api/virtual-machine/restore_instance_snapshot?id="+serverId+"&project="+project+"&instance="+instance, { name: snapshotName },  function (data) {
-        console.log(data);
-        if (data.error_code >= 400){
-          alert(data.error);
-        }
-        //Async type
-        setTimeout(() => { reloadPageContent(); }, 2000);
-        operationStatusCheck()
-      });
-    }
-
-    // Publish an image from snapshot
-    function publishSnapshot(){
-      var description = $("#publishSnapshotDescriptionInput").val();
-      var public = $("#publishSnapshotPublicInput").val();
-      var os = $("#publishSnapshotOsInput").val();
-      var release = $("#publishSnapshotReleaseInput").val();
-      var snapName = $("#publishSnapshotHiddenName").val();
-      console.log("Info: publishing image " + description + " from snapshot " + instance + "/" + snapName);
-      $.post("../api/virtual-machine/publish_instance_snapshot?id="+serverId+"&project="+project+"&instance="+instance+"&snapshot="+snapName, { description: description, os: os, release: release, public:public },  function (data) {
-        console.log(data);
-        if (data.error_code >= 400){
-          alert(data.error);
-        }
-        //Async type
-        setTimeout(() => { reloadPageContent(); }, 2000);
-        operationStatusCheck()
-      });
-    }
-
-    // Load the publish image from snapshot modal
-    function loadPublishImageFromSnapshotModal(snap){
-      $("#publishSnapshotHiddenName").val(snap);
-      $("#publishSnapshotModal").modal('show');
-    }
-
-    // Delete Instance
-    function deleteInstance(){
-      console.log("Info: confirming deletion of virtual machine " + instance);
-      if (confirm("Are you sure you want to delete virtual machine " + instance + "?") == true) {
-        console.log("Info: deleting virtual machine " + instance);
-        $.post("../api/virtual-machine/delete_instance?id=" + serverId + "&project=" + project, { instance: instance }, function (data) {
-          console.log(data);
-          if (data.error_code >= 400){
-            alert(data.error);
-          }
-          // Change window to virtual machines page
-          window.location.replace("virtual-machines?id="+serverId+"&project="+project);
-        });
-      }
-    }
-
-    // Delete snapshot
-    function deleteSnapshot(snapshot){
-      console.log("Info: confirming deletion of snapshot " + snapshot);
-      if (confirm("Are you sure you want to delete snapshot " + snapshot + "?") == true) {
-        console.log("Info: deleting snapshot " + snapshot + " from instance " + instance);
-        $.get("../api/virtual-machine/delete_instance_snapshot?id="+serverId+"&project="+project+"&instance="+instance+"&snapshot="+snapshot, function (data) {
-          console.log(data);
-          if (data.error_code >= 400){
-            alert(data.error);
-          }
-          //Async type
-          setTimeout(() => { reloadPageContent(); }, 2000);
-          operationStatusCheck()
-        });
-      }
-    }
-
-    // Attach profile to instance
-    function attachProfile(){
-      profile = $("#selectProfileInput").val()
-      console.log("Info: attaching profile " + profile + " to instance " + instance);
-      $.post("../api/virtual-machine/attach_instance_profile?id="+serverId+"&project="+project+"&instance="+instance, { name: profile, },  function (data) {
-        console.log(data);
-        if (data.error_code >= 400){
-          alert(data.error);
-        }
-        //Sync type
-        setTimeout(() => { reloadPageContent(); }, 1000);
-        operationStatusCheck()
-      });
-    }
-
-    // Detach profile from instance
-    function detachProfile(){
-      profile = $("#selectDetachProfileInput").val()
-      console.log("Info: removing profile " + profile + " from instance " + instance);
-      $.get("../api/virtual-machine/detach_instance_profile?id="+serverId+"&project="+project+"&instance="+instance+"&profile="+profile, function (data) {
-        console.log(data);
-        if (data.error_code >= 400){
-          alert(data.error);
-        }
-        //Async type
-        setTimeout(() => { reloadPageContent(); }, 2000);
-        operationStatusCheck()
-      });
-    }
-
-    // Add a disk device to instance
-    function addInstanceDiskDevice(){
-      diskDevice = $("#diskNameInput").val()
-      console.log("Info: adding disk device " + diskDevice + " to instance " + instance);
-      if ($("#diskPoolInput").val() != '') {
-        source = $("#diskSourceSelectInput").val();
-      }
-      else {
-        source = $("#diskSourceInput").val();
-      }
-      $.post("../api/virtual-machine/add_instance_disk_device?id="+serverId+"&project="+project+"&instance="+instance, { 
-        name: $("#diskNameInput").val(), 
-        pool: $("#diskPoolInput").val(),
-        source: source,
-        path: $("#diskPathInput").val(),
-        limits_read: $("#diskLimitsReadInput").val(),
-        limits_write: $("#diskLimitsWriteInput").val(),
-        limits_max: $("#diskLimitsMaxInput").val(),
-        required: $("#diskRequiredInput").val(),
-        read_only: $("#diskReadOnlyInput").val(),
-        size: $("#diskSizeInput").val(),
-        size_state: $("#diskSizeStateInput").val(),
-        recursive: $("#diskRecursiveInput").val(),
-        propagation: $("#diskPropagationInput").val(),
-        shift: $("#diskShiftInput").val(),
-        raw_mount_options: $("#diskRawMountOptionsInput").val(),
-        ceph_user_name: $("#diskCephUserNameInput").val(),
-        ceph_cluster_name: $("#diskCephClusterNameInput").val(),
-        boot_priority: $("#diskBootPriorityInput").val()
-      },  function (data) {
-        console.log(data);
-        if (data.error_code >= 400){
-          alert(data.error);
-        }
-        //Sync type
-        setTimeout(() => { reloadPageContent(); }, 1000);
-        operationStatusCheck()
-      });
-    }
-
-    // Add a GPU device to instance
-    function addInstanceGPUDevice(){
-      gpuDevice = $("#gpuDeviceNameInput").val()
-      console.log("Info: adding gpu device " + gpuDevice + " to instance " + instance);
-      $.post("../api/virtual-machine/add_instance_gpu_device?id="+serverId+"&project="+project+"&instance="+instance, { 
-        name: $("#gpuDeviceNameInput").val(), 
-        type: $("#gpuTypeInput").val(),
-        vendorid: $("#gpuVendoridInput").val(),
-        productid: $("#gpuProductidInput").val(),
-        id: $("#gpuIdInput").val(),
-        pci: $("#gpuPciInput").val(),
-        uid: $("#gpuUidInput").val(),
-        gid: $("#gpuGidInput").val(),
-        mode: $("#gpuModeInput").val(),
-        mig_ci: $("#gpuMigCiInput").val(),
-        mig_gi: $("#gpuMigGiInput").val(),
-      },  function (data) {
-        console.log(data);
-        if (data.error_code >= 400){
-          alert(data.error);
-        }
-        //Sync type
-        setTimeout(() => { reloadPageContent(); }, 1000);
-        operationStatusCheck()
-      });
-    }
-
-    // Add a network device to instance
-    function addNetworkDevice(){
-      networkDevice = $("#networkNameInput").val()
-      console.log("Info: adding network device " + networkDevice + " to instance " + instance);
-      $.post("../api/virtual-machine/add_instance_network_device?id="+serverId+"&project="+project+"&instance="+instance, { 
-        name: $("#networkNameInput").val(), 
-        nictype: $("#networkNicTypeInput").val(),
-        parent: $("#networkParentInput").val(),
-        network: $("#networkNetworkInput").val(),
-        interface_name: $("#networkInterfaceNameInput").val(),
-        mtu: $("#networkMtuInput").val(),
-        mode: $("#networkModeInput").val(),
-        hwaddr: $("#networkHwaddrInput").val(),
-        host_name: $("#networkHostNameInput").val(),
-        limits_ingress: $("#networkLimitsIngressInput").val(),
-        limits_egress: $("#networkLimitsEgressInput").val(),
-        limits_max: $("#networkLimitsMaxInput").val(),
-        ipv4_address: $("#networkIpv4AddressInput").val(),
-        ipv4_gateway: $("#networkIpv4GatewayInput").val(),
-        ipv4_host_table: $("#networkIpv4HostTableInput").val(),
-        ipv4_host_address: $("#networkIpv4HostAddressInput").val(),
-        ipv4_routes: $("#networkIpv4RoutesInput").val(),
-        ipv4_routes_external: $("#networkIpv4RoutesExternalInput").val(),
-        ipv6_address: $("#networkIpv6AddressInput").val(),
-        ipv6_gateway: $("#networkIpv6GatewayInput").val(),
-        ipv6_host_table: $("#networkIpv6HostTableInput").val(),
-        ipv6_host_address: $("#networkIpv6HostAddressInput").val(),
-        ipv6_routes: $("#networkIpv6RoutesInput").val(),
-        ipv6_routes_external: $("#networkIpv6RoutesExternalInput").val(),
-        security_mac_filtering: $("#networkSecurityMacFilteringInput").val(),
-        security_ipv4_filtering: $("#networkSecurityIpv4FilteringInput").val(),
-        security_ipv6_filtering: $("#networkSecurityIpv6FilteringInput").val(),
-        maas_subnet_ipv4: $("#networkMaasSubnetIpv4Input").val(),
-        maas_subnet_ipv6: $("#networkMaasSubnetIpv6Input").val(),
-        boot_priority: $("#networkBootPriorityInput").val(),
-        vlan: $("#networkVlanInput").val(),
-        vlan_tagged: $("#networkVlanTaggedInput").val(),
-        security_port_isolation: $("#networkSecurityPortIsolationInput").val(),
-        gvrp: $("#networkGvrpInput").val(),
-        security_acls: $("#networkSecurityAclsInput").val(),
-        security_acls_default_ingress_action: $("#networkSecurityAclsDefaultIngressActionInput").val(),
-        security_acls_default_egress_action: $("#networkSecurityAclsDefaultEgressActionInput").val(),
-        security_acls_default_ingress_logged: $("#networkSecurityAclsDefaultIngressLoggedInput").val(),
-        security_acls_default_egress_logged: $("#networkSecurityAclsDefaultEgressLoggedInput").val()
-      },  function (data) {
-        console.log(data);
-        if (data.error_code >= 400){
-          alert(data.error);
-        }
-        //Sync type
-        setTimeout(() => { reloadPageContent(); }, 1000);
-        operationStatusCheck()
-      });
-    }
-
-    // Add a proxy device to instance
-    function addInstanceProxyDevice(){
-      proxyDevice = $("#proxyDeviceNameInput").val()
-      console.log("Info: adding proxy device " + proxyDevice + " to instance " + instance);
-      $.post("../api/virtual-machine/add_instance_proxy_device?id="+serverId+"&project="+project+"&instance="+instance, { 
-        name: $("#proxyDeviceNameInput").val(), 
-        listen: $("#proxyListenInput").val(),
-        connect: $("#proxyConnectInput").val(),
-        bind: $("#proxyBindInput").val(),
-        uid: $("#proxyUidInput").val(),
-        gid: $("#proxyGidInput").val(),
-        mode: $("#proxyModeInput").val(),
-        nat: $("#proxyNatInput").val(),
-        proxy_protocol: $("#proxyProxyProtocolInput").val(),
-        security_uid: $("#proxySecurityUidInput").val(),
-        security_gid: $("#proxySecurityGidInput").val(),
-      },  function (data) {
-        console.log(data);
-        if (data.error_code >= 400){
-          alert(data.error);
-        }
-        //Sync type
-        setTimeout(() => { reloadPageContent(); }, 1000);
-        operationStatusCheck()
-      });
-    }
-
-    // Add a Unix device to instance
-    function addInstanceUnixDevice(){
-      unixDevice = $("#unixDeviceNameInput").val()
-      console.log("Info: adding Unix device " + unixDevice + " to instance " + instance);
-      $.post("../api/virtual-machine/add_instance_unix_device?id="+serverId+"&project="+project+"&instance="+instance, { 
-        name: $("#unixDeviceNameInput").val(), 
-        type: $("#unixTypeInput").val(),
-        source: $("#unixSourceInput").val(),
-        path: $("#unixPathInput").val(),
-        major: $("#unixMajorInput").val(),
-        minor: $("#unixMinorInput").val(),
-        uid: $("#unixUidInput").val(),
-        gid: $("#unixGidInput").val(),
-        mode: $("#unixModeInput").val(),
-        required: $("#unixRequiredInput").val(),
-
-      },  function (data) {
-        console.log(data);
-        if (data.error_code >= 400){
-          alert(data.error);
-        }
-        //Sync type
-        setTimeout(() => { reloadPageContent(); }, 1000);
-        operationStatusCheck()
-      });
-    }
-
-    // Add a USB device to instance
-    function addInstanceUSBDevice(){
-      usbDevice = $("#usbDeviceNameInput").val()
-      console.log("Info: adding USB device " + usbDevice + " to instance " + instance);
-      $.post("../api/virtual-machine/add_instance_usb_device?id="+serverId+"&project="+project+"&instance="+instance, { 
-        name: $("#usbDeviceNameInput").val(), 
-        vendorid: $("#usbVendoridInput").val(),
-        productid: $("#usbProductidInput").val(),
-        uid: $("#usbUidInput").val(),
-        gid: $("#usbGidInput").val(),
-        mode: $("#usbModeInput").val(),
-      },  function (data) {
-        console.log(data);
-        if (data.error_code >= 400){
-          alert(data.error);
-        }
-        //Sync type
-        setTimeout(() => { reloadPageContent(); }, 1000);
-        operationStatusCheck()
-      });     
-    }
-
-    // Create a backup of instance
-    function createBackup(){
-      backup = $("#backupName").val()
-      console.log("Info: creating backup " + backup + " for instance " + instance);
-      $.post("../api/virtual-machine/create_instance_backup?id="+serverId+"&project="+project+"&instance="+instance, { 
-        name: $("#backupName").val(), 
-        instance_only: $("#backupInstanceOnly").val(),
-        optimized_storage: $("#backupOptimizedStorage").val(),
-        compression_algorithm: $("#backupCompressionAlgorithm").val(),
-      },  function (data) {
-        console.log(data);
-        if (data.error_code >= 400){
-          alert(data.error);
-        }
-        //Async type
-        setTimeout(() => { reloadPageContent(); }, 2000);
-        operationStatusCheck()
-      }); 
-    }
-
-    // Delete a backup of instance
-    function deleteBackup(backup){
-      console.log("Info: confirming deletion of backup " + backup);
-      if (confirm("Are you sure you want to delete backup " + backup + "?") == true) {
-        console.log("Info: deleting backup " + backup + " from instance " + instance);
-        $.get("../api/virtual-machine/delete_instance_backup?id="+serverId+"&project="+project+"&instance="+instance+"&backup="+backup, function (data) {
-          console.log(data);
-          if (data.error_code >= 400){
-            alert(data.error);
-          }
-          //Async type
-          setTimeout(() => { reloadPageContent(); }, 2000);
-          operationStatusCheck()
-        });
-      }
-    }
-
-    // Export a backup to app
-    function exportBackup(backup){
-      console.log("Info: exporting backup " + backup + " from instance " + instance);
-      $.get("../api/virtual-machine/export_instance_backup?id="+serverId+"&project="+project+"&instance="+instance+"&backup="+backup, function (data) {
-        console.log(data);
-        if (data.error_code >= 400){
-          alert(data.error);
-        }
-        //Async type
-        setTimeout(() => { reloadPageContent(); }, 2000);
-        operationStatusCheck()
-      });
-    }
-
-    // Display log file in modal
-    function displayLog(logPath){
-      console.log("Info: displaying log " + logPath);
-      $.get("../api/virtual-machine/display_instance_log?id="+serverId+"&project="+project+"&log="+logPath, function (data) {
-        console.log(data);
-        if (data.error_code >= 400){
-          alert(data.error);
-        }
-        $("#logNameInput").text(logPath);
-        $("#logDataInput").val(data);
-        $("#loadLogModal").modal('show');
-      });
-    }
-
-    // Delete log file
-    function deleteLog(logPath){
-      console.log("Info: confirming deletion of log " + logPath);
-      if (confirm("Are you sure you want to delete log " + logPath + "?") == true) {
-        console.log("Info: deleting log " + logPath + " from instance " + instance);
-        $.get("../api/virtual-machine/delete_instance_log?id="+serverId+"&project="+project+"&log="+logPath, function (data) {
-          console.log(data);
-          if (data.error_code >= 400){
-            alert(data.error);
-          }
-          //Async type
-          setTimeout(() => { reloadPageContent(); }, 2000);
-          operationStatusCheck()
-        });
-      }
-    }
-
-    // Delete an instance device
-    function delete_device(device){
-      console.log("Info: confirming removal of device " + device);
-      if (confirm("Are you sure you want to remove device " + device + "?") == true) {
-        console.log("Info: removing device " + device + " from instance " + instance);
-        $.get("../api/virtual-machine/delete_instance_device?id="+serverId+"&project="+project+"&instance="+instance+"&device="+device, function (data) {
-          console.log(data);
-          if (data.error_code >= 400){
-            alert(data.error);
-          }
-          //Async type
-          setTimeout(() => { reloadPageContent(); }, 2000);
-          operationStatusCheck()
-        });
-      }
-    }
-
-    // Change properties options while adding network device
-    function changePropertySetInput(){
-      var networkPropertySetInput = $("#networkPropertySetInput").val()
-      if (networkPropertySetInput == "network"){
-        $("#networkNetworkRow").show();
-        $("#networkParentTypeRow").show();
-        $("#networkNicTypeRow").hide(); $("#networkNicTypeInput").val('');
-        $("#networkParentTypeInput").val('bridge');
-        changeParentTypeInput();
-      }
-      if (networkPropertySetInput == "nictype"){
-        $("#networkNetworkRow").hide(); $("#networkNetworkInput").val('');
-        $("#networkParentTypeRow").hide(); $("#networkParentTypeInput").val('');
-        $("#networkNicTypeRow").show();
-        $("#networkNicTypeInput").val('bridged');
-        changeNicTypeInput();
-      }
-    }
-
-    // Change options based on network type while adding network device
-    function changeNicTypeInput(){
-      var networkNicTypeInput = $("#networkNicTypeInput").val();
-      if (networkNicTypeInput == "bridged"){
-        $("#networkParentRow").show()
-        $("#networkNetworkRow").hide(); $("#networkNetworkInput").val('');
-        $("#networkInterfaceNameRow").show()
-        $("#networkMtuRow").show()
-        $("#networkHwaddrRow").show()
-        $("#networkHostNameRow").show()
-        $("#networkLimitsIngressRow").show()
-        $("#networkLimitsEgressRow").show()
-        $("#networkLimitsMaxRow").show()
-        $("#networkIpv4AddressRow").show()
-        $("#networkIpv6AddressRow").show()
-        $("#networkIpv4RoutesRow").show()
-        $("#networkIpv6RoutesRow").show()
-        $("#networkSecurityMacFilteringRow").show()
-        $("#networkSecurityIpv4FilteringRow").show()
-        $("#networkSecurityIpv6FilteringRow").show()
-        $("#networkMaasSubnetIpv4Row").show()
-        $("#networkMaasSubnetIpv6Row").show()
-        $("#networkBootPriorityRow").show()
-        $("#networkVlanRow").show()
-        $("#networkVlanTaggedRow").show()
-        $("#networkSecurityPortIsolationRow").show()
-        $("#networkGvrpRow").hide(); $("#networkGvrpInput").val('');
-        $("#networkModeRow").hide(); $("#networkModeInput").val('');
-        $("#networkIpv4GatewayRow").hide(); $("#networkIpv4GatewayInput").val('');
-        $("#networkIpv4HostTableRow").hide(); $("#networkIpv4HostTableInput").val('');
-        $("#networkIpv6GatewayRow").hide(); $("#networkIpv6GatewayInput").val('');
-        $("#networkIpv6HostTableRow").hide(); $("#networkIpv6HostTableInput").val('');;
-        $("#networkIpv4HostAddressRow").hide(); $("#networkIpv4HostAddressInput").val('');
-        $("#networkIpv6HostAddressRow").hide(); $("#networkIpv6HostAddressInput").val('');
-        $("#networkIpv4RoutesExternalRow").hide(); $("#networkIpv4RoutesExternalInput").val('');
-        $("#networkIpv6RoutesExternalRow").hide(); $("#networkIpv6RoutesExternalInput").val('');
-        $("#networkSecurityAclsRow").hide(); $("#networkSecurityAclsInput").val('');
-        $("#networkSecurityAclsDefaultIngressActionRow").hide();$("#networkSecurityAclsDefaultIngressActionInput").val('');
-        $("#networkSecurityAclsDefaultEgressActionRow").hide(); $("#networkSecurityAclsDefaultEgressActionInput").val('');
-        $("#networkSecurityAclsDefaultIngressLoggedRow").hide(); $("#networkSecurityAclsDefaultIngressLoggedInput").val('');
-        $("#networkSecurityAclsDefaultEgressLoggedRow").hide(); $("#networkSecurityAclsDefaultEgressLoggedInput").val('');
-      }
-      if (networkNicTypeInput == "macvlan"){
-        $("#networkParentRow").show()
-        $("#networkNetworkRow").hide(); $("#networkNetworkInput").val('');
-        $("#networkInterfaceNameRow").show()
-        $("#networkMtuRow").show()
-        $("#networkHwaddrRow").show()
-        $("#networkHostNameRow").hide(); $("#networkHostNameInput").val('');
-        $("#networkLimitsIngressRow").hide(); $("#networkLimitsIngressInput").val('');
-        $("#networkLimitsEgressRow").hide(); $("#networkLimitsEgressInput").val('');
-        $("#networkLimitsMaxRow").hide(); $("#networkLimitsMaxInput").val('');
-        $("#networkIpv4AddressRow").hide(); $("#networkIpv4AddressInput").val('');
-        $("#networkIpv6AddressRow").hide(); $("#networkIpv6AddressInput").val('');
-        $("#networkIpv4RoutesRow").hide(); $("#networkIpv4RoutesInput").val('');
-        $("#networkIpv6RoutesRow").hide(); $("#networkIpv6RoutesInput").val('');
-        $("#networkSecurityMacFilteringRow").hide(); $("#networkSecurityMacFilteringInput").val('');
-        $("#networkSecurityIpv4FilteringRow").hide(); $("#networkSecurityIpv4FilteringInput").val('');
-        $("#networkSecurityIpv6FilteringRow").hide(); $("#networkSecurityIpv6FilteringInput").val('');
-        $("#networkMaasSubnetIpv4Row").show()
-        $("#networkMaasSubnetIpv6Row").show()
-        $("#networkBootPriorityRow").show()
-        $("#networkVlanRow").show()
-        $("#networkVlanTaggedRow").hide(); $("#networkVlanTaggedInput").val('');
-        $("#networkSecurityPortIsolationRow").hide(); $("#networkSecurityPortIsolationInput").val('');
-        $("#networkGvrpRow").show()
-        $("#networkModeRow").hide(); $("#networkModeInput").val('');
-        $("#networkIpv4GatewayRow").hide(); $("#networkIpv4GatewayInput").val('');
-        $("#networkIpv4HostTableRow").hide(); $("#networkIpv4HostTableInput").val('');
-        $("#networkIpv6GatewayRow").hide(); $("#networkIpv6GatewayInput").val('');
-        $("#networkIpv6HostTableRow").hide(); $("#networkIpv6HostTableInput").val('');
-        $("#networkIpv4HostAddressRow").hide(); $("#networkIpv4HostAddressInput").val('');
-        $("#networkIpv6HostAddressRow").hide(); $("#networkIpv6HostAddressInput").val('');
-        $("#networkIpv4RoutesExternalRow").hide(); $("#networkIpv4RoutesExternalInput").val('');
-        $("#networkIpv6RoutesExternalRow").hide(); $("#networkIpv6RoutesExternalInput").val('');
-        $("#networkSecurityAclsRow").hide(); $("#networkSecurityAclsInput").val('');
-        $("#networkSecurityAclsDefaultIngressActionRow").hide(); $("#networkSecurityAclsDefaultIngressActionInput").val('');
-        $("#networkSecurityAclsDefaultEgressActionRow").hide(); $("#networkSecurityAclsDefaultEgressActionInput").val('');
-        $("#networkSecurityAclsDefaultIngressLoggedRow").hide(); $("#networkSecurityAclsDefaultIngressLoggedInput").val('');
-        $("#networkSecurityAclsDefaultEgressLoggedRow").hide(); $("#networkSecurityAclsDefaultEgressLoggedInput").val('');
-      }
-      if (networkNicTypeInput == "sriov"){
-        $("#networkParentRow").show()
-        $("#networkNetworkRow").hide(); $("#networkNetworkInput").val('');
-        $("#networkInterfaceNameRow").show()
-        $("#networkMtuRow").show()
-        $("#networkHwaddrRow").show()
-        $("#networkHostNameRow").hide(); $("#networkHostNameInput").val('');
-        $("#networkLimitsIngressRow").hide(); $("#networkLimitsIngressInput").val('');
-        $("#networkLimitsEgressRow").hide(); $("#networkLimitsEgressInput").val('');
-        $("#networkLimitsMaxRow").hide(); $("#networkLimitsMaxInput").val('');
-        $("#networkIpv4AddressRow").hide(); $("#networkIpv4AddressInput").val('');
-        $("#networkIpv6AddressRow").hide(); $("#networkIpv6AddressInput").val('');
-        $("#networkIpv4RoutesRow").hide(); $("#networkIpv4RoutesInput").val('');
-        $("#networkIpv6RoutesRow").hide(); $("#networkIpv6RoutesInput").val('');
-        $("#networkSecurityMacFilteringRow").show()
-        $("#networkSecurityIpv4FilteringRow").hide(); $("#networkSecurityIpv4FilteringInput").val('');
-        $("#networkSecurityIpv6FilteringRow").hide(); $("#networkSecurityIpv6FilteringInput").val('');
-        $("#networkMaasSubnetIpv4Row").show()
-        $("#networkMaasSubnetIpv6Row").show()
-        $("#networkBootPriorityRow").show()
-        $("#networkVlanRow").show()
-        $("#networkVlanTaggedRow").hide(); $("#networkVlanTaggedInput").val('');
-        $("#networkSecurityPortIsolationRow").hide(); $("#networkSecurityPortIsolationInput").val('');
-        $("#networkGvrpRow").hide(); $("#networkGvrpInput").val('');
-        $("#networkModeRow").hide(); $("#networkModeInput").val('');
-        $("#networkIpv4GatewayRow").hide(); $("#networkIpv4GatewayInput").val('');
-        $("#networkIpv4HostTableRow").hide(); $("#networkIpv4HostTableInput").val('');
-        $("#networkIpv6GatewayRow").hide(); $("#networkIpv6GatewayInput").val('');
-        $("#networkIpv6HostTableRow").hide(); $("#networkIpv6HostTableInput").val('');
-        $("#networkIpv4HostAddressRow").hide(); $("#networkIpv4HostAddressInput").val('');
-        $("#networkIpv6HostAddressRow").hide(); $("#networkIpv6HostAddressInput").val('');
-        $("#networkIpv4RoutesExternalRow").hide(); $("#networkIpv4RoutesExternalInput").val('');
-        $("#networkIpv6RoutesExternalRow").hide(); $("#networkIpv6RoutesExternalInput").val('');
-        $("#networkSecurityAclsRow").hide(); $("#networkSecurityAclsInput").val('');
-        $("#networkSecurityAclsDefaultIngressActionRow").hide(); $("#networkSecurityAclsDefaultIngressActionInput").val('');
-        $("#networkSecurityAclsDefaultEgressActionRow").hide(); $("#networkSecurityAclsDefaultEgressActionInput").val('');
-        $("#networkSecurityAclsDefaultIngressLoggedRow").hide(); $("#networkSecurityAclsDefaultIngressLoggedInput").val('');
-        $("#networkSecurityAclsDefaultEgressLoggedRow").hide(); $("#networkSecurityAclsDefaultEgressLoggedInput").val('');
-      }
-      if (networkNicTypeInput == "physical"){
-        $("#networkParentRow").show()
-        $("#networkNetworkRow").hide(); $("#networkNetworkInput").val('');
-        $("#networkInterfaceNameRow").show()
-        $("#networkMtuRow").show()
-        $("#networkHwaddrRow").show()
-        $("#networkHostNameRow").hide(); $("#networkHostNameInput").val('');
-        $("#networkLimitsIngressRow").hide(); $("#networkLimitsIngressInput").val('');
-        $("#networkLimitsEgressRow").hide(); $("#networkLimitsEgressInput").val('');
-        $("#networkLimitsMaxRow").hide(); $("#networkLimitsMaxInput").val('');
-        $("#networkIpv4AddressRow").hide(); $("#networkIpv4AddressInput").val('');
-        $("#networkIpv6AddressRow").hide(); $("#networkIpv6AddressInput").val('');
-        $("#networkIpv4RoutesRow").hide(); $("#networkIpv4RoutesInput").val('');
-        $("#networkIpv6RoutesRow").hide(); $("#networkIpv6RoutesInput").val('');
-        $("#networkSecurityMacFilteringRow").hide(); $("#networkSecurityMacFilteringInput").val('');
-        $("#networkSecurityIpv4FilteringRow").hide(); $("#networkSecurityIpv4FilteringInput").val('');
-        $("#networkSecurityIpv6FilteringRow").hide(); $("#networkSecurityIpv6FilteringInput").val('');
-        $("#networkMaasSubnetIpv4Row").show()
-        $("#networkMaasSubnetIpv6Row").show()
-        $("#networkBootPriorityRow").show()
-        $("#networkVlanRow").show()
-        $("#networkVlanTaggedRow").hide(); $("#networkVlanTaggedInput").val('');
-        $("#networkSecurityPortIsolationRow").hide(); $("#networkSecurityPortIsolationInput").val('');
-        $("#networkGvrpRow").show()
-        $("#networkModeRow").hide(); $("#networkModeInput").val('');
-        $("#networkIpv4GatewayRow").hide(); $("#networkIpv4GatewayInput").val('');
-        $("#networkIpv4HostTableRow").hide(); $("#networkIpv4HostTableInput").val('');
-        $("#networkIpv6GatewayRow").hide(); $("#networkIpv6GatewayInput").val('');
-        $("#networkIpv6HostTableRow").hide(); $("#networkIpv6HostTableInput").val('');
-        $("#networkIpv4HostAddressRow").hide(); $("#networkIpv4HostAddressInput").val('');
-        $("#networkIpv6HostAddressRow").hide(); $("#networkIpv6HostAddressInput").val('');
-        $("#networkIpv4RoutesExternalRow").hide(); $("#networkIpv4RoutesExternalInput").val('');
-        $("#networkIpv6RoutesExternalRow").hide(); $("#networkIpv6RoutesExternalInput").val('');
-        $("#networkSecurityAclsRow").hide(); $("#networkSecurityAclsInput").val('');
-        $("#networkSecurityAclsDefaultIngressActionRow").hide(); $("#networkSecurityAclsDefaultIngressActionInput").val('');
-        $("#networkSecurityAclsDefaultEgressActionRow").hide(); $("#networkSecurityAclsDefaultEgressActionInput").val('');
-        $("#networkSecurityAclsDefaultIngressLoggedRow").hide(); $("#networkSecurityAclsDefaultIngressLoggedInput").val('');
-        $("#networkSecurityAclsDefaultEgressLoggedRow").hide(); $("#networkSecurityAclsDefaultEgressLoggedInput").val('');
-      }
-      if (networkNicTypeInput == "ipvlan"){
-        $("#networkParentRow").show()
-        $("#networkNetworkRow").hide(); $("#networkNetworkInput").val('');
-        $("#networkInterfaceNameRow").show()
-        $("#networkMtuRow").show()
-        $("#networkHwaddrRow").show()
-        $("#networkHostNameRow").hide(); $("#networkHostNameInput").val('');
-        $("#networkLimitsIngressRow").hide(); $("#networkLimitsIngressInput").val('');
-        $("#networkLimitsEgressRow").hide(); $("#networkLimitsEgressInput").val('');
-        $("#networkLimitsMaxRow").hide(); $("#netnetworkLimitsMaxRowworkModeInput").val('');
-        $("#networkIpv4AddressRow").show()
-        $("#networkIpv6AddressRow").show()
-        $("#networkIpv4RoutesRow").hide(); $("#networkIpv4RoutesInput").val('');
-        $("#networkIpv6RoutesRow").hide(); $("#networkIpv6RoutesInput").val('');
-        $("#networkSecurityMacFilteringRow").hide(); $("#networkSecurityMacFilteringInput").val('');
-        $("#networkSecurityIpv4FilteringRow").hide(); $("#networkSecurityIpv4FilteringInput").val('');
-        $("#networkSecurityIpv6FilteringRow").hide(); $("#networkSecurityIpv6FilteringInput").val('');
-        $("#networkMaasSubnetIpv4Row").hide(); $("#networkMaasSubnetIpv4Input").val('');
-        $("#networkMaasSubnetIpv6Row").hide(); $("#networkMaasSubnetIpv6Input").val('');
-        $("#networkBootPriorityRow").hide(); $("#networkBootPriorityInput").val('');
-        $("#networkVlanRow").show()
-        $("#networkVlanTaggedRow").hide(); $("#networkVlanTaggedInput").val('');
-        $("#networkSecurityPortIsolationRow").hide(); $("#netnetworkSecurityPortIsolationRowworkModeInput").val('');
-        $("#networkGvrpRow").show()
-        $("#networkModeRow").show()
-        $("#networkIpv4GatewayRow").show()
-        $("#networkIpv4HostTableRow").show()
-        $("#networkIpv6GatewayRow").show()
-        $("#networkIpv6HostTableRow").show()
-        $("#networkIpv4HostAddressRow").hide(); $("#networkIpv4HostAddressInput").val('');
-        $("#networkIpv6HostAddressRow").hide(); $("#networkIpv6HostAddressInput").val('');
-        $("#networkIpv4RoutesExternalRow").hide(); $("#networkIpv4RoutesExternalInput").val('');
-        $("#networkIpv6RoutesExternalRow").hide(); $("#networkIpv6RoutesExternalInput").val('');
-        $("#networkSecurityAclsRow").hide(); $("#networkSecurityAclsInput").val('');
-        $("#networkSecurityAclsDefaultIngressActionRow").hide(); $("#networkSecurityAclsDefaultIngressActionInput").val('');
-        $("#networkSecurityAclsDefaultEgressActionRow").hide(); $("#networkSecurityAclsDefaultEgressActionInput").val('');
-        $("#networkSecurityAclsDefaultIngressLoggedRow").hide(); $("#networkSecurityAclsDefaultIngressLoggedInput").val('');
-        $("#networkSecurityAclsDefaultEgressLoggedRow").hide(); $("#networkSecurityAclsDefaultEgressLoggedInput").val('');
-      }
-      if (networkNicTypeInput == "p2p"){
-        $("#networkParentRow").hide(); $("#networkParentInput").val('');
-        $("#networkNetworkRow").hide(); $("#networkNetworkInput").val('');
-        $("#networkInterfaceNameRow").show()
-        $("#networkMtuRow").show()
-        $("#networkHwaddrRow").show()
-        $("#networkHostNameRow").show()
-        $("#networkLimitsIngressRow").show()
-        $("#networkLimitsEgressRow").show()
-        $("#networkLimitsMaxRow").show()
-        $("#networkIpv4AddressRow").hide(); $("#networkIpv4AddressInput").val('');
-        $("#networkIpv6AddressRow").hide(); $("#networkIpv6AddressInput").val('');
-        $("#networkIpv4RoutesRow").show()
-        $("#networkIpv6RoutesRow").show()
-        $("#networkSecurityMacFilteringRow").hide(); $("#networkSecurityMacFilteringInput").val('');
-        $("#networkSecurityIpv4FilteringRow").hide(); $("#netnetworkSecurityIpv4FilteringRowworkModeInput").val('');
-        $("#networkSecurityIpv6FilteringRow").hide(); $("#networkSecurityIpv6FilteringInput").val('');
-        $("#networkMaasSubnetIpv4Row").hide(); $("#networkMaasSubnetIpv4Input").val('');
-        $("#networkMaasSubnetIpv6Row").hide(); $("#networkMaasSubnetIpv6Input").val('');
-        $("#networkBootPriorityRow").show()
-        $("#networkVlanRow").hide(); $("#networkVlanInput").val('');
-        $("#networkVlanTaggedRow").hide(); $("#networkVlanTaggedInput").val('');
-        $("#networkSecurityPortIsolationRow").hide(); $("#networkSecurityPortIsolationInput").val('');
-        $("#networkGvrpRow").hide(); $("#networkGvrpInput").val('');
-        $("#networkModeRow").hide(); $("#networkModeInput").val('');
-        $("#networkIpv4GatewayRow").hide(); $("#networkIpv4GatewayInput").val('');
-        $("#networkIpv4HostTableRow").hide(); $("#networkIpv4HostTableInput").val('');
-        $("#networkIpv6GatewayRow").hide(); $("#networkIpv6GatewayInput").val('');
-        $("#networkIpv6HostTableRow").hide(); $("#networkIpv6HostTableInput").val('');
-        $("#networkIpv4HostAddressRow").hide(); $("#networkIpv4HostAddressInput").val('');
-        $("#networkIpv6HostAddressRow").hide(); $("#networkIpv6HostAddressInput").val('');
-        $("#networkIpv4RoutesExternalRow").hide(); $("#networkIpv4RoutesExternalInput").val('');
-        $("#networkIpv6RoutesExternalRow").hide(); $("#networkIpv6RoutesExternalInput").val('');
-        $("#networkSecurityAclsRow").hide(); $("#networkSecurityAclsInput").val('');
-        $("#networkSecurityAclsDefaultIngressActionRow").hide(); $("#networkSecurityAclsDefaultIngressActionInput").val('');
-        $("#networkSecurityAclsDefaultEgressActionRow").hide(); $("#networkSecurityAclsDefaultEgressActionInput").val('');
-        $("#networkSecurityAclsDefaultIngressLoggedRow").hide(); $("#networkSecurityAclsDefaultIngressLoggedInput").val('');
-        $("#networkSecurityAclsDefaultEgressLoggedRow").hide(); $("#networkSecurityAclsDefaultEgressLoggedInput").val('');
-      }
-      if (networkNicTypeInput == "routed"){
-        $("#networkParentRow").show()
-        $("#networkNetworkRow").hide(); $("#networkNetworkInput").val('');
-        $("#networkInterfaceNameRow").show()
-        $("#networkMtuRow").show()
-        $("#networkHwaddrRow").show()
-        $("#networkHostNameRow").show()
-        $("#networkLimitsIngressRow").show()
-        $("#networkLimitsEgressRow").show()
-        $("#networkLimitsMaxRow").show()
-        $("#networkIpv4AddressRow").show()
-        $("#networkIpv6AddressRow").show()
-        $("#networkIpv4RoutesRow").hide(); $("#networkIpv4RoutesInput").val('');
-        $("#networkIpv6RoutesRow").hide(); $("#networkIpv6RoutesInput").val('');
-        $("#networkSecurityMacFilteringRow").hide(); $("#networkSecurityMacFilteringInput").val('');
-        $("#networkSecurityIpv4FilteringRow").hide(); $("#networkSecurityIpv4FilteringInput").val('');
-        $("#networkSecurityIpv6FilteringRow").hide(); $("#networkSecurityIpv6FilteringInput").val('');
-        $("#networkMaasSubnetIpv4Row").hide(); $("#networkMaasSubnetIpv4Input").val('');
-        $("#networkMaasSubnetIpv6Row").hide(); $("#networkMaasSubnetIpv6Input").val('');
-        $("#networkBootPriorityRow").hide(); $("#networkBootPriorityInput").val('');
-        $("#networkVlanRow").show()
-        $("#networkVlanTaggedRow").hide(); $("#networkVlanTaggedInput").val('');
-        $("#networkSecurityPortIsolationRow").hide(); $("#networkSecurityPortIsolationInput").val('');
-        $("#networkGvrpRow").show()
-        $("#networkModeRow").hide(); $("#networkModeInput").val('');
-        $("#networkIpv4GatewayRow").show()
-        $("#networkIpv4HostTableRow").show()
-        $("#networkIpv6GatewayRow").show()
-        $("#networkIpv6HostTableRow").show()
-        $("#networkIpv4HostAddressRow").show()
-        $("#networkIpv6HostAddressRow").show()
-        $("#networkIpv4RoutesExternalRow").hide(); $("#networkIpv4RoutesExternalInput").val('');
-        $("#networkIpv6RoutesExternalRow").hide(); $("#networkIpv6RoutesExternalInput").val('');
-        $("#networkSecurityAclsRow").hide(); $("#networkSecurityAclsInput").val('');
-        $("#networkSecurityAclsDefaultIngressActionRow").hide(); $("#networkSecurityAclsDefaultIngressActionInput").val('');
-        $("#networkSecurityAclsDefaultEgressActionRow").hide(); $("#networkSecurityAclsDefaultEgressActionInput").val('');
-        $("#networkSecurityAclsDefaultIngressLoggedRow").hide(); $("#networkSecurityAclsDefaultIngressLoggedInput").val('');
-        $("#networkSecurityAclsDefaultEgressLoggedRow").hide(); $("#networkSecurityAclsDefaultEgressLoggedInput").val('');
-      }
-    }
-
-    // Change options based on parent type while adding network devices
-    function changeParentTypeInput(){
-      var networkParentTypeInput = $("#networkParentTypeInput").val();
-      if (networkParentTypeInput == "bridge"){
-        $("#networkParentRow").hide(); $("#networkParentInput").val('');
-        $("#networkNetworkRow").show()
-        $("#networkInterfaceNameRow").show()
-        $("#networkMtuRow").hide(); $("#networkMtuInput").val('');
-        $("#networkHwaddrRow").show()
-        $("#networkHostNameRow").show()
-        $("#networkLimitsIngressRow").show()
-        $("#networkLimitsEgressRow").show()
-        $("#networkLimitsMaxRow").show()
-        $("#networkIpv4AddressRow").show()
-        $("#networkIpv6AddressRow").show()
-        $("#networkIpv4RoutesRow").show()
-        $("#networkIpv6RoutesRow").show()
-        $("#networkSecurityMacFilteringRow").show()
-        $("#networkSecurityIpv4FilteringRow").show()
-        $("#networkSecurityIpv6FilteringRow").show()
-        $("#networkMaasSubnetIpv4Row").hide(); $("#networkMaasSubnetIpv4Input").val('');
-        $("#networkMaasSubnetIpv6Row").hide(); $("#networkMaasSubnetIpv6Input").val('');
-        $("#networkBootPriorityRow").show()
-        $("#networkVlanRow").show()
-        $("#networkVlanTaggedRow").show()
-        $("#networkSecurityPortIsolationRow").show()
-        $("#networkGvrpRow").hide(); $("#networkGvrpInput").val('');
-        $("#networkModeRow").hide(); $("#networkModeInput").val('');
-        $("#networkIpv4GatewayRow").hide(); $("#networkIpv4GatewayInput").val('');
-        $("#networkIpv4HostTableRow").hide(); $("#networkIpv4HostTableInput").val('');
-        $("#networkIpv6GatewayRow").hide(); $("#networkIpv6GatewayInput").val('');
-        $("#networkIpv6HostTableRow").hide(); $("#networkIpv6HostTableInput").val('');
-        $("#networkIpv4HostAddressRow").hide(); $("#networkIpv4HostAddressInput").val('');
-        $("#networkIpv6HostAddressRow").hide(); $("#networkIpv6HostAddressInput").val('');
-        $("#networkIpv4RoutesExternalRow").hide(); $("#networkIpv4RoutesExternalInput").val('');
-        $("#networkIpv6RoutesExternalRow").hide(); $("#networkIpv6RoutesExternalInput").val('');
-        $("#networkSecurityAclsRow").hide(); $("#networkSecurityAclsInput").val('');
-        $("#networkSecurityAclsDefaultIngressActionRow").hide(); $("#networkSecurityAclsDefaultIngressActionInput").val('');
-        $("#networkSecurityAclsDefaultEgressActionRow").hide(); $("#networkSecurityAclsDefaultEgressActionInput").val('');
-        $("#networkSecurityAclsDefaultIngressLoggedRow").hide(); $("#networkSecurityAclsDefaultIngressLoggedInput").val('');
-        $("#networkSecurityAclsDefaultEgressLoggedRow").hide(); $("#networkSecurityAclsDefaultEgressLoggedInput").val('');
-      }
-      if (networkParentTypeInput == "macvlan"){
-        $("#networkParentRow").hide(); $("#networkParentInput").val('');
-        $("#networkNetworkRow").show()
-        $("#networkInterfaceNameRow").show()
-        $("#networkMtuRow").hide(); $("#networkMtuInput").val('');
-        $("#networkHwaddrRow").show()
-        $("#networkHostNameRow").hide(); $("#networkHostNameInput").val('');
-        $("#networkLimitsIngressRow").hide(); $("#networkLimitsIngressInput").val('');
-        $("#networkLimitsEgressRow").hide(); $("#networkLimitsEgressInput").val('');
-        $("#networkLimitsMaxRow").hide(); $("#networkLimitsMaxInput").val('');
-        $("#networkIpv4AddressRow").hide(); $("#networkIpv4AddressInput").val('');
-        $("#networkIpv6AddressRow").hide(); $("#networkIpv6AddressInput").val('');
-        $("#networkIpv4RoutesRow").hide(); $("#networkIpv4RoutesInput").val('');
-        $("#networkIpv6RoutesRow").hide(); $("#networkIpv6RoutesInput").val('');
-        $("#networkSecurityMacFilteringRow").hide(); $("#networkSecurityMacFilteringInput").val('');
-        $("#networkSecurityIpv4FilteringRow").hide(); $("#networkSecurityIpv4FilteringInput").val('');
-        $("#networkSecurityIpv6FilteringRow").hide(); $("#networkSecurityIpv6FilteringInput").val('');
-        $("#networkMaasSubnetIpv4Row").hide(); $("#networkMaasSubnetIpv4Input").val('');
-        $("#networkMaasSubnetIpv6Row").hide(); $("#networkMaasSubnetIpv6Input").val('');
-        $("#networkBootPriorityRow").show()
-        $("#networkVlanRow").show()
-        $("#networkVlanTaggedRow").hide(); $("#networkVlanTaggedInput").val('');
-        $("#networkSecurityPortIsolationRow").hide(); $("#networkSecurityPortIsolationInput").val('');
-        $("#networkGvrpRow").show()
-        $("#networkModeRow").hide(); $("#networkModeInput").val('');
-        $("#networkIpv4GatewayRow").hide(); $("#networkIpv4GatewayInput").val('');
-        $("#networkIpv4HostTableRow").hide(); $("#networkIpv4HostTableInput").val('');
-        $("#networkIpv6GatewayRow").hide(); $("#networkIpv6GatewayInput").val('');
-        $("#networkIpv6HostTableRow").hide(); $("#networkIpv6HostTableInput").val('');
-        $("#networkIpv4HostAddressRow").hide(); $("#networkIpv4HostAddressInput").val('');
-        $("#networkIpv6HostAddressRow").hide(); $("#networkIpv6HostAddressInput").val('');
-        $("#networkIpv4RoutesExternalRow").hide(); $("#networkIpv4RoutesExternalInput").val('');
-        $("#networkIpv6RoutesExternalRow").hide(); $("#networkIpv6RoutesExternalInput").val('');
-        $("#networkSecurityAclsRow").hide(); $("#networkSecurityAclsInput").val('');
-        $("#networkSecurityAclsDefaultIngressActionRow").hide(); $("#networkSecurityAclsDefaultIngressActionInput").val('');
-        $("#networkSecurityAclsDefaultEgressActionRow").hide(); $("#networkSecurityAclsDefaultEgressActionInput").val('');
-        $("#networkSecurityAclsDefaultIngressLoggedRow").hide(); $("#networkSecurityAclsDefaultIngressLoggedInput").val('');
-        $("#networkSecurityAclsDefaultEgressLoggedRow").hide(); $("#networkSecurityAclsDefaultEgressLoggedInput").val('');
-      }
-      if (networkParentTypeInput == "ovn"){
-        $("#networkParentRow").hide(); $("#networkParentInput").val('');
-        $("#networkNetworkRow").show()
-        $("#networkInterfaceNameRow").show()
-        $("#networkMtuRow").hide(); $("#networkMtuInput").val('');
-        $("#networkHwaddrRow").show()
-        $("#networkHostNameRow").show()
-        $("#networkLimitsIngressRow").hide(); $("#networkLimitsIngressInput").val('');
-        $("#networkLimitsEgressRow").hide(); $("#networkLimitsEgressInput").val('');
-        $("#networkLimitsMaxRow").hide(); $("#networkLimitsMaxInput").val('');
-        $("#networkIpv4AddressRow").show()
-        $("#networkIpv6AddressRow").show()
-        $("#networkIpv4RoutesRow").show()
-        $("#networkIpv6RoutesRow").show()
-        $("#networkSecurityMacFilteringRow").hide(); $("#networkSecurityMacFilteringInput").val('');
-        $("#networkSecurityIpv4FilteringRow").hide(); $("#networkSecurityIpv4FilteringInput").val('');
-        $("#networkSecurityIpv6FilteringRow").hide(); $("#networkSecurityIpv6FilteringInput").val('');
-        $("#networkMaasSubnetIpv4Row").hide(); $("#networkMaasSubnetIpv4Input").val('');
-        $("#networkMaasSubnetIpv6Row").hide(); $("#networkMaasSubnetIpv6Input").val('');
-        $("#networkBootPriorityRow").show()
-        $("#networkVlanRow").hide(); $("#networkVlanInput").val('');
-        $("#networkVlanTaggedRow").hide(); $("#networkVlanTaggedInput").val('');
-        $("#networkSecurityPortIsolationRow").hide(); $("#networkSecurityPortIsolationInput").val('');
-        $("#networkGvrpRow").hide(); $("#networkGvrpInput").val('');
-        $("#networkModeRow").hide(); $("#networkModeInput").val('');
-        $("#networkIpv4GatewayRow").hide(); $("#networkIpv4GatewayInput").val('');
-        $("#networkIpv4HostTableRow").hide(); $("#networkIpv4HostTableInput").val('');
-        $("#networkIpv6GatewayRow").hide(); $("#networkIpv6GatewayInput").val('');
-        $("#networkIpv6HostTableRow").hide(); $("#networkIpv6HostTableInput").val('');
-        $("#networkIpv4HostAddressRow").hide(); $("#networkIpv4HostAddressInput").val('');
-        $("#networkIpv6HostAddressRow").hide(); $("#networkIpv6HostAddressInput").val('');
-        $("#networkIpv4RoutesExternalRow").show()
-        $("#networkIpv6RoutesExternalRow").show()
-        $("#networkSecurityAclsRow").show()
-        $("#networkSecurityAclsDefaultIngressActionRow").show()
-        $("#networkSecurityAclsDefaultEgressActionRow").show()
-        $("#networkSecurityAclsDefaultIngressLoggedRow").show()
-        $("#networkSecurityAclsDefaultEgressLoggedRow").show()
-      }
-      if (networkParentTypeInput == "sriov"){
-        $("#networkParentRow").hide(); $("#networkParentInput").val('');
-        $("#networkNetworkRow").show()
-        $("#networkInterfaceNameRow").show()
-        $("#networkMtuRow").hide(); $("#networkMtuInput").val('');
-        $("#networkHwaddrRow").show()
-        $("#networkHostNameRow").hide(); $("#networkHostNameInput").val('');
-        $("#networkLimitsIngressRow").hide(); $("#networkLimitsIngressInput").val('');
-        $("#networkLimitsEgressRow").hide(); $("#networkLimitsEgressInput").val('');
-        $("#networkLimitsMaxRow").hide(); $("#networkLimitsMaxInput").val('');
-        $("#networkIpv4AddressRow").hide(); $("#networkIpv4AddressInput").val('');
-        $("#networkIpv6AddressRow").hide(); $("#networkIpv6AddressInput").val('');
-        $("#networkIpv4RoutesRow").hide(); $("#networkIpv4RoutesInput").val('');
-        $("#networkIpv6RoutesRow").hide(); $("#networkIpv6RoutesInput").val('');
-        $("#networkSecurityMacFilteringRow").show()
-        $("#networkSecurityIpv4FilteringRow").hide(); $("#networkSecurityIpv4FilteringInput").val('');
-        $("#networkSecurityIpv6FilteringRow").hide(); $("#networkSecurityIpv6FilteringInput").val('');
-        $("#networkMaasSubnetIpv4Row").hide(); $("#networkMaasSubnetIpv4Input").val('');
-        $("#networkMaasSubnetIpv6Row").hide(); $("#networkMaasSubnetIpv6Input").val('');
-        $("#networkBootPriorityRow").show()
-        $("#networkVlanRow").show()
-        $("#networkVlanTaggedRow").hide(); $("#networkVlanTaggedInput").val('');
-        $("#networkSecurityPortIsolationRow").hide(); $("#networkSecurityPortIsolationInput").val('');
-        $("#networkGvrpRow").hide(); $("#networkGvrpInput").val('');
-        $("#networkModeRow").hide(); $("#networkModeInput").val('');
-        $("#networkIpv4GatewayRow").hide(); $("#networkIpv4GatewayInput").val('');
-        $("#networkIpv4HostTableRow").hide(); $("#networkIpv4HostTableInput").val('');
-        $("#networkIpv6GatewayRow").hide(); $("#networkIpv6GatewayInput").val('');
-        $("#networkIpv6HostTableRow").hide(); $("#networkIpv6HostTableInput").val('');
-        $("#networkIpv4HostAddressRow").hide(); $("#networkIpv4HostAddressInput").val('');
-        $("#networkIpv6HostAddressRow").hide(); $("#networkIpv6HostAddressInput").val('');
-        $("#networkIpv4RoutesExternalRow").hide(); $("#networkIpv4RoutesExternalInput").val('');
-        $("#networkIpv6RoutesExternalRow").hide(); $("#networkIpv6RoutesExternalInput").val('');
-        $("#networkSecurityAclsRow").hide(); $("#networkSecurityAclsInput").val('');
-        $("#networkSecurityAclsDefaultIngressActionRow").hide(); $("#networkSecurityAclsDefaultIngressActionInput").val('');
-        $("#networkSecurityAclsDefaultEgressActionRow").hide(); $("#networkSecurityAclsDefaultEgressActionInput").val('');
-        $("#networkSecurityAclsDefaultIngressLoggedRow").hide(); $("#networkSecurityAclsDefaultIngressLoggedInput").val('');
-        $("#networkSecurityAclsDefaultEgressLoggedRow").hide(); $("#networkSecurityAclsDefaultEgressLoggedInput").val('');
-      }
-    }
-
-    // Change the state of an instance: start, stop, freeze, unfreeze, restart, force stop
-    function changeItemState(instance, action, force=false){
-      console.log("Info: starting virtual machine " + instance);
-      $.post("../api/virtual-machine/change_instance_state?id=" + serverId + "&project=" + project, { instance: instance, action: action, force: force }, function (data) {
-        console.log(data);
-        if (data.error_code >= 400){
-          alert(data.error);
-        }
-        //Async type
-        setTimeout(() => { reloadPageContent(); }, 2000);
-        operationStatusCheck()
-      });
-    }
-
-    // Change storage volumes based on storage pool in add disk device modal
-    function changeStorageVolumeInput(){
-      var diskPoolInput = $("#diskPoolInput").val();
-      if (diskPoolInput == ""){
-        $("#diskSourceInput").show()
-        $("#diskSourceSelectInput").hide()
-      }
-      else{
-        //show and populate select field
-        $("#diskSourceSelectInput").empty().append('<option value="">(not set)</option>');
-        $.getJSON("../api/storage-volumes/list_storage_volumes?id="+serverId+"&project="+project+"&pool="+diskPoolInput, function (data) {
-          data = data.metadata
-          for (var index = 0; index < data.length; index++) {
-            if (data[index].includes('/1.0/storage-pools/' + diskPoolInput + '/volumes/custom/')){
-              optionText = data[index].replace('/1.0/storage-pools/' + diskPoolInput + '/volumes/custom/','');
-              $('#diskSourceSelectInput').append('<option value="' + optionText + '">' + optionText + '</option>');
-            }
-          }
-        })
-        $("#diskSourceInput").hide()
-        $("#diskSourceSelectInput").show()
-      }
-    }
-
-    // Dynamically change Instance Actions options based on state
-    function displayMenuOptions(data){
-      switch (data.status){
-        case "Stopped":
-          $('#startLinkButton').show();
-          $('#stopLinkButton').hide();
-          $('#unfreezeLinkButton').hide();
-          $('#startLink').show();
-          $('#stopLink').hide();
-          $('#unfreezeLink').hide();
-          $('#restartInstanceOption').prop('disabled', true).removeClass('text-primary').addClass('text-muted');
-          $('#stopInstanceForcefullyOption').prop('disabled', true).removeClass('text-primary').addClass('text-muted');
-          $('#freezeInstanceOption').prop('disabled', true).removeClass('text-primary').addClass('text-muted');
-          $('#snapshotInstanceOption').prop('disabled', false).removeClass('text-muted').addClass('text-primary');
-          $('#attachProfileOption').prop('disabled', false).removeClass('text-muted').addClass('text-primary');
-          $('#detachProfileOption').prop('disabled', false).removeClass('text-muted').addClass('text-primary');
-          $('#editInstanceOption').prop('disabled', false).removeClass('text-muted').addClass('text-primary');
-          $('#renameInstanceOption').prop('disabled', false).removeClass('text-muted').addClass('text-primary');
-          $('#copyInstanceOption').prop('disabled', false).removeClass('text-muted').addClass('text-primary');
-          $('#migrateInstanceOption').prop('disabled', false).removeClass('text-muted').addClass('text-primary');
-          $('#publishInstanceOption').prop('disabled', false).removeClass('text-muted').addClass('text-primary');
-          $('#deleteInstanceOption').prop('disabled', false).removeClass('text-muted').addClass('text-primary');
-          $('#startExecButton').prop('disabled', true);
-          $('#startConsoleButton').prop('disabled', true);
-          break;
-        case "Frozen":
-          $('#startLinkButton').hide();
-          $('#stopLinkButton').hide();
-          $('#unfreezeLinkButton').show();
-          $('#startLink').hide();
-          $('#stopLink').hide();
-          $('#unfreezeLink').show();
-          $('#restartInstanceOption').prop('disabled', true).removeClass('text-primary').addClass('text-muted');
-          $('#stopInstanceForcefullyOption').prop('disabled', true).removeClass('text-primary').addClass('text-muted');
-          $('#freezeInstanceOption').prop('disabled', true).removeClass('text-primary').addClass('text-muted');
-          $('#snapshotInstanceOption').prop('disabled', false).removeClass('text-muted').addClass('text-primary');
-          $('#attachProfileOption').prop('disabled', true).removeClass('text-primary').addClass('text-muted');
-          $('#detachProfileOption').prop('disabled', true).removeClass('text-primary').addClass('text-muted');
-          $('#editInstanceOption').prop('disabled', true).removeClass('text-primary').addClass('text-muted');
-          $('#renameInstanceOption').prop('disabled', true).removeClass('text-primary').addClass('text-muted');
-          $('#copyInstanceOption').prop('disabled', false).removeClass('text-muted').addClass('text-primary');
-          $('#migrateInstanceOption').prop('disabled', true).removeClass('text-primary').addClass('text-muted');
-          $('#publishInstanceOption').prop('disabled', true).removeClass('text-primary').addClass('text-muted');
-          $('#deleteInstanceOption').prop('disabled', true).removeClass('text-primary').addClass('text-muted');
-          $('#startExecButton').prop('disabled', true);
-          $('#startConsoleButton').prop('disabled', true);
-          break;
-        default:
-          $('#startLinkButton').hide();
-          $('#stopLinkButton').show();
-          $('#unfreezeLinkButton').hide();
-          $('#startLink').hide();
-          $('#stopLink').show();
-          $('#unfreezeLink').hide();
-          $('#restartInstanceOption').prop('disabled', false).removeClass('text-muted').addClass('text-primary');
-          $('#stopInstanceForcefullyOption').prop('disabled', false).removeClass('text-muted').addClass('text-primary');
-          $('#freezeInstanceOption').prop('disabled', false).removeClass('text-muted').addClass('text-primary');
-          $('#snapshotInstanceOption').prop('disabled', false).removeClass('text-muted').addClass('text-primary');
-          $('#attachProfileOption').prop('disabled', false).removeClass('text-muted').addClass('text-primary');
-          $('#detachProfileOption').prop('disabled', false).removeClass('text-muted').addClass('text-primary');
-          $('#editInstanceOption').prop('disabled', false).removeClass('text-muted').addClass('text-primary');
-          $('#renameInstanceOption').prop('disabled', true).removeClass('text-primary').addClass('text-muted');
-          $('#copyInstanceOption').prop('disabled', true).removeClass('text-primary').addClass('text-muted');
-          $('#migrateInstanceOption').prop('disabled', true).removeClass('text-primary').addClass('text-muted');
-          $('#publishInstanceOption').prop('disabled', true).removeClass('text-primary').addClass('text-muted');
-          $('#deleteInstanceOption').prop('disabled', true).removeClass('text-primary').addClass('text-muted');
-          if (server_clustered && server_name != target_location){
-            $('#startExecButton').prop('disabled', true);
-            $('#startConsoleButton').prop('disabled', true);
-          }
-          else {
-            $('#startExecButton').prop('disabled', false);
-            $('#startConsoleButton').prop('disabled', false);
-          }
-      }
-    }
-
-    // Show the edit instance modal
-    function editInstance(){
-      console.log("Info: viewing instance " + instance);
-      $.get("../api/virtual-machine/get_instance?id="+serverId+"&project="+project+"&name="+instance+"&recursion=1", function (data) {
-        data = data.metadata;
-
-        if (data.error_code >= 400){
-          alert(data.error);
-        }
-
-        //Clean all values in form
-        $("#editModal").find('input, select, textarea').val('');
-
-        //Set existing description value in form
-        if (data.hasOwnProperty('description')) { $("#virtualMachineDescriptionInput").val(data.description); }
-
-        //Set existing values from config in form
-        $.each(data.config, function(key, value) {
-          item = "#"+key
-          $(`[name="${key}"]`).val(value);
-          console.log(item + "=" + value)
-        })
-
-        //Set instance name on form
-        $("#instanceNameEditInput").text("Name: " + instance);
-
-        //Set json tab content
-        $("#jsonEditInput").val(JSON.stringify(data, null, 2));
-
-        //Show modal with form and json
-        $("#editModal").modal('show');
-
-      });
-    }
-
-    // Update the instance from the edit instance modal form
-    function updateInstanceForm(){
-      console.log("Info: updating instance " + instance);
-      data = $('#editForm').serialize();
-      $.post("../api/virtual-machine/update_instance?id=" + serverId + "&project=" + project + "&instance=" + encodeURI(instance), data,  function (data) {
-        console.log(data);
-        if (data.error_code >= 400){
-          alert(data.error);
-        }
-        //Sync type
-        setTimeout(() => { reloadPageContent(); }, 1000);
-        operationStatusCheck()
-      });
-    }
-
-    // Update the instance from the edit instance modal json
-    function updateInstanceJson(){
-      var instanceUpdateJSON = $("#jsonEditInstanceInput").val();
-      console.log("Info: updating instance " + instance);
-      $.post("../api/virtual-machine/update_instance?id=" + serverId + "&project=" + project + "&instance=" + encodeURI(instance), { 
-        json: instanceUpdateJSON 
-        },  function (data) {
-          console.log(data);
-          if (data.error_code >= 400){
-            alert(data.error);
-          }
-          //Sync type
-          setTimeout(() => { reloadPageContent(); }, 1000);
-          operationStatusCheck()
-      });
-    }
-
-    // Migrate the instance to new cluster host
-    function migrateInstance(){
-      var clusterHost = $("#selectClusterInput").val();
-      console.log("Info: migrating instance " + instance + " to " + clusterHost);
-      $.post("../api/virtual-machine/migrate_instance?id="+serverId+"&project="+project+"&instance="+instance+"&location="+clusterHost, {},  function (data) {
-        console.log(data);
-        if (data.error_code >= 400){
-          alert(data.error);
-        }
-        //Async type
-        setTimeout(() => { reloadPageContent(); }, 2000);
-        operationStatusCheck()
-      });
-    }
-
-    // Copy or clone the instance
-    function copyInstance(){
-      var copyName = $("#copyName").val();
-      console.log("Info: copying instance " + instance + " to " + copyName);
-      $.post("../api/virtual-machine/copy_instance?id="+serverId+"&project="+project+"&instance="+instance+"&location="+target_location, { name: copyName },  function (data) {
-        console.log(data);
-        if (data.error_code >= 400){
-          alert(data.error);
-        }
-        //Async type
-        setTimeout(() => { reloadPageContent(); }, 2000);
-        operationStatusCheck()
-      });
-    }
-
-    // Rename the instance
-    function renameInstance(){
-      var renameName = $("#renameName").val();
-      console.log("Info: renaming instance " + instance + " to " + renameName);
-      $.post("../api/virtual-machine/rename_instance?id="+serverId+"&project="+project+"&instance="+instance, { name: renameName },  function (data) {
-        console.log(data);
-        if (data.error_code >= 400){
-          alert(data.error);
-        }
-        else {
-          window.location.href = 'virtual-machine?id=' + serverId + '&project=' + project + '&instance=' + renameName;
-        }
-      });
-    }
-
-    // Publish the instance into an image
-    function publishInstance(){
-      var description = $("#publishInstanceDescriptionInput").val();
-      var os = $("#publishInstanceOsInput").val();
-      var release = $("#publishInstanceReleaseInput").val();
-      var public = $("#publishInstancePublicInput").val();
-      console.log("Info: publishing image " + description + " from instance " + instance);
-      $.post("../api/virtual-machine/publish_instance?id="+serverId+"&project="+project+"&instance="+instance, { description: description, os: os, release: release, public:public },  function (data) {
-        console.log(data);
-        if (data.error_code >= 400){
-          alert(data.error);
-        }
-        //Async type
-        setTimeout(() => { reloadPageContent(); }, 2000);
-        operationStatusCheck()
-      });
-    }
-
-    // Convert websocket array buffer data to string
-    function convertArrayBuffer2String(buf) {
-      var encoding = 'utf8';
-      var decoder = new TextDecoder(encoding);
-      var str = decoder.decode(buf);
-      return str
-    }
-
-    // Convert websocket input string to array buffer
-    function convertString2ArrayBuffer(str) {
-      var buf = new ArrayBuffer(str.length);
-      var bufView = new Uint8Array(buf);
-      for (var i=0, strLen=str.length; i < strLen; i++) {
-        bufView[i] = str.charCodeAt(i);
-      }
-      return buf;
-    }
-
-    // Setup websocket connection for console use
-    function establishInstanceWebSocketConsoleConnection() {
-      $.get("../api/virtual-machine/get_instance_websocket_host?id=" + serverId + "&project=" + project + "&instance=" + encodeURI(instance), function (data) {
-        console.log(data);
-        server_addr = data.addr
-        server_port = data.port
-
-        if (data.proxy) 
-          wss_addr = data.proxy
-        else 
-          wss_addr = data.addr + ':' + data.port;
-
-        //Check to see if we can connect to the LXD server over a secure connection
-        fetch('https://' + wss_addr + '/1.0?addr=' + server_addr + '&port=' + data.port, { mode: 'no-cors' })
-        .then(response => {
-          //If we made it here then the self-signed LXD certificate would have been already trusted by the user's browser we can setup a secure websocket connection
-          $.post("../api/virtual-machine/establish_instance_console_websocket?id=" + serverId + "&project=" + project + "&instance=" + encodeURI(instance), { 
-            width: consoleTerminal.cols,
-            height: consoleTerminal.rows
-          }, function (data) {
-            console.log(data);
-            var operation = data.operation;
-            var consoleControlURL = "wss://" + wss_addr + operation + "/websocket?secret=" + data.control + "&addr=" + server_addr + "&port=" + server_port;
-            var consoleDataURL = "wss://" + wss_addr + operation + "/websocket?secret=" + data.secret + "&addr=" + server_addr + "&port=" + server_port;
-
-            if(operation == "" && operationData.secret == ""){
-              alert("Unable to connect via websocket");
-              return;
-            }
-            
-            //Create a new "control" websocket
-            consoleControlSocket = new WebSocket(consoleControlURL);
-
-            //Listen for "control" websocket errors
-            consoleControlSocket.onerror = function (e) {
-              console.log("There was a WebSocket error: " + e);
-            }
-
-            //Listen for "control" websocket opening connection
-            consoleControlSocket.onopen = function (e) {
-              console.log( "Console Control WebSocket ReadyState: " + consoleControlSocket.readyState ); 
-            };
-    
-            //Listen for "control" websocket messages
-            consoleControlSocket.onmessage = function (e) {      
-              if (e.data instanceof ArrayBuffer) {
-                if (convertArrayBuffer2String(e.data) != null){
-                  consoleTerminal.write(convertArrayBuffer2String(e.data));
-                }
-              }
-            };
-
-            //Listen for "control" websocket closing
-            consoleControlSocket.onclose = function (e) {
-              console.log(e);
-            };
-
-            //Create a new "data" websocket
-            consoleDataSocket = new WebSocket(consoleDataURL);
-              
-            //Listen for "data" websocket errors
-            consoleDataSocket.onerror = function (e) {
-              console.log("There was a WebSocket error: " + e);
-            }
-
-            //Listen for "data" websocket opening connection
-            consoleDataSocket.onopen = function (e) {
-              //Set binaryType to ArrayBuffer. This should be default value
-              consoleDataSocket.binaryType = 'arraybuffer';
-              
-              console.log( "Console Data WebSocket ReadyState: " + consoleDataSocket.readyState );
-              consoleTerminal.write("--- Secure Websocket Connection Opened --- \r\n");
-
-              //Send return to show login screen on console connections
-              setTimeout(() => { consoleDataSocket.send(convertString2ArrayBuffer('\r')); }, 1000);
-              
-              //Switch console action buttons
-              $("#startConsoleButton").hide();
-              $("#stopConsoleButton").show();
-            };
-        
-            //Listen for "data" websocket messages
-            consoleDataSocket.onmessage = function (e) {   
-              if (e.data.length == 0) {
-                consoleControlSocket.close();
-                consoleDataSocket.close();
-              } else {   
-                if (e.data instanceof ArrayBuffer) {
-                  if (convertArrayBuffer2String(e.data) != null){
-                    consoleTerminal.write(convertArrayBuffer2String(e.data));
-                  }
-                }
-              }
-            };
-
-            //Listen for "data" websocket closing
-            consoleDataSocket.onclose = function (e) {
-              console.log(e);
-              consoleTerminal.write("\r\n--- Websocket Connection Closed  ---\r\n");
-              $("#stopConsoleButton").hide();
-              $("#startConsoleButton").show();
-            };
-
-          });
-
-        })
-        .catch((error) => {
-          console.log("Error: ", error)
-          //If we make it here then we had an error connection to LXD server. Most likely the Self-Signed Certificate is not yet trusted by the user's browser
-          data = 'There was an error connecting to your LXD server. <br />The LXD server may be using a self-signed certificate. <br />Click <a href="https://' + wss_addr + '?addr=' + server_addr + '&port=' + data.port + '" target="_blank">here</a> to accept the certificate if not yet trusted.';
-          $("#webSocketConnectionError").html(data);
-          $('#webSocketConnectionErrorModal').modal('show');
-        })
-
-      });
-
-    }
-
-    // Setup websocket connection for exec use
-    function establishInstanceWebSocketExecConnection() {
-      $.get("../api/virtual-machine/get_instance_websocket_host?id=" + serverId + "&project=" + project + "&instance=" + encodeURI(instance), function (data) {
-        console.log(data);
-        server_addr = data.addr
-        server_port = data.port
-
-        if (data.proxy) 
-          wss_addr = data.proxy
-        else 
-          wss_addr = data.addr + ':' + data.port;
-
-        //Check to see if we can connect to the LXD server over a secure connection
-        fetch('https://' + wss_addr + '/1.0?addr=' + server_addr + '&port=' + data.port, { mode: 'no-cors' })
-        .then(response => {
-          //If we made it here then the self-signed LXD certificate would have been already trusted by the user's browser we can setup a secure websocket connection
-          $.post("../api/virtual-machine/establish_instance_exec_websocket?id=" + serverId + "&project=" + project + "&instance=" + encodeURI(instance), { 
-            shell: $("#execShellInput").val(),
-            width: execTerminal.cols,
-            height: execTerminal.rows
-          }, function (data) {
-            console.log(data);
-            var operation = data.operation;
-            var execControlURL = "wss://" + wss_addr + operation + "/websocket?secret=" + data.control + "&addr=" + server_addr + "&port=" + server_port;
-            var execDataURL = "wss://" + wss_addr + operation + "/websocket?secret=" + data.secret + "&addr=" + server_addr + "&port=" + server_port;
-
-            if(operation == "" && data.secret == ""){
-              alert("Unable to connect via websocket");
-              return;
-            }
-            
-            //Create a new "control" websocket
-            execControlSocket = new WebSocket(execControlURL);
-
-            //Listen for "control" websocket errors
-            execControlSocket.onerror = function (e) {
-              console.log("There was a WebSocket error: " + e);
-            }
-
-            //Listen for "control" websocket opening connection
-            execControlSocket.onopen = function (e) {
-              console.log( "Exec Control WebSocket ReadyState: " + execControlSocket.readyState ); 
-            };
-    
-            //Listen for "control" websocket messages
-            execControlSocket.onmessage = function (e) {     
-              console.log(e) 
-              if (e.data instanceof ArrayBuffer) {
-                if (convertArrayBuffer2String(e.data) != null){
-                  execTerminal.write(convertArrayBuffer2String(e.data));
-                }
-              }
-            };
-
-            //Listen for "control" websocket closing
-            execControlSocket.onclose = function (e) {
-              console.log(e);
-            };
-
-            //Create a new "data" websocket
-            execDataSocket = new WebSocket(execDataURL);
-              
-            //Listen for "data" websocket errors
-            execDataSocket.onerror = function (e) {
-              console.log("There was a WebSocket error: " + e);
-            }
-
-            //Listen for "data" websocket opening connection
-            execDataSocket.onopen = function (e) {
-              //Set binaryType to ArrayBuffer. This should be default value
-              execDataSocket.binaryType = 'arraybuffer';
-              
-              console.log( "Exec Data WebSocket ReadyState: " + execDataSocket.readyState );
-              execTerminal.write("--- Secure Websocket Connection Opened --- \r\n");
-
-              //Switch console action buttons
-              $("#startExecButton").hide();
-              $("#stopExecButton").show();
-            };
-        
-            //Listen for "data" websocket messages
-            execDataSocket.onmessage = function (e) {  
-              if (e.data.length == 0) {
-                execControlSocket.close();
-                execDataSocket.close();
-              }
-              else {    
-                if (e.data instanceof ArrayBuffer) {
-                  if (convertArrayBuffer2String(e.data) != null){
-                    execTerminal.write(convertArrayBuffer2String(e.data));
-                  }
-                }
-              }
-            };
-
-            //Listen for "data" websocket closing
-            execDataSocket.onclose = function (e) {
-              console.log(e);
-              execTerminal.write("\r\n--- Websocket Connection Closed ---\r\n");
-              $("#stopExecButton").hide();
-              $("#startExecButton").show();
-            };
-
-          });
-
-        })
-        .catch((error) => {
-          console.log("Error: ", error)
-          //If we make it here then we had an error connection to LXD server. Most likely the Self-Signed Certificate is not yet trusted by the user's browser
-          data = 'There was an error connecting to your LXD server. <br />The LXD server may be using a self-signed certificate. <br />Visit <a href="https://' + wss_addr + '?addr=' + server_addr + '&port=' + data.port + '" target="_blank">here</a> to accept the certificate if not yet trusted.';
-          $("#webSocketConnectionError").html(data);
-          $('#webSocketConnectionErrorModal').modal('show');
-        })
-
-      });
-
-    }
-
-    // Close websocket connection for console user
-    function closeWebSocketConsoleConnection() {
-      //Closing the "control" websocket for console operations will stop the operation without crashing existing host's WebSockets.
-      consoleControlSocket.close();
-      consoleDataSocket.close();
-    }
-
-    // Close websocket connection for exec use
-    function closeWebSocketExecConnection() {
-      //Sending Ctrl+d (exit) three times to back out of potential nested shells or logins up to three deep. If not logged out, WebSocket operation may continue to run.
-      execDataSocket.send(convertString2ArrayBuffer('\04 \r \04 \r \04 \r'))
-
-      //Closing the "control" websocket for console operations will stop the operation without crashing existing host WebSockets.
-      execControlSocket.close();
-      execDataSocket.close();
-    }
-
-
-    $(document).ready(function(){
-
-      //If id or project variables are missing redirect to servers page
-      if (!serverId || !project) {
-        window.location.href = 'servers';
-      }
-      else {
-        $("#instance_title").text(instance);
-        loadPageContent()
-        operationStatusCheck()
-      }
-    
-    });
-
-  </script>
-
-
-{% endblock script %}

+ 0 - 328
lxconsole/templates/virtual-machines.html

@@ -1,328 +0,0 @@
-{% extends "main.html" %}
-
-{% block header %}
-  <div class="row mb-2">
-    <div class="col-sm-6">
-      <h1>{{ page_title | safe }}</h1>
-    </div>
-    <div class="col-sm-6">
-      <a class="btn btn-outline-primary float-sm-right mr-4" href="#" data-toggle="modal" data-target="#addModal" title="Add Virtual Machine" aria-hidden="true">
-        <i class="fas fa-plus fa-sm fa-fw"></i> Virtual Machine
-      </a>
-    </div>
-  </div>
-{% endblock header %}
-
-{% block content %}
-  <div class="col-12">
-    <div class="card">
-      <div class="card-header">
-        <h3 class="card-title">Virtual Machines</h3>
-        <div class="card-tools">
-          <button type="button" class="btn btn-tool" onclick="reloadPageContent()" title="Refresh">
-          <i class="fas fa-sync"></i>
-          </button>
-        </div>
-      </div>
-      <div class="card-body">
-        <table class="table table-hover" id="myDataTable" width="100%" cellspacing="0">
-        </table>
-      </div>
-    </div>
-  </div>
-{% endblock content %}
-
-{% block modal %}
-  {% include 'modals/virtual-machines.html' %}
-{% endblock modal %}
-
-{% block script %}
-  <script>
-    var reloadTime = 10000;
-    const queryString = window.location.search;
-    const urlParams = new URLSearchParams(queryString);
-    const serverId = urlParams.get('id');
-    const project = urlParams.get('project');
-    var editedVirtualMachine = ''
-    applySidebarStyles();
-    applySidebarLinks();
-    populateSidebarLinks();
-    populateNavbarLinks();
-
-    function reloadPageContent() {
-      //Clear the automatic page reload
-      clearTimeout(pageReloadTimeout);
-
-      //Reload the datatables content
-      $('#myDataTable').DataTable().ajax.reload(null, false);
-
-      //Set the automatic page reload
-      pageReloadTimeout = setTimeout(() => { reloadPageContent(); }, reloadTime);
-    }
-
-    function loadPageContent(){
-
-      //Display the current project
-      $("#selectedProject").text(project);
-
-      //Populate the Server dropdown
-      $.getJSON("../api/servers/list_servers?id="+serverId, function (data) {
-        data = data.data
-        for (var index = 0; index < data.length; index++) {
-          if (data[index].name == '')
-            optionText = data[index].addr
-          else
-            optionText = data[index].name
-          if (data[index].id == serverId)
-            $('#serverListNav').append('<option value="' + data[index].id + '" selected="selected">' + optionText + '</option>');
-          else
-            $('#serverListNav').append('<option value="' + data[index].id + '">' + optionText + '</option>');
-        }
-      })
-
-      //Populate the Project dropdown
-      $.getJSON("../api/projects/list_projects?id="+serverId+"&project="+project, function (data) {
-        data = data.metadata
-        for (var index = 0; index < data.length; index++) {
-          optionText = data[index].replace('/1.0/projects/','');
-          if (optionText == project)
-            $('#projectListNav').append('<option value="' + optionText + '" selected="selected">' + optionText + '</option>');
-          else
-            $('#projectListNav').append('<option value="' + optionText + '">' + optionText + '</option>');
-        }
-      })
-
-      //Populate the modal Profile dropdown
-      $.getJSON("../api/profiles/list_profiles?id="+serverId+"&project="+project, function (data) {
-        data = data.metadata
-        for (var index = 0; index < data.length; index++) {
-          //When using projects other than default and no recursion, it gets like URL variable with "?"
-          optionText = data[index].split("?")
-          optionText = optionText[0].replace('/1.0/profiles/','');
-          if (optionText == 'default') {
-            $('#virtualMachineProfileInput').append('<option value="' + optionText + '" selected="selected">' + optionText + '</option>');
-          }
-          else {
-            $('#virtualMachineProfileInput').append('<option value="' + optionText + '">' + optionText + '</option>');
-          }
-        }
-      })
-
-      //Populate the modal Location dropdown
-      $.getJSON("../api/cluster-members/list_cluster_members?id="+serverId+"&project="+project, function (data) {
-        data = data.metadata
-        for (var index = 0; index < data.length; index++) {
-          optionText = data[index].replace('/1.0/cluster/members/','');
-          $('#virtualMachineLocationInput').append('<option value="' + optionText + '">' + optionText + '</option>');
-        }
-      })
-      $.getJSON("../api/cluster-groups/list_cluster_groups?id="+serverId+"&project="+project, function (data) {
-        data = data.metadata
-        for (var index = 0; index < data.length; index++) {
-          optionText = data[index].replace('/1.0/cluster/groups/','');
-          $('#containerLocationInput').append('<option value="@' + optionText + '">@' + optionText + '</option>');
-        }
-      })
-
-      //Populate the modal Image dropdown
-      $.getJSON("../api/images/list_images?id="+serverId+"&project="+project+"&recursion=1", function (data) {
-        data = data.metadata
-        for (var index = 0; index < data.length; index++) {
-          if (data[index].hasOwnProperty('type')) {
-            if(data[index].type == 'virtual-machine'){
-              $('#virtualMachineImageInput').append('<option value="' + data[index].fingerprint + '">' + data[index].properties.description + '</option>');
-            }
-          }
-        }
-      })
-
-      // Configure Datatable
-      $('#myDataTable').DataTable({
-        ajax: {
-          url: "../api/virtual-machines/list_instances?id="+serverId+"&project=" + project + "&recursion=2",
-          dataType: "json",
-          dataSrc: "metadata",
-          contentType: "application/json"
-        },
-        columns: [
-          { title: "Name", data: function (row, type, set) {
-              if (row.hasOwnProperty('name')) {
-                if (row.name)
-                  return '<a href="../virtual-machine?id=' + serverId + '&project=' + project + '&instance=' + row.name + '">' + row.name + '</a>';
-              }
-              return '-'
-            },
-          },
-          { title: "OS", data: function (row, type, set) {
-              if (row.hasOwnProperty('expanded_config')) {
-                if (row.expanded_config.hasOwnProperty('image.os')) {
-                  if (row.expanded_config['image.os']){
-                    return row.expanded_config['image.os']
-                  }
-                }
-              }
-              return '-'
-            },
-          },
-          { title: "Location", data: function (row, type, set) {
-              if (row.hasOwnProperty('location')) {
-                if (row.location){
-                  return row.location
-                }
-              }
-              return '-'
-            },
-          },
-          { title: "IPv4", data: function (row, type, set) {
-              if (row.hasOwnProperty('ipv4_addresses')) {
-                if (row.ipv4_addresses.length > 0){
-                  return row.ipv4_addresses.join(', <br />')
-                }
-              }
-              return '-'
-            },
-          },
-          { title: "IPv6", data: function (row, type, set) {
-              if (row.hasOwnProperty('ipv6_addresses')) {
-                if (row.ipv6_addresses.length > 0){
-                  return row.ipv6_addresses.join(', <br />')
-                }
-              }
-              return '-'
-            },
-          },
-          { title: "Memory", data: function (row, type, set) {
-              if (row.hasOwnProperty('memory')) {
-                if (row.memory){
-                  if (type === 'display'){
-                    return (row.memory / 1024 / 1024).toFixed(2) + ' MiB'
-                  }
-                  return row.memory
-                }
-              }
-              return '-'
-            },
-          },
-          { title: "Root Disk", data: function (row, type, set) {
-              if (row.hasOwnProperty('disk')) {
-                if (row.disk){
-                  if (type === 'display'){
-                    return (row.disk / 1024 / 1024).toFixed(2) + ' MiB'
-                  }
-                  return row.disk
-                }
-              }
-              return '-'
-            },
-          },
-          { title: "Status", data: function (row, type, set) {
-              if (row.hasOwnProperty('status')) {
-                if (row.status){
-                  return row.status
-                }
-              }
-              return '-'
-            },
-          },
-          { title: "Actions", data: function (row, type, set) {
-              links = ''
-              if (row.hasOwnProperty('name') && row.hasOwnProperty('status')) {
-                if (row.name && row.status){
-                  if (row.status == 'Frozen')
-                    links += '<a href="#" onclick=changeItemState(\''+row.name+'\',\'unfreeze\')><i class="fas fa-pause fa-lg" style="color:#ddd" title="Edit" aria-hidden="true"></i></a>'
-                  else if (row.status == 'Stopped')
-                    links += '<a href="#" onclick=changeItemState(\''+row.name+'\',\'start\')><i class="fas fa-play fa-lg" style="color:#ddd" title="Edit" aria-hidden="true"></i></a>'
-                  else if (row.status == 'Running')
-                    links += '<a href="#" onclick=changeItemState(\''+row.name+'\',\'stop\')><i class="fas fa-stop fa-lg" style="color:#ddd" title="Edit" aria-hidden="true"></i></a>'
-                  links += '&nbsp' + '&nbsp' 
-                  links += '<a href="#" onclick=deleteInstance(\''+row.name+'\')><i class="fas fa-trash-alt fa-lg" style="color:#ddd" title="Delete" aria-hidden="true"></i></a>'
-                }
-              }
-              return links
-            },
-          },
-        ],
-        order: [],
-      });
-
-      //Set reload page content
-      pageReloadTimeout = setTimeout(() => { reloadPageContent(); }, reloadTime);
-
-    }
-
-    // Change state start/stop of instance
-    function changeItemState(name, action){
-      console.log("Info: starting container " + name);
-      $.post("../api/virtual-machines/change_instance_state?id=" + serverId + "&project=" + project, { name: name, action: action }, function (data) {
-        console.log(data);
-        if (data.error_code >= 400){
-          alert(data.error);
-        }
-        //Async type
-        setTimeout(() => { reloadPageContent(); }, 2000);
-        operationStatusCheck()
-      });
-    }
-
-    // Add instance
-    function addItem(){
-      console.log("Info: adding new virtual machine");
-      data = $('#addForm').serialize();
-      $.post("../api/virtual-machines/add_instance?id="+serverId+"&project="+project, data, function (data) {
-        console.log(data);
-        if (data.error_code >= 400){
-          alert(data.error);
-        }
-        //Aync type
-        setTimeout(() => { reloadPageContent(); }, 2000);
-        operationStatusCheck()
-      });
-    }
-
-    // Delete instance
-    function deleteInstance(name){
-      console.log("Info: confirming deletion of container " + name);
-      if (confirm("Are you sure you want to delete container " + name + "?") == true) {
-        console.log("Info: deleting container " + name);
-        $.post("../api/virtual-machines/delete_instance?id=" + serverId + "&project=" + project, { name: name }, function (data) {
-          console.log(data);
-          if (data.error_code >= 400){
-            alert(data.error);
-          }
-          //Async type
-          setTimeout(() => { reloadPageContent(); }, 2000);
-          operationStatusCheck()
-        });
-      }
-    }
-
-    // Create instance from JSON
-    function createItemUsingJSON(){
-      var json = $("#jsonCreateInput").val();
-      console.log("Info: adding new instance");
-      $.post("../api/virtual-machines/add_instance?id="+serverId+"&project="+project, { json: json },  function (data) {
-        console.log(data);
-        if (data.error_code >= 400){
-          alert(data.error);
-        }
-        //Async type
-        setTimeout(() => { reloadPageContent(); }, 2000);
-        operationStatusCheck()
-      });
-    }
-
-    $(document).ready(function(){
-
-      //If id or project variables are missing redirect to servers page
-      if (!serverId || !project) {
-        window.location.href = 'servers';
-      }
-      else {
-        loadPageContent()
-        operationStatusCheck()
-      }
-      
-    });
-
-  </script>
-{% endblock script %}

+ 4 - 5
roadmap.txt

@@ -1,18 +1,17 @@
-# 0.4.0
-- Convert to bootstrap 5
+# 0.5.0
 - Add dark theme option
 - Add bootstrap toast notifications
 - Add warnings
 
-# 0.5.0
+# 0.6.0
 - Add two factor authentication option
 - Add password complexity requirements option
 
-# 0.6.0
+# 0.7.0
 - Add support for MariaDB and Postgres database backends
 - Add logs page
 
-# 0.7.0
+# 0.8.0
 - Add offcanvas sidebars where appropriate for additional information
 - Include rename tasks in tables with edit form on new tab
 

Some files were not shown because too many files changed in this diff