Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
1.0k views
in Technique[技术] by (71.8m points)

ansible - Calculate number of days between two variable (one a set variable, the other from fact)

I've been looking around like crazy to find a solution to this but so far I've been unsuccessful : Calculate number of days between an inventory variable and an Ansible fact.

I have no issue when I manually set both variable, both are recognized as a date and I can work my may around from there like so : (this is the expected output)

Task working between 2 manually set variables:

---
- hosts: localhost

  vars:
    prev_date: 2020-12-01
    cur_date: 2020-12-31

  tasks:
    - name: prev_date debug
      debug:
        msg:
          - "prev_date: {{ prev_date }}"
          - "prev_date type: {{ prev_date | type_debug }}"

    - name: cur_date debug
      debug:
        msg:
          - "cur_date: {{ cur_date }}"
          - "cur_date type: {{ cur_date | type_debug }}"

    # This is the output I want to get but I want cur_date from a dynamic source (fact or shell through register)
    - name: Calculate number of days between prev_date and cur_date (intended result)
      debug:
        msg: "Number of days = {{ (cur_date - prev_date).days }}"

Working output:

TASK [prev_date debug] *************************************************************************************************************************************************
Thursday 31 December 2020  12:55:28 +0100 (0:00:00.227)       0:00:00.227 *****
ok: [localhost] => {
    "msg": [
        "prev_date: 2020-12-01",
        "prev_date type: date"
    ]
}

TASK [cur_date debug] **************************************************************************************************************************************************
Thursday 31 December 2020  12:55:29 +0100 (0:00:00.249)       0:00:00.476 *****
ok: [localhost] => {
    "msg": [
        "cur_date: 2020-12-31",
        "cur_date type: date"
    ]
}

TASK [Calculate number of days between prev_date and cur_date (intended result)] ***************************************************************************************
Thursday 31 December 2020  12:55:29 +0100 (0:00:00.144)       0:00:00.621 *****
ok: [localhost] => {
    "msg": "Number of days = 30"
}

Now when I want to use ansible fact to get the current date dynamically on each run (ansible_date_time.date) because of the variables type

Sample of tasks to reproduce the error

    - name: Value and type of ansible_date_time.date
      debug:
        msg:
          - "ansible_date_time.date: {{ ansible_date_time.date }}"
          - "ansible_date_time.date type: {{ ansible_date_time.date | type_debug }}"

    # Failing due to conditional not working with attribute not being date on ansible_date_time.date
    - name: Calculate number of days between ansible_date_time.date
      debug:
        msg:
          - "Number of days = {{ (ansible_date_time.date - prev_date).days }}"

I get the following output and error:

TASK [New source ansible fact date] ************************************************************************************************************************************
Thursday 31 December 2020  13:06:41 +0100 (0:00:00.143)       0:00:00.741 *****
ok: [localhost] => {
    "msg": [
        "ansible_date_time.date: 2020-12-31",
        "ansible_date_time.date type: AnsibleUnsafeText"
    ]
}

TASK [Calculate number of days between ansible_date_time.date] *********************************************************************************************************
Thursday 31 December 2020  13:06:41 +0100 (0:00:00.150)       0:00:00.892 *****
fatal: [localhost]: FAILED! => {"msg": "Unexpected templating type error occurred on (Number of days = {{ (ansible_date_time.date - prev_date).days }}): unsupported operand type(s) for -: 'AnsibleUnsafeText' and 'datetime.date'"}

I tried find ways to create a new variable out of ansible_date_time.date but I was unable to convert it to datetime.date if that's even possible.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

ansible_date_time.date is a string, so you will have to convert it to a date or a datetime.

Surprisingly enough, Ansible does not have any means to convert a string to a date right away, but you can convert it to a datetime using the to_datetime filter.

Then, because prev_date contains a date and not a datetime, you can convert the datetime you just created to a date via the date() function of Python's datetime.

So the playbook would be:

- hosts: all
      
  tasks:
    - debug:
        msg: "{{ ((ansible_date_time.date | to_datetime('%Y-%m-%d')).date() - prev_date).days }}"
      vars:
        prev_date: 2020-12-01

Which will give:

PLAY [all] *******************************************************************************************************

TASK [Gathering Facts] *******************************************************************************************
ok: [localhost]

TASK [debug] *****************************************************************************************************
ok: [localhost] => {
    "msg": "30"
}

PLAY RECAP *******************************************************************************************************
localhost                  : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0 

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...