--- # 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 }}