简体   繁体   English

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

[英]How to sort version numbers in Ansible

I'm building an Ansible playbook in which I want to make a backup of a database in case I need to upgrade the software.我正在构建一个 Ansible 剧本,我想在其中备份数据库,以防我需要升级软件。 For this I want to compare the highest version number that is available to the version number that is installed.为此,我想将可用的最高版本号与已安装的版本号进行比较。 In case the latest version is hight than the installed version I'll back up the database.如果最新版本高于安装的版本,我将备份数据库。

The problem however is that I cannot find a good way to sort version numbers in Ansible. The standard sort filter sorts on strings instead of numbers/versions.然而,问题是我找不到在 Ansible 中对版本号进行排序的好方法。标准排序过滤器对字符串而不是数字/版本进行排序。

This is what I'm doing right now:这就是我现在正在做的事情:

- 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, "<")

The playbook above works, as long as version numbers stay underneath the number 10 (eg 1.2.3, but not 1.10.1) since sorting is performed like a string.只要版本号保持在数字 10 以下(例如 1.2.3,而不是 1.10.1),上面的剧本就可以工作,因为排序就像字符串一样执行。 When the version number has to sort eg 1.2.3 and 1.10.1, it will take 1.2.3 as latest version.当版本号需要排序时,例如 1.2.3 和 1.10.1,它将以 1.2.3 作为最新版本。

To show the issue:显示问题:

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

Does anyone know a good way to sort version numbers in Ansible?有谁知道在 Ansible 中对版本号进行排序的好方法吗?

Q: Does anyone know a good way to sort version numbers in Ansible?问:有谁知道在 Ansible 中排序版本号的好方法吗?

A: Use filter_plugin. A:使用filter_plugin。 For example the filter例如过滤器

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
            }

with the playbook与剧本

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

gives

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

For your convenience, the filter is available at Github ansible-plugins .为方便起见,该过滤器可在 Github ansible-plugins 获得


Version comparison does the job to iterate the list and compare items. 版本比较可以迭代列表并比较项目。 See the example below看下面的例子

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"

It's now solved in another way.现在用另一种方式解决了。 Instead of sorting the versions I compared the current version to all available versions.我没有对版本进行排序,而是将当前版本与所有可用版本进行了比较。

  • I've started by setting an update variable to false我首先将更新变量设置为 false
  • Next I compared the installed version to every available version接下来我将安装的版本与每个可用版本进行了比较
  • If installed version > current version, set the update variable to true如果已安装版本 > 当前版本,请将更新变量设置为 true

The task performing the backup will only be performed when the update variable is 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

The current accepted answer offers a very nice solution, using a filter_plugin .当前接受的答案提供了一个非常好的解决方案,使用filter_plugin Unfortunately, the distutils Python package that is uses appears to be deprecated.不幸的是,使用的distutils Python package 似乎已被弃用。 Some googling led me to the packaging package, which offers a similar Version class. Here's an updated filter_plugin that doesn't use distutils :一些谷歌搜索让我找到了包装package,它提供了一个类似的版本 class。这是一个不使用distutils的更新的filter_plugin

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
        }

It's working well for us, but I don't want to promise that the behavior will be exactly the same in every situation.它对我们来说工作得很好,但我不想 promise 在每种情况下行为都完全相同。

All the answers here provide a custom way of sorting versions, I'd like to point out that stock ansible can do this already:这里的所有答案都提供了一种自定义的版本排序方式,我想指出库存 ansible 已经可以做到这一点

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

https://docs.ansible.com/ansible/latest/collections/community/general/docsite/filter_guide_working_with_versions.html https://docs.ansible.com/ansible/latest/collections/community/general/docsite/filter_guide_working_with_versions.html

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM