--- # Update WMT client code from the controller's WMT_project folder # ────────────────────────────────────────────────────────────────────────── # Use this for devices that have not yet received the HTTP auto-update, # or whenever you need to force a code push from the server. # # What this playbook does: # 1. Ensure WMT directory exists on the target # 2. Back up the current app.py as app.py.bak. # 3. Copy everything from /home/pi/Desktop/WMT_project/ on the CONTROLLER # → /home/pi/Desktop/WMT/ on the TARGET # The data/ directory on the target is fully preserved (never touched) # 4. Fix file ownership # 5. Restart the wmt systemd service # # The data/ directory (config.txt, idmasa.txt, tag.txt, log.txt, device_info.txt) # is intentionally excluded — device-specific settings stay intact. # # Run via: Ansible > Playbooks > "Update WMT Code" # ────────────────────────────────────────────────────────────────────────── - name: Update WMT client code from WMT_project folder hosts: all gather_facts: false become: false vars: controller_src: /home/pi/Desktop/WMT_project/ wmt_dir: /home/pi/Desktop/WMT tasks: # ── 1. Ensure WMT directory exists ──────────────────────────────────── - name: Ensure WMT directory exists on target file: path: "{{ wmt_dir }}" state: directory owner: pi group: pi mode: '0755' # ── 2. Back up current app.py ───────────────────────────────────────── - name: Read first line of current app.py (for backup filename) shell: head -1 {{ wmt_dir }}/app.py 2>/dev/null || echo "unknown" register: local_first_line changed_when: false ignore_errors: true - name: Extract local version number set_fact: local_version: >- {{ local_first_line.stdout | regex_search('version\s+([\d.]+)', '\1') | first | default('old') }} - name: Back up current app.py copy: src: "{{ wmt_dir }}/app.py" dest: "{{ wmt_dir }}/app.py.bak.{{ local_version }}" remote_src: true owner: pi group: pi mode: preserve ignore_errors: true - name: Show backup info debug: msg: "Backed up app.py v{{ local_version }} → app.py.bak.{{ local_version }}" # ── 3. Snapshot data/ before copy (audit) ──────────────────────────── - name: List current data/ files (audit) shell: ls -1 {{ wmt_dir }}/data/ 2>/dev/null || echo "(empty or missing)" register: data_files_before changed_when: false - name: Show data/ files that will be preserved debug: msg: "data/ contents (will NOT be changed): {{ data_files_before.stdout_lines }}" # ── 4. Sync WMT_project → WMT on target, excluding data/ ───────────── # synchronize uses rsync under the hood; delegate_to pushes # from the controller to the target. - name: Sync WMT_project to target (exclude data/ and junk files) synchronize: src: "{{ controller_src }}" dest: "{{ wmt_dir }}/" recursive: true delete: false checksum: true rsync_opts: - "--exclude=data/" - "--exclude=.git/" - "--exclude=.gitignore" - "--exclude=__pycache__/" - "--exclude=*.pyc" - "--exclude=*.pyo" - "--exclude=*.log" - "--exclude=*.bak" - "--exclude=venv/" - "--exclude=.venv/" - "--exclude=node_modules/" - "--exclude=.*" register: sync_result - name: Show sync summary debug: msg: "Sync completed. Changed: {{ sync_result.changed }}" # ── 5. Fix ownership ────────────────────────────────────────────────── - name: Set correct ownership on WMT directory become: true file: path: "{{ wmt_dir }}" owner: pi group: pi recurse: true # ── 6. Verify data/ is still intact ────────────────────────────────── - name: List data/ files after update (verification) shell: ls -1 {{ wmt_dir }}/data/ 2>/dev/null || echo "(empty)" register: data_files_after changed_when: false - name: Show data/ contents after update (should match before) debug: msg: "{{ data_files_after.stdout_lines }}" # ── 7. Restart WMT service ──────────────────────────────────────────── - name: Restart WMT systemd service become: true systemd: name: wmt state: restarted enabled: true register: service_result ignore_errors: true - name: Show service state debug: msg: "WMT service state: {{ service_result.status.ActiveState | default('unknown') }}" when: service_result is not failed - name: Warn if service restart failed debug: msg: "WARNING: wmt service restart failed – the device may need a manual reboot." when: service_result is failed vars: wmt_dir: /home/pi/Desktop/WMT tmp_zip: /tmp/wmt_update.zip # Controller address – override on CLI with -e "server_url=http://..." server_url: "http://{{ hostvars[inventory_hostname]['ansible_host'] | default(ansible_host) | regex_replace('\\d+\\.\\d+$', '10.76.157.1') }}" tasks: # ── 0. Resolve server URL ───────────────────────────────────────────── # The monitoring server address is read from the device's own config.txt # so we don't have to hard-code it here. - name: Read server_host from WMT config.txt shell: | grep -E '^\s*server_host\s*=' {{ wmt_dir }}/data/config.txt 2>/dev/null \ | head -1 | awk -F'=' '{print $2}' | tr -d ' \r\n' register: cfg_server_host changed_when: false ignore_errors: true - name: Read server_port from WMT config.txt shell: | grep -E '^\s*server_port\s*=' {{ wmt_dir }}/data/config.txt 2>/dev/null \ | head -1 | awk -F'=' '{print $2}' | tr -d ' \r\n' register: cfg_server_port changed_when: false ignore_errors: true - name: Set monitoring server base URL set_fact: monitoring_base: "http://{{ cfg_server_host.stdout | default('rpi-ansible') }}:{{ cfg_server_port.stdout | default('5000') }}" - name: Show resolved server URL debug: msg: "Monitoring server: {{ monitoring_base }}" # ── 1. Check latest version on server ──────────────────────────────── - name: Query latest WMT version from monitoring server uri: url: "{{ monitoring_base }}/api/wmt/client/version" method: GET return_content: true timeout: 15 register: version_response ignore_errors: true - name: Show server version info debug: msg: "Server release: v{{ version_response.json.version | default('unknown') }} ({{ version_response.json.filename | default('n/a') }})" when: version_response is not failed - name: Fail if server version endpoint unreachable fail: msg: "Cannot reach {{ monitoring_base }}/api/wmt/client/version – is the server running?" when: version_response is failed # ── 2. Get current local version ───────────────────────────────────── - name: Read first line of local app.py shell: head -1 {{ wmt_dir }}/app.py 2>/dev/null || echo "unknown" register: local_first_line changed_when: false - name: Extract local version number set_fact: local_version: "{{ local_first_line.stdout | regex_search('version\\s+([\\d.]+)', '\\1') | first | default('0') }}" - name: Show local version debug: msg: "Local version: {{ local_version }} | Server version: {{ version_response.json.version }}" # ── 3. Ensure WMT directory exists ─────────────────────────────────── - name: Ensure WMT directory exists file: path: "{{ wmt_dir }}" state: directory owner: pi group: pi mode: '0755' # ── 4. Download release zip ─────────────────────────────────────────── - name: Download WMT release zip from monitoring server get_url: url: "{{ monitoring_base }}/api/wmt/client/download" dest: "{{ tmp_zip }}" force: true timeout: 120 mode: '0644' # ── 5. Back up current app.py ───────────────────────────────────────── - name: Back up current app.py copy: src: "{{ wmt_dir }}/app.py" dest: "{{ wmt_dir }}/app.py.bak.{{ local_version }}" remote_src: true owner: pi group: pi mode: preserve ignore_errors: true # ── 6. Extract zip – skip data/ directory ───────────────────────────── - name: Extract WMT release zip (preserving data/ directory) shell: | cd {{ wmt_dir }} python3 - <<'EOF' import zipfile, os, sys zip_path = "{{ tmp_zip }}" dest = "{{ wmt_dir }}" skipped = 0 extracted = 0 with zipfile.ZipFile(zip_path, 'r') as zf: for member in zf.infolist(): p = member.filename.replace('\\', '/') if p.startswith('data/') or p == 'data': skipped += 1 continue zf.extract(member, dest) extracted += 1 print(f"Extracted {extracted} files, skipped {skipped} data/ entries") EOF register: extract_result changed_when: true - name: Show extraction result debug: msg: "{{ extract_result.stdout }}" # ── 7. Fix ownership ────────────────────────────────────────────────── - name: Set correct ownership on WMT directory become: true file: path: "{{ wmt_dir }}" owner: pi group: pi recurse: true # ── 8. Clean up temp zip ────────────────────────────────────────────── - name: Remove temporary zip file file: path: "{{ tmp_zip }}" state: absent # ── 9. Restart WMT service ──────────────────────────────────────────── - name: Restart WMT systemd service become: true systemd: name: wmt state: restarted enabled: true register: service_result ignore_errors: true - name: Show service restart result debug: msg: "Service state: {{ service_result.status.ActiveState | default('unknown') }}" when: service_result is not failed - name: Warn if service restart failed debug: msg: "WARNING: wmt service restart failed – the device may need a manual reboot." when: service_result is failed