-
-import os
-from pathlib import Path
-import subprocess
-import sys
-from typing import Optional, Union
-
-# external requirement
-import psutil
-
-# from nominatim.version import NOMINATIM_VERSION
-# from nominatim.db.connection import connect
-
-
-class ReportSystemInformation:
- """Generate a report about the host system including software versions, memory,
- storage, and database configuration."""
- def __init__(self):
- self._memory: int = psutil.virtual_memory().total
- self.friendly_memory: str = self._friendly_memory_string(self._memory)
- # psutil.cpu_count(logical=False) returns the number of CPU cores.
- # For number of logical cores (Hypthreaded), call psutil.cpu_count() or os.cpu_count()
- self.num_cpus: int = psutil.cpu_count(logical=False)
- self.os_info: str = self._os_name_info()
-
-### These are commented out because they have not been tested.
-# self.nominatim_ver: str = '{0[0]}.{0[1]}.{0[2]}-{0[3]}'.format(NOMINATIM_VERSION)
-# self._pg_version = conn.server_version_tuple()
-# self._postgis_version = conn.postgis_version_tuple()
-# self.postgresql_ver: str = self._convert_version(self._pg_version)
-# self.postgis_ver: str = self._convert_version(self._postgis_version)
-
- self.nominatim_ver: str = ""
- self.postgresql_ver: str = ""
- self.postgresql_config: str = ""
- self.postgis_ver: str = ""
-
- # the below commands require calling the shell to gather information
- self.disk_free: str = self._run_command(["df", "-h"])
- self.lsblk: str = self._run_command("lsblk")
- # psutil.disk_partitions() <- this function is similar to the above, but it is cross platform
-
- # Note: `systemd-detect-virt` command only works on Linux, on other OSes
- # should give a message: "Unknown (unable to find the 'systemd-detect-virt' command)"
- self.container_vm_env: str = self._run_command("systemd-detect-virt")
-
- def _convert_version(self, ver_tup: tuple) -> str:
- """converts tuple version (ver_tup) to a string representation"""
- return ".".join(map(str,ver_tup))
-
- def _friendly_memory_string(self, mem: int) -> str:
- """Create a user friendly string for the amount of memory specified as mem"""
- mem_magnitude = ('bytes', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB')
- mag = 0
- # determine order of magnitude
- while mem > 1000:
- mem /= 1000
- mag += 1
-
- return f"{mem:.1f} {mem_magnitude[mag]}"
-
-
- def _run_command(self, cmd: Union[str, list]) -> str:
- """Runs a command using the shell and returns the output from stdout"""
- try:
- if sys.version_info < (3, 7):
- cap_out = subprocess.run(cmd, stdout=subprocess.PIPE)
- else:
- cap_out = subprocess.run(cmd, capture_output=True)
- return cap_out.stdout.decode("utf-8")
- except FileNotFoundError:
- # non-Linux system should end up here
- return f"Unknown (unable to find the '{cmd}' command)"
-
-
- def _os_name_info(self) -> str:
- """Obtain Operating System Name (and possibly the version)"""
-
- os_info = None
- # man page os-release(5) details meaning of the fields
- if Path("/etc/os-release").is_file():
- os_info = self._from_file_find_line_portion("/etc/os-release", "PRETTY_NAME", "=")
- # alternative location
- elif Path("/usr/lib/os-release").is_file():
- os_info = self._from_file_find_line_portion("/usr/lib/os-release", "PRETTY_NAME", "=")
-
- # fallback on Python's os name
- if(os_info is None or os_info == ""):
- os_info = os.name
-
- # if the above is insufficient, take a look at neofetch's approach to OS detection
- return os_info
-
-
- # Note: Intended to be used on informational files like /proc
- def _from_file_find_line_portion(self, filename: str, start: str, sep: str,
- fieldnum: int = 1) -> Optional[str]:
- """open filename, finds the line starting with the 'start' string.
- Splits the line using seperator and returns a "fieldnum" from the split."""
- with open(filename) as fh:
- for line in fh:
- if line.startswith(start):
- result = line.split(sep)[fieldnum].strip()
- return result
-
- def report(self, out = sys.stdout, err = sys.stderr) -> None:
- """Generates the Markdown report.
-
- Optionally pass out or err parameters to redirect the output of stdout
- and stderr to other file objects."""
-
- # NOTE: This should be a report format. Any conversions or lookup has be
- # done, do that action in the __init__() or another function.
- message = """
-Use this information in your issue report at https://github.com/osm-search/Nominatim/issues
-Copy and paste or redirect the output of the file:
- $ ./collect_os_info.py > report.md
-"""
- report = f"""
-**Software Environment:**
-- Python version: {sys.version}
-- Nominatim version: {self.nominatim_ver}
-- PostgreSQL version: {self.postgresql_ver}
-- PostGIS version: {self.postgis_ver}
-- OS: {self.os_info}
-
-
-**Hardware Configuration:**
-- RAM: {self.friendly_memory}
-- number of CPUs: {self.num_cpus}
-- bare metal/AWS/other cloud service (per systemd-detect-virt(1)): {self.container_vm_env}
-- type and size of disks:
-**`df -h` - df - report file system disk space usage: **
-```
-{self.disk_free}
-```
-
-**lsblk - list block devices: **
-```
-{self.lsblk}
-```
-
-
-**Postgresql Configuration:**
-```
-{self.postgresql_config}
-```
-**Notes**
-Please add any notes about anything above anything above that is incorrect.
- """
-
- print(message, file = err)
- print(report, file = out)
-
-
-if __name__ == "__main__":
- sys_info = ReportSystemInformation()
- sys_info.report()
\ No newline at end of file