mirror of https://git.48k.eu/ogcp
ogcp: add support for multi-ip repositories
Add support for the new API REST for repository management where the address is a list of ips instead of a single string. Add dynamic address creation in /action/repo/update and /action/repo/add forms through delete and add buttons in the form. Update /image/restore and /cache/fetch to use repository_id. Add additional repository form validations.master
parent
bcd18241c7
commit
31766a3d07
|
@ -122,7 +122,10 @@ class RepoForm(FlaskForm):
|
|||
server = HiddenField()
|
||||
repo_id = HiddenField()
|
||||
name = StringField(label=_l('Name'))
|
||||
ip = StringField(label=_l('IP'))
|
||||
addr = FieldList(
|
||||
StringField(label=_l('Address')),
|
||||
label=_l('Addresses'),
|
||||
)
|
||||
submit = SubmitField(label=_l('Submit'))
|
||||
|
||||
class FolderForm(FlaskForm):
|
||||
|
|
|
@ -9,9 +9,28 @@
|
|||
|
||||
<h2 class="mx-5 subhead-heading">{{_('Delete repo')}}</h2>
|
||||
|
||||
{{ wtf.quick_form(form,
|
||||
action=url_for('action_repo_delete'),
|
||||
method='post',
|
||||
button_map={'submit': 'danger'},
|
||||
extra_classes="mx-5") }}
|
||||
<form class="form mx-5" method="POST">
|
||||
{{ form.hidden_tag() }}
|
||||
|
||||
{{ form.server() }}
|
||||
{{ form.repo_id() }}
|
||||
|
||||
<div class="form-group">
|
||||
{{ form.name.label }}
|
||||
{{ form.name(class="form-control") }}
|
||||
</div>
|
||||
|
||||
<div class="form-group" id="ip-fields">
|
||||
{{ form.addr.label }}
|
||||
{% for addr in form.addr %}
|
||||
{{ addr(class="form-control mb-2") }}
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
{{ form.submit(class="btn btn-primary") }}
|
||||
</div>
|
||||
|
||||
</form>
|
||||
|
||||
{% endblock %}
|
||||
|
|
|
@ -9,5 +9,23 @@
|
|||
|
||||
<h2 class="mx-5 subhead-heading">{{_('Repo details')}}</h2>
|
||||
|
||||
{{ wtf.quick_form(form, extra_classes="mx-5") }}
|
||||
<form class="form mx-5" method="POST">
|
||||
{{ form.hidden_tag() }}
|
||||
|
||||
{{ form.server() }}
|
||||
{{ form.repo_id() }}
|
||||
|
||||
<div class="form-group">
|
||||
{{ form.name.label }}
|
||||
{{ form.name(class="form-control") }}
|
||||
</div>
|
||||
|
||||
<div class="form-group" id="ip-fields">
|
||||
{{ form.addr.label }}
|
||||
{% for addr in form.addr %}
|
||||
{{ addr(class="form-control mb-2") }}
|
||||
{% endfor %}
|
||||
</div>
|
||||
</form>
|
||||
|
||||
{% endblock %}
|
||||
|
|
|
@ -9,9 +9,6 @@
|
|||
|
||||
<h2 class="mx-5 subhead-heading">{{_('Add repo')}}</h2>
|
||||
|
||||
{{ wtf.quick_form(form,
|
||||
action=url_for('action_repo_add'),
|
||||
method='post',
|
||||
button_map={'submit': 'primary'},
|
||||
extra_classes="mx-5") }}
|
||||
{% include 'repo_inspector.html' %}
|
||||
|
||||
{% endblock %}
|
||||
|
|
|
@ -9,9 +9,6 @@
|
|||
|
||||
<h2 class="mx-5 subhead-heading">{{_('Update repo')}}</h2>
|
||||
|
||||
{{ wtf.quick_form(form,
|
||||
action=url_for('action_repo_update'),
|
||||
method='post',
|
||||
button_map={'submit': 'primary'},
|
||||
extra_classes="mx-5") }}
|
||||
{% include 'repo_inspector.html' %}
|
||||
|
||||
{% endblock %}
|
||||
|
|
|
@ -0,0 +1,63 @@
|
|||
<form class="form mx-5" method="POST">
|
||||
{{ form.hidden_tag() }}
|
||||
|
||||
{{ form.server() }}
|
||||
{{ form.repo_id() }}
|
||||
|
||||
<div class="form-group">
|
||||
{{ form.name.label }}
|
||||
{{ form.name(class="form-control", required=True) }}
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
{{ form.addr.label }}
|
||||
<div id="ip-fields">
|
||||
{% for addr in form.addr %}
|
||||
<div class="d-flex align-items-center mb-2">
|
||||
{{ addr(class="form-control me-2", placeholder=_("Enter IP Address"), required=True) }}
|
||||
<button type="button" class="btn btn-danger" onclick="removeIPField(this)">{{_('Remove') }}</button>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
<button type="button" class="btn btn-primary" onclick="addIPField()">{{_('Add address') }}</button>
|
||||
|
||||
{{ form.submit(class="btn btn-success") }}
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<script>
|
||||
function addIPField() {
|
||||
const container = document.createElement('div');
|
||||
container.classList.add('d-flex', 'align-items-center', 'mb-2');
|
||||
|
||||
const newField = document.createElement('input');
|
||||
newField.setAttribute('type', 'text');
|
||||
newField.setAttribute('name', 'addr-' + document.querySelectorAll('input[name^="addr-"]').length);
|
||||
newField.classList.add('form-control', 'me-2');
|
||||
newField.setAttribute('placeholder', '{{ _('Enter IP Address') }}');
|
||||
newField.required = true;
|
||||
|
||||
const removeButton = document.createElement('button');
|
||||
removeButton.setAttribute('type', 'button');
|
||||
removeButton.classList.add('btn', 'btn-danger');
|
||||
removeButton.innerText = '{{ _('Remove') }}';
|
||||
removeButton.onclick = function() {
|
||||
removeIPField(this);
|
||||
};
|
||||
|
||||
container.appendChild(newField);
|
||||
container.appendChild(removeButton);
|
||||
document.getElementById('ip-fields').appendChild(container);
|
||||
}
|
||||
|
||||
function removeIPField(elem) {
|
||||
const ipFieldsContainer = document.getElementById('ip-fields');
|
||||
const ipFieldDivs = ipFieldsContainer.querySelectorAll('.d-flex');
|
||||
|
||||
if (ipFieldDivs.length <= 1) {
|
||||
return;
|
||||
}
|
||||
const parentDiv = elem.parentElement;
|
||||
parentDiv.remove();
|
||||
}
|
||||
</script>
|
|
@ -30,6 +30,7 @@ from ogcp.og_server import OGServer, servers
|
|||
from flask_babel import lazy_gettext as _l
|
||||
from flask_babel import gettext, _
|
||||
from ogcp import app, ogcp_cfg_path
|
||||
from wtforms import StringField
|
||||
import unicodedata
|
||||
import ipaddress
|
||||
import requests
|
||||
|
@ -952,17 +953,10 @@ def action_image_restore():
|
|||
if requires_cache and not image_fits_in_cache(server, clients_info, image):
|
||||
return redirect(url_for('commands'))
|
||||
|
||||
try:
|
||||
repository = get_repository(image['repo_id'], server)
|
||||
except ServerError:
|
||||
return ogserver_down('commands')
|
||||
except ServerErrorCode:
|
||||
return ogserver_error('commands')
|
||||
|
||||
payload = {'disk': disk,
|
||||
'partition': partition,
|
||||
'name': image['name'],
|
||||
'repository': repository['ip'],
|
||||
'repository_id': image['repo_id'],
|
||||
'clients': ips,
|
||||
'type': form.method.data,
|
||||
'profile': str(image['software_id']),
|
||||
|
@ -1347,15 +1341,8 @@ def action_image_fetch():
|
|||
flash(_(f'Image to fetch was not found'), category='error')
|
||||
return redirect(url_for('commands'))
|
||||
|
||||
try:
|
||||
repository = get_repository(image['repo_id'], server)
|
||||
except ServerError:
|
||||
return ogserver_down('commands')
|
||||
except ServerErrorCode:
|
||||
return ogserver_error('commands')
|
||||
|
||||
payload = {'clients': ips,
|
||||
'repository': repository['ip'],
|
||||
'repository_id': image['repo_id'],
|
||||
'type': form.method.data,
|
||||
'image': image['name']}
|
||||
|
||||
|
@ -3040,6 +3027,34 @@ def manage_repos():
|
|||
responses = multi_request('get', '/repositories')
|
||||
return render_template('repos.html', repos_resp=responses)
|
||||
|
||||
def repo_addr_is_valid(form):
|
||||
invalid_ips = []
|
||||
empty_ips = 0
|
||||
ip_count = 0
|
||||
for ip in form.addr:
|
||||
ip_count += 1
|
||||
ip = ip.data.strip()
|
||||
if not ip:
|
||||
empty_ips += 1
|
||||
continue
|
||||
if not is_valid_ip(ip):
|
||||
invalid_ips.append('"' + ip + '"')
|
||||
|
||||
res = True
|
||||
if empty_ips > 0:
|
||||
res = False
|
||||
flash(_(f'{empty_ips} addresses are invalid'), category='error')
|
||||
|
||||
if invalid_ips:
|
||||
res = False
|
||||
flash(_(f'The following addresses are invalid: {" ".join(invalid_ips)}'), category='error')
|
||||
|
||||
if ip_count > 16:
|
||||
res = False
|
||||
flash(_('More than 16 addresses is not supported'), category='error')
|
||||
|
||||
return res
|
||||
|
||||
@app.route('/action/repo/add', methods=['POST', 'GET'])
|
||||
@login_required
|
||||
def action_repo_add():
|
||||
|
@ -3048,8 +3063,14 @@ def action_repo_add():
|
|||
if not form.validate():
|
||||
flash(form.errors, category='error')
|
||||
return redirect(url_for('manage_repos'))
|
||||
|
||||
if not repo_addr_is_valid(form):
|
||||
return redirect(url_for('manage_repos'))
|
||||
|
||||
addr = [ip.data.strip() for ip in form.addr]
|
||||
|
||||
payload = {"name": form.name.data,
|
||||
"ip": form.ip.data,
|
||||
"addr": addr,
|
||||
"center": 1}
|
||||
server = get_server_from_ip_port(form.server.data)
|
||||
r = server.post('/repository/add', payload)
|
||||
|
@ -3068,6 +3089,7 @@ def action_repo_add():
|
|||
return redirect(url_for('manage_repos'))
|
||||
|
||||
form.server.data = params['repos-server']
|
||||
form.addr.append_entry('')
|
||||
|
||||
responses = multi_request('get', '/repositories')
|
||||
return render_template('actions/repos_add.html', form=form,
|
||||
|
@ -3079,9 +3101,15 @@ def action_repo_update():
|
|||
form = RepoForm(request.form)
|
||||
if request.method == 'POST':
|
||||
server = get_server_from_ip_port(form.server.data)
|
||||
payload = { 'repo_id': int(form.repo_id.data),
|
||||
|
||||
if not repo_addr_is_valid(form):
|
||||
return redirect(url_for('manage_repos'))
|
||||
|
||||
addr = [ip.data.strip() for ip in form.addr]
|
||||
|
||||
payload = { 'id': int(form.repo_id.data),
|
||||
'name': form.name.data,
|
||||
'ip': form.ip.data,
|
||||
'addr': addr,
|
||||
'center': 1}
|
||||
r = server.post('/repository/update', payload)
|
||||
if not r:
|
||||
|
@ -3115,7 +3143,8 @@ def action_repo_update():
|
|||
form.server.data = server_ip_port
|
||||
form.repo_id.data = repo_id
|
||||
form.name.data = repository['name']
|
||||
form.ip.data = repository['ip']
|
||||
for addr in repository['addr']:
|
||||
form.addr.append_entry(addr)
|
||||
|
||||
responses = multi_request('get', '/repositories')
|
||||
return render_template('actions/repos_update.html', form=form,
|
||||
|
@ -3127,7 +3156,7 @@ def action_repo_delete():
|
|||
form = RepoForm(request.form)
|
||||
if request.method == 'POST':
|
||||
server = get_server_from_ip_port(form.server.data)
|
||||
payload = { 'id': form.repo_id.data }
|
||||
payload = { 'id': int(form.repo_id.data) }
|
||||
r = server.post('/repository/delete', payload)
|
||||
if not r:
|
||||
return ogserver_down('manage_repos')
|
||||
|
@ -3165,8 +3194,11 @@ def action_repo_delete():
|
|||
form.repo_id.data = repo_id
|
||||
form.name.data = repository['name']
|
||||
form.name.render_kw = {'readonly': True}
|
||||
form.ip.data = repository['ip']
|
||||
form.ip.render_kw = {'readonly': True}
|
||||
form.name.data = repository['name']
|
||||
for addr in repository['addr']:
|
||||
form.addr.append_entry(addr)
|
||||
for field in form.addr:
|
||||
field.render_kw = {'readonly': True}
|
||||
responses = multi_request('get', '/repositories')
|
||||
return render_template('actions/delete_repo.html', form=form,
|
||||
repos_resp=responses)
|
||||
|
@ -3199,8 +3231,10 @@ def action_repo_info():
|
|||
return ogserver_error('manage_repos')
|
||||
form.name.data = repository['name']
|
||||
form.name.render_kw = {'readonly': True}
|
||||
form.ip.data = repository['ip']
|
||||
form.ip.render_kw = {'readonly': True}
|
||||
for addr in repository['addr']:
|
||||
form.addr.append_entry(addr)
|
||||
for field in form.addr:
|
||||
field.render_kw = {'readonly': True}
|
||||
form.submit.render_kw = {"style": "visibility:hidden;"}
|
||||
responses = multi_request('get', '/repositories')
|
||||
return render_template('actions/repo_details.html', form=form,
|
||||
|
|
Loading…
Reference in New Issue