Name:           dracs
Version:        1.15.1
Release:        %autorelease
Summary:        Dell Rack & Asset Control System - CLI inventory tool for managing Dell bare-metal systems

License:        GPL-3.0-or-later
URL:            https://github.com/kambiz-aghaiepour/dracs
Source:         %{pypi_source dracs}

BuildArch:      noarch
BuildRequires:  python3-devel
BuildRequires:  systemd-rpm-macros


%global _description %{expand:
Simple, portable, self-contained dynamic CLI inventory tool for managing
Dell bare-metal systems inventory, warranty and lifecycle. Plugs directly
into Dell Support API, provides live hardware data management via SNMP,
and utilizes a portable SQLite database.}

%description %_description

%package -n     python3-dracs
Summary:        %{summary}
Requires:       nginx
Requires:       openssl
Requires:       python3-websockify
Requires:       tftp-server
Requires:       tftp
Provides:       user(dracs)
Provides:       group(dracs)

%description -n python3-dracs %_description


%prep
%autosetup -p1 -n dracs-%{version}


%generate_buildrequires
%pyproject_buildrequires


%build
%pyproject_wheel


%install
%pyproject_install
%pyproject_save_files -l dracs

install -D -m 0644 systemd/dracs-webapp.service %{buildroot}%{_unitdir}/dracs-webapp.service
install -d -m 0755 %{buildroot}%{_sysconfdir}/dracs
install -d -m 0755 %{buildroot}%{_sharedstatedir}/dracs
install -d -m 0755 %{buildroot}%{_sharedstatedir}/dracs/web/firmware
install -d -m 0755 %{buildroot}%{_sharedstatedir}/dracs/web/bios
install -d -m 0755 %{buildroot}%{_sharedstatedir}/dracs/web/tsr
install -d -m 0755 %{buildroot}%{_localstatedir}/log/dracs


%pre -n python3-dracs
getent group dracs >/dev/null || groupadd -r dracs
getent passwd dracs >/dev/null || \
    useradd -r -g dracs -M -d %{_sharedstatedir}/dracs -s /sbin/nologin \
    -c "DRACS service account" dracs
exit 0


%post -n python3-dracs
%systemd_post dracs-webapp.service

if [ $1 -eq 1 ]; then
    CONF_DIR=%{_sysconfdir}/dracs
    FQDN=$(hostname -f 2>/dev/null || hostname)

    # Seed config files on first install only
    if [ ! -f "${CONF_DIR}/.env" ] && [ ! -f "${CONF_DIR}/drac-passwords.ini" ] && [ ! -f "${CONF_DIR}/BIOS-filename.ini" ]; then
        cd "${CONF_DIR}" && sudo -u dracs %{_bindir}/dracs init 1>/dev/null 2>&1 || :

        # Rename example files to active config files
        [ -f "${CONF_DIR}/.env.example" ] && [ ! -f "${CONF_DIR}/.env" ] && \
            mv "${CONF_DIR}/.env.example" "${CONF_DIR}/.env"
        [ -f "${CONF_DIR}/drac-passwords.ini.example" ] && [ ! -f "${CONF_DIR}/drac-passwords.ini" ] && \
            mv "${CONF_DIR}/drac-passwords.ini.example" "${CONF_DIR}/drac-passwords.ini"
        [ -f "${CONF_DIR}/BIOS-filename.ini.example" ] && [ ! -f "${CONF_DIR}/BIOS-filename.ini" ] && \
            mv "${CONF_DIR}/BIOS-filename.ini.example" "${CONF_DIR}/BIOS-filename.ini"

        chown dracs:dracs "${CONF_DIR}"/.env "${CONF_DIR}"/drac-passwords.ini "${CONF_DIR}"/BIOS-filename.ini 2>/dev/null || :

        # Create system-wide config from .env
        [ -f "${CONF_DIR}/.env" ] && [ ! -f "${CONF_DIR}/dracs.conf" ] && \
            cp "${CONF_DIR}/.env" "${CONF_DIR}/dracs.conf" && \
            chown dracs:dracs "${CONF_DIR}/dracs.conf"
        # cleanup .env
        [ -f "${CONF_DIR}/dracs.conf" ] && [ -f "${CONF_DIR}/.env" ] && \
            rm -f "${CONF_DIR}/.env"
    fi

    # Edit config for flask secret and db path
    FLASK_SECRET=$(python -c "import secrets; print(secrets.token_hex(32))")
    sed -i "s/^FLASK_SECRET_KEY=.*/FLASK_SECRET_KEY=${FLASK_SECRET}/g" "${CONF_DIR}/dracs.conf"

    DRACS_DB=%{_sharedstatedir}/dracs/warranty.db
    sed -i "s,^DRACS_DB=.*,DRACS_DB=${DRACS_DB},g" "${CONF_DIR}/dracs.conf"

    # initialize db if non-existent
    [ ! -f "$DRACS_DB" ] && sudo -u dracs %{_bindir}/dracs li 1>/dev/null 2>&1 || :

    # Deploy nginx configs on first install only
    EXAMPLES_DIR=%{python3_sitelib}/dracs/examples/nginx
    NGINX_DIR=%{_sysconfdir}/nginx/conf.d

    if [ -d "${NGINX_DIR}" ]; then
        if [ ! -f "${NGINX_DIR}/dracs.conf" ] && [ -f "${EXAMPLES_DIR}/dracs.conf.example" ]; then
            cp "${EXAMPLES_DIR}/dracs.conf.example" "${NGINX_DIR}/dracs.conf"
            sed -i "s/dracs\.example\.com/${FQDN}/g" "${NGINX_DIR}/dracs.conf"
        fi

        if [ ! -f "${NGINX_DIR}/dracs_ssl.conf" ] && [ -f "${EXAMPLES_DIR}/dracs_ssl.conf.example" ]; then
            cp "${EXAMPLES_DIR}/dracs_ssl.conf.example" "${NGINX_DIR}/dracs_ssl.conf"
            sed -i "s/dracs\.example\.com/${FQDN}/g" "${NGINX_DIR}/dracs_ssl.conf"
        fi
    fi

    # Generate self-signed SSL certificate if not present
    CERT_DIR=/etc/pki/tls/certs
    if [ ! -f "${CERT_DIR}/${FQDN}.pem" ] || [ ! -f "${CERT_DIR}/${FQDN}.key" ]; then
        openssl req -x509 -nodes -days 3650 -newkey rsa:2048 \
            -keyout "${CERT_DIR}/${FQDN}.key" \
            -out "${CERT_DIR}/${FQDN}.pem" \
            -subj "/CN=${FQDN}" 2>/dev/null || :
        chmod 0600 "${CERT_DIR}/${FQDN}.key" 2>/dev/null || :
    fi

    # Configure TFTP server for iDRAC write access
    if [ -f /usr/lib/systemd/system/tftp.service ] && [ ! -f /etc/systemd/system/tftp.service ]; then
        cp /usr/lib/systemd/system/tftp.service /etc/systemd/system/tftp.service
        sed -i 's|^ExecStart=.*|ExecStart=/usr/sbin/in.tftpd -c -p -s /var/lib/tftpboot|' \
            /etc/systemd/system/tftp.service
    fi
    systemctl daemon-reload 2>/dev/null || :
    systemctl enable --now tftp.socket 2>/dev/null || :
    systemctl restart tftp.service 2>/dev/null || :
    chmod 777 /var/lib/tftpboot 2>/dev/null || :

    # SELinux booleans for TFTP
    setsebool -P tftp_home_dir 1 2>/dev/null || :
    setsebool -P tftp_anon_write 1 2>/dev/null || :
fi

# Open firewall ports 80, 443, and TFTP
if command -v firewall-cmd &>/dev/null && systemctl is-enabled firewalld &>/dev/null; then
    firewall-cmd --permanent --add-port=80/tcp 2>/dev/null || :
    firewall-cmd --permanent --add-port=443/tcp 2>/dev/null || :
    firewall-cmd --permanent --add-service=tftp 2>/dev/null || :
    firewall-cmd --reload 2>/dev/null || :
elif systemctl is-enabled iptables &>/dev/null; then
    iptables -C INPUT -p tcp --dport 80 -j ACCEPT 2>/dev/null || \
        iptables -I INPUT -p tcp --dport 80 -j ACCEPT 2>/dev/null || :
    iptables -C INPUT -p tcp --dport 443 -j ACCEPT 2>/dev/null || \
        iptables -I INPUT -p tcp --dport 443 -j ACCEPT 2>/dev/null || :
    modprobe nf_conntrack_tftp 2>/dev/null || :
    iptables -C INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT 2>/dev/null || \
        iptables -I INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT 2>/dev/null || :
    iptables -C INPUT -p udp --dport 69 -j ACCEPT 2>/dev/null || \
        iptables -I INPUT -p udp --dport 69 -j ACCEPT 2>/dev/null || :
    service iptables save 2>/dev/null || :
fi


%preun -n python3-dracs
%systemd_preun dracs-webapp.service


%postun -n python3-dracs
%systemd_postun_with_restart dracs-webapp.service


%check
%pyproject_check_import


%files -n python3-dracs -f %{pyproject_files}
%{_bindir}/dracs
%{_bindir}/dracs-webapp
%{_unitdir}/dracs-webapp.service
%dir %attr(0755, dracs, dracs) %{_sysconfdir}/dracs
%dir %attr(0755, dracs, dracs) %{_sharedstatedir}/dracs
%dir %attr(0755, dracs, dracs) %{_sharedstatedir}/dracs/web
%dir %attr(0755, dracs, dracs) %{_sharedstatedir}/dracs/web/firmware
%dir %attr(0755, dracs, dracs) %{_sharedstatedir}/dracs/web/bios
%dir %attr(0755, dracs, dracs) %{_sharedstatedir}/dracs/web/tsr
%dir %attr(0755, dracs, dracs) %{_localstatedir}/log/dracs


%changelog
%autochangelog
