mirror of https://git.48k.eu/ogcp
482 lines
18 KiB
Python
482 lines
18 KiB
Python
from flask import g, render_template, url_for, redirect, request, jsonify, make_response
|
|
from ogcp.forms.action_forms import (
|
|
WOLForm, PartitionForm, ClientDetailsForm, HardwareForm, SessionForm,
|
|
ImageRestoreForm, ImageCreateForm, SoftwareForm
|
|
)
|
|
from ogcp.og_server import OGServer
|
|
from flask_babel import _
|
|
from ogcp import app
|
|
import requests
|
|
|
|
FS_CODES = {
|
|
0: 'DISK',
|
|
1: 'EMPTY',
|
|
2: 'CACHE',
|
|
6: 'EXT4',
|
|
13: 'NTFS'
|
|
}
|
|
|
|
PART_TYPE_CODES = {
|
|
0: 'EMPTY',
|
|
1: 'DISK',
|
|
7: 'NTFS',
|
|
131: 'LINUX',
|
|
202: 'CACHE',
|
|
218: 'DATA'
|
|
}
|
|
|
|
PART_SCHEME_CODES = {
|
|
1: 'MSDOS',
|
|
2: 'GPT'
|
|
}
|
|
|
|
def parse_ips(checkboxes_dict):
|
|
ips = set()
|
|
for key, ips_list in checkboxes_dict.items():
|
|
if key != 'csrf_token':
|
|
ips.update(ips_list.split(' '))
|
|
return ips
|
|
|
|
def get_client_setup(ip):
|
|
payload = payload = {'client': list(ip)}
|
|
r = g.server.get('/client/setup', payload)
|
|
db_partitions = r.json()['partitions']
|
|
for partition in db_partitions:
|
|
if partition['partition'] == 0:
|
|
partition['code'] = PART_SCHEME_CODES[partition['code']]
|
|
else:
|
|
partition['code'] = PART_TYPE_CODES[partition['code']]
|
|
|
|
partition['filesystem'] = FS_CODES[partition['filesystem']]
|
|
return db_partitions
|
|
|
|
def parse_scopes_from_tree(tree, scope_type):
|
|
scopes = []
|
|
for scope in tree['scope']:
|
|
if scope['type'] == scope_type:
|
|
scopes.append(scope)
|
|
else:
|
|
scopes += parse_scopes_from_tree(scope, scope_type)
|
|
return scopes
|
|
|
|
@app.before_request
|
|
def load_config():
|
|
g.server = OGServer()
|
|
|
|
@app.errorhandler(404)
|
|
def page_not_found(error):
|
|
return render_template('error.html', message=error), 404
|
|
|
|
@app.errorhandler(500)
|
|
def server_error(error):
|
|
return render_template('error.html', message=error), 500
|
|
|
|
@app.route('/')
|
|
def index():
|
|
return render_template('base.html')
|
|
|
|
@app.route('/scopes/')
|
|
def scopes():
|
|
def add_state_and_ips(scope, clients):
|
|
if 'ip' in scope:
|
|
filtered_client = filter(lambda x: x['addr']==scope['ip'], clients)
|
|
client = next(filtered_client, False)
|
|
if client:
|
|
scope['state'] = client['state']
|
|
else:
|
|
scope['state'] = 'OFF'
|
|
scope['ip'] = [scope['ip']]
|
|
else:
|
|
scope['ip'] = []
|
|
for child in scope['scope']:
|
|
scope['ip'] += add_state_and_ips(child, clients)
|
|
return scope['ip']
|
|
|
|
r = g.server.get('/scopes')
|
|
scopes = r.json()
|
|
r = g.server.get('/clients')
|
|
clients = r.json()
|
|
add_state_and_ips(scopes, clients['clients'])
|
|
return render_template('scopes.html', scopes=scopes, clients=clients)
|
|
|
|
@app.route('/action/poweroff', methods=['POST'])
|
|
def action_poweroff():
|
|
ips = parse_ips(request.form.to_dict())
|
|
payload = {'clients': list(ips)}
|
|
g.server.post('/poweroff', payload)
|
|
return make_response("200 OK", 200)
|
|
|
|
@app.route('/action/wol', methods=['GET', 'POST'])
|
|
def action_wol():
|
|
form = WOLForm(request.form)
|
|
if request.method == 'POST' and form.validate():
|
|
wol_type = form.wol_type.data
|
|
ips = parse_ips(request.form.to_dict())
|
|
payload = {'type': wol_type, 'clients': list(ips)}
|
|
g.server.post('/wol', payload)
|
|
return make_response("200 OK", 200)
|
|
else:
|
|
ips = parse_ips(request.args.to_dict())
|
|
form.ips.data = " ".join(ips)
|
|
return render_template('actions/wol.html', form=form)
|
|
|
|
@app.route('/action/setup', methods=['GET'])
|
|
def action_setup_show():
|
|
ips = parse_ips(request.args.to_dict())
|
|
db_partitions = get_client_setup(ips)
|
|
forms = [PartitionForm() for _ in db_partitions]
|
|
forms = list(forms)
|
|
|
|
for form, db_part in zip(forms, db_partitions):
|
|
form.ips.data = " ".join(ips)
|
|
form.disk.data = db_part['disk']
|
|
form.partition.data = db_part['partition']
|
|
# XXX: Should separate whole disk form from partition setup form
|
|
if db_part['code'] in PART_SCHEME_CODES.values():
|
|
form.part_type.choices = list(PART_SCHEME_CODES.values())
|
|
form.part_type.data = db_part['code']
|
|
form.fs.data = db_part['filesystem']
|
|
form.size.data = db_part['size']
|
|
form.modify.render_kw = {"formaction": url_for('action_setup_modify')}
|
|
form.delete.render_kw = {"formaction": url_for('action_setup_delete')}
|
|
return render_template('actions/setup.html', forms=forms)
|
|
|
|
@app.route('/action/setup/modify', methods=['POST'])
|
|
def action_setup_modify():
|
|
form = PartitionForm(request.form)
|
|
if form.validate():
|
|
ips = form.ips.data.split(' ')
|
|
db_partitions = get_client_setup(ips)
|
|
|
|
payload = {'clients': ips,
|
|
'disk': str(form.disk.data),
|
|
'cache': str(0),
|
|
'cache_size': str(0),
|
|
'partition_setup': []}
|
|
|
|
for db_part in db_partitions:
|
|
if db_part['partition'] == 0:
|
|
# Set partition scheme
|
|
payload['type'] = db_part['code']
|
|
continue
|
|
partition_setup = {'partition': str(db_part['partition']),
|
|
'code': db_part['code'],
|
|
'filesystem': db_part['filesystem'],
|
|
'size': str(db_part['size']),
|
|
'format': str(int(False))}
|
|
payload['partition_setup'].append(partition_setup)
|
|
|
|
# Ensure a 4 partition setup
|
|
for i in range(len(db_partitions), 5):
|
|
empty_part = {
|
|
'partition': str(i),
|
|
'code': 'EMPTY',
|
|
'filesystem': 'EMPTY',
|
|
'size': '0',
|
|
'format': '0',
|
|
}
|
|
payload['partition_setup'].append(empty_part)
|
|
|
|
modified_part = payload['partition_setup'][int(form.partition.data) - 1]
|
|
modified_part['filesystem'] = str(form.fs.data)
|
|
modified_part['code'] = str(form.part_type.data)
|
|
modified_part['size'] = str(form.size.data)
|
|
modified_part['format'] = str(int(form.format_partition.data))
|
|
|
|
r = g.server.post('/setup', payload=payload)
|
|
if r.status_code == requests.codes.ok:
|
|
return redirect(url_for("scopes"))
|
|
return make_response("400 Bad Request", 400)
|
|
|
|
@app.route('/action/setup/delete', methods=['POST'])
|
|
def action_setup_delete():
|
|
form = PartitionForm(request.form)
|
|
if form.validate():
|
|
ips = form.ips.data.split(' ')
|
|
db_partitions = get_client_setup(ips)
|
|
|
|
payload = {'clients': ips,
|
|
'disk': str(form.disk.data),
|
|
'cache': str(0),
|
|
'cache_size': str(0),
|
|
'partition_setup': []}
|
|
|
|
for db_part in db_partitions:
|
|
if db_part['partition'] == 0:
|
|
# Skip if this is disk setup.
|
|
continue
|
|
partition_setup = {'partition': str(db_part['partition']),
|
|
'code': db_part['code'],
|
|
'filesystem': db_part['filesystem'],
|
|
'size': str(db_part['size']),
|
|
'format': str(int(False))}
|
|
payload['partition_setup'].append(partition_setup)
|
|
|
|
modified_part = payload['partition_setup'][int(form.partition.data) - 1]
|
|
modified_part['filesystem'] = FS_CODES[1]
|
|
modified_part['code'] = PART_TYPE_CODES[0]
|
|
modified_part['size'] = str(0)
|
|
modified_part['format'] = str(int(True))
|
|
|
|
r = g.server.post('/setup', payload=payload)
|
|
if r.status_code == requests.codes.ok:
|
|
return make_response("200 OK", 200)
|
|
return make_response("400 Bad Request", 400)
|
|
|
|
@app.route('/action/image/restore', methods=['GET', 'POST'])
|
|
def action_image_restore():
|
|
def search_image(images_list, image_id):
|
|
for image in images_list:
|
|
if image['id'] == image_id:
|
|
return image
|
|
return False
|
|
|
|
form = ImageRestoreForm(request.form)
|
|
if request.method == 'POST':
|
|
ips = form.ips.data.split(' ')
|
|
disk, partition = form.partition.data.split(' ')
|
|
image_id = form.image.data
|
|
r = g.server.get('/images')
|
|
images_list = r.json()['images']
|
|
image = search_image(images_list, int(image_id))
|
|
if not image:
|
|
return make_response("400 Bad Request", 400)
|
|
|
|
payload = {'disk': disk,
|
|
'partition': partition,
|
|
'name': image['name'],
|
|
'repository': g.server.ip,
|
|
'clients': ips,
|
|
'type': form.method.data,
|
|
'profile': str(image['software_id']),
|
|
'id': str(image['id'])}
|
|
g.server.post('/image/restore', payload)
|
|
if r.status_code == requests.codes.ok:
|
|
return make_response("200 OK", 200)
|
|
return make_response("400 Bad Request", 400)
|
|
else:
|
|
ips = parse_ips(request.args.to_dict())
|
|
form.ips.data = ' '.join(ips)
|
|
r = g.server.get('/images')
|
|
for image in r.json()['images']:
|
|
form.image.choices.append((image['id'], image['name']))
|
|
r = g.server.get('/client/setup', payload={'client': list(ips)})
|
|
for partition in r.json()['partitions']:
|
|
disk_id = partition['disk']
|
|
part_id = partition['partition']
|
|
fs_id = partition['filesystem']
|
|
|
|
if part_id == 0:
|
|
# This is the disk data, not a partition.
|
|
continue
|
|
|
|
choice_value = f"{disk_id} {part_id}"
|
|
choice_name = (f"{_('Disk')} {disk_id} - "
|
|
f"{_('Partition')} {part_id} - "
|
|
f"{_('FS')} {FS_CODES[fs_id]}")
|
|
form.partition.choices.append((choice_value, choice_name))
|
|
return render_template('actions/image_restore.html', form=form)
|
|
|
|
@app.route('/action/hardware', methods=['GET', 'POST'])
|
|
def action_hardware():
|
|
form = HardwareForm(request.form)
|
|
if request.method == 'POST':
|
|
ips = form.ips.data.split(' ')
|
|
r = g.server.post('/hardware', payload={'clients': ips})
|
|
if r.status_code == requests.codes.ok:
|
|
return make_response("200 OK", 200)
|
|
return make_response("400 Bad Request", 400)
|
|
else:
|
|
ips = parse_ips(request.args.to_dict())
|
|
form.ips.data = ' '.join(ips)
|
|
r = g.server.get('/hardware', payload={'client': list(ips)})
|
|
hardware = r.json()['hardware']
|
|
return render_template('actions/hardware.html', form=form,
|
|
hardware=hardware)
|
|
|
|
@app.route('/action/software', methods=['GET', 'POST'])
|
|
def action_software():
|
|
form = SoftwareForm(request.form)
|
|
if request.method == 'POST':
|
|
ips = form.ips.data.split(' ')
|
|
disk, partition = form.os.data.split(' ')
|
|
if form.view.data:
|
|
r = g.server.get('/software', payload={'client': ips,
|
|
'disk': int(disk),
|
|
'partition': int(partition)})
|
|
if r.status_code == requests.codes.ok:
|
|
return r.json()
|
|
|
|
elif form.update.data:
|
|
r = g.server.post('/software', payload={'clients': ips,
|
|
'disk': disk,
|
|
'partition': partition})
|
|
if r.status_code == requests.codes.ok:
|
|
return make_response(f"Se generó correctamente el perfil "
|
|
f"software de {ips[0]} D:{disk} "
|
|
f"P:{partition}",
|
|
200)
|
|
|
|
return make_response("400 Bad Request", 400)
|
|
else:
|
|
ips = parse_ips(request.args.to_dict())
|
|
form.ips.data = ' '.join(ips)
|
|
r = g.server.get('/client/setup', payload={'client': list(ips)})
|
|
|
|
for part in r.json()['partitions'][1:]:
|
|
form.os.choices.append(
|
|
(f"{part.get('disk')} {part.get('partition')}",
|
|
f"Disco {part.get('disk')} | Partición {part.get('partition')} "
|
|
f"| {PART_TYPE_CODES[part.get('code')]} "
|
|
f"{FS_CODES[part.get('filesystem')]}")
|
|
)
|
|
return render_template('actions/software.html', form=form)
|
|
|
|
@app.route('/action/session', methods=['GET', 'POST'])
|
|
def action_session():
|
|
form = SessionForm(request.form)
|
|
if request.method == 'POST':
|
|
ips = form.ips.data.split(' ')
|
|
disk, partition = form.os.data.split(' ')
|
|
r = g.server.post('/session', payload={'clients': ips,
|
|
'disk': str(disk),
|
|
'partition': str(partition)})
|
|
if r.status_code == requests.codes.ok:
|
|
return make_response("200 OK", 200)
|
|
return make_response("400 Bad Request", 400)
|
|
else:
|
|
ips = parse_ips(request.args.to_dict())
|
|
form.ips.data = ' '.join(ips)
|
|
r = g.server.get('/session', payload={'client': list(ips)})
|
|
sessions = r.json()['sessions']
|
|
for os in sessions:
|
|
choice = (f"{os['disk']} {os['partition']}",
|
|
f"{os['name']} ({os['disk']},{os['partition']})")
|
|
form.os.choices.append(choice)
|
|
return render_template('actions/session.html', form=form)
|
|
|
|
@app.route('/action/client/info', methods=['GET'])
|
|
def action_client_info():
|
|
form = ClientDetailsForm()
|
|
ips = parse_ips(request.args.to_dict())
|
|
payload = {'client': list(ips)}
|
|
r = g.server.get('/client/info', payload)
|
|
db_client = r.json()
|
|
|
|
form.name.data = db_client['name']
|
|
form.ip.data = db_client['ip']
|
|
form.mac.data = db_client['mac']
|
|
form.serial_number.data = db_client['serial_number']
|
|
form.netmask.data = db_client['netmask']
|
|
form.livedir.data = db_client['livedir']
|
|
form.remote.data = db_client['remote']
|
|
form.maintenance.data = db_client['maintenance']
|
|
form.netiface.data = db_client['netiface']
|
|
form.netdriver.data = db_client['netdriver']
|
|
form.repo.data = db_client['repo_id']
|
|
form.room.data = db_client['room']
|
|
form.boot.data = db_client['boot']
|
|
|
|
r = g.server.get('/mode')
|
|
available_modes = [(mode, mode) for mode in r.json()['modes']]
|
|
form.boot.choices = list(available_modes)
|
|
|
|
r = g.server.get('/scopes')
|
|
rooms = parse_scopes_from_tree(r.json(), 'room')
|
|
rooms = [(room['id'], room['name']) for room in rooms]
|
|
form.room.choices = list(rooms)
|
|
|
|
form.create.render_kw = {"style": "visibility:hidden;"}
|
|
return render_template('actions/client_details.html', form=form)
|
|
|
|
@app.route('/action/client/add', methods=['GET', 'POST'])
|
|
def action_client_add():
|
|
form = ClientDetailsForm(request.form)
|
|
if request.method == 'POST':
|
|
payload = {"boot": form.boot.data,
|
|
"ip": form.ip.data,
|
|
"livedir": form.livedir.data,
|
|
"mac": form.mac.data,
|
|
"maintenance": form.maintenance.data,
|
|
"name": form.name.data,
|
|
"netdriver": form.netdriver.data,
|
|
"netiface": form.netiface.data,
|
|
"netmask": form.netmask.data,
|
|
"remote": form.remote.data,
|
|
"repo_id": int(form.repo.data),
|
|
"room": int(form.room.data),
|
|
"serial_number": form.serial_number.data}
|
|
|
|
r = g.server.post('/client/add', payload)
|
|
if r.status_code == requests.codes.ok:
|
|
return make_response("200 OK", 200)
|
|
return make_response("400 Bad Request", 400)
|
|
else:
|
|
r = g.server.get('/mode')
|
|
available_modes = [(mode, mode) for mode in r.json()['modes']]
|
|
form.boot.choices = list(available_modes)
|
|
|
|
r = g.server.get('/scopes')
|
|
rooms = parse_scopes_from_tree(r.json(), 'room')
|
|
rooms = [(room['id'], room['name']) for room in rooms]
|
|
form.room.choices = list(rooms)
|
|
|
|
form.create.render_kw = {"formaction": url_for('action_client_add')}
|
|
return render_template('actions/client_details.html', form=form)
|
|
|
|
@app.route('/action/image/create', methods=['GET', 'POST'])
|
|
def action_image_create():
|
|
form = ImageCreateForm(request.form)
|
|
if request.method == 'POST':
|
|
ip = form.ip.data
|
|
r = g.server.get('/client/info', payload={"client": [ip]})
|
|
disk, partition, code = form.os.data.split(' ')
|
|
payload = {"clients": [ip],
|
|
"disk": disk,
|
|
"partition": partition,
|
|
"code": code,
|
|
"name": form.name.data,
|
|
"repository": g.server.ip,
|
|
"id": "0", # This is ignored by the server.
|
|
"description": form.description.data,
|
|
"group_id": 0, # Default group.
|
|
"center_id": r.json()["center"]}
|
|
r = g.server.post('/image/create', payload)
|
|
if r.status_code == requests.codes.ok:
|
|
return make_response("200 OK", 200)
|
|
return make_response("400 Bad Request", 400)
|
|
else:
|
|
ips = parse_ips(request.args.to_dict())
|
|
form.ip.data = " ".join(ips)
|
|
r = g.server.get('/client/setup', payload={'client': list(ips)})
|
|
for partition in r.json()['partitions']:
|
|
disk_id = partition['disk']
|
|
part_id = partition['partition']
|
|
fs_id = partition['filesystem']
|
|
code = partition['code']
|
|
|
|
if part_id == 0:
|
|
# This is the disk data, not a partition.
|
|
continue
|
|
|
|
choice_value = f"{disk_id} {part_id} {code}"
|
|
choice_name = (f"{_('Disk')} {disk_id} | "
|
|
f"{_('Partition')} {part_id} | "
|
|
f"{_('FS')} {FS_CODES[fs_id]}")
|
|
form.os.choices.append((choice_value, choice_name))
|
|
return render_template('actions/image_create.html', form=form)
|
|
|
|
@app.route('/action/reboot', methods=['POST'])
|
|
def action_reboot():
|
|
ips = parse_ips(request.form.to_dict())
|
|
payload = {'clients': list(ips)}
|
|
g.server.post('/reboot', payload)
|
|
return make_response("200 OK", 200)
|
|
|
|
@app.route('/action/refresh', methods=['POST'])
|
|
def action_refresh():
|
|
ips = parse_ips(request.form.to_dict())
|
|
payload = {'clients': list(ips)}
|
|
g.server.post('/refresh', payload)
|
|
return make_response("200 OK", 200)
|