From 287d28fb105a3be207f61089fd3f026f4ef77dec Mon Sep 17 00:00:00 2001 From: matthewalanpenning Date: Tue, 24 Oct 2023 05:28:27 -0400 Subject: [PATCH] v0.4.0 --- CHANGELOG.md | 7 + lxconsole/api/__init__.py | 12 +- lxconsole/api/container.py | 1156 ------- .../api/{virtual_machine.py => instance.py} | 233 +- lxconsole/api/{containers.py => instances.py} | 71 +- lxconsole/api/virtual_machines.py | 217 -- lxconsole/routes.py | 26 +- .../css/bootstrap/bootstrap.min.css.map | 1 + lxconsole/static/css/styles.css | 7 +- lxconsole/static/js/sidebar.js | 9 +- lxconsole/templates/access-controls.html | 9 +- lxconsole/templates/certificates.html | 9 +- lxconsole/templates/cluster-groups.html | 9 +- lxconsole/templates/cluster-members.html | 9 +- lxconsole/templates/containers.html | 332 -- lxconsole/templates/groups.html | 9 +- lxconsole/templates/head.html | 14 +- lxconsole/templates/images.html | 9 +- .../{container.html => instance.html} | 554 +-- lxconsole/templates/instances.html | 632 ++++ lxconsole/templates/logs.html | 5 +- lxconsole/templates/main.html | 19 +- .../templates/modals/access-controls.html | 28 +- lxconsole/templates/modals/certificates.html | 20 +- .../templates/modals/cluster-groups.html | 36 +- .../templates/modals/cluster-members.html | 34 +- lxconsole/templates/modals/groups.html | 12 +- lxconsole/templates/modals/images.html | 36 +- .../modals/{container.html => instance.html} | 491 +-- .../{containers.html => instances.html} | 300 +- lxconsole/templates/modals/main.html | 12 +- lxconsole/templates/modals/network-acl.html | 22 +- lxconsole/templates/modals/network-acls.html | 26 +- lxconsole/templates/modals/network-zones.html | 34 +- lxconsole/templates/modals/network.html | 70 +- lxconsole/templates/modals/networks.html | 70 +- lxconsole/templates/modals/operations.html | 4 +- lxconsole/templates/modals/profiles.html | 26 +- lxconsole/templates/modals/projects.html | 80 +- lxconsole/templates/modals/roles.html | 8 +- lxconsole/templates/modals/servers.html | 30 +- lxconsole/templates/modals/simplestreams.html | 6 +- lxconsole/templates/modals/storage-pools.html | 42 +- .../templates/modals/storage-volumes.html | 34 +- lxconsole/templates/modals/users.html | 34 +- .../templates/modals/virtual-machine.html | 2361 ------------- .../templates/modals/virtual-machines.html | 655 ---- lxconsole/templates/navbar.html | 12 +- lxconsole/templates/network-acl.html | 18 +- lxconsole/templates/network-acls.html | 9 +- lxconsole/templates/network-zones.html | 9 +- lxconsole/templates/network.html | 51 +- lxconsole/templates/networks.html | 9 +- lxconsole/templates/operations.html | 5 +- lxconsole/templates/profiles.html | 9 +- lxconsole/templates/projects.html | 9 +- lxconsole/templates/roles.html | 9 +- lxconsole/templates/server.html | 9 +- lxconsole/templates/servers.html | 9 +- lxconsole/templates/sidebar.html | 16 +- lxconsole/templates/simplestreams.html | 9 +- lxconsole/templates/storage-pools.html | 9 +- lxconsole/templates/storage-volumes.html | 9 +- lxconsole/templates/users.html | 9 +- lxconsole/templates/virtual-machine.html | 2965 ----------------- lxconsole/templates/virtual-machines.html | 328 -- roadmap.txt | 9 +- 67 files changed, 2208 insertions(+), 9124 deletions(-) delete mode 100644 lxconsole/api/container.py rename lxconsole/api/{virtual_machine.py => instance.py} (88%) rename lxconsole/api/{containers.py => instances.py} (89%) delete mode 100644 lxconsole/api/virtual_machines.py create mode 100644 lxconsole/static/css/bootstrap/bootstrap.min.css.map delete mode 100644 lxconsole/templates/containers.html rename lxconsole/templates/{container.html => instance.html} (84%) create mode 100644 lxconsole/templates/instances.html rename lxconsole/templates/modals/{container.html => instance.html} (84%) rename lxconsole/templates/modals/{containers.html => instances.html} (80%) delete mode 100644 lxconsole/templates/modals/virtual-machine.html delete mode 100644 lxconsole/templates/modals/virtual-machines.html delete mode 100644 lxconsole/templates/virtual-machine.html delete mode 100644 lxconsole/templates/virtual-machines.html diff --git a/CHANGELOG.md b/CHANGELOG.md index c7086d5..9b4dad0 100644 --- a/CHANGELOG.md +++ b/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 diff --git a/lxconsole/api/__init__.py b/lxconsole/api/__init__.py index 3ff4092..a32b3f5 100644 --- a/lxconsole/api/__init__.py +++ b/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/', view_func=container.api_container_endpoint, methods=['GET', 'POST']) -api.add_url_rule('/containers/', view_func=containers.api_containers_endpoint, methods=['GET', 'POST']) +api.add_url_rule('/instance/', view_func=instance.api_instance_endpoint, methods=['GET', 'POST']) +api.add_url_rule('/instances/', view_func=instances.api_instances_endpoint, methods=['GET', 'POST']) api.add_url_rule('/servers/', view_func=servers.api_servers_endpoint, methods=['GET', 'POST']) api.add_url_rule('/server/', view_func=server.api_server_endpoint) api.add_url_rule('/certificates/', view_func=certificates.api_certificates_endpoint, methods=['GET', 'POST']) @@ -51,8 +49,6 @@ api.add_url_rule('/projects/', view_func=projects.api_projects_endpoin api.add_url_rule('/simplestreams/', view_func=simplestreams.api_simplestreams_endpoint, methods=['GET', 'POST']) api.add_url_rule('/storage-pools/', view_func=storage_pools.api_storage_pools_endpoint, methods=['GET', 'POST']) api.add_url_rule('/storage-volumes/', view_func=storage_volumes.api_storage_volumes_endpoint, methods=['GET', 'POST']) -api.add_url_rule('/virtual-machine/', view_func=virtual_machine.api_virtual_machine_endpoint, methods=['GET', 'POST']) -api.add_url_rule('/virtual-machines/', view_func=virtual_machines.api_virtual_machines_endpoint, methods=['GET', 'POST']) api.add_url_rule('/users/', view_func=users.api_users_endpoint, methods=['GET', 'POST']) api.add_url_rule('/groups/', view_func=groups.api_groups_endpoint, methods=['GET', 'POST']) diff --git a/lxconsole/api/container.py b/lxconsole/api/container.py deleted file mode 100644 index 60738f9..0000000 --- a/lxconsole/api/container.py +++ /dev/null @@ -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 = - #2 = - #3 = - #4 = - 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()) diff --git a/lxconsole/api/virtual_machine.py b/lxconsole/api/instance.py similarity index 88% rename from lxconsole/api/virtual_machine.py rename to lxconsole/api/instance.py index b795a75..e43ee54 100644 --- a/lxconsole/api/virtual_machine.py +++ b/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 = + #2 = + #3 = + #4 = + 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() diff --git a/lxconsole/api/containers.py b/lxconsole/api/instances.py similarity index 89% rename from lxconsole/api/containers.py rename to lxconsole/api/instances.py index 8f079ee..2c195a7 100644 --- a/lxconsole/api/containers.py +++ b/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() diff --git a/lxconsole/api/virtual_machines.py b/lxconsole/api/virtual_machines.py deleted file mode 100644 index 82eae7d..0000000 --- a/lxconsole/api/virtual_machines.py +++ /dev/null @@ -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()) diff --git a/lxconsole/routes.py b/lxconsole/routes.py index 71ca004..16e6265 100644 --- a/lxconsole/routes.py +++ b/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////") @login_required def backups(serverId, project, instance, filename): diff --git a/lxconsole/static/css/bootstrap/bootstrap.min.css.map b/lxconsole/static/css/bootstrap/bootstrap.min.css.map new file mode 100644 index 0000000..336fa28 --- /dev/null +++ b/lxconsole/static/css/bootstrap/bootstrap.min.css.map @@ -0,0 +1 @@ +{"version":3,"sources":["../../scss/mixins/_banner.scss","../../scss/_root.scss","../../scss/vendor/_rfs.scss","../../scss/_reboot.scss","dist/css/bootstrap.css","../../scss/mixins/_border-radius.scss","../../scss/_type.scss","../../scss/mixins/_lists.scss","../../scss/_images.scss","../../scss/mixins/_image.scss","../../scss/_containers.scss","../../scss/mixins/_container.scss","../../scss/mixins/_breakpoints.scss","../../scss/_grid.scss","../../scss/mixins/_grid.scss","../../scss/_tables.scss","../../scss/mixins/_table-variants.scss","../../scss/forms/_labels.scss","../../scss/forms/_form-text.scss","../../scss/forms/_form-control.scss","../../scss/mixins/_transition.scss","../../scss/mixins/_gradients.scss","../../scss/forms/_form-select.scss","../../scss/forms/_form-check.scss","../../scss/forms/_form-range.scss","../../scss/forms/_floating-labels.scss","../../scss/forms/_input-group.scss","../../scss/mixins/_forms.scss","../../scss/_buttons.scss","../../scss/mixins/_buttons.scss","../../scss/_transitions.scss","../../scss/_dropdown.scss","../../scss/mixins/_caret.scss","../../scss/_button-group.scss","../../scss/_nav.scss","../../scss/_navbar.scss","../../scss/_card.scss","../../scss/_accordion.scss","../../scss/_breadcrumb.scss","../../scss/_pagination.scss","../../scss/mixins/_pagination.scss","../../scss/_badge.scss","../../scss/_alert.scss","../../scss/mixins/_alert.scss","../../scss/_progress.scss","../../scss/_list-group.scss","../../scss/mixins/_list-group.scss","../../scss/_close.scss","../../scss/_toasts.scss","../../scss/_modal.scss","../../scss/mixins/_backdrop.scss","../../scss/_tooltip.scss","../../scss/mixins/_reset-text.scss","../../scss/_popover.scss","../../scss/_carousel.scss","../../scss/mixins/_clearfix.scss","../../scss/_spinners.scss","../../scss/_offcanvas.scss","../../scss/_placeholders.scss","../../scss/helpers/_color-bg.scss","../../scss/helpers/_colored-links.scss","../../scss/helpers/_ratio.scss","../../scss/helpers/_position.scss","../../scss/helpers/_stacks.scss","../../scss/helpers/_visually-hidden.scss","../../scss/mixins/_visually-hidden.scss","../../scss/helpers/_stretched-link.scss","../../scss/helpers/_text-truncation.scss","../../scss/mixins/_text-truncate.scss","../../scss/helpers/_vr.scss","../../scss/mixins/_utilities.scss","../../scss/utilities/_api.scss"],"names":[],"mappings":"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","sourcesContent":["@mixin bsBanner($file) {\n /*!\n * Bootstrap #{$file} v5.2.3 (https://getbootstrap.com/)\n * Copyright 2011-2022 The Bootstrap Authors\n * Copyright 2011-2022 Twitter, Inc.\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n */\n}\n\n",":root {\n // Note: Custom variable values only support SassScript inside `#{}`.\n\n // Colors\n //\n // Generate palettes for full colors, grays, and theme colors.\n\n @each $color, $value in $colors {\n --#{$prefix}#{$color}: #{$value};\n }\n\n @each $color, $value in $grays {\n --#{$prefix}gray-#{$color}: #{$value};\n }\n\n @each $color, $value in $theme-colors {\n --#{$prefix}#{$color}: #{$value};\n }\n\n @each $color, $value in $theme-colors-rgb {\n --#{$prefix}#{$color}-rgb: #{$value};\n }\n\n --#{$prefix}white-rgb: #{to-rgb($white)};\n --#{$prefix}black-rgb: #{to-rgb($black)};\n --#{$prefix}body-color-rgb: #{to-rgb($body-color)};\n --#{$prefix}body-bg-rgb: #{to-rgb($body-bg)};\n\n // Fonts\n\n // Note: Use `inspect` for lists so that quoted items keep the quotes.\n // See https://github.com/sass/sass/issues/2383#issuecomment-336349172\n --#{$prefix}font-sans-serif: #{inspect($font-family-sans-serif)};\n --#{$prefix}font-monospace: #{inspect($font-family-monospace)};\n --#{$prefix}gradient: #{$gradient};\n\n // Root and body\n // scss-docs-start root-body-variables\n @if $font-size-root != null {\n --#{$prefix}root-font-size: #{$font-size-root};\n }\n --#{$prefix}body-font-family: #{$font-family-base};\n @include rfs($font-size-base, --#{$prefix}body-font-size);\n --#{$prefix}body-font-weight: #{$font-weight-base};\n --#{$prefix}body-line-height: #{$line-height-base};\n --#{$prefix}body-color: #{$body-color};\n @if $body-text-align != null {\n --#{$prefix}body-text-align: #{$body-text-align};\n }\n --#{$prefix}body-bg: #{$body-bg};\n // scss-docs-end root-body-variables\n\n // scss-docs-start root-border-var\n --#{$prefix}border-width: #{$border-width};\n --#{$prefix}border-style: #{$border-style};\n --#{$prefix}border-color: #{$border-color};\n --#{$prefix}border-color-translucent: #{$border-color-translucent};\n\n --#{$prefix}border-radius: #{$border-radius};\n --#{$prefix}border-radius-sm: #{$border-radius-sm};\n --#{$prefix}border-radius-lg: #{$border-radius-lg};\n --#{$prefix}border-radius-xl: #{$border-radius-xl};\n --#{$prefix}border-radius-2xl: #{$border-radius-2xl};\n --#{$prefix}border-radius-pill: #{$border-radius-pill};\n // scss-docs-end root-border-var\n\n --#{$prefix}link-color: #{$link-color};\n --#{$prefix}link-hover-color: #{$link-hover-color};\n\n --#{$prefix}code-color: #{$code-color};\n\n --#{$prefix}highlight-bg: #{$mark-bg};\n}\n","// stylelint-disable property-blacklist, scss/dollar-variable-default\n\n// SCSS RFS mixin\n//\n// Automated responsive values for font sizes, paddings, margins and much more\n//\n// Licensed under MIT (https://github.com/twbs/rfs/blob/main/LICENSE)\n\n// Configuration\n\n// Base value\n$rfs-base-value: 1.25rem !default;\n$rfs-unit: rem !default;\n\n@if $rfs-unit != rem and $rfs-unit != px {\n @error \"`#{$rfs-unit}` is not a valid unit for $rfs-unit. Use `px` or `rem`.\";\n}\n\n// Breakpoint at where values start decreasing if screen width is smaller\n$rfs-breakpoint: 1200px !default;\n$rfs-breakpoint-unit: px !default;\n\n@if $rfs-breakpoint-unit != px and $rfs-breakpoint-unit != em and $rfs-breakpoint-unit != rem {\n @error \"`#{$rfs-breakpoint-unit}` is not a valid unit for $rfs-breakpoint-unit. Use `px`, `em` or `rem`.\";\n}\n\n// Resize values based on screen height and width\n$rfs-two-dimensional: false !default;\n\n// Factor of decrease\n$rfs-factor: 10 !default;\n\n@if type-of($rfs-factor) != number or $rfs-factor <= 1 {\n @error \"`#{$rfs-factor}` is not a valid $rfs-factor, it must be greater than 1.\";\n}\n\n// Mode. Possibilities: \"min-media-query\", \"max-media-query\"\n$rfs-mode: min-media-query !default;\n\n// Generate enable or disable classes. Possibilities: false, \"enable\" or \"disable\"\n$rfs-class: false !default;\n\n// 1 rem = $rfs-rem-value px\n$rfs-rem-value: 16 !default;\n\n// Safari iframe resize bug: https://github.com/twbs/rfs/issues/14\n$rfs-safari-iframe-resize-bug-fix: false !default;\n\n// Disable RFS by setting $enable-rfs to false\n$enable-rfs: true !default;\n\n// Cache $rfs-base-value unit\n$rfs-base-value-unit: unit($rfs-base-value);\n\n@function divide($dividend, $divisor, $precision: 10) {\n $sign: if($dividend > 0 and $divisor > 0 or $dividend < 0 and $divisor < 0, 1, -1);\n $dividend: abs($dividend);\n $divisor: abs($divisor);\n @if $dividend == 0 {\n @return 0;\n }\n @if $divisor == 0 {\n @error \"Cannot divide by 0\";\n }\n $remainder: $dividend;\n $result: 0;\n $factor: 10;\n @while ($remainder > 0 and $precision >= 0) {\n $quotient: 0;\n @while ($remainder >= $divisor) {\n $remainder: $remainder - $divisor;\n $quotient: $quotient + 1;\n }\n $result: $result * 10 + $quotient;\n $factor: $factor * .1;\n $remainder: $remainder * 10;\n $precision: $precision - 1;\n @if ($precision < 0 and $remainder >= $divisor * 5) {\n $result: $result + 1;\n }\n }\n $result: $result * $factor * $sign;\n $dividend-unit: unit($dividend);\n $divisor-unit: unit($divisor);\n $unit-map: (\n \"px\": 1px,\n \"rem\": 1rem,\n \"em\": 1em,\n \"%\": 1%\n );\n @if ($dividend-unit != $divisor-unit and map-has-key($unit-map, $dividend-unit)) {\n $result: $result * map-get($unit-map, $dividend-unit);\n }\n @return $result;\n}\n\n// Remove px-unit from $rfs-base-value for calculations\n@if $rfs-base-value-unit == px {\n $rfs-base-value: divide($rfs-base-value, $rfs-base-value * 0 + 1);\n}\n@else if $rfs-base-value-unit == rem {\n $rfs-base-value: divide($rfs-base-value, divide($rfs-base-value * 0 + 1, $rfs-rem-value));\n}\n\n// Cache $rfs-breakpoint unit to prevent multiple calls\n$rfs-breakpoint-unit-cache: unit($rfs-breakpoint);\n\n// Remove unit from $rfs-breakpoint for calculations\n@if $rfs-breakpoint-unit-cache == px {\n $rfs-breakpoint: divide($rfs-breakpoint, $rfs-breakpoint * 0 + 1);\n}\n@else if $rfs-breakpoint-unit-cache == rem or $rfs-breakpoint-unit-cache == \"em\" {\n $rfs-breakpoint: divide($rfs-breakpoint, divide($rfs-breakpoint * 0 + 1, $rfs-rem-value));\n}\n\n// Calculate the media query value\n$rfs-mq-value: if($rfs-breakpoint-unit == px, #{$rfs-breakpoint}px, #{divide($rfs-breakpoint, $rfs-rem-value)}#{$rfs-breakpoint-unit});\n$rfs-mq-property-width: if($rfs-mode == max-media-query, max-width, min-width);\n$rfs-mq-property-height: if($rfs-mode == max-media-query, max-height, min-height);\n\n// Internal mixin used to determine which media query needs to be used\n@mixin _rfs-media-query {\n @if $rfs-two-dimensional {\n @if $rfs-mode == max-media-query {\n @media (#{$rfs-mq-property-width}: #{$rfs-mq-value}), (#{$rfs-mq-property-height}: #{$rfs-mq-value}) {\n @content;\n }\n }\n @else {\n @media (#{$rfs-mq-property-width}: #{$rfs-mq-value}) and (#{$rfs-mq-property-height}: #{$rfs-mq-value}) {\n @content;\n }\n }\n }\n @else {\n @media (#{$rfs-mq-property-width}: #{$rfs-mq-value}) {\n @content;\n }\n }\n}\n\n// Internal mixin that adds disable classes to the selector if needed.\n@mixin _rfs-rule {\n @if $rfs-class == disable and $rfs-mode == max-media-query {\n // Adding an extra class increases specificity, which prevents the media query to override the property\n &,\n .disable-rfs &,\n &.disable-rfs {\n @content;\n }\n }\n @else if $rfs-class == enable and $rfs-mode == min-media-query {\n .enable-rfs &,\n &.enable-rfs {\n @content;\n }\n }\n @else {\n @content;\n }\n}\n\n// Internal mixin that adds enable classes to the selector if needed.\n@mixin _rfs-media-query-rule {\n\n @if $rfs-class == enable {\n @if $rfs-mode == min-media-query {\n @content;\n }\n\n @include _rfs-media-query {\n .enable-rfs &,\n &.enable-rfs {\n @content;\n }\n }\n }\n @else {\n @if $rfs-class == disable and $rfs-mode == min-media-query {\n .disable-rfs &,\n &.disable-rfs {\n @content;\n }\n }\n @include _rfs-media-query {\n @content;\n }\n }\n}\n\n// Helper function to get the formatted non-responsive value\n@function rfs-value($values) {\n // Convert to list\n $values: if(type-of($values) != list, ($values,), $values);\n\n $val: '';\n\n // Loop over each value and calculate value\n @each $value in $values {\n @if $value == 0 {\n $val: $val + ' 0';\n }\n @else {\n // Cache $value unit\n $unit: if(type-of($value) == \"number\", unit($value), false);\n\n @if $unit == px {\n // Convert to rem if needed\n $val: $val + ' ' + if($rfs-unit == rem, #{divide($value, $value * 0 + $rfs-rem-value)}rem, $value);\n }\n @else if $unit == rem {\n // Convert to px if needed\n $val: $val + ' ' + if($rfs-unit == px, #{divide($value, $value * 0 + 1) * $rfs-rem-value}px, $value);\n }\n @else {\n // If $value isn't a number (like inherit) or $value has a unit (not px or rem, like 1.5em) or $ is 0, just print the value\n $val: $val + ' ' + $value;\n }\n }\n }\n\n // Remove first space\n @return unquote(str-slice($val, 2));\n}\n\n// Helper function to get the responsive value calculated by RFS\n@function rfs-fluid-value($values) {\n // Convert to list\n $values: if(type-of($values) != list, ($values,), $values);\n\n $val: '';\n\n // Loop over each value and calculate value\n @each $value in $values {\n @if $value == 0 {\n $val: $val + ' 0';\n }\n\n @else {\n // Cache $value unit\n $unit: if(type-of($value) == \"number\", unit($value), false);\n\n // If $value isn't a number (like inherit) or $value has a unit (not px or rem, like 1.5em) or $ is 0, just print the value\n @if not $unit or $unit != px and $unit != rem {\n $val: $val + ' ' + $value;\n }\n\n @else {\n // Remove unit from $value for calculations\n $value: divide($value, $value * 0 + if($unit == px, 1, divide(1, $rfs-rem-value)));\n\n // Only add the media query if the value is greater than the minimum value\n @if abs($value) <= $rfs-base-value or not $enable-rfs {\n $val: $val + ' ' + if($rfs-unit == rem, #{divide($value, $rfs-rem-value)}rem, #{$value}px);\n }\n @else {\n // Calculate the minimum value\n $value-min: $rfs-base-value + divide(abs($value) - $rfs-base-value, $rfs-factor);\n\n // Calculate difference between $value and the minimum value\n $value-diff: abs($value) - $value-min;\n\n // Base value formatting\n $min-width: if($rfs-unit == rem, #{divide($value-min, $rfs-rem-value)}rem, #{$value-min}px);\n\n // Use negative value if needed\n $min-width: if($value < 0, -$min-width, $min-width);\n\n // Use `vmin` if two-dimensional is enabled\n $variable-unit: if($rfs-two-dimensional, vmin, vw);\n\n // Calculate the variable width between 0 and $rfs-breakpoint\n $variable-width: #{divide($value-diff * 100, $rfs-breakpoint)}#{$variable-unit};\n\n // Return the calculated value\n $val: $val + ' calc(' + $min-width + if($value < 0, ' - ', ' + ') + $variable-width + ')';\n }\n }\n }\n }\n\n // Remove first space\n @return unquote(str-slice($val, 2));\n}\n\n// RFS mixin\n@mixin rfs($values, $property: font-size) {\n @if $values != null {\n $val: rfs-value($values);\n $fluidVal: rfs-fluid-value($values);\n\n // Do not print the media query if responsive & non-responsive values are the same\n @if $val == $fluidVal {\n #{$property}: $val;\n }\n @else {\n @include _rfs-rule {\n #{$property}: if($rfs-mode == max-media-query, $val, $fluidVal);\n\n // Include safari iframe resize fix if needed\n min-width: if($rfs-safari-iframe-resize-bug-fix, (0 * 1vw), null);\n }\n\n @include _rfs-media-query-rule {\n #{$property}: if($rfs-mode == max-media-query, $fluidVal, $val);\n }\n }\n }\n}\n\n// Shorthand helper mixins\n@mixin font-size($value) {\n @include rfs($value);\n}\n\n@mixin padding($value) {\n @include rfs($value, padding);\n}\n\n@mixin padding-top($value) {\n @include rfs($value, padding-top);\n}\n\n@mixin padding-right($value) {\n @include rfs($value, padding-right);\n}\n\n@mixin padding-bottom($value) {\n @include rfs($value, padding-bottom);\n}\n\n@mixin padding-left($value) {\n @include rfs($value, padding-left);\n}\n\n@mixin margin($value) {\n @include rfs($value, margin);\n}\n\n@mixin margin-top($value) {\n @include rfs($value, margin-top);\n}\n\n@mixin margin-right($value) {\n @include rfs($value, margin-right);\n}\n\n@mixin margin-bottom($value) {\n @include rfs($value, margin-bottom);\n}\n\n@mixin margin-left($value) {\n @include rfs($value, margin-left);\n}\n","// stylelint-disable declaration-no-important, selector-no-qualifying-type, property-no-vendor-prefix\n\n\n// Reboot\n//\n// Normalization of HTML elements, manually forked from Normalize.css to remove\n// styles targeting irrelevant browsers while applying new styles.\n//\n// Normalize is licensed MIT. https://github.com/necolas/normalize.css\n\n\n// Document\n//\n// Change from `box-sizing: content-box` so that `width` is not affected by `padding` or `border`.\n\n*,\n*::before,\n*::after {\n box-sizing: border-box;\n}\n\n\n// Root\n//\n// Ability to the value of the root font sizes, affecting the value of `rem`.\n// null by default, thus nothing is generated.\n\n:root {\n @if $font-size-root != null {\n @include font-size(var(--#{$prefix}root-font-size));\n }\n\n @if $enable-smooth-scroll {\n @media (prefers-reduced-motion: no-preference) {\n scroll-behavior: smooth;\n }\n }\n}\n\n\n// Body\n//\n// 1. Remove the margin in all browsers.\n// 2. As a best practice, apply a default `background-color`.\n// 3. Prevent adjustments of font size after orientation changes in iOS.\n// 4. Change the default tap highlight to be completely transparent in iOS.\n\n// scss-docs-start reboot-body-rules\nbody {\n margin: 0; // 1\n font-family: var(--#{$prefix}body-font-family);\n @include font-size(var(--#{$prefix}body-font-size));\n font-weight: var(--#{$prefix}body-font-weight);\n line-height: var(--#{$prefix}body-line-height);\n color: var(--#{$prefix}body-color);\n text-align: var(--#{$prefix}body-text-align);\n background-color: var(--#{$prefix}body-bg); // 2\n -webkit-text-size-adjust: 100%; // 3\n -webkit-tap-highlight-color: rgba($black, 0); // 4\n}\n// scss-docs-end reboot-body-rules\n\n\n// Content grouping\n//\n// 1. Reset Firefox's gray color\n\nhr {\n margin: $hr-margin-y 0;\n color: $hr-color; // 1\n border: 0;\n border-top: $hr-border-width solid $hr-border-color;\n opacity: $hr-opacity;\n}\n\n\n// Typography\n//\n// 1. Remove top margins from headings\n// By default, `

`-`

` all receive top and bottom margins. We nuke the top\n// margin for easier control within type scales as it avoids margin collapsing.\n\n%heading {\n margin-top: 0; // 1\n margin-bottom: $headings-margin-bottom;\n font-family: $headings-font-family;\n font-style: $headings-font-style;\n font-weight: $headings-font-weight;\n line-height: $headings-line-height;\n color: $headings-color;\n}\n\nh1 {\n @extend %heading;\n @include font-size($h1-font-size);\n}\n\nh2 {\n @extend %heading;\n @include font-size($h2-font-size);\n}\n\nh3 {\n @extend %heading;\n @include font-size($h3-font-size);\n}\n\nh4 {\n @extend %heading;\n @include font-size($h4-font-size);\n}\n\nh5 {\n @extend %heading;\n @include font-size($h5-font-size);\n}\n\nh6 {\n @extend %heading;\n @include font-size($h6-font-size);\n}\n\n\n// Reset margins on paragraphs\n//\n// Similarly, the top margin on `

`s get reset. However, we also reset the\n// bottom margin to use `rem` units instead of `em`.\n\np {\n margin-top: 0;\n margin-bottom: $paragraph-margin-bottom;\n}\n\n\n// Abbreviations\n//\n// 1. Add the correct text decoration in Chrome, Edge, Opera, and Safari.\n// 2. Add explicit cursor to indicate changed behavior.\n// 3. Prevent the text-decoration to be skipped.\n\nabbr[title] {\n text-decoration: underline dotted; // 1\n cursor: help; // 2\n text-decoration-skip-ink: none; // 3\n}\n\n\n// Address\n\naddress {\n margin-bottom: 1rem;\n font-style: normal;\n line-height: inherit;\n}\n\n\n// Lists\n\nol,\nul {\n padding-left: 2rem;\n}\n\nol,\nul,\ndl {\n margin-top: 0;\n margin-bottom: 1rem;\n}\n\nol ol,\nul ul,\nol ul,\nul ol {\n margin-bottom: 0;\n}\n\ndt {\n font-weight: $dt-font-weight;\n}\n\n// 1. Undo browser default\n\ndd {\n margin-bottom: .5rem;\n margin-left: 0; // 1\n}\n\n\n// Blockquote\n\nblockquote {\n margin: 0 0 1rem;\n}\n\n\n// Strong\n//\n// Add the correct font weight in Chrome, Edge, and Safari\n\nb,\nstrong {\n font-weight: $font-weight-bolder;\n}\n\n\n// Small\n//\n// Add the correct font size in all browsers\n\nsmall {\n @include font-size($small-font-size);\n}\n\n\n// Mark\n\nmark {\n padding: $mark-padding;\n background-color: var(--#{$prefix}highlight-bg);\n}\n\n\n// Sub and Sup\n//\n// Prevent `sub` and `sup` elements from affecting the line height in\n// all browsers.\n\nsub,\nsup {\n position: relative;\n @include font-size($sub-sup-font-size);\n line-height: 0;\n vertical-align: baseline;\n}\n\nsub { bottom: -.25em; }\nsup { top: -.5em; }\n\n\n// Links\n\na {\n color: var(--#{$prefix}link-color);\n text-decoration: $link-decoration;\n\n &:hover {\n color: var(--#{$prefix}link-hover-color);\n text-decoration: $link-hover-decoration;\n }\n}\n\n// And undo these styles for placeholder links/named anchors (without href).\n// It would be more straightforward to just use a[href] in previous block, but that\n// causes specificity issues in many other styles that are too complex to fix.\n// See https://github.com/twbs/bootstrap/issues/19402\n\na:not([href]):not([class]) {\n &,\n &:hover {\n color: inherit;\n text-decoration: none;\n }\n}\n\n\n// Code\n\npre,\ncode,\nkbd,\nsamp {\n font-family: $font-family-code;\n @include font-size(1em); // Correct the odd `em` font sizing in all browsers.\n}\n\n// 1. Remove browser default top margin\n// 2. Reset browser default of `1em` to use `rem`s\n// 3. Don't allow content to break outside\n\npre {\n display: block;\n margin-top: 0; // 1\n margin-bottom: 1rem; // 2\n overflow: auto; // 3\n @include font-size($code-font-size);\n color: $pre-color;\n\n // Account for some code outputs that place code tags in pre tags\n code {\n @include font-size(inherit);\n color: inherit;\n word-break: normal;\n }\n}\n\ncode {\n @include font-size($code-font-size);\n color: var(--#{$prefix}code-color);\n word-wrap: break-word;\n\n // Streamline the style when inside anchors to avoid broken underline and more\n a > & {\n color: inherit;\n }\n}\n\nkbd {\n padding: $kbd-padding-y $kbd-padding-x;\n @include font-size($kbd-font-size);\n color: $kbd-color;\n background-color: $kbd-bg;\n @include border-radius($border-radius-sm);\n\n kbd {\n padding: 0;\n @include font-size(1em);\n font-weight: $nested-kbd-font-weight;\n }\n}\n\n\n// Figures\n//\n// Apply a consistent margin strategy (matches our type styles).\n\nfigure {\n margin: 0 0 1rem;\n}\n\n\n// Images and content\n\nimg,\nsvg {\n vertical-align: middle;\n}\n\n\n// Tables\n//\n// Prevent double borders\n\ntable {\n caption-side: bottom;\n border-collapse: collapse;\n}\n\ncaption {\n padding-top: $table-cell-padding-y;\n padding-bottom: $table-cell-padding-y;\n color: $table-caption-color;\n text-align: left;\n}\n\n// 1. Removes font-weight bold by inheriting\n// 2. Matches default `` alignment by inheriting `text-align`.\n// 3. Fix alignment for Safari\n\nth {\n font-weight: $table-th-font-weight; // 1\n text-align: inherit; // 2\n text-align: -webkit-match-parent; // 3\n}\n\nthead,\ntbody,\ntfoot,\ntr,\ntd,\nth {\n border-color: inherit;\n border-style: solid;\n border-width: 0;\n}\n\n\n// Forms\n//\n// 1. Allow labels to use `margin` for spacing.\n\nlabel {\n display: inline-block; // 1\n}\n\n// Remove the default `border-radius` that macOS Chrome adds.\n// See https://github.com/twbs/bootstrap/issues/24093\n\nbutton {\n // stylelint-disable-next-line property-disallowed-list\n border-radius: 0;\n}\n\n// Explicitly remove focus outline in Chromium when it shouldn't be\n// visible (e.g. as result of mouse click or touch tap). It already\n// should be doing this automatically, but seems to currently be\n// confused and applies its very visible two-tone outline anyway.\n\nbutton:focus:not(:focus-visible) {\n outline: 0;\n}\n\n// 1. Remove the margin in Firefox and Safari\n\ninput,\nbutton,\nselect,\noptgroup,\ntextarea {\n margin: 0; // 1\n font-family: inherit;\n @include font-size(inherit);\n line-height: inherit;\n}\n\n// Remove the inheritance of text transform in Firefox\nbutton,\nselect {\n text-transform: none;\n}\n// Set the cursor for non-` {% 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) { diff --git a/lxconsole/templates/certificates.html b/lxconsole/templates/certificates.html index 55c6141..d318787 100644 --- a/lxconsole/templates/certificates.html +++ b/lxconsole/templates/certificates.html @@ -6,9 +6,9 @@

{{ page_title | safe }}

{% 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) { diff --git a/lxconsole/templates/cluster-groups.html b/lxconsole/templates/cluster-groups.html index 4519ead..fc18089 100644 --- a/lxconsole/templates/cluster-groups.html +++ b/lxconsole/templates/cluster-groups.html @@ -6,9 +6,9 @@

{{ page_title | safe }}

{% 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) { diff --git a/lxconsole/templates/cluster-members.html b/lxconsole/templates/cluster-members.html index 37a3bed..91ae516 100644 --- a/lxconsole/templates/cluster-members.html +++ b/lxconsole/templates/cluster-members.html @@ -7,9 +7,9 @@ @@ -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) { diff --git a/lxconsole/templates/containers.html b/lxconsole/templates/containers.html deleted file mode 100644 index f83fa0b..0000000 --- a/lxconsole/templates/containers.html +++ /dev/null @@ -1,332 +0,0 @@ -{% extends "main.html" %} - -{% block header %} -
-
-

{{ page_title | safe }}

-
- -
-{% endblock header %} - -{% block content %} -
-
-
-

Containers

-
- -
-
-
- -
-
-
-
-{% endblock content %} - -{% block modal %} - {% include 'modals/containers.html' %} -{% endblock modal %} - -{% block script %} - -{% endblock script %} \ No newline at end of file diff --git a/lxconsole/templates/groups.html b/lxconsole/templates/groups.html index b853424..8b188c4 100644 --- a/lxconsole/templates/groups.html +++ b/lxconsole/templates/groups.html @@ -6,9 +6,9 @@

{{ page_title | safe }}

{% 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) { diff --git a/lxconsole/templates/head.html b/lxconsole/templates/head.html index aa922aa..80aee92 100644 --- a/lxconsole/templates/head.html +++ b/lxconsole/templates/head.html @@ -10,10 +10,11 @@ - - - - + + + + + @@ -24,11 +25,6 @@ - - - - - diff --git a/lxconsole/templates/images.html b/lxconsole/templates/images.html index cbf8e2d..cb6cbb1 100644 --- a/lxconsole/templates/images.html +++ b/lxconsole/templates/images.html @@ -6,9 +6,9 @@

{{ page_title | safe }}

{% 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) { diff --git a/lxconsole/templates/container.html b/lxconsole/templates/instance.html similarity index 84% rename from lxconsole/templates/container.html rename to lxconsole/templates/instance.html index 4eeeb62..8047e9b 100644 --- a/lxconsole/templates/container.html +++ b/lxconsole/templates/instance.html @@ -6,10 +6,9 @@

{{ page_title | safe }}

- - @@ -49,11 +48,11 @@
@@ -107,11 +106,11 @@ Backups
@@ -193,19 +192,20 @@
+ + + + + +{% endblock content %} + +{% block modal %} + {% include 'modals/instances.html' %} +{% endblock modal %} + +{% block script %} + +{% endblock script %} \ No newline at end of file diff --git a/lxconsole/templates/logs.html b/lxconsole/templates/logs.html index 0d4e9ac..b021d3a 100644 --- a/lxconsole/templates/logs.html +++ b/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) { diff --git a/lxconsole/templates/main.html b/lxconsole/templates/main.html index a79df90..8d756fb 100644 --- a/lxconsole/templates/main.html +++ b/lxconsole/templates/main.html @@ -3,7 +3,7 @@ {% include 'head.html' %} - +
@@ -40,7 +40,7 @@
- Version 0.3.0 + Version 0.4.0
Copyright © 2020-Present Penning Labs. All rights reserved.
@@ -51,20 +51,15 @@ + + + - + - + - - - - - - - - diff --git a/lxconsole/templates/modals/access-controls.html b/lxconsole/templates/modals/access-controls.html index 66b9c21..d4d9b84 100644 --- a/lxconsole/templates/modals/access-controls.html +++ b/lxconsole/templates/modals/access-controls.html @@ -4,7 +4,7 @@
diff --git a/lxconsole/templates/modals/cluster-groups.html b/lxconsole/templates/modals/cluster-groups.html index b2f9638..98369b0 100644 --- a/lxconsole/templates/modals/cluster-groups.html +++ b/lxconsole/templates/modals/cluster-groups.html @@ -4,17 +4,17 @@ @@ -89,17 +89,17 @@
@@ -136,8 +136,8 @@
@@ -152,7 +152,7 @@ diff --git a/lxconsole/templates/modals/cluster-members.html b/lxconsole/templates/modals/cluster-members.html index fd80f59..2180f44 100644 --- a/lxconsole/templates/modals/cluster-members.html +++ b/lxconsole/templates/modals/cluster-members.html @@ -4,17 +4,17 @@ @@ -77,17 +77,17 @@
@@ -125,8 +125,8 @@
@@ -141,7 +141,7 @@ diff --git a/lxconsole/templates/modals/groups.html b/lxconsole/templates/modals/groups.html index dcfee82..f2cef27 100644 --- a/lxconsole/templates/modals/groups.html +++ b/lxconsole/templates/modals/groups.html @@ -4,7 +4,7 @@ @@ -53,7 +53,7 @@ diff --git a/lxconsole/templates/modals/images.html b/lxconsole/templates/modals/images.html index be2411b..ea1b0a4 100644 --- a/lxconsole/templates/modals/images.html +++ b/lxconsole/templates/modals/images.html @@ -4,17 +4,17 @@ @@ -143,7 +143,7 @@ diff --git a/lxconsole/templates/modals/container.html b/lxconsole/templates/modals/instance.html similarity index 84% rename from lxconsole/templates/modals/container.html rename to lxconsole/templates/modals/instance.html index 2a7a33d..8831ef2 100644 --- a/lxconsole/templates/modals/container.html +++ b/lxconsole/templates/modals/instance.html @@ -1,11 +1,10 @@ - @@ -81,7 +80,7 @@ @@ -113,7 +112,7 @@ @@ -144,7 +143,7 @@ @@ -176,7 +175,7 @@ @@ -244,7 +243,7 @@ @@ -372,7 +371,7 @@ @@ -404,7 +403,7 @@