【问题标题】:Calculate number of days between two variable (one a set variable, the other from fact)计算两个变量之间的天数(一个是设定变量,另一个来自事实)
【发布时间】:2020-12-31 12:19:59
【问题描述】:

我一直在疯狂地寻找解决方案,但到目前为止我一直没有成功:计算库存变量和 Ansible 事实之间的天数。

当我手动设置两个变量时我没有问题,两者都被识别为日期,我可以从那里开始工作:(这是预期的输出)

在 2 个手动设置的变量之间工作的任务:

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

工作输出:

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

现在,由于变量类型,我想使用 ansible fact 在每次运行时动态获取当前日期 (ansible_date_time.date)

重现错误的任务示例

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

我得到以下输出和错误:

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'"}

我尝试找到从 ansible_date_time.date 中创建新变量的方法,但如果可能的话,我无法将其转换为 datetime.date

【问题讨论】:

    标签: ansible yaml jinja2


    【解决方案1】:

    ansible_date_time.date 是一个字符串,因此您必须将其转换为 datedatetime

    令人惊讶的是,Ansible 无法立即将字符串转换为date,但您可以使用to_datetime filter 将其转换为datetime

    然后,由于prev_date 包含date 而不是datetime,因此您可以通过Python 的datetimedate() 函数将刚刚创建的datetime 转换为date

    所以剧本是:

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

    这会给:

    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 
    

    【讨论】:

    • 该死的,我尝试了这么多组合,花了这么多时间在这上面。是的,ansible 是有限的,并且不提供将 str 转换为日期的方法,一段时间后发现了这一点。我也尝试过使用 to_datetime 来做到这一点,但我在语法中错过了“.date()”,这是我希望得到的最优雅的答案,谢谢伙计。
    • @Geoffrey 如果您发现“开箱即用”ansible 受限于您的任何要求,创建您自己的自定义过滤器(或任何其他类型的插件)非常简单,您将获得所有python 的力量触手可及。 => docs.ansible.com/ansible/latest/dev_guide/…
    【解决方案2】:

    下面的任务完成了这项工作

        - debug:
            msg: "Number of days =
                  {{ ((ansible_date_time.date|to_datetime('%Y-%m-%d') -
                      (prev_date ~ ' 00:00:00')|to_datetime)).days }}"
    

    【讨论】:

    • 看着这个我以类似的prev_date|string|to_datetime结尾。根据我的测试,(prev_date ~ ' 00:00:00')|to_datetime 正在执行隐式字符串转换,这得到了您的 sn-p 也可以执行 (prev_date ~ '')|to_datetime 的支持这一事实
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-06-09
    • 1970-01-01
    • 2014-05-12
    • 1970-01-01
    • 1970-01-01
    • 2014-10-13
    • 1970-01-01
    相关资源
    最近更新 更多