mirror of
https://github.com/ansible-collections/community.general.git
synced 2024-09-14 20:13:21 +02:00
filter: add new time convert filter (#347)
* filter: add new time convert filters The plugin include: - to_seconds - to_minutes - to_hours * refactor and extend * more UX improvements * Apply suggestions from code review Co-authored-by: Felix Fontein <felix@fontein.de> * even more UX improvments * fix indentation * fix for py3 * enable aix in ci * simplify * add to_months, use 360d as year. * rearrange tests * year back to 365 days Co-authored-by: Felix Fontein <felix@fontein.de>
This commit is contained in:
parent
cd5e3e2d85
commit
945296f314
3 changed files with 233 additions and 0 deletions
149
plugins/filter/time.py
Normal file
149
plugins/filter/time.py
Normal file
|
@ -0,0 +1,149 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Copyright (c) 2020, René Moser <mail@renemoser.net>
|
||||||
|
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||||
|
|
||||||
|
from __future__ import (absolute_import, division, print_function)
|
||||||
|
__metaclass__ = type
|
||||||
|
|
||||||
|
import re
|
||||||
|
from ansible.errors import AnsibleFilterError
|
||||||
|
|
||||||
|
|
||||||
|
UNIT_FACTORS = {
|
||||||
|
'ms': [],
|
||||||
|
's': [1000],
|
||||||
|
'm': [1000, 60],
|
||||||
|
'h': [1000, 60, 60],
|
||||||
|
'd': [1000, 60, 60, 24],
|
||||||
|
'w': [1000, 60, 60, 24, 7],
|
||||||
|
'mo': [1000, 60, 60, 24, 30],
|
||||||
|
'y': [1000, 60, 60, 24, 365],
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
UNIT_TO_SHORT_FORM = {
|
||||||
|
'millisecond': 'ms',
|
||||||
|
'milliseconds': 'ms',
|
||||||
|
'msec': 'ms',
|
||||||
|
'msecs': 'ms',
|
||||||
|
'msecond': 'ms',
|
||||||
|
'mseconds': 'ms',
|
||||||
|
'sec': 's',
|
||||||
|
'secs': 's',
|
||||||
|
'second': 's',
|
||||||
|
'seconds': 's',
|
||||||
|
'hour': 'h',
|
||||||
|
'hours': 'h',
|
||||||
|
'min': 'm',
|
||||||
|
'mins': 'm',
|
||||||
|
'minute': 'm',
|
||||||
|
'minutes': 'm',
|
||||||
|
'day': 'd',
|
||||||
|
'days': 'd',
|
||||||
|
'week': 'w',
|
||||||
|
'weeks': 'w',
|
||||||
|
'month': 'mo',
|
||||||
|
'months': 'mo',
|
||||||
|
'year': 'y',
|
||||||
|
'years': 'y',
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def multiply(factors):
|
||||||
|
result = 1
|
||||||
|
for factor in factors:
|
||||||
|
result = result * factor
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
def divide(divisors):
|
||||||
|
result = 1
|
||||||
|
for divisor in divisors:
|
||||||
|
result = result / divisor
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
def to_time_unit(human_time, unit='ms'):
|
||||||
|
''' Return a time unit from a human readable string '''
|
||||||
|
unit = UNIT_TO_SHORT_FORM.get(unit, unit)
|
||||||
|
if unit not in UNIT_FACTORS:
|
||||||
|
available_units = sorted(list(UNIT_FACTORS.keys()) + list(UNIT_TO_SHORT_FORM.keys()))
|
||||||
|
raise AnsibleFilterError("to_time_unit() can not convert to the following unit: %s. "
|
||||||
|
"Available units: %s" % (unit, ', '.join(available_units)))
|
||||||
|
result = 0
|
||||||
|
for h_time_string in human_time.split():
|
||||||
|
res = re.match(r'(-?\d+)(\w+)', h_time_string)
|
||||||
|
if not res:
|
||||||
|
raise AnsibleFilterError(
|
||||||
|
"to_time_unit() can not interpret following string: %s" % human_time)
|
||||||
|
|
||||||
|
h_time_int = int(res.group(1))
|
||||||
|
h_time_unit = res.group(2)
|
||||||
|
|
||||||
|
h_time_unit = UNIT_TO_SHORT_FORM.get(h_time_unit, h_time_unit)
|
||||||
|
if h_time_unit not in UNIT_FACTORS:
|
||||||
|
raise AnsibleFilterError(
|
||||||
|
"to_time_unit() can not interpret following string: %s" % human_time)
|
||||||
|
|
||||||
|
time_in_milliseconds = h_time_int * multiply(UNIT_FACTORS[h_time_unit])
|
||||||
|
result += time_in_milliseconds
|
||||||
|
return round(result * divide(UNIT_FACTORS[unit]), 12)
|
||||||
|
|
||||||
|
|
||||||
|
def to_milliseconds(human_time):
|
||||||
|
''' Return milli seconds from a human readable string '''
|
||||||
|
return to_time_unit(human_time, 'ms')
|
||||||
|
|
||||||
|
|
||||||
|
def to_seconds(human_time):
|
||||||
|
''' Return seconds from a human readable string '''
|
||||||
|
return to_time_unit(human_time, 's')
|
||||||
|
|
||||||
|
|
||||||
|
def to_minutes(human_time):
|
||||||
|
''' Return minutes from a human readable string '''
|
||||||
|
return to_time_unit(human_time, 'm')
|
||||||
|
|
||||||
|
|
||||||
|
def to_hours(human_time):
|
||||||
|
''' Return hours from a human readable string '''
|
||||||
|
return to_time_unit(human_time, 'h')
|
||||||
|
|
||||||
|
|
||||||
|
def to_days(human_time):
|
||||||
|
''' Return days from a human readable string '''
|
||||||
|
return to_time_unit(human_time, 'd')
|
||||||
|
|
||||||
|
|
||||||
|
def to_weeks(human_time):
|
||||||
|
''' Return weeks from a human readable string '''
|
||||||
|
return to_time_unit(human_time, 'w')
|
||||||
|
|
||||||
|
|
||||||
|
def to_months(human_time):
|
||||||
|
''' Return months from a human readable string '''
|
||||||
|
return to_time_unit(human_time, 'mo')
|
||||||
|
|
||||||
|
|
||||||
|
def to_years(human_time):
|
||||||
|
''' Return years from a human readable string '''
|
||||||
|
return to_time_unit(human_time, 'y')
|
||||||
|
|
||||||
|
|
||||||
|
class FilterModule(object):
|
||||||
|
''' Ansible time jinja2 filters '''
|
||||||
|
|
||||||
|
def filters(self):
|
||||||
|
filters = {
|
||||||
|
'to_time_unit': to_time_unit,
|
||||||
|
'to_milliseconds': to_milliseconds,
|
||||||
|
'to_seconds': to_seconds,
|
||||||
|
'to_minutes': to_minutes,
|
||||||
|
'to_hours': to_hours,
|
||||||
|
'to_days': to_days,
|
||||||
|
'to_weeks': to_weeks,
|
||||||
|
'to_months': to_months,
|
||||||
|
'to_years': to_years,
|
||||||
|
}
|
||||||
|
|
||||||
|
return filters
|
2
tests/integration/targets/filter_to_time_unit/aliases
Normal file
2
tests/integration/targets/filter_to_time_unit/aliases
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
shippable/posix/group2
|
||||||
|
skip/python2.6 # filters are controller only, and we no longer support Python 2.6 on the controller
|
82
tests/integration/targets/filter_to_time_unit/tasks/main.yml
Normal file
82
tests/integration/targets/filter_to_time_unit/tasks/main.yml
Normal file
|
@ -0,0 +1,82 @@
|
||||||
|
---
|
||||||
|
- name: test to_milliseconds filter
|
||||||
|
assert:
|
||||||
|
that:
|
||||||
|
- "('1000ms' | community.general.to_milliseconds) == 1000"
|
||||||
|
- "('1s' | community.general.to_milliseconds) == 1000"
|
||||||
|
- "('1m' | community.general.to_milliseconds) == 60000"
|
||||||
|
|
||||||
|
- name: test to_seconds filter
|
||||||
|
assert:
|
||||||
|
that:
|
||||||
|
- "('1000msecs' | community.general.to_seconds) == 1"
|
||||||
|
- "('1ms' | community.general.to_seconds) == 0.001"
|
||||||
|
- "('12m' | community.general.to_seconds) == 720"
|
||||||
|
- "('300minutes' | community.general.to_seconds) == 18000"
|
||||||
|
- "('3h 12m' | community.general.to_seconds) == 11520"
|
||||||
|
- "('2days 3hours 12mins 15secs' | community.general.to_seconds) == 184335"
|
||||||
|
- "('2d -2d -12s' | community.general.to_seconds) == -12"
|
||||||
|
|
||||||
|
- name: test to_minutes filter
|
||||||
|
assert:
|
||||||
|
that:
|
||||||
|
- "('30s' | community.general.to_minutes) == 0.5"
|
||||||
|
- "('12m' | community.general.to_minutes) == 12"
|
||||||
|
- "('3h 72m' | community.general.to_minutes) == 252"
|
||||||
|
- "('300s' | community.general.to_minutes) == 5"
|
||||||
|
|
||||||
|
- name: test to_hours filter
|
||||||
|
assert:
|
||||||
|
that:
|
||||||
|
- "('30m' | community.general.to_hours) == 0.5"
|
||||||
|
- "('3h 119m 61s' | community.general.to_hours) > 5"
|
||||||
|
|
||||||
|
- name: test to_days filter
|
||||||
|
assert:
|
||||||
|
that:
|
||||||
|
- "('1year' | community.general.to_days) == 365"
|
||||||
|
- "('1week' | community.general.to_days) == 7"
|
||||||
|
- "('2weeks' | community.general.to_days) == 14"
|
||||||
|
- "('1mo' | community.general.to_days) == 30"
|
||||||
|
|
||||||
|
- name: test to_weeks filter
|
||||||
|
assert:
|
||||||
|
that:
|
||||||
|
- "('1y' | community.general.to_weeks | int) == 52"
|
||||||
|
- "('7d' | community.general.to_weeks) == 1"
|
||||||
|
|
||||||
|
- name: test to_months filter
|
||||||
|
assert:
|
||||||
|
that:
|
||||||
|
- "('30d' | community.general.to_months) == 1"
|
||||||
|
- "('1year' | community.general.to_months | int) == 12"
|
||||||
|
|
||||||
|
- name: test to_years filter
|
||||||
|
assert:
|
||||||
|
that:
|
||||||
|
- "('365d' | community.general.to_years | int) == 1"
|
||||||
|
- "('12mo' | community.general.to_years | round(0, 'ceil')) == 1"
|
||||||
|
|
||||||
|
- name: test fail unknown unit
|
||||||
|
debug:
|
||||||
|
msg: "{{ '1s' | community.general.to_time_unit('lightyears') }}"
|
||||||
|
ignore_errors: yes
|
||||||
|
register: res
|
||||||
|
|
||||||
|
- name: verify test fail unknown unit
|
||||||
|
assert:
|
||||||
|
that:
|
||||||
|
- res is failed
|
||||||
|
- "'to_time_unit() can not convert to the following unit: lightyears' in res.msg"
|
||||||
|
|
||||||
|
- name: test fail unknown string
|
||||||
|
debug:
|
||||||
|
msg: "{{ '1 s' | community.general.to_time_unit('s') }}"
|
||||||
|
ignore_errors: yes
|
||||||
|
register: res
|
||||||
|
|
||||||
|
- name: test fail unknown string
|
||||||
|
assert:
|
||||||
|
that:
|
||||||
|
- res is failed
|
||||||
|
- "'to_time_unit() can not interpret following string' in res.msg"
|
Loading…
Reference in a new issue