如何用Ansible获取C盘剩余空间?win_disk_facts模块使用疑问
Hey there! Let's break down your two Ansible issues one by one— I've run into similar Windows disk fact headaches before, so I know exactly where you might be getting stuck.
Problem 1: selectattr("drive_letter", "C") returns empty results
The issue here has two key reasons:
- Wrong attribute nesting: The
drive_letterfield isn't directly on the top-leveldiskobject—it lives inside the nestedpartitions→volumesstructure under each disk. Your current filter is trying to filter disks by a property they don't even have. - Incorrect drive letter format:
win_disk_factsreturns drive letters with a colon (e.g.,C:) instead of justC. Even if you were filtering the right level, matching against"C"would never find a match.
Fixes to grab the C drive without hardcoding indexes
You have two clean, reliable options:
Option 1: Use json_query (best for nested structures)
json_query is built for digging into complex nested data. This one-liner directly pulls the C: volume details:
- name: Fetch C drive details with json_query set_fact: c_drive: "{{ ansible_facts.disks | json_query('[].partitions[].volumes[] | [?drive_letter == `C:`] | [0]') }}"
You can then access the remaining space with {{ c_drive.size_remaining }}.
Option 2: Use nested Jinja filters
If you prefer sticking to core Jinja tools, flatten the nested lists first, then filter:
- name: Set C drive variable with Jinja filters set_fact: c_drive: "{{ ansible_facts.disks | sum(attribute='partitions', start=[]) | sum(attribute='volumes', start=[]) | selectattr('drive_letter', 'equalto', 'C:') | first }}"
sum(attribute='partitions', start=[])flattens all partitions from all disks into a single list- The second
sumflattens all volumes from those partitions selectattrpicks the volume with drive letterC:firstgrabs the only (in most cases) matching volume
Problem 2: Variable diskC is undefined after assignment
If directly printing the hardcoded index path works but storing it in diskC doesn't, here are the most likely fixes:
1. Fix syntax errors in set_fact
Double-check your task for missing quotes or YAML formatting issues. For example:
# Correct syntax - name: Define diskC variable set_fact: diskC: "{{ ansible_facts.disks[0].partitions[1].volumes[0].size_remaining }}" # Wrong (missing quotes around the Jinja expression) - name: Define diskC variable set_fact: diskC: ansible_facts.disks[0].partitions[1].volumes[0].size_remaining
2. Ensure variable assignment runs in the right context
If your set_fact task is inside a when clause that doesn't evaluate to true, or if it's in a separate play without fact persistence, diskC won't be defined. Make sure the set_fact runs immediately after win_disk_facts in the same play.
3. Add safety checks for filter-based assignments
If you tried assigning diskC using your original broken filter, the result would be an empty list. Using | first on an empty list throws a Jinja error, which stops set_fact from completing—so diskC never gets created. Add a safety net:
- name: Set diskC safely set_fact: diskC: "{{ (ansible_facts.disks | sum(attribute='partitions', start=[]) | sum(attribute='volumes', start=[]) | selectattr('drive_letter', 'equalto', 'C:') | list) | first | default(None) }}"
default(None) ensures diskC gets set to None instead of failing if no C: drive is found.
Once you have your C drive variable defined, checking for less than 4GB is straightforward:
- name: Warn if C drive has insufficient space debug: msg: "C drive has less than 4GB remaining ({{ c_drive.size_remaining | human_readable }})" when: c_drive.size_remaining < 4*1024*1024*1024 # Convert 4GB to bytes
内容的提问来源于stack exchange,提问作者Junn Sorran

