arthexis 0.1.21__py3-none-any.whl → 0.1.23__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of arthexis might be problematic. Click here for more details.
- {arthexis-0.1.21.dist-info → arthexis-0.1.23.dist-info}/METADATA +9 -8
- {arthexis-0.1.21.dist-info → arthexis-0.1.23.dist-info}/RECORD +33 -33
- config/settings.py +4 -0
- config/urls.py +5 -0
- core/admin.py +224 -32
- core/environment.py +2 -239
- core/models.py +903 -65
- core/release.py +0 -5
- core/system.py +76 -0
- core/tests.py +181 -9
- core/user_data.py +42 -2
- core/views.py +68 -27
- nodes/admin.py +211 -60
- nodes/apps.py +11 -0
- nodes/models.py +35 -7
- nodes/tests.py +288 -1
- nodes/views.py +101 -48
- ocpp/admin.py +32 -2
- ocpp/consumers.py +1 -0
- ocpp/models.py +52 -3
- ocpp/tasks.py +99 -1
- ocpp/tests.py +350 -2
- ocpp/views.py +300 -6
- pages/admin.py +112 -15
- pages/apps.py +32 -0
- pages/forms.py +31 -8
- pages/models.py +42 -2
- pages/tests.py +386 -28
- pages/urls.py +10 -0
- pages/views.py +347 -18
- {arthexis-0.1.21.dist-info → arthexis-0.1.23.dist-info}/WHEEL +0 -0
- {arthexis-0.1.21.dist-info → arthexis-0.1.23.dist-info}/licenses/LICENSE +0 -0
- {arthexis-0.1.21.dist-info → arthexis-0.1.23.dist-info}/top_level.txt +0 -0
core/environment.py
CHANGED
|
@@ -1,17 +1,10 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
import os
|
|
4
|
-
import re
|
|
5
|
-
import shlex
|
|
6
|
-
import subprocess
|
|
7
|
-
from pathlib import Path
|
|
8
|
-
|
|
9
|
-
from django import forms
|
|
10
4
|
from django.conf import settings
|
|
11
5
|
from django.contrib import admin
|
|
12
|
-
from django.core.exceptions import PermissionDenied
|
|
13
6
|
from django.template.response import TemplateResponse
|
|
14
|
-
from django.urls import path
|
|
7
|
+
from django.urls import path
|
|
15
8
|
from django.utils.translation import gettext_lazy as _
|
|
16
9
|
|
|
17
10
|
|
|
@@ -21,243 +14,18 @@ def _get_django_settings():
|
|
|
21
14
|
)
|
|
22
15
|
|
|
23
16
|
|
|
24
|
-
class NetworkSetupForm(forms.Form):
|
|
25
|
-
prompt_for_password = forms.BooleanField(
|
|
26
|
-
label=_("Prompt for new WiFi password"),
|
|
27
|
-
required=False,
|
|
28
|
-
help_text=_("Add --password to request a password even when one is already configured."),
|
|
29
|
-
)
|
|
30
|
-
access_point_name = forms.CharField(
|
|
31
|
-
label=_("Access point name"),
|
|
32
|
-
required=False,
|
|
33
|
-
max_length=32,
|
|
34
|
-
help_text=_("Use --ap to set the wlan0 access point name."),
|
|
35
|
-
)
|
|
36
|
-
skip_firewall_validation = forms.BooleanField(
|
|
37
|
-
label=_("Skip firewall validation"),
|
|
38
|
-
required=False,
|
|
39
|
-
help_text=_("Add --no-firewall to bypass firewall port checks."),
|
|
40
|
-
)
|
|
41
|
-
skip_access_point_configuration = forms.BooleanField(
|
|
42
|
-
label=_("Skip access point configuration"),
|
|
43
|
-
required=False,
|
|
44
|
-
help_text=_("Add --no-ap to leave the access point configuration unchanged."),
|
|
45
|
-
)
|
|
46
|
-
allow_unsafe_changes = forms.BooleanField(
|
|
47
|
-
label=_("Allow modifying the active internet connection"),
|
|
48
|
-
required=False,
|
|
49
|
-
help_text=_("Include --unsafe to allow changes that may interrupt connectivity."),
|
|
50
|
-
)
|
|
51
|
-
interactive = forms.BooleanField(
|
|
52
|
-
label=_("Prompt before each step"),
|
|
53
|
-
required=False,
|
|
54
|
-
help_text=_("Run the script with --interactive to confirm each action."),
|
|
55
|
-
)
|
|
56
|
-
install_watchdog = forms.BooleanField(
|
|
57
|
-
label=_("Install WiFi watchdog service"),
|
|
58
|
-
required=False,
|
|
59
|
-
initial=True,
|
|
60
|
-
help_text=_("Keep selected to retain the watchdog or clear to add --no-watchdog."),
|
|
61
|
-
)
|
|
62
|
-
vnc_validation = forms.ChoiceField(
|
|
63
|
-
label=_("VNC validation"),
|
|
64
|
-
choices=(
|
|
65
|
-
("default", _("Use script default (skip validation)")),
|
|
66
|
-
("require", _("Require that a VNC service is enabled (--vnc)")),
|
|
67
|
-
),
|
|
68
|
-
initial="default",
|
|
69
|
-
required=True,
|
|
70
|
-
)
|
|
71
|
-
ethernet_subnet = forms.CharField(
|
|
72
|
-
label=_("Ethernet subnet"),
|
|
73
|
-
required=False,
|
|
74
|
-
help_text=_("Provide Z, Z/P (prefix 16 or 24), X.Y.Z, or X.Y.Z/P to supply --subnet."),
|
|
75
|
-
)
|
|
76
|
-
update_ap_password_only = forms.BooleanField(
|
|
77
|
-
label=_("Update access point password only"),
|
|
78
|
-
required=False,
|
|
79
|
-
help_text=_("Use --ap-set-password without running other setup steps."),
|
|
80
|
-
)
|
|
81
|
-
|
|
82
|
-
def clean_ethernet_subnet(self) -> str:
|
|
83
|
-
value = self.cleaned_data.get("ethernet_subnet", "")
|
|
84
|
-
if not value:
|
|
85
|
-
return ""
|
|
86
|
-
raw = value.strip()
|
|
87
|
-
match = re.fullmatch(
|
|
88
|
-
r"(?P<first>\d{1,3})(?:\.(?P<second>\d{1,3})\.(?P<third>\d{1,3}))?(?:/(?P<prefix>\d{1,2}))?",
|
|
89
|
-
raw,
|
|
90
|
-
)
|
|
91
|
-
if not match:
|
|
92
|
-
raise forms.ValidationError(
|
|
93
|
-
_("Enter a subnet in the form Z, Z/P, X.Y.Z, or X.Y.Z/P with prefix 16 or 24."),
|
|
94
|
-
)
|
|
95
|
-
first_octet = int(match.group("first"))
|
|
96
|
-
second = match.group("second")
|
|
97
|
-
third = match.group("third")
|
|
98
|
-
if second is not None and third is not None:
|
|
99
|
-
octets = [first_octet, int(second), int(third)]
|
|
100
|
-
for octet in octets:
|
|
101
|
-
if octet < 0 or octet > 255:
|
|
102
|
-
raise forms.ValidationError(
|
|
103
|
-
_("Subnet octets must be between 0 and 255."),
|
|
104
|
-
)
|
|
105
|
-
if octets[2] > 254:
|
|
106
|
-
raise forms.ValidationError(
|
|
107
|
-
_("The third subnet octet must be between 0 and 254."),
|
|
108
|
-
)
|
|
109
|
-
subnet_value = ".".join(str(octet) for octet in octets)
|
|
110
|
-
else:
|
|
111
|
-
if first_octet < 0 or first_octet > 254:
|
|
112
|
-
raise forms.ValidationError(
|
|
113
|
-
_("Subnet value must be between 0 and 254."),
|
|
114
|
-
)
|
|
115
|
-
subnet_value = str(first_octet)
|
|
116
|
-
prefix_value = match.group("prefix")
|
|
117
|
-
if prefix_value:
|
|
118
|
-
prefix = int(prefix_value)
|
|
119
|
-
if prefix not in {16, 24}:
|
|
120
|
-
raise forms.ValidationError(
|
|
121
|
-
_("Subnet prefix must be 16 or 24."),
|
|
122
|
-
)
|
|
123
|
-
return f"{subnet_value}/{prefix}"
|
|
124
|
-
return subnet_value
|
|
125
|
-
|
|
126
|
-
def clean(self) -> dict:
|
|
127
|
-
cleaned_data = super().clean()
|
|
128
|
-
if cleaned_data.get("update_ap_password_only"):
|
|
129
|
-
other_flags = [
|
|
130
|
-
cleaned_data.get("prompt_for_password"),
|
|
131
|
-
bool(cleaned_data.get("access_point_name")),
|
|
132
|
-
cleaned_data.get("skip_firewall_validation"),
|
|
133
|
-
cleaned_data.get("skip_access_point_configuration"),
|
|
134
|
-
cleaned_data.get("allow_unsafe_changes"),
|
|
135
|
-
cleaned_data.get("interactive"),
|
|
136
|
-
bool(cleaned_data.get("ethernet_subnet")),
|
|
137
|
-
cleaned_data.get("vnc_validation") == "require",
|
|
138
|
-
not cleaned_data.get("install_watchdog", True),
|
|
139
|
-
]
|
|
140
|
-
if any(other_flags):
|
|
141
|
-
raise forms.ValidationError(
|
|
142
|
-
_(
|
|
143
|
-
"Update access point password only cannot be combined with other network-setup options."
|
|
144
|
-
)
|
|
145
|
-
)
|
|
146
|
-
return cleaned_data
|
|
147
|
-
|
|
148
|
-
def build_command(self, script_path: Path) -> list[str]:
|
|
149
|
-
command = [str(script_path)]
|
|
150
|
-
data = self.cleaned_data
|
|
151
|
-
if data.get("update_ap_password_only"):
|
|
152
|
-
command.append("--ap-set-password")
|
|
153
|
-
return command
|
|
154
|
-
if data.get("prompt_for_password"):
|
|
155
|
-
command.append("--password")
|
|
156
|
-
access_point_name = data.get("access_point_name")
|
|
157
|
-
if access_point_name:
|
|
158
|
-
command.extend(["--ap", access_point_name])
|
|
159
|
-
if data.get("skip_firewall_validation"):
|
|
160
|
-
command.append("--no-firewall")
|
|
161
|
-
if data.get("skip_access_point_configuration"):
|
|
162
|
-
command.append("--no-ap")
|
|
163
|
-
if data.get("allow_unsafe_changes"):
|
|
164
|
-
command.append("--unsafe")
|
|
165
|
-
if data.get("interactive"):
|
|
166
|
-
command.append("--interactive")
|
|
167
|
-
if not data.get("install_watchdog"):
|
|
168
|
-
command.append("--no-watchdog")
|
|
169
|
-
if data.get("vnc_validation") == "require":
|
|
170
|
-
command.append("--vnc")
|
|
171
|
-
ethernet_subnet = data.get("ethernet_subnet")
|
|
172
|
-
if ethernet_subnet:
|
|
173
|
-
command.extend(["--subnet", ethernet_subnet])
|
|
174
|
-
return command
|
|
175
|
-
|
|
176
|
-
|
|
177
17
|
def _environment_view(request):
|
|
178
18
|
env_vars = sorted(os.environ.items())
|
|
179
19
|
context = admin.site.each_context(request)
|
|
180
|
-
environment_tasks: list[dict[str, str]] = []
|
|
181
|
-
if request.user.is_superuser:
|
|
182
|
-
environment_tasks.append(
|
|
183
|
-
{
|
|
184
|
-
"name": _("Run network-setup"),
|
|
185
|
-
"description": _(
|
|
186
|
-
"Configure network services, stage managed NGINX sites, and review script output."
|
|
187
|
-
),
|
|
188
|
-
"url": reverse("admin:environment-network-setup"),
|
|
189
|
-
}
|
|
190
|
-
)
|
|
191
20
|
context.update(
|
|
192
21
|
{
|
|
193
22
|
"title": _("Environment"),
|
|
194
23
|
"env_vars": env_vars,
|
|
195
|
-
"environment_tasks":
|
|
24
|
+
"environment_tasks": [],
|
|
196
25
|
}
|
|
197
26
|
)
|
|
198
27
|
return TemplateResponse(request, "admin/environment.html", context)
|
|
199
28
|
|
|
200
|
-
|
|
201
|
-
def _environment_network_setup_view(request):
|
|
202
|
-
if not request.user.is_superuser:
|
|
203
|
-
raise PermissionDenied
|
|
204
|
-
|
|
205
|
-
script_path = Path(settings.BASE_DIR) / "network-setup.sh"
|
|
206
|
-
command_result: dict[str, object] | None = None
|
|
207
|
-
|
|
208
|
-
if request.method == "POST":
|
|
209
|
-
form = NetworkSetupForm(request.POST)
|
|
210
|
-
if form.is_valid():
|
|
211
|
-
command = form.build_command(script_path)
|
|
212
|
-
if not script_path.exists():
|
|
213
|
-
form.add_error(None, _("The network-setup.sh script could not be found."))
|
|
214
|
-
else:
|
|
215
|
-
try:
|
|
216
|
-
completed = subprocess.run(
|
|
217
|
-
command,
|
|
218
|
-
capture_output=True,
|
|
219
|
-
text=True,
|
|
220
|
-
cwd=settings.BASE_DIR,
|
|
221
|
-
check=False,
|
|
222
|
-
)
|
|
223
|
-
except FileNotFoundError:
|
|
224
|
-
form.add_error(None, _("The network-setup.sh script could not be executed."))
|
|
225
|
-
except OSError as exc:
|
|
226
|
-
form.add_error(
|
|
227
|
-
None,
|
|
228
|
-
_("Unable to execute network-setup.sh: %(error)s")
|
|
229
|
-
% {"error": str(exc)},
|
|
230
|
-
)
|
|
231
|
-
else:
|
|
232
|
-
if hasattr(shlex, "join"):
|
|
233
|
-
command_display = shlex.join(command)
|
|
234
|
-
else:
|
|
235
|
-
command_display = " ".join(shlex.quote(part) for part in command)
|
|
236
|
-
command_result = {
|
|
237
|
-
"command": command_display,
|
|
238
|
-
"stdout": completed.stdout,
|
|
239
|
-
"stderr": completed.stderr,
|
|
240
|
-
"returncode": completed.returncode,
|
|
241
|
-
"succeeded": completed.returncode == 0,
|
|
242
|
-
}
|
|
243
|
-
else:
|
|
244
|
-
form = NetworkSetupForm()
|
|
245
|
-
|
|
246
|
-
context = admin.site.each_context(request)
|
|
247
|
-
context.update(
|
|
248
|
-
{
|
|
249
|
-
"title": _("Run network-setup"),
|
|
250
|
-
"form": form,
|
|
251
|
-
"command_result": command_result,
|
|
252
|
-
"task_description": _(
|
|
253
|
-
"Configure script flags, execute network-setup, and review the captured output."
|
|
254
|
-
),
|
|
255
|
-
"back_url": reverse("admin:environment"),
|
|
256
|
-
}
|
|
257
|
-
)
|
|
258
|
-
return TemplateResponse(request, "admin/environment_network_setup.html", context)
|
|
259
|
-
|
|
260
|
-
|
|
261
29
|
def _config_view(request):
|
|
262
30
|
context = admin.site.each_context(request)
|
|
263
31
|
context.update(
|
|
@@ -276,11 +44,6 @@ def patch_admin_environment_view() -> None:
|
|
|
276
44
|
def get_urls():
|
|
277
45
|
urls = original_get_urls()
|
|
278
46
|
custom = [
|
|
279
|
-
path(
|
|
280
|
-
"environment/network-setup/",
|
|
281
|
-
admin.site.admin_view(_environment_network_setup_view),
|
|
282
|
-
name="environment-network-setup",
|
|
283
|
-
),
|
|
284
47
|
path(
|
|
285
48
|
"environment/",
|
|
286
49
|
admin.site.admin_view(_environment_view),
|