Refactoring into roles

This commit is contained in:
John Burwell 2025-04-26 12:59:37 -05:00
parent 1469b78faa
commit b4b67ba15b
31 changed files with 401 additions and 208 deletions

0
.ansible/.lock Normal file
View File

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
venv

4
.vscode/settings.json vendored Normal file
View File

@ -0,0 +1,4 @@
{
"ansible.python.interpreterPath": "/Users/john/Projects/ham-hotspot/venv/bin/python",
"ansible.validation.lint.arguments": "--fix"
}

View File

@ -0,0 +1,28 @@
---
# Global variables for Ham Hotspot provisioning
wifi:
country: US # ISO country code, affects regulatory Wi-Fi behavior
ssid: HamHotspot # Wi-Fi SSID
password: change_me_now # Wi-Fi password
channel: 6 # Wi-Fi channel (2.4 GHz band, e.g., 6 is common)
network:
lan_subnet: 192.168.7.0/24
lan_gateway: 192.168.7.1/24
lan_dns: 8.8.8.8
lan_domain: hamhotspot.internal
radios:
- port_name: radio0
device: plughw:AllInOneCable # Could be audio device for Direwolf, or real serial
speed: 1200
mycall: KI5QKX-11
ip_address: 44.127.254.1/24
# Example for second radio (optional, add when ready)
# - port_name: radio1
# device: /dev/ttyUSB1
# speed: 1200
# mycall: N0CALL-1
# ip_address: 44.31.1.2

View File

@ -1,184 +0,0 @@
---
- name: Ham Hotspot Bootstrap
hosts: localhost
become: yes
connection: local
vars_files:
- ../config/desired_state.yml
handlers:
- import_tasks: ../handlers/main.yml
tasks:
- name: Install base apt packages
apt:
name:
- ax25-tools
- ax25-apps
- libax25
- dnsmasq
- hostapd
- python3-flask
- build-essential
- cmake
- git
- alsa-utils
- libasound2-dev
- libudev-dev
- avahi-daemon
- libavahi-client-dev
state: present
update_cache: yes
- name: Clone Direwolf from GitHub
git:
repo: 'https://github.com/wb2osz/direwolf.git'
dest: /usr/local/src/direwolf
update: no
- name: Build Direwolf
shell: |
mkdir -p /usr/local/src/direwolf/build
cd /usr/local/src/direwolf/build
cmake ..
make -j4
args:
chdir: /usr/local/src/direwolf
creates: /usr/local/src/direwolf/build/direwolf
- name: Install Direwolf
shell: |
cd /usr/local/src/direwolf/build
make install
args:
chdir: /usr/local/src/direwolf/build
creates: /usr/local/bin/direwolf
- name: Copy systemd service templates
copy:
src: ../systemd/
dest: /lib/systemd/system/
mode: '0644'
owner: root
group: root
- name: Create /etc/ham-hotspot directory
file:
path: /etc/ham-hotspot
state: directory
mode: '0755'
owner: root
group: root
- name: Deploy Direwolf configuration
template:
src: ../templates/direwolf.conf.j2
dest: /etc/ham-hotspot/direwolf-{{ radio.port_name }}.conf
mode: '0644'
- name: Deploy hostapd configuration
template:
src: ../templates/hostapd.conf.j2
dest: /etc/hostapd/hostapd.conf
mode: '0644'
notify: Restart hostapd
- name: Deploy dnsmasq configuration
template:
src: ../templates/dnsmasq.conf.j2
dest: /etc/dnsmasq.d/ham-hotspot.conf
mode: '0644'
notify: Restart dnsmasq
- name: Deploy axports configuration
template:
src: ../templates/axports.j2
dest: /etc/ax25/axports
mode: '0644'
- name: Enable IP forwarding
copy:
dest: /etc/sysctl.d/ham-hotspot.conf
content: |
net.ipv4.ip_forward=1
mode: '0644'
- name: Unmask hostapd service
systemd:
name: hostapd
masked: no
- name: Ensure /etc/wpa_supplicant/wpa_supplicant.conf exists
file:
path: /etc/wpa_supplicant/wpa_supplicant.conf
state: touch
owner: root
group: root
mode: '0644'
- name: Ensure Wi-Fi country is set in wpa_supplicant.conf
blockinfile:
path: /etc/wpa_supplicant/wpa_supplicant.conf
marker: "# {mark} ANSIBLE MANAGED BLOCK - Wi-Fi Country Setting"
block: |
country={{ wifi.country }}
when: ansible_facts['distribution'] in ['Debian', 'Raspbian']
- name: Install unblock-wlan.service
copy:
src: ../systemd/unblock-wlan.service
dest: /etc/systemd/system/unblock-wlan.service
mode: '0644'
owner: root
group: root
- name: Reload systemd daemon
systemd:
daemon_reload: yes
- name: Enable and start unblock-wlan.service
systemd:
name: unblock-wlan.service
enabled: yes
state: started
- name: Enable and start Direwolf instance
systemd:
name: direwolf@radio0.service
enabled: yes
state: started
- name: Enable and start KISS TNC instance
systemd:
name: kisstnc@radio0.service
enabled: yes
state: started
- name: Enable and start AX.25 daemon
systemd:
name: ax25d.service
enabled: yes
state: started
- name: Assign static IP to ax0
shell: |
ip addr add {{ radio.ip_address }}/24 dev ax0 || true
ip link set ax0 up
- name: Enable and start hostapd
systemd:
name: hostapd.service
enabled: yes
state: started
- name: Assign static IP to wlan0
shell: |
ip addr add {{ network.lan_gateway }}/24 dev wlan0 || true
ip link set wlan0 up
- name: Enable and start dnsmasq
systemd:
name: dnsmasq.service
enabled: yes
state: started

13
ansible/site.yml Normal file
View File

@ -0,0 +1,13 @@
---
- name: Configure Ham Hotspot
hosts: localhost
connection: local
become: true
roles:
- base
- networking
- direwolf
- ax25
# - tuning
# - webui

View File

@ -1,19 +0,0 @@
# Configuration state for Ham Hotspot
wifi:
country: US
ssid: HamHotspot
password: change_me_now
channel: 6
network:
lan_subnet: 192.168.73.0/24
lan_gateway: 192.168.73.1
radio:
device: plughw:AllInOneCable
speed: 1200
mycall: KI5QKX-11
port_name: radio0
ip_address: 44.31.1.1/24
ptt: CM108

View File

@ -1,4 +1,8 @@
---
- name: Reload systemd
systemd:
daemon_reload: yes
- name: Restart hostapd
systemd:
name: hostapd

38
roles/ax25/tasks/main.yml Normal file
View File

@ -0,0 +1,38 @@
---
- name: Deploy axports configuration
ansible.builtin.template:
src: axports.j2
dest: /etc/ax25/axports
mode: "0644"
- name: Enable and start Direwolf instance
ansible.builtin.systemd:
name: direwolf@{{ radio.port_name }}.service
enabled: true
state: started
- name: Enable and start KISS TNC instance
ansible.builtin.systemd:
name: kisstnc@{{ radio.port_name }}.service
enabled: true
state: started
- name: Enable and start AX.25 daemon
ansible.builtin.systemd:
name: ax25d.service
enabled: true
state: started
# Deploy AX.25 systemd-networkd configs
- name: Deploy AX.25 systemd-networkd configs
loop: "{{ radios }}"
loop_control:
loop_var: radio
vars:
ax_iface: "{{ 'ax' + loop.index0 | string }}"
ansible.builtin.template:
src: ax.network.j2
dest: "/etc/systemd/network/{{ ax_iface }}.network"
owner: root
group: root
mode: "0644"

View File

@ -0,0 +1,5 @@
[Match]
Name={{ ax_iface }}
[Network]
Address={{ radio.ip_address }}

View File

@ -0,0 +1,3 @@
{% for radio in radios %}
{{ radio.port_name }} {{ radio.mycall }} {{ radio.speed }} 255 7 Ham Hotspot Radio {{ loop.index0 }}
{% endfor %}

47
roles/base/tasks/main.yml Normal file
View File

@ -0,0 +1,47 @@
---
- name: Install base system packages
apt:
name:
- ax25-tools
- ax25-apps
- libax25
- dnsmasq
- hostapd
- python3-flask
- build-essential
- cmake
- git
- alsa-utils
- libasound2-dev
state: present
update_cache: yes
- name: Install unblock-wlan service
template:
src: unblock-wlan.service.j2
dest: /etc/systemd/system/unblock-wlan.service
mode: '0644'
notify: Reload systemd
- name: Ensure /etc/wpa_supplicant/wpa_supplicant.conf exists
file:
path: /etc/wpa_supplicant/wpa_supplicant.conf
state: touch
owner: root
group: root
mode: '0644'
- name: Ensure Wi-Fi country is set
blockinfile:
path: /etc/wpa_supplicant/wpa_supplicant.conf
marker: "# {mark} ANSIBLE MANAGED BLOCK - Wi-Fi Country Setting"
block: |
country={{ wifi.country }}
when: ansible_facts['distribution'] in ['Debian', 'Raspbian']
notify: Restart unblock-wlan service
- name: Unmask hostapd service
systemd:
name: hostapd
masked: no
notify: Reload systemd

View File

@ -0,0 +1,44 @@
---
- name: Clone Direwolf from GitHub
git:
repo: 'https://github.com/wb2osz/direwolf.git'
dest: /usr/local/src/direwolf
update: no
- name: Build Direwolf
shell: |
mkdir -p /usr/local/src/direwolf/build
cd /usr/local/src/direwolf/build
cmake ..
make -j4
args:
chdir: /usr/local/src/direwolf
creates: /usr/local/src/direwolf/build/direwolf
- name: Install Direwolf
shell: |
cd /usr/local/src/direwolf/build
make install
args:
chdir: /usr/local/src/direwolf/build
creates: /usr/local/bin/direwolf
- name: Deploy Direwolf configuration
template:
src: direwolf.conf.j2
dest: /etc/ham-hotspot/direwolf-{{ radio.port_name }}.conf
mode: '0644'
- name: Deploy Direwolf systemd service
template:
src: direwolf@.service.j2
dest: /etc/systemd/system/direwolf@.service
mode: '0644'
notify: Reload systemd
- name: Deploy kisstnc systemd service
template:
src: kisstnc@.service.j2
dest: /etc/systemd/system/kisstnc@.service
mode: '0644'
notify: Reload systemd

View File

@ -0,0 +1,22 @@
---
- name: Reload systemd
ansible.builtin.systemd:
daemon_reload: true
- name: Restart systemd-networkd
ansible.builtin.systemd:
name: systemd-networkd
state: restarted
enabled: true
- name: Restart systemd-resolved
ansible.builtin.systemd:
name: systemd-resolved
state: restarted
enabled: true
- name: Restart hostapd
ansible.builtin.systemd:
name: hostapd
state: restarted
enabled: true

View File

@ -0,0 +1,39 @@
---
- name: Disable and stop legacy services
ansible.builtin.systemd:
name: "{{ item }}"
enabled: false
state: stopped
masked: true
loop:
- networking
- ifupdown
- ifupdown-pre
- dhcpcd
- dnsmasq
- isc-dhcp-client
- isc-dhcp-server
- isc-dhcp-common
- rsyslog
- name: Remove legacy configuration files
ansible.builtin.file:
path: "{{ item }}"
state: absent
loop:
- /etc/network
- /etc/dhcp
- name: Remove legacy packages
ansible.builtin.package:
name:
- ifupdown
- isc-dhcp-client
- isc-dhcp-server
- isc-dhcp-common
- dnsmasq
- rsyslog
- network-manager
- avahi-daemon
- libnss-mdns
state: absent

View File

@ -0,0 +1,30 @@
---
- name: Set up systemd networking
ansible.builtin.import_tasks:
file: systemd_networking.yml
tags: systemd_networking
- name: Set up devices
ansible.builtin.import_tasks:
file: systemd_networking_devices.yml
tags: devices
- name: Shut down legacy networking
ansible.builtin.import_tasks:
file: legacy_networking.yml
tags: legacy_networking
# Deploy hostapd configuration
- name: Deploy hostapd configuration
ansible.builtin.template:
src: hostapd.conf.j2
dest: /etc/hostapd/hostapd.conf
mode: "0644"
notify: Restart hostapd
# Start hostapd
- name: Enable and start hostapd
ansible.builtin.systemd:
name: hostapd
enabled: true
state: started

View File

@ -0,0 +1,27 @@
---
- name: Install systemd networking packages
ansible.builtin.package:
name:
- systemd-networkd
- systemd-resolved
- libnss-resolve
- libnss-mdns
state: present
- name: Create symlink for resolv.conf
ansible.builtin.file:
src: /run/systemd/resolve/stub-resolv.conf
dest: /etc/resolv.conf
state: link
- name: Enable and start systemd-networkd
ansible.builtin.systemd:
name: systemd-networkd
enabled: true
state: started
- name: Enable and start systemd-resolved
ansible.builtin.systemd:
name: systemd-resolved
enabled: true
state: started

View File

@ -0,0 +1,41 @@
---
# Create the bridge device (br0)
- name: Deploy br0 systemd-networkd bridge device (netdev)
ansible.builtin.template:
src: br0.netdev.j2
dest: /etc/systemd/network/br0.netdev
owner: root
group: root
mode: "0644"
notify: Restart systemd-networkd
# Configure br0 (assign IP and start DHCP server)
- name: Deploy br0 systemd-networkd network config
ansible.builtin.template:
src: br0.network.j2
dest: /etc/systemd/network/br0.network
owner: root
group: root
mode: "0644"
notify: Restart systemd-networkd
# Configure wlan0 to be a bridge device
- name: Deploy wlan0 systemd-networkd bridge config
ansible.builtin.template:
src: wlan0.network.j2
dest: /etc/systemd/network/wlan0.network
owner: root
group: root
mode: "0644"
notify: Restart systemd-networkd
# Configure eth0 to be a bridge device
- name: Deploy eth0 systemd-networkd bridge config
ansible.builtin.template:
src: eth0.network.j2
dest: /etc/systemd/network/eth0.network
owner: root
group: root
mode: "0644"
failed_when: false # (in case eth0 doesn't exist, e.g., Pi Zero)
notify: Restart systemd-networkd

View File

@ -0,0 +1,3 @@
[NetDev]
Name=br0
Kind=bridge

View File

@ -0,0 +1,15 @@
[Match]
Name=br0
[Network]
Address={{ network.lan_gateway }}
DHCPServer=yes
IPMasquade=ipv4
MulticastDNS=yes
LLMNR=yes
[DHCPServer]
PoolOffset=100
PoolSize=100
DNS={{ network.lan_dns }}
DomainName={{ network.lan_domain }}

View File

@ -0,0 +1,9 @@
[Match]
Name=eth0
[Network]
# Bridge=br0 # We could bridge it with wlan, but that would leave us with no internet uplink
LLMNR=yes
MulticastDNS=yes
DHCP=ipv4

View File

@ -0,0 +1,5 @@
[Match]
Name=wlan0
[Network]
Bridge=br0

View File

@ -0,0 +1,23 @@
---
- name: Deploy AX.25 tuning systemd templates
template:
src: ../templates/ax-tune@.service.j2
dest: /etc/systemd/system/ax-tune@.service
mode: '0644'
- name: Prune old AX.25 tuning services
import_tasks: prune_old_ax_tune.yml
- name: Enable and start AX.25 tuning services
loop: "{{ radios }}"
loop_control:
loop_var: radio
vars:
ax_iface: "{{ 'ax' + loop.index0|string }}"
radio_port: "{{ radio.port_name }}"
block:
- name: Enable tuning service for {{ ax_iface }}
systemd:
name: "ax-tune@{{ ax_iface }}.service"
enabled: yes
state: started

View File

@ -1 +0,0 @@
radio0 {{ radio.mycall }} 0 255 1 PiRadio AX.25 port

View File

@ -1,4 +0,0 @@
interface=wlan0
dhcp-range={{ network.lan_gateway | regex_replace('\.1$', '.100') }},{{ network.lan_gateway | regex_replace('\.1$', '.200') }},12h
dhcp-option=3,{{ network.lan_gateway }}
dhcp-option=6,8.8.8.8