454 lines
16 KiB
YAML
454 lines
16 KiB
YAML
---
|
||
# Update_Rest_WMT_client – Push standard WMT client files to target devices
|
||
# ──────────────────────────────────────────────────────────────────────────
|
||
# What this playbook does (in order):
|
||
#
|
||
# 1. Verify that WMT_project exists on the controller
|
||
# 2. Kill any running WMT app.py on the target
|
||
# 3. Remove previous WMT_old (if any) and rename WMT → WMT_old
|
||
# 4. Copy WMT_project → fresh WMT on the target
|
||
# 5. Fix execute permissions on scripts
|
||
# 6. Migrate config values: old config.txt → new config.txt
|
||
# Rules:
|
||
# • For every key that exists in BOTH old and new config → use old value
|
||
# • Key exists only in new config (new feature) → keep new default
|
||
# • Key exists only in old config (removed key) → skip / ignore
|
||
# File structure, comments, and new keys are always from
|
||
# the new template (WMT_project/data/config.txt).
|
||
# 7. Restore runtime data files (log.txt, tag.txt) from WMT_old
|
||
# 8. Delete WMT_old (migration complete, backup no longer needed)
|
||
# 9. Reboot the target host
|
||
#
|
||
# Run via: Ansible > Playbooks > "Update_Rest_WMT_client" or
|
||
# POST /api/ansible/execute { "playbook": "Update_Rest_WMT_client.yml" }
|
||
# ──────────────────────────────────────────────────────────────────────────
|
||
|
||
- name: Update WMT client files on target devices
|
||
hosts: all
|
||
gather_facts: false
|
||
become: false
|
||
|
||
tasks:
|
||
|
||
# ── 1. Verify source exists on the controller ─────────────────────────
|
||
- name: Check WMT_project source folder exists on controller
|
||
delegate_to: localhost
|
||
stat:
|
||
path: /home/pi/Desktop/WMT_project
|
||
register: wmt_project_stat
|
||
|
||
- name: Fail if WMT_project is missing on the controller
|
||
delegate_to: localhost
|
||
fail:
|
||
msg: >
|
||
/home/pi/Desktop/WMT_project not found on the Ansible controller.
|
||
Ensure the WMT_project folder is present before running this playbook.
|
||
when: not wmt_project_stat.stat.exists
|
||
|
||
# ── 2. Kill any running WMT app.py ────────────────────────────────────
|
||
- name: Stop running WMT app.py (if any)
|
||
shell: pkill -f "python3.*WMT/app.py"
|
||
ignore_errors: true
|
||
changed_when: false
|
||
|
||
- name: Wait for process to terminate
|
||
wait_for:
|
||
timeout: 4
|
||
|
||
# ── 3a. Remove previous WMT_old backup (if one exists from a prior run)
|
||
- name: Check if WMT_old already exists
|
||
stat:
|
||
path: /home/pi/Desktop/WMT_old
|
||
register: wmt_old_stat
|
||
|
||
- name: Remove previous WMT_old folder
|
||
file:
|
||
path: /home/pi/Desktop/WMT_old
|
||
state: absent
|
||
when: wmt_old_stat.stat.exists
|
||
|
||
# ── 3b. Rename current WMT → WMT_old ─────────────────────────────────
|
||
- name: Check if WMT folder currently exists
|
||
stat:
|
||
path: /home/pi/Desktop/WMT
|
||
register: wmt_stat
|
||
|
||
- name: Rename WMT to WMT_old
|
||
command: mv /home/pi/Desktop/WMT /home/pi/Desktop/WMT_old
|
||
when: wmt_stat.stat.exists
|
||
|
||
# ── 4. Copy fresh WMT_project → WMT ──────────────────────────────────
|
||
- name: Copy WMT_project to target as /home/pi/Desktop/WMT
|
||
copy:
|
||
src: /home/pi/Desktop/WMT_project/
|
||
dest: /home/pi/Desktop/WMT/
|
||
owner: pi
|
||
group: pi
|
||
mode: preserve
|
||
force: true
|
||
|
||
- name: Ensure WMT/data directory exists
|
||
file:
|
||
path: /home/pi/Desktop/WMT/data
|
||
state: directory
|
||
owner: pi
|
||
group: pi
|
||
mode: '0755'
|
||
|
||
# ── 5. Fix execute permissions ────────────────────────────────────────
|
||
- name: Ensure app.py is executable
|
||
file:
|
||
path: /home/pi/Desktop/WMT/app.py
|
||
owner: pi
|
||
group: pi
|
||
mode: '0755'
|
||
|
||
- name: Ensure setup_port_capability.sh is executable
|
||
file:
|
||
path: /home/pi/Desktop/WMT/setup_port_capability.sh
|
||
state: file
|
||
owner: pi
|
||
group: pi
|
||
mode: '0755'
|
||
ignore_errors: true
|
||
|
||
# ── 6. Migrate config values from old config.txt into new template ────
|
||
#
|
||
# Strategy (line-preserving Python migration):
|
||
# • Read WMT_old/data/config.txt → source of device-specific values
|
||
# • Read WMT/data/config.txt → new template (correct keys & comments)
|
||
# • Walk the new template line by line:
|
||
# - Keep all comment lines and blank lines unchanged
|
||
# - For each key=value line:
|
||
# If old config has the SAME section + key → replace value with old value
|
||
# If old config does NOT have that key → keep new default value
|
||
# - Keys only in old config are silently ignored (removed features)
|
||
# • Write the result back to WMT/data/config.txt
|
||
#
|
||
- name: Check if old config.txt exists in WMT_old
|
||
stat:
|
||
path: /home/pi/Desktop/WMT_old/data/config.txt
|
||
register: old_cfg_stat
|
||
|
||
- name: Migrate config values (old → new template)
|
||
shell: |
|
||
python3 << 'PYEOF'
|
||
import configparser, os, re, sys
|
||
|
||
old_path = '/home/pi/Desktop/WMT_old/data/config.txt'
|
||
new_path = '/home/pi/Desktop/WMT/data/config.txt'
|
||
|
||
if not os.path.exists(old_path):
|
||
print('No old config.txt found – keeping new defaults as-is')
|
||
sys.exit(0)
|
||
|
||
if not os.path.exists(new_path):
|
||
print('New config.txt missing – nothing to migrate into')
|
||
sys.exit(1)
|
||
|
||
# Parse old config to get existing values
|
||
old = configparser.ConfigParser()
|
||
old.read(old_path)
|
||
|
||
# Walk new template line by line, replacing values where old config has them
|
||
current_section = None
|
||
output_lines = []
|
||
migrated = []
|
||
kept_new = []
|
||
|
||
with open(new_path, 'r') as f:
|
||
for line in f:
|
||
stripped = line.rstrip('\n')
|
||
|
||
# Detect section header e.g. [device]
|
||
section_match = re.match(r'^\s*\[([^\]]+)\]\s*$', stripped)
|
||
if section_match:
|
||
current_section = section_match.group(1)
|
||
output_lines.append(line)
|
||
continue
|
||
|
||
# Detect key = value line (skip comments and blank lines)
|
||
kv_match = re.match(r'^([^#;\s][^=]*?)\s*=\s*(.*)', stripped)
|
||
if kv_match and current_section:
|
||
key = kv_match.group(1).strip()
|
||
new_val = kv_match.group(2)
|
||
|
||
if old.has_section(current_section) and old.has_option(current_section, key):
|
||
old_val = old.get(current_section, key)
|
||
if old_val != new_val:
|
||
output_lines.append(f'{key}={old_val}\n')
|
||
migrated.append(f' [{current_section}] {key} = {old_val!r} (was: {new_val!r})')
|
||
else:
|
||
output_lines.append(line)
|
||
else:
|
||
output_lines.append(line)
|
||
kept_new.append(f' [{current_section}] {key} = {new_val!r} (new key – keeping default)')
|
||
else:
|
||
output_lines.append(line)
|
||
|
||
with open(new_path, 'w') as f:
|
||
f.writelines(output_lines)
|
||
|
||
print('=== Config migration complete ===')
|
||
if migrated:
|
||
print(f'Migrated {len(migrated)} value(s) from old config:')
|
||
for m in migrated:
|
||
print(m)
|
||
if kept_new:
|
||
print(f'Kept {len(kept_new)} new default(s) (not in old config):')
|
||
for k in kept_new:
|
||
print(k)
|
||
PYEOF
|
||
register: cfg_migration_result
|
||
when: old_cfg_stat.stat.exists
|
||
changed_when: true
|
||
|
||
- name: Show config migration output
|
||
debug:
|
||
msg: "{{ cfg_migration_result.stdout_lines }}"
|
||
when: old_cfg_stat.stat.exists
|
||
|
||
- name: Note – no old config found, new defaults kept
|
||
debug:
|
||
msg: "WMT_old/data/config.txt not found – new WMT_project defaults will be used."
|
||
when: not old_cfg_stat.stat.exists
|
||
|
||
# ── 7. Restore runtime data files from WMT_old ───────────────────────
|
||
- name: Check if log.txt exists in WMT_old
|
||
stat:
|
||
path: /home/pi/Desktop/WMT_old/data/log.txt
|
||
register: old_log_stat
|
||
|
||
- name: Restore log.txt from WMT_old
|
||
copy:
|
||
src: /home/pi/Desktop/WMT_old/data/log.txt
|
||
dest: /home/pi/Desktop/WMT/data/log.txt
|
||
owner: pi
|
||
group: pi
|
||
mode: '0644'
|
||
remote_src: true
|
||
when: old_log_stat.stat.exists
|
||
|
||
- name: Check if tag.txt exists in WMT_old
|
||
stat:
|
||
path: /home/pi/Desktop/WMT_old/data/tag.txt
|
||
register: old_tag_stat
|
||
|
||
- name: Restore tag.txt from WMT_old (pending card posts)
|
||
copy:
|
||
src: /home/pi/Desktop/WMT_old/data/tag.txt
|
||
dest: /home/pi/Desktop/WMT/data/tag.txt
|
||
owner: pi
|
||
group: pi
|
||
mode: '0644'
|
||
remote_src: true
|
||
when: old_tag_stat.stat.exists
|
||
|
||
# ── 8. Remove WMT_old now that migration is complete ─────────────────
|
||
- name: Remove WMT_old folder (migration done, no longer needed)
|
||
file:
|
||
path: /home/pi/Desktop/WMT_old
|
||
state: absent
|
||
|
||
# ── 9. Show final config and reboot ───────────────────────────────────
|
||
- name: Show final config.txt on target
|
||
command: cat /home/pi/Desktop/WMT/data/config.txt
|
||
register: final_cfg
|
||
changed_when: false
|
||
|
||
- name: Display final config.txt
|
||
debug:
|
||
msg: "{{ final_cfg.stdout_lines }}"
|
||
|
||
- name: Show updated app.py version
|
||
command: head -1 /home/pi/Desktop/WMT/app.py
|
||
register: app_version
|
||
changed_when: false
|
||
|
||
- name: Report update summary
|
||
debug:
|
||
msg: >
|
||
✓ WMT updated on {{ inventory_hostname }} – {{ app_version.stdout }}.
|
||
Rebooting now to apply changes.
|
||
|
||
- name: Reboot target to apply all changes
|
||
become: true
|
||
reboot:
|
||
msg: "Rebooting after WMT client update"
|
||
reboot_timeout: 180
|
||
pre_reboot_delay: 3
|
||
post_reboot_delay: 15
|
||
|
||
|
||
- name: Update WMT client files on target devices
|
||
hosts: all
|
||
gather_facts: false
|
||
become: false
|
||
|
||
tasks:
|
||
|
||
# ── 1. Confirm WMT_project source exists on the controller ────────────
|
||
- name: Check that WMT_project source folder exists on controller
|
||
delegate_to: localhost
|
||
stat:
|
||
path: /home/pi/Desktop/WMT_project
|
||
register: wmt_project_stat
|
||
|
||
- name: Fail if WMT_project is missing on the controller
|
||
delegate_to: localhost
|
||
fail:
|
||
msg: >
|
||
/home/pi/Desktop/WMT_project was not found on the Ansible controller.
|
||
Make sure the WMT_project folder is present before running this playbook.
|
||
when: not wmt_project_stat.stat.exists
|
||
|
||
# ── 2. Ensure WMT destination directory exists on target ─────────────
|
||
- name: Ensure /home/pi/Desktop/WMT directory exists
|
||
file:
|
||
path: /home/pi/Desktop/WMT
|
||
state: directory
|
||
owner: pi
|
||
group: pi
|
||
mode: '0755'
|
||
|
||
# ── 3. Kill any running WMT app.py process ────────────────────────────
|
||
- name: Stop running WMT app.py (if any)
|
||
shell: pkill -f "python3.*WMT/app.py"
|
||
ignore_errors: true
|
||
changed_when: false
|
||
|
||
- name: Wait for process to terminate
|
||
wait_for:
|
||
timeout: 3
|
||
|
||
# ── 4. Copy WMT_project → WMT, preserving device-specific data files ─
|
||
- name: Copy WMT_project files to target (excluding device-specific data)
|
||
copy:
|
||
src: /home/pi/Desktop/WMT_project/
|
||
dest: /home/pi/Desktop/WMT/
|
||
owner: pi
|
||
group: pi
|
||
mode: preserve
|
||
force: true
|
||
# Exclude device-specific files that must never be overwritten
|
||
# Note: Ansible's copy module does not support 'exclude' natively;
|
||
# we restore the originals in step 4b–4e below.
|
||
|
||
# ── 4b-4e. Restore device-specific data files from the target backup ──
|
||
# Strategy: before overwriting we slurp the existing files, then
|
||
# write them back so the 'copy' above cannot clobber them.
|
||
|
||
- name: Check if device config.txt exists (pre-copy)
|
||
stat:
|
||
path: /home/pi/Desktop/WMT/data/config.txt
|
||
register: cfg_stat
|
||
|
||
- name: Slurp existing config.txt (if present)
|
||
slurp:
|
||
src: /home/pi/Desktop/WMT/data/config.txt
|
||
register: cfg_backup
|
||
when: cfg_stat.stat.exists
|
||
|
||
- name: Restore config.txt after copy (device config must not be overwritten)
|
||
copy:
|
||
content: "{{ cfg_backup.content | b64decode }}"
|
||
dest: /home/pi/Desktop/WMT/data/config.txt
|
||
owner: pi
|
||
group: pi
|
||
mode: '0644'
|
||
when: cfg_stat.stat.exists
|
||
|
||
# idmasa.txt is a legacy Prezenta file – not used by WMT, not restored
|
||
|
||
- name: Check if log.txt exists
|
||
stat:
|
||
path: /home/pi/Desktop/WMT/data/log.txt
|
||
register: log_stat
|
||
|
||
- name: Slurp existing log.txt (if present)
|
||
slurp:
|
||
src: /home/pi/Desktop/WMT/data/log.txt
|
||
register: log_backup
|
||
when: log_stat.stat.exists
|
||
|
||
- name: Restore log.txt after copy
|
||
copy:
|
||
content: "{{ log_backup.content | b64decode }}"
|
||
dest: /home/pi/Desktop/WMT/data/log.txt
|
||
owner: pi
|
||
group: pi
|
||
mode: '0644'
|
||
when: log_stat.stat.exists
|
||
|
||
- name: Check if tag.txt exists
|
||
stat:
|
||
path: /home/pi/Desktop/WMT/data/tag.txt
|
||
register: tag_stat
|
||
|
||
- name: Slurp existing tag.txt (if present)
|
||
slurp:
|
||
src: /home/pi/Desktop/WMT/data/tag.txt
|
||
register: tag_backup
|
||
when: tag_stat.stat.exists
|
||
|
||
- name: Restore tag.txt after copy
|
||
copy:
|
||
content: "{{ tag_backup.content | b64decode }}"
|
||
dest: /home/pi/Desktop/WMT/data/tag.txt
|
||
owner: pi
|
||
group: pi
|
||
mode: '0644'
|
||
when: tag_stat.stat.exists
|
||
|
||
# ── 5. Fix execute permissions on scripts ─────────────────────────────
|
||
- name: Ensure app.py is executable
|
||
file:
|
||
path: /home/pi/Desktop/WMT/app.py
|
||
owner: pi
|
||
group: pi
|
||
mode: '0755'
|
||
|
||
- name: Ensure setup_port_capability.sh is executable
|
||
file:
|
||
path: /home/pi/Desktop/WMT/setup_port_capability.sh
|
||
state: file
|
||
owner: pi
|
||
group: pi
|
||
mode: '0755'
|
||
ignore_errors: true
|
||
|
||
# ── 6. Ensure WMT/data directory is intact ────────────────────────────
|
||
- name: Ensure WMT/data directory exists
|
||
file:
|
||
path: /home/pi/Desktop/WMT/data
|
||
state: directory
|
||
owner: pi
|
||
group: pi
|
||
mode: '0755'
|
||
|
||
# ── 7. Restart WMT app in a new lxterminal session ────────────────────
|
||
- name: Launch WMT app.py in background lxterminal
|
||
shell: >
|
||
DISPLAY=:0 lxterminal -e
|
||
"bash -c 'cd /home/pi/Desktop/WMT; python3 app.py; exec bash'" &
|
||
environment:
|
||
DISPLAY: ":0"
|
||
ignore_errors: true
|
||
changed_when: true
|
||
|
||
- name: Wait for WMT app to start
|
||
wait_for:
|
||
timeout: 5
|
||
|
||
# ── 8. Confirm update on target ───────────────────────────────────────
|
||
- name: Show updated app.py version line
|
||
command: head -1 /home/pi/Desktop/WMT/app.py
|
||
register: app_version
|
||
changed_when: false
|
||
|
||
- name: Report update result
|
||
debug:
|
||
msg: >
|
||
✓ WMT client updated on {{ inventory_hostname }} ({{ ansible_host }}).
|
||
Version: {{ app_version.stdout }}
|