--- # Install Prometheus + Windows Exporter on Windows and open firewall for Grafana - name: Define Prometheus Versions and install dir ansible.builtin.set_fact: prometheus_version: "{{ prometheus_version | default('3.6.0') }}" prometheus_install_dir: "{{ prometheus_install_dir | default('C:\\Prometheus') }}" prometheus_listen_address: "{{ prometheus_listen_address | default('0.0.0.0:9090') }}" nssm_dir: "{{ nssm_dir | default('C:\\nssm') }}" nssm_version: "{{ nssm_version | default('2.24') }}" windows_exporter_version: "{{ windows_exporter_version | default('0.31.3') }}" windows_exporter_collectors: "{{ windows_exporter_collectors | default(['cache', 'cpu', 'cpu_info', 'diskdrive', 'memory', 'net', 'os', 'process', 'service', 'tcp', 'time', 'update']) }}" - name: Define Windows Exporter defaults ansible.builtin.set_fact: __nssm_url: "https://nssm.cc/release/nssm-{{ nssm_version }}.zip" __prometheus_zip_url: "https://github.com/prometheus/prometheus/releases/download/v{{ prometheus_version }}/prometheus-{{ prometheus_version }}.windows-amd64.zip" __prometheus_zip_path: "{{ (ansible_env.TEMP | default('C:\\Windows\\Temp')) }}\\prometheus-{{ prometheus_version }}.zip" __prometheus_home: "{{ prometheus_install_dir }}\\prometheus-{{ prometheus_version }}.windows-amd64" __windows_exporter_msi_url: "https://github.com/prometheus-community/windows_exporter/releases/download/v{{ windows_exporter_version }}/windows_exporter-{{ windows_exporter_version }}-amd64.msi" __windows_exporter_msi_path: "{{ (ansible_env.TEMP | default('C:\\Windows\\Temp')) }}\\windows_exporter-{{ windows_exporter_version }}-amd64.msi" __nssm_zip_path: "{{ (ansible_env.TEMP | default('C:\\Windows\\Temp')) }}\\nssm.zip" __nssm_exe: "{{ nssm_dir }}\\nssm.exe" - name: Create Prometheus installation directories ansible.windows.win_file: path: "{{ item }}" state: directory loop: - "{{ prometheus_install_dir }}" - "{{ prometheus_install_dir }}\\data" - "{{ nssm_dir }}" - name: Download required files (Prometheus, NSSM, Windows Exporter) ansible.windows.win_get_url: url: "{{ item.url }}" dest: "{{ item.dest }}" force: false loop: - { url: "{{ __prometheus_zip_url }}", dest: "{{ __prometheus_zip_path }}" } - { url: "{{ __nssm_url }}", dest: "{{ __nssm_zip_path }}" } - { url: "{{ __windows_exporter_msi_url }}", dest: "{{ __windows_exporter_msi_path }}", } - name: Extract downloaded archives community.windows.win_unzip: src: "{{ item.src }}" dest: "{{ item.dest }}" delete_archive: false creates: "{{ item.creates | default(omit) }}" loop: - { src: "{{ __prometheus_zip_path }}", dest: "{{ prometheus_install_dir }}", creates: "{{ __prometheus_home }}\\prometheus.exe", } - { src: "{{ __nssm_zip_path }}", dest: "{{ nssm_dir }}" } - name: Verify Prometheus binary is present ansible.windows.win_stat: path: "{{ __prometheus_home }}\\prometheus.exe" register: prometheus_bin - name: Fail if Prometheus binary is missing ansible.builtin.fail: msg: >- Prometheus binary not found at {{ __prometheus_home }}\prometheus.exe. Check download/unzip and prometheus_version. when: not prometheus_bin.stat.exists - name: Deploy Prometheus configuration ansible.windows.win_copy: dest: "{{ prometheus_install_dir }}\\prometheus.yml" content: | global: scrape_interval: 15s evaluation_interval: 15s scrape_configs: - job_name: 'prometheus' static_configs: - targets: ['localhost:9090'] - job_name: 'windows' static_configs: - targets: ['localhost:9182'] - name: Check if promtool exists ansible.windows.win_stat: path: "{{ __prometheus_home }}\\promtool.exe" register: promtool_bin - name: Validate Prometheus config with promtool ansible.windows.win_command: >- "{{ __prometheus_home }}\promtool.exe" check config "{{ prometheus_install_dir }}\prometheus.yml" register: promtool_check changed_when: false failed_when: promtool_check.rc != 0 when: promtool_bin.stat.exists - name: Copy NSSM executable (win64) ansible.windows.win_copy: src: "{{ nssm_dir }}\\nssm-2.24\\win64\\nssm.exe" dest: "{{ __nssm_exe }}" remote_src: true - name: Remove existing Prometheus service if present ansible.windows.win_service: name: Prometheus state: absent ignore_errors: true - name: Install Prometheus service via NSSM ansible.windows.win_command: >- "{{ __nssm_exe }}" install Prometheus "{{ __prometheus_home }}\prometheus.exe" --config.file={{ prometheus_install_dir }}\prometheus.yml --storage.tsdb.path={{ prometheus_install_dir }}\data --web.listen-address={{ prometheus_listen_address }} --web.console.templates={{ __prometheus_home }}\consoles --web.console.libraries={{ __prometheus_home }}\console_libraries args: chdir: "{{ __prometheus_home }}" register: nssm_install changed_when: nssm_install.rc == 0 - name: Set Prometheus AppDirectory via NSSM ansible.windows.win_command: >- "{{ __nssm_exe }}" set Prometheus AppDirectory "{{ __prometheus_home }}" - name: Configure Prometheus stdout log via NSSM ansible.windows.win_command: >- "{{ __nssm_exe }}" set Prometheus AppStdout "{{ prometheus_install_dir }}\prometheus-service.out.log" - name: Configure Prometheus stderr log via NSSM ansible.windows.win_command: >- "{{ __nssm_exe }}" set Prometheus AppStderr "{{ prometheus_install_dir }}\prometheus-service.err.log" - name: Set Prometheus Start mode to AUTO via NSSM ansible.windows.win_command: >- "{{ __nssm_exe }}" set Prometheus Start SERVICE_AUTO_START - name: Ensure Prometheus service is running (skip in check mode) ansible.windows.win_service: name: Prometheus start_mode: auto state: started when: not ansible_check_mode | default(false) - name: Wait for Prometheus to listen on 9090 (skip in check mode) ansible.windows.win_wait_for: port: 9090 delay: 0 timeout: 30 when: not ansible_check_mode | default(false) - name: Install Windows Exporter ansible.windows.win_package: path: "{{ __windows_exporter_msi_path }}" arguments: 'ENABLED_COLLECTORS={{ windows_exporter_collectors | join(",") }}' state: present - name: Ensure windows_exporter service is running ansible.windows.win_service: name: windows_exporter start_mode: auto state: started - name: Set firewall remote IPs when string provided ansible.builtin.set_fact: grafana_remoteip: "{{ grafana_prometheus_sources }}" when: - grafana_prometheus_sources is defined - grafana_prometheus_sources is string - name: Set firewall remote IPs when list provided ansible.builtin.set_fact: grafana_remoteip: "{{ grafana_prometheus_sources | join(',') }}" when: - grafana_prometheus_sources is defined - not (grafana_prometheus_sources is string) - name: Allow inbound Prometheus (9090) from Grafana community.windows.win_firewall_rule: name: Prometheus 9090 (Grafana) localport: 9090 protocol: tcp direction: in action: allow enabled: true # Provide one or more IPs/CIDRs in grafana_prometheus_sources (e.g. ['203.0.113.10']) remoteip: "{{ grafana_remoteip | default(omit) }}" state: present