summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlejandro Sirgo Rica <asirgo@soleta.eu>2024-09-10 13:33:05 +0200
committerAlejandro Sirgo Rica <asirgo@soleta.eu>2024-09-10 15:11:11 +0200
commit6b33268b5c03db29cb003acb4e2042c9254402d2 (patch)
treecb6ceec1c3949177efa592a1466f8d26a9f21667
parenta1b164b1062eb7ba6b724ebe84d8d7e0b308e234 (diff)
ogcp: add view to assign repo to clients
Add /action/repo/set in Commands to assign a repository to multiple clients. The view includes the actual repo assigned in the client pills and shows a table with the clients grouped by repo when multiple repos are assigned among the selected clients.
-rw-r--r--ogcp/forms/action_forms.py5
-rw-r--r--ogcp/templates/actions/repo_set.html69
-rw-r--r--ogcp/templates/commands.html2
-rw-r--r--ogcp/views.py62
4 files changed, 137 insertions, 1 deletions
diff --git a/ogcp/forms/action_forms.py b/ogcp/forms/action_forms.py
index b4dfe7b..49c9f60 100644
--- a/ogcp/forms/action_forms.py
+++ b/ogcp/forms/action_forms.py
@@ -189,6 +189,11 @@ class OgliveForm(FlaskForm):
oglive = SelectField(label=_l('ogLive'))
ok = SubmitField(label=_l('Submit'))
+class SetRepoForm(FlaskForm):
+ ips = HiddenField()
+ repo = SelectField(label=_l('Repository'))
+ ok = SubmitField(label=_l('Submit'))
+
class ImageCreateForm(FlaskForm):
ip = HiddenField()
os = SelectField(label=_l('Partition'), choices=[])
diff --git a/ogcp/templates/actions/repo_set.html b/ogcp/templates/actions/repo_set.html
new file mode 100644
index 0000000..bdd7abf
--- /dev/null
+++ b/ogcp/templates/actions/repo_set.html
@@ -0,0 +1,69 @@
+{% extends 'commands.html' %}
+{% import "bootstrap/wtf.html" as wtf %}
+{% import "macros.html" as macros %}
+
+{% set sidebar_state = 'disabled' %}
+{% set btn_back = true %}
+
+{% block nav_setup %} active{% endblock %}
+{% block content %}
+
+{% set ip_list = form.ips.data.split(' ') %}
+{% set ip_count = ip_list | length %}
+<h2 class="mx-5 subhead-heading">
+ {{ _('Changing repository of %(ip_count)d computer(s)', ip_count=ip_count) }}
+</h2>
+
+{{ macros.cmd_selected_clients(selected_clients) }}
+
+{% if repos_set|length > 1 %}
+<div class="mx-5 form-group">
+ <p>Selected clients have different ogLive</p>
+
+ <table class="table table-hover">
+ <thead class="thead-light">
+ <tr>
+ <th>Repository</th>
+ <th>Clients</th>
+ </tr>
+ </thead>
+ <tbody class="text-left">
+ {% for repo, clients in repos_set.items() %}
+ <tr>
+ <th>{{repo}}</th>
+ <td>
+ {% for ip in clients %}<div class="card d-inline-block" style="padding: 5px; margin: 3px;">{{ ip }}</div>{% endfor %}
+ </td>
+ </tr>
+ {% endfor %}
+ </tbody>
+ </table>
+</div>
+{% endif %}
+
+{{ wtf.quick_form(form,
+ action=url_for('action_repo_set'),
+ method='post',
+ button_map={'ok': 'primary'},
+ extra_classes="m-5") }}
+
+
+<!-- jQuery -->
+<script src="{{ url_for('static', filename='AdminLTE/plugins/jquery/jquery.min.js') }}"></script>
+<script>
+ var reposSet = {{ repos_set|tojson|safe }};
+ // Update pill data
+ $('.badge-pill').each(function(index) {
+ for (const repo in reposSet) {
+ for (const clientName of reposSet[repo]) {
+ if ($(this).html().includes(clientName)) {
+ $(this).html($(this).html() + '<br>' + repo);
+ break;
+ }
+ }
+ }
+ });
+</script>
+
+
+{% endblock %}
diff --git a/ogcp/templates/commands.html b/ogcp/templates/commands.html
index 48630ea..41a0917 100644
--- a/ogcp/templates/commands.html
+++ b/ogcp/templates/commands.html
@@ -40,6 +40,8 @@
<div class="dropdown-menu" aria-labelledby="dropdownMenuButton">
<input class="btn btn-light dropdown-item{% block nav_setup_set_bootmode %}{% endblock %}" type="submit" value="{{ _('Set boot mode') }}"
form="scopesForm" formaction="{{ url_for('action_mode') }}" formmethod="get">
+ <input class="btn btn-light dropdown-item{% block nav_setup_set_repo %}{% endblock %}" type="submit" value="{{ _('Set repository') }}"
+ form="scopesForm" formaction="{{ url_for('action_repo_set') }}" formmethod="get">
<input class="btn btn-light dropdown-item{% block nav_setup_set_oglive %}{% endblock %}" type="submit" value="{{ _('Set ogLive') }}"
form="scopesForm" formaction="{{ url_for('action_oglive') }}" formmethod="get">
<input class="btn btn-light dropdown-item{% block nav_setup_setup %}{% endblock %}" type="submit" value="{{ _('Partition & Format') }}"
diff --git a/ogcp/views.py b/ogcp/views.py
index 77bad42..c24cb73 100644
--- a/ogcp/views.py
+++ b/ogcp/views.py
@@ -15,7 +15,7 @@ from ogcp.forms.action_forms import (
GenericForm, SelectClientForm, ImageUpdateForm, ImportClientsForm,
ServerForm, DeleteRepositoryForm, RepoForm, FolderForm, CacheForm,
ClientMoveForm, RunScriptForm, ImageConfigForm, ImageFetchForm,
- ServerConfigurationForm
+ ServerConfigurationForm, SetRepoForm
)
from flask_login import (
current_user, LoginManager,
@@ -2416,6 +2416,66 @@ def action_oglive():
selected_clients=selected_clients)
+def get_clients_repo_dictionary(ips, server, repositories):
+ repos = {}
+ repo_id_to_name = {repo["id"]: repo["name"] for repo in repositories}
+
+ for ip in ips:
+ r = server.get('/client/info', payload={"client": [ip]})
+ if not r:
+ raise ServerError
+ if r.status_code != requests.codes.ok:
+ raise ServerErrorCode
+ resp = r.json()
+ repo_name = repo_id_to_name[resp['repo_id']]
+ if repo_name not in repos:
+ repos[repo_name] = [ip]
+ else:
+ repos[repo_name].append(ip)
+ return repos
+
+@app.route('/action/repo/set', methods=['GET', 'POST'])
+@login_required
+def action_repo_set():
+ form = SetRepoForm(request.form)
+ if request.method == 'POST':
+ ips = form.ips.data.split(' ')
+ payload = {'clients': ips, 'id': int(form.repo.data)}
+ server = get_server_from_clients(ips)
+ r = server.post('/client/repo', payload)
+ if not r:
+ return ogserver_down('commands')
+ if r.status_code == requests.codes.ok:
+ flash(_('Repo set ogLive request sent successfully'),
+ category='info')
+ else:
+ flash(_('Ogserver replied with status code not ok'),
+ category='error')
+ 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(list(ips))
+ try:
+ repositories = get_repositories(server)
+ repos_set = get_clients_repo_dictionary(ips, server, repositories)
+ except ServerError:
+ return ogserver_down('commands')
+ except ServerErrorCode:
+ return ogserver_error('commands')
+
+ form.repo.choices = [(repo["id"], repo["name"]) for repo in repositories]
+
+ scopes, clients = get_scopes(set(ips))
+ selected_clients = list(get_selected_clients(scopes['scope']).items())
+ return render_template('actions/repo_set.html', repos_set=repos_set, form=form, scopes=scopes,
+ selected_clients=selected_clients)
+
+
@app.route('/action/image/create', methods=['GET', 'POST'])
@login_required
def action_image_create():