Skip to content
GitLab
Projects
Groups
Snippets
Help
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
F
foris-subordinates-plugin
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
1
Issues
1
List
Boards
Labels
Service Desk
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Operations
Operations
Incidents
Environments
Analytics
Analytics
CI / CD
Repository
Value Stream
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Turris
Foris
foris-subordinates-plugin
Commits
ebb71412
Verified
Commit
ebb71412
authored
Mar 21, 2019
by
Štěpán Henek
🐻
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
netboot plugin logic integrated
parent
7e2f1e34
Changes
7
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
270 additions
and
60 deletions
+270
-60
foris_plugins/subordinates/__init__.py
foris_plugins/subordinates/__init__.py
+109
-57
foris_plugins/subordinates/handlers.py
foris_plugins/subordinates/handlers.py
+32
-2
foris_plugins/subordinates/static/js/subordinates.js
foris_plugins/subordinates/static/js/subordinates.js
+56
-0
foris_plugins/subordinates/templates/javascript/subordinates/subordinates.js.j2
...ates/templates/javascript/subordinates/subordinates.js.j2
+11
-0
foris_plugins/subordinates/templates/subordinates/_subordinates_list_netboot.html.j2
...templates/subordinates/_subordinates_list_netboot.html.j2
+34
-0
foris_plugins/subordinates/templates/subordinates/_subordinates_list_setup.html.j2
...s/templates/subordinates/_subordinates_list_setup.html.j2
+1
-1
foris_plugins/subordinates/templates/subordinates/subordinates_netboot.html.j2
...nates/templates/subordinates/subordinates_netboot.html.j2
+27
-0
No files found.
foris_plugins/subordinates/__init__.py
View file @
ebb71412
...
...
@@ -33,12 +33,11 @@ from . import handlers
class
CommonPage
(
ConfigPageMixin
):
def
_prepare_render_args
(
self
,
args
):
args
[
'PLUGIN_NAME'
]
=
SubordinatesPlugin
.
PLUGIN_NAME
args
[
'PLUGIN_STYLES'
]
=
SubordinatesPlugin
.
PLUGIN_STYLES
args
[
'PLUGIN_STATIC_SCRIPTS'
]
=
SubordinatesPlugin
.
PLUGIN_STATIC_SCRIPTS
args
[
'PLUGIN_DYNAMIC_SCRIPTS'
]
=
SubordinatesPlugin
.
PLUGIN_DYNAMIC_SCRIPTS
args
[
"PLUGIN_NAME"
]
=
SubordinatesPlugin
.
PLUGIN_NAME
args
[
"PLUGIN_STYLES"
]
=
SubordinatesPlugin
.
PLUGIN_STYLES
args
[
"PLUGIN_STATIC_SCRIPTS"
]
=
SubordinatesPlugin
.
PLUGIN_STATIC_SCRIPTS
args
[
"PLUGIN_DYNAMIC_SCRIPTS"
]
=
SubordinatesPlugin
.
PLUGIN_DYNAMIC_SCRIPTS
def
render
(
self
,
**
kwargs
):
self
.
_prepare_render_args
(
kwargs
)
...
...
@@ -63,17 +62,20 @@ class SubordinatesSetupPage(CommonPage, handlers.SubordinatesConfigHandler):
super
(
SubordinatesSetupPage
,
self
).
save
(
no_messages
=
True
,
*
args
,
**
kwargs
)
data
=
self
.
form
.
callback_results
if
data
[
"result"
]:
messages
.
success
(
_
(
"Token was successfully added and client '%(controller_id)s' "
"should be visible in a moment."
)
%
dict
(
controller_id
=
data
[
"controller_id"
]))
messages
.
success
(
_
(
"Token was successfully added and client '%(controller_id)s' "
"should be visible in a moment."
)
%
dict
(
controller_id
=
data
[
"controller_id"
])
)
else
:
messages
.
error
(
_
(
"Failed to add token."
))
return
data
[
"result"
]
def
_check_and_get_controller_id
(
self
):
if
bottle
.
request
.
method
!=
'POST'
:
if
bottle
.
request
.
method
!=
"POST"
:
messages
.
error
(
_
(
"Wrong HTTP method."
))
bottle
.
redirect
(
reverse
(
"config_page"
,
page_name
=
"remote"
))
...
...
@@ -92,15 +94,14 @@ class SubordinatesSetupPage(CommonPage, handlers.SubordinatesConfigHandler):
def
_ajax_delete
(
self
):
controller_id
=
self
.
_check_and_get_controller_id
()
res
=
current_state
.
backend
.
perform
(
"subordinates"
,
"del"
,
{
"controller_id"
:
controller_id
})
res
=
current_state
.
backend
.
perform
(
"subordinates"
,
"del"
,
{
"controller_id"
:
controller_id
})
if
res
[
"result"
]:
return
bottle
.
template
(
"subordinates/_subordinates_message.html.j2"
,
message
=
{
"classes"
:
[
'success'
],
"classes"
:
[
"success"
],
"text"
:
_
(
"Subordinate '%(controller_id)s' was successfully deleted."
)
%
dict
(
controller_id
=
controller_id
)
%
dict
(
controller_id
=
controller_id
)
,
},
template_adapter
=
bottle
.
Jinja2Template
,
)
...
...
@@ -108,44 +109,43 @@ class SubordinatesSetupPage(CommonPage, handlers.SubordinatesConfigHandler):
return
bottle
.
template
(
"subordinates/_subordinates_message.html.j2"
,
message
=
{
"classes"
:
[
'error'
],
"classes"
:
[
"error"
],
"text"
:
_
(
"Failed to delete subordinate '%(controller_id)s'."
)
%
dict
(
controller_id
=
controller_id
)
%
dict
(
controller_id
=
controller_id
)
,
},
template_adapter
=
bottle
.
Jinja2Template
,
)
def
_ajax_set_enabled
(
self
,
enabled
):
controller_id
=
self
.
_check_and_get_controller_id
()
res
=
current_state
.
backend
.
perform
(
"subordinates"
,
"set_enabled"
,
{
"controller_id"
:
controller_id
,
"enabled"
:
enabled
,
})
res
=
current_state
.
backend
.
perform
(
"subordinates"
,
"set_enabled"
,
{
"controller_id"
:
controller_id
,
"enabled"
:
enabled
}
)
if
res
[
"result"
]:
if
enabled
:
message
=
{
"classes"
:
[
'success'
],
"classes"
:
[
"success"
],
"text"
:
_
(
"Subordinate '%(controller_id)s' was sucessfuly enabled."
)
%
dict
(
controller_id
=
controller_id
)
%
dict
(
controller_id
=
controller_id
)
,
}
else
:
message
=
{
"classes"
:
[
'success'
],
"classes"
:
[
"success"
],
"text"
:
_
(
"Subordinate '%(controller_id)s' was sucessfuly disabled."
)
%
dict
(
controller_id
=
controller_id
)
%
dict
(
controller_id
=
controller_id
)
,
}
else
:
if
enabled
:
message
=
{
"classes"
:
[
'error'
],
"classes"
:
[
"error"
],
"text"
:
_
(
"Failed to enable subordinate '%(controller_id)s'."
)
%
dict
(
controller_id
=
controller_id
)
%
dict
(
controller_id
=
controller_id
)
,
}
else
:
message
=
{
"classes"
:
[
'error'
],
"classes"
:
[
"error"
],
"text"
:
_
(
"Failed to disable subordinate '%(controller_id)s'."
)
%
dict
(
controller_id
=
controller_id
)
%
dict
(
controller_id
=
controller_id
)
,
}
return
bottle
.
template
(
...
...
@@ -177,9 +177,9 @@ class SubordinatesSetupPage(CommonPage, handlers.SubordinatesConfigHandler):
return
False
return
ConfigPageMixin
.
is_enabled_static
(
cls
)
def
get_page_form
(
self
,
form_name
:
str
,
data
:
dict
,
controller_id
:
str
)
->
typing
.
Tuple
[
fapi
.
ForisAjaxForm
,
typing
.
Callable
[[
dict
],
typing
.
Tuple
[
'str'
,
'str'
]]
]:
def
get_page_form
(
self
,
form_name
:
str
,
data
:
dict
,
controller_id
:
str
)
->
typing
.
Tuple
[
fapi
.
ForisAjaxForm
,
typing
.
Callable
[[
dict
],
typing
.
Tuple
[
"str"
,
"str"
]]
]:
"""Returns appropriate foris form and handler to generate response
"""
form
:
fapi
.
ForisAjaxForm
...
...
@@ -189,16 +189,16 @@ class SubordinatesSetupPage(CommonPage, handlers.SubordinatesConfigHandler):
def
prepare_message
(
results
:
dict
)
->
dict
:
if
results
[
"result"
]:
message
=
{
"classes"
:
[
'success'
],
"classes"
:
[
"success"
],
"text"
:
_
(
"Device '%(controller_id)s' was sucessfully updated."
)
%
dict
(
controller_id
=
data
[
"controller_id"
])
%
dict
(
controller_id
=
data
[
"controller_id"
])
,
}
else
:
message
=
{
"classes"
:
[
'error'
],
"classes"
:
[
"error"
],
"text"
:
_
(
"Failed to update subordinate '%(controller_id)s'."
)
%
dict
(
controller_id
=
data
[
"controller_id"
])
%
dict
(
controller_id
=
data
[
"controller_id"
])
,
}
return
message
...
...
@@ -213,21 +213,22 @@ class SubordinatesSetupPage(CommonPage, handlers.SubordinatesConfigHandler):
def
prepare_message
(
results
:
dict
)
->
dict
:
if
results
[
"result"
]:
message
=
{
"classes"
:
[
'success'
],
"classes"
:
[
"success"
],
"text"
:
_
(
"Subsubordinate '%(controller_id)s' was sucessfully updated."
)
%
dict
(
controller_id
=
data
[
"controller_id"
])
%
dict
(
controller_id
=
data
[
"controller_id"
])
,
}
else
:
message
=
{
"classes"
:
[
'error'
],
"classes"
:
[
"error"
],
"text"
:
_
(
"Failed to update subsubordinate '%(controller_id)s'."
)
%
dict
(
controller_id
=
data
[
"controller_id"
])
%
dict
(
controller_id
=
data
[
"controller_id"
])
,
}
return
message
form
.
url
=
reverse
(
"config_ajax_form"
,
page_name
=
"subordinates-setup"
,
form_name
=
"subsub-form"
)
"config_ajax_form"
,
page_name
=
"subordinates-setup"
,
form_name
=
"subsub-form"
)
return
form
,
prepare_message
raise
bottle
.
HTTPError
(
404
,
"No form '%s' not found."
%
form_name
)
...
...
@@ -272,9 +273,9 @@ class SubordinatesWifiPage(CommonPage):
return
self
.
_ajax_list_subordinates
()
raise
ValueError
(
"Unknown AJAX action."
)
def
get_page_form
(
self
,
form_name
:
str
,
data
:
dict
,
controller_id
:
str
)
->
typing
.
Tuple
[
fapi
.
ForisAjaxForm
,
typing
.
Callable
[[
dict
],
typing
.
Tuple
[
'str'
,
'str'
]]
]:
def
get_page_form
(
self
,
form_name
:
str
,
data
:
dict
,
controller_id
:
str
)
->
typing
.
Tuple
[
fapi
.
ForisAjaxForm
,
typing
.
Callable
[[
dict
],
typing
.
Tuple
[
"str"
,
"str"
]]
]:
"""Returns appropriate foris form and handler to generate response
"""
if
form_name
==
"wifi-form"
:
...
...
@@ -283,15 +284,12 @@ class SubordinatesWifiPage(CommonPage):
def
prepare_message
(
results
:
dict
)
->
dict
:
if
results
[
"result"
]:
message
=
{
"classes"
:
[
'success'
],
"text"
:
_
(
"Wifi settings was sucessfully updated."
)
"classes"
:
[
"success"
],
"text"
:
_
(
"Wifi settings was sucessfully updated."
)
,
}
else
:
message
=
{
"classes"
:
[
'error'
],
"text"
:
_
(
"Failed to update Wifi settings."
)
}
message
=
{
"classes"
:
[
"error"
],
"text"
:
_
(
"Failed to update Wifi settings."
)}
return
message
form
.
url
=
reverse
(
...
...
@@ -302,14 +300,69 @@ class SubordinatesWifiPage(CommonPage):
raise
bottle
.
HTTPError
(
404
,
"No form '%s' not found."
%
form_name
)
# This represents a plugin page
class
SubordinatesNetbootPage
(
CommonPage
,
handlers
.
NetbootConfigHandler
):
slug
=
"subordinates-netboot"
menu_order
=
3
template
=
"subordinates/subordinates_netboot"
template_type
=
"jinja2"
def
save
(
self
,
*
args
,
**
kwargs
):
# Handle form result here
return
super
().
save
(
*
args
,
**
kwargs
)
def
render
(
self
,
**
kwargs
):
self
.
_prepare_render_args
(
kwargs
)
return
super
().
render
(
**
kwargs
)
def
_action_list
(
self
):
res
=
current_state
.
backend
.
perform
(
"netboot"
,
"list"
)
return
bottle
.
template
(
"subordinates/_subordinates_list_netboot.html.j2"
,
records
=
res
[
"devices"
],
template_adapter
=
bottle
.
Jinja2Template
,
)
def
_action_generic
(
self
,
action
):
if
bottle
.
request
.
method
!=
"POST"
:
messages
.
error
(
_
(
"Wrong HTTP method."
))
bottle
.
redirect
(
reverse
(
"config_page"
,
page_name
=
"remote"
))
form
=
self
.
get_serial_form
(
bottle
.
request
.
POST
.
decode
())
if
not
form
.
data
[
"serial"
]:
raise
bottle
.
HTTPError
(
404
,
"serial not found"
)
res
=
current_state
.
backend
.
perform
(
"netboot"
,
action
,
{
"serial"
:
form
.
data
[
"serial"
]})
bottle
.
response
.
set_header
(
"Content-Type"
,
"application/json"
)
return
res
def
_action_revoke
(
self
):
return
self
.
_action_generic
(
"revoke"
)
def
_action_accept
(
self
):
return
self
.
_action_generic
(
"accept"
)
def
call_ajax_action
(
self
,
action
):
if
action
==
"list"
:
return
self
.
_action_list
()
if
action
==
"revoke"
:
return
self
.
_action_revoke
()
if
action
==
"accept"
:
return
self
.
_action_accept
()
raise
ValueError
(
"Unknown AJAX action."
)
class
SubordinatesJoinedPage
(
JoinedPages
):
userfriendly_title
=
gettext
(
"Managed devices"
)
slug
=
"subordinates"
no_url
=
True
subpages
:
typing
.
Iterable
[
typing
.
Type
[
'ConfigPageMixin'
]]
=
[
subpages
:
typing
.
Iterable
[
typing
.
Type
[
"ConfigPageMixin"
]]
=
[
SubordinatesSetupPage
,
SubordinatesWifiPage
,
SubordinatesNetbootPage
,
]
@
classmethod
...
...
@@ -330,13 +383,12 @@ class SubordinatesPlugin(ForisPlugin):
PLUGIN_NAME
=
"subordinates"
DIRNAME
=
os
.
path
.
dirname
(
os
.
path
.
abspath
(
__file__
))
PLUGIN_STYLES
=
[
]
PLUGIN_STATIC_SCRIPTS
=
[
"js/subordinates.js"
,
# static js file
]
PLUGIN_DYNAMIC_SCRIPTS
=
[
"subordinates.js"
,
# dynamic js file (a template which will be rendered to javascript)
PLUGIN_STYLES
:
typing
.
List
[
str
]
=
[]
PLUGIN_STATIC_SCRIPTS
:
typing
.
List
[
str
]
=
[
"js/subordinates.js"
]
# static js file
PLUGIN_DYNAMIC_SCRIPTS
:
typing
.
List
[
str
]
=
[
"subordinates.js"
# dynamic js file (a template which will be rendered to javascript)
]
def
__init__
(
self
,
app
):
...
...
foris_plugins/subordinates/handlers.py
View file @
ebb71412
...
...
@@ -18,10 +18,10 @@ import base64
import
bottle
import
typing
from
foris
import
fapi
from
foris
import
fapi
,
validators
from
foris.form
import
File
,
Hidden
,
Textbox
from
foris.state
import
current_state
from
foris.utils.translators
import
gettext
as
_
from
foris.utils.translators
import
gettext
as
_
,
gettext_dummy
as
gettext
from
foris.config_handlers.base
import
BaseConfigHandler
from
foris.config_handlers.wifi
import
WifiEditForm
...
...
@@ -195,3 +195,33 @@ class SubordinatesWifiHandler(BaseConfigHandler):
def
get_form
(
self
):
ajax_form
=
WifiEditForm
(
self
.
data
)
return
ajax_form
.
foris_form
class
NetbootConfigHandler
(
BaseConfigHandler
):
STATE_ACCEPTED
=
gettext
(
"accepted"
)
STATE_INCOMMING
=
gettext
(
"incomming"
)
userfriendly_title
=
gettext
(
"Netboot"
)
def
get_form
(
self
):
form
=
fapi
.
ForisForm
(
"netboot"
,
{})
form
.
add_section
(
name
=
"main_section"
,
title
=
self
.
userfriendly_title
,
)
def
form_cb
(
data
):
return
"save_result"
,
{}
form
.
add_callback
(
form_cb
)
return
form
def
get_serial_form
(
self
,
data
=
None
):
generate_serial_form
=
fapi
.
ForisForm
(
"serial_form"
,
data
)
serial_section
=
generate_serial_form
.
add_section
(
"serial_section"
,
title
=
None
)
serial_section
.
add_field
(
Textbox
,
name
=
"serial"
,
label
=
" "
,
required
=
True
,
validators
=
[
validators
.
MacAddress
()],
)
return
generate_serial_form
foris_plugins/subordinates/static/js/subordinates.js
View file @
ebb71412
// TODO separete reasonable part for dynamic js
Foris
.
initNetbootRecordsForms
=
()
=>
{
$
(
"
.record-form
"
).
submit
((
e
)
=>
{
e
.
preventDefault
();
let
form
=
$
(
e
.
currentTarget
);
let
action
=
$
(
e
.
originalEvent
.
explicitOriginalTarget
).
val
();
switch
(
action
)
{
case
"
revoke
"
:
$
.
ajax
({
type
:
"
POST
"
,
url
:
form
.
attr
(
'
action
'
),
data
:
`
${
form
.
serialize
()}
&action=
${
action
}
`
,
success
:
(
data
)
=>
{
if
(
data
.
result
)
{
Foris
.
loadNetbootList
();
// TODO success message
}
else
{
// TODO error message
}
},
});
break
;
case
"
accept
"
:
$
.
ajax
({
type
:
"
POST
"
,
url
:
form
.
attr
(
'
action
'
),
data
:
`
${
form
.
serialize
()}
&action=
${
action
}
`
,
success
:
(
data
)
=>
{
if
(
data
.
result
)
{
Foris
.
loadNetbootList
();
// TODO success message
}
else
{
// TODO error message
}
},
});
form
.
find
(
"
button
"
).
prop
(
'
disabled
'
,
true
);
break
;
}
});
}
Foris
.
addWsHanlder
(
"
netboot
"
,
(
msg
)
=>
{
switch
(
msg
.
action
)
{
case
"
revoke
"
:
case
"
accept
"
:
Foris
.
loadNetbootList
();
break
;
}
});
// Update chart after page is rendred
$
(
document
).
ready
(
function
()
{
Foris
.
initNetbootRecordsForms
();
Foris
.
loadNetbootList
();
});
foris_plugins/subordinates/templates/javascript/subordinates/subordinates.js.j2
View file @
ebb71412
Foris.messages.subordinatesSubordinatesFailed = (controller_id) => {
return `{% trans controller_id="${controller_id}" %}Connection to '{{ controller_id }}' was interrupted.{% endtrans %}`;
};
Foris.netbootMessages = {
}
Foris.loadNetbootList = () => {
$.get('{{ url("config_ajax", page_name="subordinates-netboot") }}', {action: "list"})
.done((response) => {
$("#records-table").replaceWith(response);
Foris.initNetbootRecordsForms();
})
}
foris_plugins/subordinates/templates/subordinates/_subordinates_list_netboot.html.j2
0 → 100644
View file @
ebb71412
{% if records %}
<table id="records-table">
<thead><th>{% trans %}Serial{% endtrans %}</th><th>{% trans %}Paired{% endtrans %}</th><th></th></thead>
<tbody>
{% for record in records %}
<tr>
<td>{{ record.serial }}</td>
{% if record.state == "accepted" %}
<td title="{% trans %}Paired{% endtrans %}">
<i class="fas fa-check"></i>
</td>
{% else %}
<td title="{% trans %}Unpaired{% endtrans %}">
<i class="fas fa-times"></i>
</td>
{% endif %}
<td>
<form action="{{ url("config_ajax", page_name="subordinates-netboot") }}" method="post" class="record-form">
<input type="hidden" name="serial" value="{{ record.serial }}">
<input type="hidden" name="csrf_token" value="{{ get_csrf_token() }}">
{% if record.state == "accepted" %}
<button name="action" value="revoke" type="submit">{% trans %}Revoke{% endtrans %}</button>
{% else %}
<button name="action" value="accept" type="submit">{% trans %}Accept{% endtrans %}</button>
{% endif %}
</form>
</td>
</tr>
{% endfor %}
</tbody>
</table>
{% else %}
<p id="records-table">{% trans %}No suitable devices found.{% endtrans %}</p>
{% endif %}
foris_plugins/subordinates/templates/subordinates/_subordinates_list_setup.html.j2
View file @
ebb71412
{% macro sub_buttons(controller_id, enabled, form_class) -%}
<form action="{{ url("config_ajax", page_name="subordinates") }}" method="post" class="subordinate-buttons {{ form_class }}">
<form action="{{ url("config_ajax", page_name="subordinates
-setup
") }}" method="post" class="subordinate-buttons {{ form_class }}">
<input type="hidden" name="controller_id" value="{{ controller_id }}">
<input type="hidden" name="csrf_token" value="{{ get_csrf_token() }}">
{% if enabled %}
...
...
foris_plugins/subordinates/templates/subordinates/subordinates_netboot.html.j2
0 → 100644
View file @
ebb71412
{% extends 'config/base.html.j2' %}
{% block config_base %}
{% if is_xhr is not defined %}
<div id="page-subordinates-netboot" class="config-page">
{% endif %}
{% include '_messages.html.j2' %}
<p>{% trans %}Manage devices which can be booted from this device through network.{% endtrans %}</p>
</form>
<h3>{% trans %}Devices suitable for netboot{% endtrans %}</h3>
<div id="records-table">
{% trans %}Loading devices...{% endtrans %}
</div>
<br />
<div class="message info">
{%- trans setup_url=url("config_page", page_name="subordinates-setup") %}
Note that if everything goes well the accepted devices should <strong>eventually appear</strong> on <a href="{{ setup_url }}">Set up</a> page.
{% endtrans -%}
</div>
{% if is_xhr is not defined %}
</div>
{% endif %}
{% endblock %}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment