summaryrefslogtreecommitdiffstats
path: root/ogcp
diff options
context:
space:
mode:
authorAlejandro Sirgo Rica <asirgo@soleta.eu>2024-06-19 17:21:13 +0200
committerAlejandro Sirgo Rica <asirgo@soleta.eu>2024-06-25 13:53:04 +0200
commitaf8236b18948b083c408df39306fc36bc26b51b7 (patch)
tree69d5e2ba2ccee58601e61b0c902b4d0438798720 /ogcp
parent8bcd8fd7a4c7d36a1bca2b3c36765fc773a1af78 (diff)
ogcp: add support to run scripts in clients
Add view at /action/script/run to visualize the available scripts and run a single script file in the selected clients. Use shell/list to request the script list and shell/run API call to request the execution.
Diffstat (limited to 'ogcp')
-rw-r--r--ogcp/forms/action_forms.py9
-rw-r--r--ogcp/templates/actions/script_run.html25
-rw-r--r--ogcp/templates/commands.html9
-rw-r--r--ogcp/views.py71
4 files changed, 113 insertions, 1 deletions
diff --git a/ogcp/forms/action_forms.py b/ogcp/forms/action_forms.py
index 9e3a9f6..d650506 100644
--- a/ogcp/forms/action_forms.py
+++ b/ogcp/forms/action_forms.py
@@ -147,6 +147,15 @@ class ClientMoveForm(FlaskForm):
scopes = SelectField(label=_l('Scopes'), validate_choice=False)
submit = SubmitField(label=_l('Submit'))
+class RunScriptForm(FlaskForm):
+ ips = HiddenField()
+ script = SelectField(label=_l('Script'),
+ choices=[],
+ validators=[InputRequired()],
+ validate_choice=False)
+ arguments = StringField(label=_l('Arguments'))
+ submit = SubmitField(label=_l('Submit'))
+
class ImportClientsForm(FlaskForm):
server = HiddenField()
room = SelectField(label=_l('Room'))
diff --git a/ogcp/templates/actions/script_run.html b/ogcp/templates/actions/script_run.html
new file mode 100644
index 0000000..700134e
--- /dev/null
+++ b/ogcp/templates/actions/script_run.html
@@ -0,0 +1,25 @@
+{% extends 'commands.html' %}
+{% import "bootstrap/wtf.html" as wtf %}
+{% import "macros.html" as macros %}
+
+{% set sidebar_state = 'disabled' %}
+{% set btn_back = true %}
+
+{% block nav_client %} active {% endblock %}
+{% block nav_script_run %} active {% endblock %}
+{% block content %}
+
+{% set ip_list = form.ips.data.split(' ') %}
+{% set ip_count = ip_list | length %}
+<h1 class="m-5">
+ {{ _('Run script for %(ip_count)d client(s)', ip_count=ip_count) }}
+</h1>
+
+{{ macros.cmd_selected_clients(selected_clients) }}
+
+{{ wtf.quick_form(form,
+ method='post',
+ button_map={'submit': 'primary'},
+ extra_classes="mx-5") }}
+
+{% endblock %}
diff --git a/ogcp/templates/commands.html b/ogcp/templates/commands.html
index aa3c4b4..eab9f29 100644
--- a/ogcp/templates/commands.html
+++ b/ogcp/templates/commands.html
@@ -88,6 +88,15 @@
</div>
<div class="dropdown btn">
+ <button class="btn btn-secondary btn-light dropdown-toggle{% block nav_script %}{% endblock %}" type="button" id="dropdownMenuButton" data-toggle="dropdown" aria-expanded="false">
+ {{ _('Script') }}
+ </button>
+ <div class="dropdown-menu" aria-labelledby="dropdownMenuButton">
+ <input class="btn btn-light dropdown-item{% block nav_run_script %}{% endblock %}" type="submit" value="{{ _('Run') }}"
+ form="scopesForm" formaction="{{ url_for('action_run_script') }}" formmethod="get">
+ </div>
+
+ <div class="dropdown btn">
<button class="btn btn-secondary btn-light dropdown-toggle{% block nav_logs %}{% endblock %}" type="button" id="dropdownMenuButton" data-toggle="dropdown" aria-expanded="false">
Logs
</button>
diff --git a/ogcp/views.py b/ogcp/views.py
index 92dbf32..109957a 100644
--- a/ogcp/views.py
+++ b/ogcp/views.py
@@ -14,7 +14,7 @@ from ogcp.forms.action_forms import (
RoomForm, DeleteRoomForm, CenterForm, DeleteCenterForm, OgliveForm,
GenericForm, SelectClientForm, ImageUpdateForm, ImportClientsForm,
ServerForm, DeleteRepositoryForm, RepoForm, FolderForm, CacheForm,
- ClientMoveForm
+ ClientMoveForm, RunScriptForm
)
from flask_login import (
current_user, LoginManager,
@@ -1812,6 +1812,75 @@ def action_client_delete():
else:
return redirect(url_for('scopes'))
+@app.route('/action/script/run', methods=['GET', 'POST'])
+@login_required
+def action_run_script():
+ form = RunScriptForm(request.form)
+ if request.method == 'POST':
+ ips = form.ips.data.split(' ')
+ if not validate_elements(ips):
+ return redirect(url_for('commands'))
+
+ arguments = form.arguments.data.split(' ')
+ cmd_elems = [form.script.data] + arguments
+
+ payload = {
+ 'clients': ips,
+ 'run': ';|\n\r'.join(cmd_elems),
+ 'echo': True
+ }
+ server = get_server_from_clients(ips)
+ r = server.post('/shell/run', payload)
+
+ if not r:
+ return ogserver_down('commands')
+ if r.status_code != requests.codes.ok:
+ return ogserver_error('commands')
+
+ flash(_('Script run sent successfully'), category='info')
+ return redirect(url_for('commands'))
+ else:
+ ips = parse_elements(request.args.to_dict())
+ form.ips.data = " ".join(ips)
+ if not validate_elements(ips):
+ return redirect(url_for('commands'))
+
+ server = get_server_from_clients(ips)
+ different_setups = False
+ reference_patitioning = None
+ for ip in ips:
+ r = server.get('/client/setup', payload={'client': [ip]})
+ if not r:
+ return ogserver_down('commands')
+ if r.status_code != requests.codes.ok:
+ return ogserver_error('commands')
+
+ partitions = r.json()['partitions'][1:]
+ if not reference_patitioning:
+ reference_patitioning = partitions
+ elif reference_patitioning != partitions:
+ different_setups = True
+
+ if different_setups:
+ flash(_('Some clients don\'t have same configuration'), category='info')
+
+ r = server.get('/shell/list')
+ if not r:
+ return ogserver_down('commands')
+ if r.status_code != requests.codes.ok:
+ return ogserver_error('commands')
+
+ scripts = r.json()['scripts']
+
+ for script in scripts:
+ form.script.choices.append((script, script))
+
+ scopes, clients = get_scopes(set(ips))
+ selected_clients = list(get_selected_clients(scopes['scope']).items())
+ return render_template('actions/script_run.html', form=form,
+ selected_clients=selected_clients,
+ scopes=scopes)
+
def get_clients_modes(ips, server):
modes = {}
for ip in ips: