feat: add JMRI headless server role and main-street-station host
- New ansible/roles/jmri role: installs OpenJDK 21 headless, creates jmri service user, downloads JMRI 5.10, deploys JmriFaceless systemd unit - Handles dialout group membership for serial device access - Config restore task for post-reinstall recovery from GitHub backup - host_vars/main-street-station: profile_id and serial device (TODO: fill in) - Inventory: jmri_server group with main-street-station at 192.168.10.45 - Playbook: day1_deploy_jmri.yml (linux-baseline + jmri)
This commit is contained in:
16
ansible/host_vars/main-street-station/main.yml
Normal file
16
ansible/host_vars/main-street-station/main.yml
Normal file
@@ -0,0 +1,16 @@
|
||||
---
|
||||
# Host-specific vars for main-street-station (JMRI headless server)
|
||||
# LCRR - Lake Country Railroad, Milwaukee Road Oct 1956, HO scale
|
||||
|
||||
# JMRI profile ID — find with: ls ~/.jmri/profiles/ on the old box
|
||||
# Format: <name>.<8-char-hex> e.g. LCRR.3d3f1dfc
|
||||
# TODO: fill in after restoring config from GitHub backup
|
||||
jmri_profile_id: ""
|
||||
|
||||
# USB serial device for NCE command station
|
||||
# Verify after install: ls -la /dev/ttyUSB* /dev/ttyACM*
|
||||
jmri_serial_device: /dev/ttyUSB0
|
||||
|
||||
# Path to JMRI config backup for restore task (leave empty to skip)
|
||||
# Point at a local checkout of the LCRR GitHub repo
|
||||
jmri_config_src: ""
|
||||
@@ -80,6 +80,13 @@ honcho_server:
|
||||
ansible_user: wed
|
||||
ansible_become: true
|
||||
|
||||
jmri_server:
|
||||
hosts:
|
||||
main-street-station:
|
||||
ansible_host: 192.168.10.45
|
||||
ansible_user: wed
|
||||
ansible_become: true
|
||||
|
||||
papermc_server:
|
||||
# ansible-galaxy role install engonzal.papermc
|
||||
hosts:
|
||||
|
||||
24
ansible/playbooks/day1_deploy_jmri.yml
Normal file
24
ansible/playbooks/day1_deploy_jmri.yml
Normal file
@@ -0,0 +1,24 @@
|
||||
---
|
||||
# ============================================================================
|
||||
# day1_deploy_jmri.yml
|
||||
# ----------------------------------------------------------------------------
|
||||
# Deploys JMRI JmriFaceless headless server on main-street-station.
|
||||
# Applies linux-baseline first, then the jmri role.
|
||||
#
|
||||
# Usage:
|
||||
# ansible-playbook playbooks/day1_deploy_jmri.yml
|
||||
# ansible-playbook playbooks/day1_deploy_jmri.yml -e target=main-street-station
|
||||
#
|
||||
# Prerequisites:
|
||||
# 1. Host is in inventory under jmri_server group
|
||||
# 2. jmri_profile_id is set in host_vars/main-street-station.yml
|
||||
# 3. SSH access as 'wed' with sudo
|
||||
# ============================================================================
|
||||
|
||||
- name: Deploy JMRI headless server
|
||||
hosts: "{{ target | default('jmri_server') }}"
|
||||
become: true
|
||||
gather_facts: true
|
||||
roles:
|
||||
- linux-baseline
|
||||
- jmri
|
||||
25
ansible/roles/jmri/defaults/main.yml
Normal file
25
ansible/roles/jmri/defaults/main.yml
Normal file
@@ -0,0 +1,25 @@
|
||||
---
|
||||
# JMRI version to install
|
||||
jmri_version: "5.10"
|
||||
jmri_install_dir: /opt/JMRI
|
||||
jmri_download_url: "https://github.com/JMRI/JMRI/releases/download/v{{ jmri_version }}/JMRI.{{ jmri_version }}+Rca461bd266.tgz"
|
||||
|
||||
# Service user
|
||||
jmri_user: jmri
|
||||
jmri_group: jmri
|
||||
jmri_home: /home/jmri
|
||||
|
||||
# Profile — override per-host in inventory
|
||||
# Find on the old box: ls ~/.jmri/profiles/
|
||||
jmri_profile_id: ""
|
||||
|
||||
# Config restore source (path to the backed-up .jmri directory)
|
||||
jmri_config_src: ""
|
||||
|
||||
# Ports (for documentation / firewall rules)
|
||||
jmri_json_port: 12080
|
||||
jmri_withrottle_port: 12090
|
||||
|
||||
# USB serial device for NCE (set per-host in inventory)
|
||||
# e.g. /dev/ttyUSB0 or /dev/ttyACM0
|
||||
jmri_serial_device: /dev/ttyUSB0
|
||||
9
ansible/roles/jmri/handlers/main.yml
Normal file
9
ansible/roles/jmri/handlers/main.yml
Normal file
@@ -0,0 +1,9 @@
|
||||
---
|
||||
- name: Reload systemd
|
||||
ansible.builtin.systemd:
|
||||
daemon_reload: true
|
||||
|
||||
- name: Restart jmri
|
||||
ansible.builtin.systemd:
|
||||
name: jmri
|
||||
state: restarted
|
||||
13
ansible/roles/jmri/meta/main.yml
Normal file
13
ansible/roles/jmri/meta/main.yml
Normal file
@@ -0,0 +1,13 @@
|
||||
---
|
||||
galaxy_info:
|
||||
role_name: jmri
|
||||
author: JARVIS
|
||||
description: Deploy JMRI JmriFaceless headless server as a systemd service
|
||||
license: MIT
|
||||
min_ansible_version: "2.12"
|
||||
platforms:
|
||||
- name: Ubuntu
|
||||
versions:
|
||||
- jammy
|
||||
- noble
|
||||
dependencies: []
|
||||
87
ansible/roles/jmri/tasks/main.yml
Normal file
87
ansible/roles/jmri/tasks/main.yml
Normal file
@@ -0,0 +1,87 @@
|
||||
---
|
||||
- name: Install Java runtime (headless)
|
||||
ansible.builtin.apt:
|
||||
name: openjdk-21-jre-headless
|
||||
state: present
|
||||
update_cache: true
|
||||
|
||||
- name: Create JMRI system group
|
||||
ansible.builtin.group:
|
||||
name: "{{ jmri_group }}"
|
||||
state: present
|
||||
system: true
|
||||
|
||||
- name: Create JMRI service user
|
||||
ansible.builtin.user:
|
||||
name: "{{ jmri_user }}"
|
||||
group: "{{ jmri_group }}"
|
||||
home: "{{ jmri_home }}"
|
||||
shell: /usr/sbin/nologin
|
||||
system: true
|
||||
create_home: true
|
||||
state: present
|
||||
|
||||
- name: Add JMRI user to dialout group (serial device access)
|
||||
ansible.builtin.user:
|
||||
name: "{{ jmri_user }}"
|
||||
groups: dialout
|
||||
append: true
|
||||
|
||||
- name: Check if JMRI is already installed at correct version
|
||||
ansible.builtin.stat:
|
||||
path: "{{ jmri_install_dir }}/JmriFaceless"
|
||||
register: jmri_binary
|
||||
|
||||
- name: Download JMRI release archive
|
||||
ansible.builtin.get_url:
|
||||
url: "{{ jmri_download_url }}"
|
||||
dest: /tmp/JMRI-{{ jmri_version }}.tgz
|
||||
mode: '0644'
|
||||
when: not jmri_binary.stat.exists
|
||||
|
||||
- name: Create JMRI install directory
|
||||
ansible.builtin.file:
|
||||
path: "{{ jmri_install_dir }}"
|
||||
state: directory
|
||||
owner: "{{ jmri_user }}"
|
||||
group: "{{ jmri_group }}"
|
||||
mode: '0755'
|
||||
|
||||
- name: Extract JMRI archive
|
||||
ansible.builtin.unarchive:
|
||||
src: /tmp/JMRI-{{ jmri_version }}.tgz
|
||||
dest: "{{ jmri_install_dir }}"
|
||||
remote_src: true
|
||||
owner: "{{ jmri_user }}"
|
||||
group: "{{ jmri_group }}"
|
||||
extra_opts: ['--strip-components=1']
|
||||
when: not jmri_binary.stat.exists
|
||||
|
||||
- name: Restore JMRI config from backup
|
||||
ansible.builtin.copy:
|
||||
src: "{{ jmri_config_src }}/"
|
||||
dest: "{{ jmri_home }}/.jmri/"
|
||||
owner: "{{ jmri_user }}"
|
||||
group: "{{ jmri_group }}"
|
||||
mode: '0644'
|
||||
directory_mode: '0755'
|
||||
when: jmri_config_src | length > 0
|
||||
notify: Restart jmri
|
||||
|
||||
- name: Deploy JmriFaceless systemd unit
|
||||
ansible.builtin.template:
|
||||
src: jmri.service.j2
|
||||
dest: /etc/systemd/system/jmri.service
|
||||
owner: root
|
||||
group: root
|
||||
mode: '0644'
|
||||
notify:
|
||||
- Reload systemd
|
||||
- Restart jmri
|
||||
|
||||
- name: Enable and start JMRI service
|
||||
ansible.builtin.systemd:
|
||||
name: jmri
|
||||
enabled: true
|
||||
state: started
|
||||
daemon_reload: true
|
||||
35
ansible/roles/jmri/templates/jmri.service.j2
Normal file
35
ansible/roles/jmri/templates/jmri.service.j2
Normal file
@@ -0,0 +1,35 @@
|
||||
[Unit]
|
||||
Description=JMRI Server (JmriFaceless)
|
||||
Documentation=https://www.jmri.org/
|
||||
After=network.target
|
||||
# Give USB devices time to enumerate after boot
|
||||
After=dev-{{ jmri_serial_device | basename }}.device
|
||||
Wants=dev-{{ jmri_serial_device | basename }}.device
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
User={{ jmri_user }}
|
||||
Group={{ jmri_group }}
|
||||
WorkingDirectory={{ jmri_install_dir }}
|
||||
|
||||
# JmriFaceless requires a profile ID
|
||||
# Find yours: ls ~/.jmri/profiles/
|
||||
ExecStart={{ jmri_install_dir }}/JmriFaceless --profile={{ jmri_profile_id }}
|
||||
|
||||
# Restart on failure, not on clean exit (e.g. intentional shutdown from Jython)
|
||||
Restart=on-failure
|
||||
RestartSec=10
|
||||
|
||||
# Give hardware time to settle before retry
|
||||
TimeoutStartSec=30
|
||||
|
||||
# Logging — view with: journalctl -u jmri -f
|
||||
StandardOutput=journal
|
||||
StandardError=journal
|
||||
SyslogIdentifier=jmri
|
||||
|
||||
# Serial device access
|
||||
SupplementaryGroups=dialout
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
Reference in New Issue
Block a user