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.
master
Alejandro Sirgo Rica 2024-09-10 13:33:05 +02:00
parent a1b164b106
commit 6b33268b5c
4 changed files with 137 additions and 1 deletions

View File

@ -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=[])

View File

@ -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 %}

View File

@ -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') }}"

View File

@ -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():