from pyinfra import host
from pyinfra.facts.server import LinuxDistribution, Which
from pyinfra.facts.apt import AptPackages
from pyinfra.facts.pip import PipPackages
from pyinfra.facts.npm import NpmPackages
from pyinfra.operations import apt, pip, npm
from packaging import version
# Get system info
distro = host.get_fact(LinuxDistribution)
print(f"\nConfiguring packages on {distro['name']} {distro['version']}")
# Define required system packages
system_packages = {
"nginx": "1.18.0",
"postgresql": "14",
"redis-server": None, # Any version
}
# Check system packages
installed_system = host.get_fact(AptPackages)
missing_system = []
for package, min_version in system_packages.items():
if package not in installed_system:
missing_system.append(package)
print(f"❌ {package}: not installed")
else:
installed_ver = installed_system[package]
print(f"✓ {package}: {installed_ver}")
if min_version:
installed_parsed = version.parse(installed_ver.split("-")[0])
min_parsed = version.parse(min_version)
if installed_parsed < min_parsed:
print(f" ⚠️ Version {installed_ver} < {min_version}")
if missing_system:
apt.packages(
name="Install missing system packages",
packages=missing_system,
update=True,
_sudo=True,
)
# Check Python environment
if host.get_fact(Which, command="python3"):
venv_path = "/opt/myapp/venv"
python_packages = host.get_fact(PipPackages, virtualenv=venv_path)
required_python = ["django>=4.2", "celery>=5.3", "psycopg2-binary"]
pip.packages(
name="Install Python packages",
packages=required_python,
virtualenv=venv_path,
_sudo=True,
)
# Check Node.js environment
if host.get_fact(Which, command="npm"):
node_packages = host.get_fact(NpmPackages)
required_node = ["express", "socket.io", "winston"]
missing_node = [p for p in required_node if p not in node_packages]
if missing_node:
npm.packages(
name="Install Node.js packages",
packages=missing_node,
)
print("\n✓ Package configuration complete")