mirror of
https://git.selfprivacy.org/SelfPrivacy/selfprivacy-rest-api.git
synced 2025-01-11 18:39:30 +00:00
Merge pull request 'Volume management fixes' (#45) from fix/do-volumes into master
Reviewed-on: https://git.selfprivacy.org/SelfPrivacy/selfprivacy-rest-api/pulls/45 Reviewed-by: houkime <houkime@protonmail.com>
This commit is contained in:
commit
a1267946fc
|
@ -27,4 +27,4 @@ async def get_token_header(
|
||||||
|
|
||||||
def get_api_version() -> str:
|
def get_api_version() -> str:
|
||||||
"""Get API version"""
|
"""Get API version"""
|
||||||
return "2.2.0"
|
return "2.2.1"
|
||||||
|
|
|
@ -23,7 +23,7 @@ class Storage:
|
||||||
else str(volume.size),
|
else str(volume.size),
|
||||||
free_space=str(volume.fsavail),
|
free_space=str(volume.fsavail),
|
||||||
used_space=str(volume.fsused),
|
used_space=str(volume.fsused),
|
||||||
root=volume.name == "sda1",
|
root=volume.is_root(),
|
||||||
name=volume.name,
|
name=volume.name,
|
||||||
model=volume.model,
|
model=volume.model,
|
||||||
serial=volume.serial,
|
serial=volume.serial,
|
||||||
|
|
|
@ -3,13 +3,12 @@ import base64
|
||||||
import subprocess
|
import subprocess
|
||||||
import typing
|
import typing
|
||||||
|
|
||||||
from selfprivacy_api.jobs import Job, JobStatus, Jobs
|
from selfprivacy_api.jobs import Job, Jobs
|
||||||
from selfprivacy_api.services.generic_service_mover import FolderMoveNames, move_service
|
from selfprivacy_api.services.generic_service_mover import FolderMoveNames, move_service
|
||||||
from selfprivacy_api.services.generic_status_getter import get_service_status
|
from selfprivacy_api.services.generic_status_getter import get_service_status
|
||||||
from selfprivacy_api.services.service import Service, ServiceDnsRecord, ServiceStatus
|
from selfprivacy_api.services.service import Service, ServiceDnsRecord, ServiceStatus
|
||||||
from selfprivacy_api.utils import ReadUserData, WriteUserData, get_domain
|
from selfprivacy_api.utils import ReadUserData, WriteUserData, get_domain
|
||||||
from selfprivacy_api.utils.block_devices import BlockDevice
|
from selfprivacy_api.utils.block_devices import BlockDevice
|
||||||
from selfprivacy_api.utils.huey import huey
|
|
||||||
import selfprivacy_api.utils.network as network_utils
|
import selfprivacy_api.utils.network as network_utils
|
||||||
from selfprivacy_api.services.bitwarden.icon import BITWARDEN_ICON
|
from selfprivacy_api.services.bitwarden.icon import BITWARDEN_ICON
|
||||||
|
|
||||||
|
@ -121,14 +120,6 @@ class Bitwarden(Service):
|
||||||
def get_folders() -> typing.List[str]:
|
def get_folders() -> typing.List[str]:
|
||||||
return ["/var/lib/bitwarden", "/var/lib/bitwarden_rs"]
|
return ["/var/lib/bitwarden", "/var/lib/bitwarden_rs"]
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def get_drive() -> str:
|
|
||||||
with ReadUserData() as user_data:
|
|
||||||
if user_data.get("useBinds", False):
|
|
||||||
return user_data.get("bitwarden", {}).get("location", "sda1")
|
|
||||||
else:
|
|
||||||
return "sda1"
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_dns_records() -> typing.List[ServiceDnsRecord]:
|
def get_dns_records() -> typing.List[ServiceDnsRecord]:
|
||||||
"""Return list of DNS records for Bitwarden service."""
|
"""Return list of DNS records for Bitwarden service."""
|
||||||
|
|
|
@ -83,7 +83,7 @@ def move_service(
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
# Make sure the volume is mounted
|
# Make sure the volume is mounted
|
||||||
if volume.name != "sda1" and f"/volumes/{volume.name}" not in volume.mountpoints:
|
if not volume.is_root() and f"/volumes/{volume.name}" not in volume.mountpoints:
|
||||||
Jobs.update(
|
Jobs.update(
|
||||||
job=job,
|
job=job,
|
||||||
status=JobStatus.ERROR,
|
status=JobStatus.ERROR,
|
||||||
|
|
|
@ -9,7 +9,6 @@ from selfprivacy_api.services.generic_status_getter import get_service_status
|
||||||
from selfprivacy_api.services.service import Service, ServiceDnsRecord, ServiceStatus
|
from selfprivacy_api.services.service import Service, ServiceDnsRecord, ServiceStatus
|
||||||
from selfprivacy_api.utils import ReadUserData, WriteUserData, get_domain
|
from selfprivacy_api.utils import ReadUserData, WriteUserData, get_domain
|
||||||
from selfprivacy_api.utils.block_devices import BlockDevice
|
from selfprivacy_api.utils.block_devices import BlockDevice
|
||||||
from selfprivacy_api.utils.huey import huey
|
|
||||||
import selfprivacy_api.utils.network as network_utils
|
import selfprivacy_api.utils.network as network_utils
|
||||||
from selfprivacy_api.services.gitea.icon import GITEA_ICON
|
from selfprivacy_api.services.gitea.icon import GITEA_ICON
|
||||||
|
|
||||||
|
@ -116,14 +115,6 @@ class Gitea(Service):
|
||||||
def get_folders() -> typing.List[str]:
|
def get_folders() -> typing.List[str]:
|
||||||
return ["/var/lib/gitea"]
|
return ["/var/lib/gitea"]
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def get_drive() -> str:
|
|
||||||
with ReadUserData() as user_data:
|
|
||||||
if user_data.get("useBinds", False):
|
|
||||||
return user_data.get("gitea", {}).get("location", "sda1")
|
|
||||||
else:
|
|
||||||
return "sda1"
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_dns_records() -> typing.List[ServiceDnsRecord]:
|
def get_dns_records() -> typing.List[ServiceDnsRecord]:
|
||||||
return [
|
return [
|
||||||
|
|
|
@ -3,16 +3,13 @@ import base64
|
||||||
import subprocess
|
import subprocess
|
||||||
import typing
|
import typing
|
||||||
|
|
||||||
from selfprivacy_api.jobs import Job, Jobs
|
from selfprivacy_api.jobs import Job
|
||||||
from selfprivacy_api.services.generic_service_mover import FolderMoveNames, move_service
|
|
||||||
from selfprivacy_api.services.generic_status_getter import (
|
from selfprivacy_api.services.generic_status_getter import (
|
||||||
get_service_status,
|
|
||||||
get_service_status_from_several_units,
|
get_service_status_from_several_units,
|
||||||
)
|
)
|
||||||
from selfprivacy_api.services.service import Service, ServiceDnsRecord, ServiceStatus
|
from selfprivacy_api.services.service import Service, ServiceDnsRecord, ServiceStatus
|
||||||
from selfprivacy_api.utils import ReadUserData, WriteUserData, get_domain
|
from selfprivacy_api.utils import ReadUserData, WriteUserData, get_domain
|
||||||
from selfprivacy_api.utils.block_devices import BlockDevice
|
from selfprivacy_api.utils.block_devices import BlockDevice
|
||||||
from selfprivacy_api.utils.huey import huey
|
|
||||||
import selfprivacy_api.utils.network as network_utils
|
import selfprivacy_api.utils.network as network_utils
|
||||||
from selfprivacy_api.services.jitsi.icon import JITSI_ICON
|
from selfprivacy_api.services.jitsi.icon import JITSI_ICON
|
||||||
|
|
||||||
|
@ -87,18 +84,27 @@ class Jitsi(Service):
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def stop():
|
def stop():
|
||||||
subprocess.run(["systemctl", "stop", "jitsi-videobridge.service"])
|
subprocess.run(
|
||||||
subprocess.run(["systemctl", "stop", "jicofo.service"])
|
["systemctl", "stop", "jitsi-videobridge.service"],
|
||||||
|
check=False,
|
||||||
|
)
|
||||||
|
subprocess.run(["systemctl", "stop", "jicofo.service"], check=False)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def start():
|
def start():
|
||||||
subprocess.run(["systemctl", "start", "jitsi-videobridge.service"])
|
subprocess.run(
|
||||||
subprocess.run(["systemctl", "start", "jicofo.service"])
|
["systemctl", "start", "jitsi-videobridge.service"],
|
||||||
|
check=False,
|
||||||
|
)
|
||||||
|
subprocess.run(["systemctl", "start", "jicofo.service"], check=False)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def restart():
|
def restart():
|
||||||
subprocess.run(["systemctl", "restart", "jitsi-videobridge.service"])
|
subprocess.run(
|
||||||
subprocess.run(["systemctl", "restart", "jicofo.service"])
|
["systemctl", "restart", "jitsi-videobridge.service"],
|
||||||
|
check=False,
|
||||||
|
)
|
||||||
|
subprocess.run(["systemctl", "restart", "jicofo.service"], check=False)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_configuration():
|
def get_configuration():
|
||||||
|
@ -116,10 +122,6 @@ class Jitsi(Service):
|
||||||
def get_folders() -> typing.List[str]:
|
def get_folders() -> typing.List[str]:
|
||||||
return ["/var/lib/jitsi-meet"]
|
return ["/var/lib/jitsi-meet"]
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def get_drive() -> str:
|
|
||||||
return "sda1"
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_dns_records() -> typing.List[ServiceDnsRecord]:
|
def get_dns_records() -> typing.List[ServiceDnsRecord]:
|
||||||
ip4 = network_utils.get_ip4()
|
ip4 = network_utils.get_ip4()
|
||||||
|
|
|
@ -4,16 +4,14 @@ import base64
|
||||||
import subprocess
|
import subprocess
|
||||||
import typing
|
import typing
|
||||||
|
|
||||||
from selfprivacy_api.jobs import Job, JobStatus, Jobs
|
from selfprivacy_api.jobs import Job, Jobs
|
||||||
from selfprivacy_api.services.generic_service_mover import FolderMoveNames, move_service
|
from selfprivacy_api.services.generic_service_mover import FolderMoveNames, move_service
|
||||||
from selfprivacy_api.services.generic_status_getter import (
|
from selfprivacy_api.services.generic_status_getter import (
|
||||||
get_service_status,
|
|
||||||
get_service_status_from_several_units,
|
get_service_status_from_several_units,
|
||||||
)
|
)
|
||||||
from selfprivacy_api.services.service import Service, ServiceDnsRecord, ServiceStatus
|
from selfprivacy_api.services.service import Service, ServiceDnsRecord, ServiceStatus
|
||||||
import selfprivacy_api.utils as utils
|
from selfprivacy_api import utils
|
||||||
from selfprivacy_api.utils.block_devices import BlockDevice
|
from selfprivacy_api.utils.block_devices import BlockDevice
|
||||||
from selfprivacy_api.utils.huey import huey
|
|
||||||
import selfprivacy_api.utils.network as network_utils
|
import selfprivacy_api.utils.network as network_utils
|
||||||
from selfprivacy_api.services.mailserver.icon import MAILSERVER_ICON
|
from selfprivacy_api.services.mailserver.icon import MAILSERVER_ICON
|
||||||
|
|
||||||
|
@ -23,7 +21,7 @@ class MailServer(Service):
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_id() -> str:
|
def get_id() -> str:
|
||||||
return "mailserver"
|
return "email"
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_display_name() -> str:
|
def get_display_name() -> str:
|
||||||
|
@ -78,18 +76,18 @@ class MailServer(Service):
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def stop():
|
def stop():
|
||||||
subprocess.run(["systemctl", "stop", "dovecot2.service"])
|
subprocess.run(["systemctl", "stop", "dovecot2.service"], check=False)
|
||||||
subprocess.run(["systemctl", "stop", "postfix.service"])
|
subprocess.run(["systemctl", "stop", "postfix.service"], check=False)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def start():
|
def start():
|
||||||
subprocess.run(["systemctl", "start", "dovecot2.service"])
|
subprocess.run(["systemctl", "start", "dovecot2.service"], check=False)
|
||||||
subprocess.run(["systemctl", "start", "postfix.service"])
|
subprocess.run(["systemctl", "start", "postfix.service"], check=False)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def restart():
|
def restart():
|
||||||
subprocess.run(["systemctl", "restart", "dovecot2.service"])
|
subprocess.run(["systemctl", "restart", "dovecot2.service"], check=False)
|
||||||
subprocess.run(["systemctl", "restart", "postfix.service"])
|
subprocess.run(["systemctl", "restart", "postfix.service"], check=False)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_configuration():
|
def get_configuration():
|
||||||
|
@ -107,14 +105,6 @@ class MailServer(Service):
|
||||||
def get_folders() -> typing.List[str]:
|
def get_folders() -> typing.List[str]:
|
||||||
return ["/var/vmail", "/var/sieve"]
|
return ["/var/vmail", "/var/sieve"]
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def get_drive() -> str:
|
|
||||||
with utils.ReadUserData() as user_data:
|
|
||||||
if user_data.get("useBinds", False):
|
|
||||||
return user_data.get("mailserver", {}).get("location", "sda1")
|
|
||||||
else:
|
|
||||||
return "sda1"
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_dns_records() -> typing.List[ServiceDnsRecord]:
|
def get_dns_records() -> typing.List[ServiceDnsRecord]:
|
||||||
domain = utils.get_domain()
|
domain = utils.get_domain()
|
||||||
|
@ -142,7 +132,7 @@ class MailServer(Service):
|
||||||
type="MX", name=domain, content=domain, ttl=3600, priority=10
|
type="MX", name=domain, content=domain, ttl=3600, priority=10
|
||||||
),
|
),
|
||||||
ServiceDnsRecord(
|
ServiceDnsRecord(
|
||||||
type="TXT", name="_dmarc", content=f"v=DMARC1; p=none", ttl=18000
|
type="TXT", name="_dmarc", content="v=DMARC1; p=none", ttl=18000
|
||||||
),
|
),
|
||||||
ServiceDnsRecord(
|
ServiceDnsRecord(
|
||||||
type="TXT",
|
type="TXT",
|
||||||
|
@ -157,7 +147,7 @@ class MailServer(Service):
|
||||||
|
|
||||||
def move_to_volume(self, volume: BlockDevice) -> Job:
|
def move_to_volume(self, volume: BlockDevice) -> Job:
|
||||||
job = Jobs.add(
|
job = Jobs.add(
|
||||||
type_id="services.mailserver.move",
|
type_id="services.email.move",
|
||||||
name="Move Mail Server",
|
name="Move Mail Server",
|
||||||
description=f"Moving mailserver data to {volume.name}",
|
description=f"Moving mailserver data to {volume.name}",
|
||||||
)
|
)
|
||||||
|
@ -167,7 +157,7 @@ class MailServer(Service):
|
||||||
volume,
|
volume,
|
||||||
job,
|
job,
|
||||||
FolderMoveNames.default_foldermoves(self),
|
FolderMoveNames.default_foldermoves(self),
|
||||||
"mailserver",
|
"email",
|
||||||
)
|
)
|
||||||
|
|
||||||
return job
|
return job
|
||||||
|
|
|
@ -120,15 +120,6 @@ class Nextcloud(Service):
|
||||||
def get_folders() -> typing.List[str]:
|
def get_folders() -> typing.List[str]:
|
||||||
return ["/var/lib/nextcloud"]
|
return ["/var/lib/nextcloud"]
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def get_drive() -> str:
|
|
||||||
"""Get the name of disk where Nextcloud is installed."""
|
|
||||||
with ReadUserData() as user_data:
|
|
||||||
if user_data.get("useBinds", False):
|
|
||||||
return user_data.get("nextcloud", {}).get("location", "sda1")
|
|
||||||
else:
|
|
||||||
return "sda1"
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_dns_records() -> typing.List[ServiceDnsRecord]:
|
def get_dns_records() -> typing.List[ServiceDnsRecord]:
|
||||||
return [
|
return [
|
||||||
|
|
|
@ -2,8 +2,7 @@
|
||||||
import base64
|
import base64
|
||||||
import subprocess
|
import subprocess
|
||||||
import typing
|
import typing
|
||||||
from selfprivacy_api.jobs import Job, Jobs
|
from selfprivacy_api.jobs import Job
|
||||||
from selfprivacy_api.services.generic_service_mover import FolderMoveNames, move_service
|
|
||||||
from selfprivacy_api.services.generic_status_getter import get_service_status
|
from selfprivacy_api.services.generic_status_getter import get_service_status
|
||||||
from selfprivacy_api.services.service import Service, ServiceDnsRecord, ServiceStatus
|
from selfprivacy_api.services.service import Service, ServiceDnsRecord, ServiceStatus
|
||||||
from selfprivacy_api.utils import ReadUserData, WriteUserData
|
from selfprivacy_api.utils import ReadUserData, WriteUserData
|
||||||
|
@ -77,15 +76,15 @@ class Ocserv(Service):
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def stop():
|
def stop():
|
||||||
subprocess.run(["systemctl", "stop", "ocserv.service"])
|
subprocess.run(["systemctl", "stop", "ocserv.service"], check=False)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def start():
|
def start():
|
||||||
subprocess.run(["systemctl", "start", "ocserv.service"])
|
subprocess.run(["systemctl", "start", "ocserv.service"], check=False)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def restart():
|
def restart():
|
||||||
subprocess.run(["systemctl", "restart", "ocserv.service"])
|
subprocess.run(["systemctl", "restart", "ocserv.service"], check=False)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_configuration():
|
def get_configuration():
|
||||||
|
@ -99,10 +98,6 @@ class Ocserv(Service):
|
||||||
def get_logs():
|
def get_logs():
|
||||||
return ""
|
return ""
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def get_drive() -> str:
|
|
||||||
return "sda1"
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_dns_records() -> typing.List[ServiceDnsRecord]:
|
def get_dns_records() -> typing.List[ServiceDnsRecord]:
|
||||||
return [
|
return [
|
||||||
|
|
|
@ -119,14 +119,6 @@ class Pleroma(Service):
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def get_drive() -> str:
|
|
||||||
with ReadUserData() as user_data:
|
|
||||||
if user_data.get("useBinds", False):
|
|
||||||
return user_data.get("pleroma", {}).get("location", "sda1")
|
|
||||||
else:
|
|
||||||
return "sda1"
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_dns_records() -> typing.List[ServiceDnsRecord]:
|
def get_dns_records() -> typing.List[ServiceDnsRecord]:
|
||||||
return [
|
return [
|
||||||
|
|
|
@ -6,10 +6,11 @@ import typing
|
||||||
from pydantic import BaseModel
|
from pydantic import BaseModel
|
||||||
from selfprivacy_api.jobs import Job
|
from selfprivacy_api.jobs import Job
|
||||||
|
|
||||||
from selfprivacy_api.utils.block_devices import BlockDevice
|
from selfprivacy_api.utils.block_devices import BlockDevice, BlockDevices
|
||||||
|
|
||||||
from selfprivacy_api.services.generic_size_counter import get_storage_usage
|
from selfprivacy_api.services.generic_size_counter import get_storage_usage
|
||||||
from selfprivacy_api.services.owned_path import OwnedPath
|
from selfprivacy_api.services.owned_path import OwnedPath
|
||||||
|
from selfprivacy_api import utils
|
||||||
from selfprivacy_api.utils.waitloop import wait_until_true
|
from selfprivacy_api.utils.waitloop import wait_until_true
|
||||||
|
|
||||||
DEFAULT_START_STOP_TIMEOUT = 10 * 60
|
DEFAULT_START_STOP_TIMEOUT = 10 * 60
|
||||||
|
@ -197,10 +198,23 @@ class Service(ABC):
|
||||||
def get_dns_records() -> typing.List[ServiceDnsRecord]:
|
def get_dns_records() -> typing.List[ServiceDnsRecord]:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@staticmethod
|
@classmethod
|
||||||
@abstractmethod
|
def get_drive(cls) -> str:
|
||||||
def get_drive() -> str:
|
"""
|
||||||
pass
|
Get the name of the drive/volume where the service is located.
|
||||||
|
Example values are `sda1`, `vda`, `sdb`.
|
||||||
|
"""
|
||||||
|
root_device: str = BlockDevices().get_root_block_device().name
|
||||||
|
if not cls.is_movable():
|
||||||
|
return root_device
|
||||||
|
with utils.ReadUserData() as userdata:
|
||||||
|
if userdata.get("useBinds", False):
|
||||||
|
return userdata.get(cls.get_id(), {}).get(
|
||||||
|
"location",
|
||||||
|
root_device,
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
return root_device
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_folders(cls) -> typing.List[str]:
|
def get_folders(cls) -> typing.List[str]:
|
||||||
|
|
|
@ -10,7 +10,6 @@ from os import path
|
||||||
|
|
||||||
from selfprivacy_api.jobs import Job
|
from selfprivacy_api.jobs import Job
|
||||||
from selfprivacy_api.services.service import Service, ServiceDnsRecord, ServiceStatus
|
from selfprivacy_api.services.service import Service, ServiceDnsRecord, ServiceStatus
|
||||||
from selfprivacy_api.utils import ReadUserData, get_domain
|
|
||||||
from selfprivacy_api.utils.block_devices import BlockDevice
|
from selfprivacy_api.utils.block_devices import BlockDevice
|
||||||
import selfprivacy_api.utils.network as network_utils
|
import selfprivacy_api.utils.network as network_utils
|
||||||
|
|
||||||
|
|
|
@ -71,6 +71,12 @@ class BlockDevice:
|
||||||
def __hash__(self):
|
def __hash__(self):
|
||||||
return hash(self.name)
|
return hash(self.name)
|
||||||
|
|
||||||
|
def is_root(self) -> bool:
|
||||||
|
"""
|
||||||
|
Return True if the block device is the root device.
|
||||||
|
"""
|
||||||
|
return "/" in self.mountpoints
|
||||||
|
|
||||||
def stats(self) -> typing.Dict[str, typing.Any]:
|
def stats(self) -> typing.Dict[str, typing.Any]:
|
||||||
"""
|
"""
|
||||||
Update current data and return a dictionary of stats.
|
Update current data and return a dictionary of stats.
|
||||||
|
@ -175,6 +181,9 @@ class BlockDevices(metaclass=SingletonMetaclass):
|
||||||
# Ignore devices with type "rom"
|
# Ignore devices with type "rom"
|
||||||
if device["type"] == "rom":
|
if device["type"] == "rom":
|
||||||
continue
|
continue
|
||||||
|
# Ignore iso9660 devices
|
||||||
|
if device["fstype"] == "iso9660":
|
||||||
|
continue
|
||||||
if device["fstype"] is None:
|
if device["fstype"] is None:
|
||||||
if "children" in device:
|
if "children" in device:
|
||||||
for child in device["children"]:
|
for child in device["children"]:
|
||||||
|
@ -218,3 +227,12 @@ class BlockDevices(metaclass=SingletonMetaclass):
|
||||||
if mountpoint in block_device.mountpoints:
|
if mountpoint in block_device.mountpoints:
|
||||||
block_devices.append(block_device)
|
block_devices.append(block_device)
|
||||||
return block_devices
|
return block_devices
|
||||||
|
|
||||||
|
def get_root_block_device(self) -> BlockDevice:
|
||||||
|
"""
|
||||||
|
Return the root block device.
|
||||||
|
"""
|
||||||
|
for block_device in self.block_devices:
|
||||||
|
if "/" in block_device.mountpoints:
|
||||||
|
return block_device
|
||||||
|
raise RuntimeError("No root block device found")
|
||||||
|
|
2
setup.py
2
setup.py
|
@ -2,7 +2,7 @@ from setuptools import setup, find_packages
|
||||||
|
|
||||||
setup(
|
setup(
|
||||||
name="selfprivacy_api",
|
name="selfprivacy_api",
|
||||||
version="2.2.0",
|
version="2.2.1",
|
||||||
packages=find_packages(),
|
packages=find_packages(),
|
||||||
scripts=[
|
scripts=[
|
||||||
"selfprivacy_api/app.py",
|
"selfprivacy_api/app.py",
|
||||||
|
|
|
@ -488,3 +488,21 @@ def test_get_block_devices_by_mountpoint(lsblk_full_mock, authorized_client):
|
||||||
def test_get_block_devices_by_mountpoint_no_match(lsblk_full_mock, authorized_client):
|
def test_get_block_devices_by_mountpoint_no_match(lsblk_full_mock, authorized_client):
|
||||||
block_devices = BlockDevices().get_block_devices_by_mountpoint("/foo")
|
block_devices = BlockDevices().get_block_devices_by_mountpoint("/foo")
|
||||||
assert len(block_devices) == 0
|
assert len(block_devices) == 0
|
||||||
|
|
||||||
|
|
||||||
|
def test_get_root_block_device(lsblk_full_mock, authorized_client):
|
||||||
|
block_device = BlockDevices().get_root_block_device()
|
||||||
|
assert block_device is not None
|
||||||
|
assert block_device.name == "sda1"
|
||||||
|
assert block_device.path == "/dev/sda1"
|
||||||
|
assert block_device.fsavail == "4605702144"
|
||||||
|
assert block_device.fssize == "19814920192"
|
||||||
|
assert block_device.fstype == "ext4"
|
||||||
|
assert block_device.fsused == "14353719296"
|
||||||
|
assert block_device.mountpoints == ["/nix/store", "/"]
|
||||||
|
assert block_device.label is None
|
||||||
|
assert block_device.uuid == "ec80c004-baec-4a2c-851d-0e1807135511"
|
||||||
|
assert block_device.size == "20210236928"
|
||||||
|
assert block_device.model is None
|
||||||
|
assert block_device.serial is None
|
||||||
|
assert block_device.type == "part"
|
||||||
|
|
Loading…
Reference in a new issue