diff options
author | Alejandro Sirgo Rica <asirgo@soleta.eu> | 2024-06-19 17:21:13 +0200 |
---|---|---|
committer | Alejandro Sirgo Rica <asirgo@soleta.eu> | 2024-06-25 13:53:04 +0200 |
commit | af8236b18948b083c408df39306fc36bc26b51b7 (patch) | |
tree | 69d5e2ba2ccee58601e61b0c902b4d0438798720 /ogcp | |
parent | 8bcd8fd7a4c7d36a1bca2b3c36765fc773a1af78 (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.py | 9 | ||||
-rw-r--r-- | ogcp/templates/actions/script_run.html | 25 | ||||
-rw-r--r-- | ogcp/templates/commands.html | 9 | ||||
-rw-r--r-- | ogcp/views.py | 71 |
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: |