# ───────────────────────────────────────────────────────────
# Ansible Control Node — Alpine-based, QEMU-bootable
#
# Dual-purpose image:
#   1. Run directly: docker run --rm -it ansible-node ansible-playbook ...
#   2. Convert to QEMU disk: scripts/build-qemu.sh extracts this rootfs
#      into a bootable qcow2 for pc-q35-10.0
#
# Integrations:
#   • Windows       — pywinrm + kerberos → WinRM
#   • Cisco ASA     — cisco.asa + paramiko → SSH/CLI
#   • Cisco Catalyst— cisco.ios + paramiko → SSH/CLI
#   • Cisco NX-OS   — cisco.nxos + paramiko → SSH/NX-API
#   • Linux         — native SSH (built-in ansible)
#   • VMware        — pyvmomi → vCenter/ESXi SOAP API
#   • MSSQL         — pymssql → SQL Server TDS
# ───────────────────────────────────────────────────────────

FROM alpine:3.20

# ── System labels ──────────────────────────────────────────
LABEL org.opencontainers.image.title="Ansible Control Node"
LABEL org.opencontainers.image.description="Minimal Ansible control node for Windows, Cisco, VMware, MSSQL, and Linux targets. QEMU-bootable via build-qemu.sh."
LABEL org.opencontainers.image.authors="ansible_testing"

# ── Kernel + base system ──────────────────────────────
# alpine-base = openrc + busybox + mdev + init scripts (no systemd)
# linux-virt  = kernel optimized for VMs (virtio, no firmware)
# docker      = container runtime for nested workloads
RUN apk add --no-cache \
    alpine-base \
    linux-virt \
    e2fsprogs \
    docker \
    docker-openrc \
    # ── Networking ────────────────────────────────────────
    dhcpcd \
    openssh-client \
    openssh-server \
    curl \
    wget \
    ca-certificates \
    bind-tools \
    # ── Kerberos (WinRM Kerberos auth to Windows) ────────
    krb5 \
    krb5-server \
    # ── FreeTDS (pymssql → MSSQL TDS protocol) ───────────
    freetds \
    freetds-dev \
    # ── Ansible + Python + SSH pw provider ───────────────
    ansible \
    sshpass \
    py3-pip \
    python3 \
    python3-dev \
    # ── Build deps for pip packages (purged after) ───────
    gcc \
    musl-dev \
    openssl-dev \
    krb5-dev \
    libffi-dev \
    # ── Quality-of-life ──────────────────────────────────
    bash \
    bash-completion \
    vim \
    tmux \
    git \
    jq \
    less \
    sudo

# ── Python packages for target integrations ──────────────
RUN pip3 install --no-cache-dir --break-system-packages \
    # Windows: WinRM + Kerberos
    'pywinrm[kerberos]>=0.4' \
    requests-kerberos \
    requests-ntlm \
    # Cisco: SSH/NETCONF/RESTCONF
    paramiko>=2.7 \
    ncclient>=0.6 \
    netmiko>=4.0 \
    scp \
    # VMware: vCenter/ESXi SOAP API
    pyvmomi>=8.0 \
    requests \
    # MSSQL: TDS protocol
    pymssql>=2.2 \
    # General utilities (required by many Ansible modules)
    jmespath>=1.0 \
    xmltodict>=0.13 \
    pyyaml>=6.0 \
    cryptography>=41.0 \
    packaging

# ── Ansible collections for all target types ──────────────
RUN ansible-galaxy collection install \
    # Windows management
    ansible.windows \
    # Network common (required by Cisco collections)
    ansible.netcommon \
    ansible.utils \
    # Cisco ASA firewalls
    cisco.asa \
    # Cisco Catalyst / IOS / IOS-XE switches & routers
    cisco.ios \
    # Cisco Nexus / NX-OS data center switches
    cisco.nxos \
    # VMware vCenter / ESXi
    community.vmware \
    # MSSQL Server
    community.general \
    community.mysql \
    microsoft.sql \
    # Crypto/certificates (needed for various modules)
    community.crypto \
    # Generic collection with many useful modules
    community.general

# ── OpenRC: enable boot services ──────────────────────────
# sysinit — devices, logging, hardware
RUN rc-update add devfs sysinit && \
    rc-update add dmesg sysinit && \
    rc-update add mdev sysinit && \
    rc-update add hwdrivers sysinit
# boot — modules, networking, hostname (urandom handled by bootmisc)
RUN rc-update add modules boot && \
    rc-update add sysctl boot && \
    rc-update add bootmisc boot && \
    rc-update add hostname boot && \
    rc-update add networking boot
# default — SSH, DHCP, Docker daemon
RUN rc-update add sshd default && \
    rc-update add dhcpcd default && \
    rc-update add docker default

# ── Serial console (ttyS0) for QEMU -nographic ────────────
RUN echo 'ttyS0::respawn:/sbin/agetty -L 115200 ttyS0 xterm-256color' \
    >> /etc/inittab

# ── Hostname (hosts managed by init/dhcpcd at boot) ────────
RUN echo 'ansible-node' > /etc/hostname

# ── SSH: allow root + ansible user ────────────────────────
RUN ssh-keygen -A && \
    sed -i 's/#PermitRootLogin prohibit-password/PermitRootLogin yes/' \
        /etc/ssh/sshd_config && \
    sed -i 's/#PasswordAuthentication yes/PasswordAuthentication yes/' \
        /etc/ssh/sshd_config && \
    echo 'UseDNS no' >> /etc/ssh/sshd_config

# ── Users ─────────────────────────────────────────────────
# Root password (change on first boot!)
RUN echo 'root:ansible' | chpasswd

# Ansible service user
RUN adduser -D ansible && \
    echo 'ansible:ansible' | chpasswd && \
    addgroup ansible wheel && \
    echo '%wheel ALL=(ALL) NOPASSWD: ALL' >> /etc/sudoers

# ── Docker: enable ansible user to run docker ─────────────
RUN addgroup ansible docker

# ── Working directory ─────────────────────────────────────
RUN mkdir -p /ansible/playbooks /ansible/inventory && \
    chown -R ansible:ansible /ansible

# ── Ansible config ────────────────────────────────────────
RUN mkdir -p /etc/ansible && \
    printf '[defaults]\n\
host_key_checking = False\n\
stdout_callback = yaml\n\
callback_whitelist = profile_tasks\n\
retry_files_enabled = False\n\
\n\
[ssh_connection]\n\
pipelining = True\n\
control_path = /tmp/ansible-%%h-%%p-%%r' \
    > /etc/ansible/ansible.cfg

# ── Default inventory (placeholder) ───────────────────────
RUN printf '[windows]\n\
# win-host.example.com\n\
\n\
[cisco_asa]\n\
# asa-firewall.example.com\n\
\n\
[cisco_ios]\n\
# catalyst-switch.example.com\n\
\n\
[cisco_nxos]\n\
# nexus-switch.example.com\n\
\n\
[vmware]\n\
# vcenter.example.com\n\
\n\
[mssql]\n\
# sql-server.example.com\n\
\n\
[linux]\n\
# debian-host.example.com\n\
\n\
[all:vars]\n\
ansible_user=ansible\n' \
    > /etc/ansible/hosts

# ── MOTD (friendly boot message) ──────────────────────────
RUN printf '\n\
\e[1;32m╔════════════════════════════════════════════════╗\e[0m\n\
\e[1;32m║   Ansible Control Node — Alpine Linux         ║\e[0m\n\
\e[1;32m╠════════════════════════════════════════════════╣\e[0m\n\
\e[1;32m║  Windows • Cisco • VMware • MSSQL • Linux     ║\e[0m\n\
\e[1;32m╠════════════════════════════════════════════════╣\e[0m\n\
\e[1;32m║  SSH:   ssh ansible@<ip> -p 22                ║\e[0m\n\
\e[1;32m║  Dir:   /ansible                               ║\e[0m\n\
\e[1;32m╚════════════════════════════════════════════════╝\e[0m\n\
' > /etc/motd

# ── First-boot: expand rootfs to fill disk, gen SSH keys ─
RUN printf '#!/bin/sh\n\
# Expand root filesystem to fill the underlying disk\n\
ROOTDEV=$(findmnt -n -o SOURCE / 2>/dev/null || echo /dev/vda)\n\
resize2fs "$ROOTDEV" 2>/dev/null || true\n\
# Re-generate SSH host keys if running from a cloned image\n\
if [ ! -f /etc/ssh/.host-keys-generated ]; then\n\
    ssh-keygen -A && touch /etc/ssh/.host-keys-generated\n\
fi\n' \
    > /etc/local.d/00-first-boot.start && \
    chmod +x /etc/local.d/00-first-boot.start && \
    rc-update add local default

WORKDIR /ansible
CMD ["/sbin/init"]
