如何在 Ansible 中对版本号进行排序

问题描述 投票:0回答:4

我正在构建一个 Ansible 剧本,我想在其中备份数据库,以备需要升级软件时使用。为此,我想将可用的最高版本号与已安装的版本号进行比较。如果最新版本比安装的版本高,我会备份数据库。

但是问题是我找不到在 Ansible 中对版本号进行排序的好方法。标准排序过滤器按字符串而不是数字/版本进行排序。

这就是我现在正在做的事情:

- name: Get package version
  yum:
    list: package
  register: software_version

- name: Read which version is installed and available
  set_fact:
    software_version_installed: "{{ software_version | json_query(\"results[?yumstate=='installed'].version\") | sort | last }}"
    software_version_available: "{{ software_version | json_query(\"results[?yumstate=='available'].version\") | sort | last }}"

- name: Backup old database file on remote host
  copy:
    src: "{{ software.database_path }}"
    dest: "{{ software.database_path }}_{{ ansible_date_time.date }}_v{{ software_version_installed }}"
    remote_src: yes
  when: software_version_installed is version(software_version_available, "<")

只要版本号保持在数字 10 以下(例如 1.2.3,但不是 1.10.1),上面的剧本就可以工作,因为排序是像字符串一样执行的。当版本号必须排序时,例如1.2.3和1.10.1,以1.2.3为最新版本。

显示问题:

- name: Read which version is installed and available
  set_fact:
    software_versions: [ "2.5.0", "2.9.0", "2.10.0", "2.11.0" ]

- name: Debug
  debug:
    var: software_versions | sort

TASK [grafana : Debug]**********************************
ok: [localhost] => {
    "software_versions | sort": [
        "2.10.0",
        "2.11.0",
        "2.5.0",
        "2.9.0"
    ]
}

有人知道在 Ansible 中对版本号进行排序的好方法吗?

sorting ansible jinja2
4个回答
5
投票

问:有人知道 Ansible 中对版本号进行排序的好方法吗?

A:使用filter_plugin。例如过滤器

shell> cat filter_plugins/version_sort.py
from distutils.version import LooseVersion

def version_sort(l):
    return sorted(l, key=LooseVersion)

class FilterModule(object):

    def filters(self):
        return {
            'version_sort' : version_sort
            }

与剧本

shell> cat test-versions.yml
- name: Sort versions
  hosts: localhost

  vars:
    versions:
      - "0.1.0"
      - "0.1.5"
      - "0.11.11"
      - "0.9.11"
      - "0.9.3"
      - "0.10.2"
      - "0.6.1"
      - "0.6.0"
      - "0.11.0"
      - "0.6.5"
    
  tasks:
    - debug:
        msg: "{{ versions|version_sort }}"

给予

    "msg": [
        "0.1.0", 
        "0.1.5", 
        "0.6.0", 
        "0.6.1", 
        "0.6.5", 
        "0.9.3", 
        "0.9.11", 
        "0.10.2", 
        "0.11.0", 
        "0.11.11"
    ]

为了您的方便,可以在 Github ansible-plugins 上使用该过滤器。


版本比较负责迭代列表并比较项目。请参阅下面的示例

shell> cat test-versions.yml
- hosts: localhost
    vars:
      version_installed: "1.10.1"
      versions:
        - "1.1.3"
        - "1.2.3"
        - "1.7.5"
        - "1.10.7"
    tasks:
      - debug: msg="{{ item }} is newer than {{ version_installed }}"
        loop: "{{ versions }}"
        when: item is version(version_installed, '>')
shell> ansible-playbook test-versions.yml | grep msg
"msg": "1.10.7 is newer than 1.10.1"

5
投票

这里的所有答案都提供了一种自定义版本排序方式,我想指出的是 从 v2.10 开始,Ansible 已经可以通过

version_sort
过滤器来做到这一点:

- name: Sort list by version number
  debug:
    var: ansible_versions | community.general.version_sort
  vars:
    ansible_versions:
      - '2.8.0'
      - '2.11.0'
      - '2.7.0'
      - '2.10.0'
      - '2.9.0'

另请参阅过滤器指南 - 使用版本


3
投票

现在已经用另一种方式解决了。我没有对版本进行排序,而是将当前版本与所有可用版本进行比较。

  • 我首先将更新变量设置为 false
  • 接下来我将已安装的版本与每个可用版本进行比较
  • 如果安装的版本 > 当前版本,请将更新变量设置为 true

执行备份的任务仅当更新变量为 true 时才会执行。

- name: Get package version
  yum:
    list: package
  register: software_version

- name: Read which version is installed and available
  set_fact:
    software_update: false
    software_version_installed: "{{ software_version | json_query(\"results[?yumstate=='installed'].version\") | last }}"
    software_version_available: "{{ software_version | json_query(\"results[?yumstate=='available'].version\") }}"

- name: Check if upgrade is needed
  set_fact:
    software_update: true
  when: software_version_installed is version(item, "<")
  with_items: "{{ software_version_available }}"

- name: Backup old database file on remote host
  copy:
    src: "{{ software.database_path }}"
    dest: "{{ software.database_path }}_{{ ansible_date_time.date }}_v{{ software_version_installed }}"
    remote_src: yes
  when: software_update

2
投票

当前接受的答案提供了一个非常好的解决方案,使用

filter_plugin
。不幸的是,所使用的
distutils
Python 包似乎已被弃用。一些谷歌搜索让我找到了 packaging 包,它提供了类似的 Version 类。这是更新的
filter_plugin
,不使用
distutils
:

from packaging.version import Version

def version_sort(l):
    return sorted(l, key=Version)

class FilterModule(object):

    def filters(self):
        return {
            'version_sort': version_sort
        }

它对我们来说效果很好,但我不想保证在每种情况下行为都完全相同。

© www.soinside.com 2019 - 2024. All rights reserved.