simo 2.11.1__py3-none-any.whl → 2.11.3__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 simo might be problematic. Click here for more details.
- simo/backups/__pycache__/tasks.cpython-312.pyc +0 -0
- simo/backups/tasks.py +96 -11
- {simo-2.11.1.dist-info → simo-2.11.3.dist-info}/METADATA +1 -1
- {simo-2.11.1.dist-info → simo-2.11.3.dist-info}/RECORD +8 -8
- {simo-2.11.1.dist-info → simo-2.11.3.dist-info}/WHEEL +0 -0
- {simo-2.11.1.dist-info → simo-2.11.3.dist-info}/entry_points.txt +0 -0
- {simo-2.11.1.dist-info → simo-2.11.3.dist-info}/licenses/LICENSE.md +0 -0
- {simo-2.11.1.dist-info → simo-2.11.3.dist-info}/top_level.txt +0 -0
|
Binary file
|
simo/backups/tasks.py
CHANGED
|
@@ -196,28 +196,110 @@ def get_backup_device(lsblk_data):
|
|
|
196
196
|
partition’ – is used.
|
|
197
197
|
"""
|
|
198
198
|
|
|
199
|
+
_MIN_SIZE_BYTES = 32 * 1024 * 1024 * 1024 # 32 GiB – keep in sync with
|
|
200
|
+
# _find_blank_removable_device.
|
|
201
|
+
|
|
202
|
+
def _device_size_bytes(dev_name: str):
|
|
203
|
+
"""Return size of *dev_name* in bytes (or ``None`` on failure)."""
|
|
204
|
+
|
|
205
|
+
for cmd in (
|
|
206
|
+
f"blockdev --getsize64 /dev/{dev_name}",
|
|
207
|
+
f"lsblk -b -dn -o SIZE /dev/{dev_name}",
|
|
208
|
+
):
|
|
209
|
+
try:
|
|
210
|
+
out = subprocess.check_output(
|
|
211
|
+
cmd, shell=True, stderr=subprocess.DEVNULL
|
|
212
|
+
).strip()
|
|
213
|
+
return int(out)
|
|
214
|
+
except Exception:
|
|
215
|
+
continue
|
|
216
|
+
return None
|
|
217
|
+
|
|
218
|
+
# ------------------------------------------------------------------
|
|
219
|
+
# Helper: does the filesystem already contain legacy backups?
|
|
220
|
+
# ------------------------------------------------------------------
|
|
221
|
+
|
|
222
|
+
def _entry_has_simo_backups(entry: dict) -> bool:
|
|
223
|
+
"""Return *True* when *entry* hosts legacy ``simo_backups`` folder.
|
|
224
|
+
|
|
225
|
+
The implementation borrows heavily from the _fs_is_empty() helper –
|
|
226
|
+
we temporarily mount the filesystem read-only when it is not mounted
|
|
227
|
+
yet, inspect the directory listing and clean everything up.
|
|
228
|
+
"""
|
|
229
|
+
|
|
230
|
+
mountpoint = entry.get("mountpoint")
|
|
231
|
+
cleanup = False
|
|
232
|
+
|
|
233
|
+
if not mountpoint:
|
|
234
|
+
tmp_dir = f"/tmp/simo-bk-{uuid.uuid4().hex[:8]}"
|
|
235
|
+
try:
|
|
236
|
+
os.makedirs(tmp_dir, exist_ok=True)
|
|
237
|
+
res = subprocess.run(
|
|
238
|
+
f"mount -o ro /dev/{entry['name']} {tmp_dir}",
|
|
239
|
+
shell=True,
|
|
240
|
+
stderr=subprocess.PIPE,
|
|
241
|
+
)
|
|
242
|
+
if res.returncode:
|
|
243
|
+
shutil.rmtree(tmp_dir, ignore_errors=True)
|
|
244
|
+
return False
|
|
245
|
+
mountpoint = tmp_dir
|
|
246
|
+
cleanup = True
|
|
247
|
+
except Exception:
|
|
248
|
+
shutil.rmtree(tmp_dir, ignore_errors=True)
|
|
249
|
+
return False
|
|
250
|
+
|
|
251
|
+
has_backups = os.path.isdir(os.path.join(mountpoint, "simo_backups"))
|
|
252
|
+
|
|
253
|
+
if cleanup:
|
|
254
|
+
subprocess.run(f"umount {mountpoint}", shell=True)
|
|
255
|
+
shutil.rmtree(mountpoint, ignore_errors=True)
|
|
256
|
+
|
|
257
|
+
return has_backups
|
|
258
|
+
|
|
259
|
+
# ------------------------------------------------------------------
|
|
260
|
+
# Phase 1 – look for properly prepared BACKUP partition **>=32 GiB**.
|
|
261
|
+
# This is the preferred modern approach.
|
|
262
|
+
# ------------------------------------------------------------------
|
|
263
|
+
|
|
199
264
|
for device in lsblk_data:
|
|
200
265
|
if not device.get("hotplug"):
|
|
201
266
|
continue
|
|
202
267
|
|
|
268
|
+
# Capacity check – skip devices smaller than the required threshold.
|
|
269
|
+
size_bytes = _device_size_bytes(device["name"])
|
|
270
|
+
if size_bytes is None:
|
|
271
|
+
print(f"Could not obtain capacity of: {device['name']}")
|
|
272
|
+
continue
|
|
273
|
+
|
|
274
|
+
if size_bytes < _MIN_SIZE_BYTES:
|
|
275
|
+
continue
|
|
276
|
+
|
|
203
277
|
# Prefer partitions explicitly labelled "BACKUP".
|
|
204
278
|
for child in device.get("children", []):
|
|
205
279
|
if _has_backup_label(child):
|
|
206
280
|
return child
|
|
207
281
|
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
# NOTE: We intentionally keep this logic after the new BACKUP label
|
|
212
|
-
# check so that freshly provisioned media (ext4+label) wins.
|
|
282
|
+
# ------------------------------------------------------------------
|
|
283
|
+
# Phase 2 – look for **existing** legacy backup drives.
|
|
284
|
+
# ------------------------------------------------------------------
|
|
213
285
|
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
286
|
+
if _find_blank_removable_device(lsblk_data):
|
|
287
|
+
# New empty disk is available, let's use it instead of trying to find
|
|
288
|
+
# legacy media
|
|
289
|
+
return None
|
|
290
|
+
|
|
291
|
+
for device in lsblk_data:
|
|
292
|
+
if not device.get("hotplug"):
|
|
293
|
+
continue
|
|
294
|
+
|
|
295
|
+
# Check the whole device first.
|
|
296
|
+
if device.get("mountpoint") or device.get("fstype"):
|
|
297
|
+
if _entry_has_simo_backups(device):
|
|
298
|
+
return device
|
|
217
299
|
|
|
218
|
-
#
|
|
300
|
+
# Check its partitions (if any).
|
|
219
301
|
for child in device.get("children", []):
|
|
220
|
-
if (child
|
|
302
|
+
if _entry_has_simo_backups(child):
|
|
221
303
|
return child
|
|
222
304
|
|
|
223
305
|
# Nothing has been found.
|
|
@@ -577,6 +659,9 @@ def perform_backup():
|
|
|
577
659
|
mac = str(hex(uuid.getnode()))
|
|
578
660
|
device_backups_path = f'{sd_mountpoint}/simo_backups/hub-{mac}'
|
|
579
661
|
|
|
662
|
+
if not os.path.exists(device_backups_path):
|
|
663
|
+
os.makedirs(device_backups_path)
|
|
664
|
+
|
|
580
665
|
drop_current_instance()
|
|
581
666
|
hub_meta = {
|
|
582
667
|
'instances': [inst.name for inst in Instance.objects.all()]
|
|
@@ -765,4 +850,4 @@ def setup_periodic_tasks(sender, **kwargs):
|
|
|
765
850
|
sender.add_periodic_task(60 * 60, check_backups.s())
|
|
766
851
|
# perform auto backup every 12 hours
|
|
767
852
|
sender.add_periodic_task(60 * 60 * 12, perform_backup.s())
|
|
768
|
-
sender.add_periodic_task(60 * 60, clean_old_logs.s())
|
|
853
|
+
sender.add_periodic_task(60 * 60, clean_old_logs.s())
|
|
@@ -65,7 +65,7 @@ simo/backups/admin.py,sha256=cEakxnQlOHvUf8LdBdekXpDAvnqPoVN8y7pnN3WK29A,2487
|
|
|
65
65
|
simo/backups/dynamic_settings.py,sha256=Q52RLa3UQsmAhqkwR16cM6pbBnIbXqmVQ2oIUP2ZVD0,416
|
|
66
66
|
simo/backups/models.py,sha256=-tgILgkqmBEuxBwoymKZN1a0UVQzmJvqWrIGYMMFDaQ,695
|
|
67
67
|
simo/backups/rescue.img.xz,sha256=sErJUejbS9wMlmeLXeTbzOjOEsXxLnHMn0tTJpn2ITo,62389472
|
|
68
|
-
simo/backups/tasks.py,sha256=
|
|
68
|
+
simo/backups/tasks.py,sha256=5f50Unkb4h0D3wcYYXK40EiwlRfL9LYHX85sJra-R9Q,30205
|
|
69
69
|
simo/backups/__pycache__/__init__.cpython-312.pyc,sha256=TAMZORllxjDG2r6KsDbR085kId1pURDKwMAaykHlt0w,125
|
|
70
70
|
simo/backups/__pycache__/__init__.cpython-38.pyc,sha256=vzOf-JIMeZ6P85FyvTpYev3mscFosUy-SJTshcQbOHU,161
|
|
71
71
|
simo/backups/__pycache__/admin.cpython-312.pyc,sha256=f0XBNqkwkFmJMx3C5328Axk_Ph6ZXElPrgOKN8pCuUY,3821
|
|
@@ -74,7 +74,7 @@ simo/backups/__pycache__/dynamic_settings.cpython-312.pyc,sha256=PpnbOuz78x3hFQY
|
|
|
74
74
|
simo/backups/__pycache__/dynamic_settings.cpython-38.pyc,sha256=51gJFjn_XqQBRoHeubo6ppb9pNuFQKI5hAR0ms9flE8,731
|
|
75
75
|
simo/backups/__pycache__/models.cpython-312.pyc,sha256=Re77ADeTs4A4SYXvAVJ3kscH4nAx9FtkagejTZRLI7s,1704
|
|
76
76
|
simo/backups/__pycache__/models.cpython-38.pyc,sha256=zclX7HwOT4_izweyKNQ8LmgSHb3hNcYcfsSiwwfQoLY,1220
|
|
77
|
-
simo/backups/__pycache__/tasks.cpython-312.pyc,sha256=
|
|
77
|
+
simo/backups/__pycache__/tasks.cpython-312.pyc,sha256=rKK_7VRSP_a7_jajp7H3vaZRQDTucGN8DnUsil6_7GI,34593
|
|
78
78
|
simo/backups/__pycache__/tasks.cpython-38.pyc,sha256=bKz_Rxt_H0lC0d9_4Dxqv7cirQDSH9LVurZZC0LU94s,9179
|
|
79
79
|
simo/backups/migrations/0001_initial.py,sha256=0LzCusTUyYf61ksiepdnqXIuYYNTNd_djh_Wa484HA0,770
|
|
80
80
|
simo/backups/migrations/0002_backuplog_backup_level_backup_size.py,sha256=w9T9MQWuecy91OZE1fMExriwPuXA8HMPKsPwXhmC8_k,1023
|
|
@@ -11004,9 +11004,9 @@ simo/users/templates/invitations/expired_msg.html,sha256=47DEQpj8HBSa-_TImW-5JCe
|
|
|
11004
11004
|
simo/users/templates/invitations/expired_suggestion.html,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
11005
11005
|
simo/users/templates/invitations/taken_msg.html,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
11006
11006
|
simo/users/templates/invitations/taken_suggestion.html,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
11007
|
-
simo-2.11.
|
|
11008
|
-
simo-2.11.
|
|
11009
|
-
simo-2.11.
|
|
11010
|
-
simo-2.11.
|
|
11011
|
-
simo-2.11.
|
|
11012
|
-
simo-2.11.
|
|
11007
|
+
simo-2.11.3.dist-info/licenses/LICENSE.md,sha256=M7wm1EmMGDtwPRdg7kW4d00h1uAXjKOT3HFScYQMeiE,34916
|
|
11008
|
+
simo-2.11.3.dist-info/METADATA,sha256=DtRo89tZHFPFXfWl3eeu90EIPEzPwDBvzHg_-nTwo4A,2028
|
|
11009
|
+
simo-2.11.3.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
11010
|
+
simo-2.11.3.dist-info/entry_points.txt,sha256=S9PwnUYmTSW7681GKDCxUbL0leRJIaRk6fDQIKgbZBA,135
|
|
11011
|
+
simo-2.11.3.dist-info/top_level.txt,sha256=GmS1hrAbpVqn9OWZh6UX82eIOdRLgYA82RG9fe8v4Rs,5
|
|
11012
|
+
simo-2.11.3.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|