How to filter GCP objects based on date of their creation in Ansible
If you ever wonder why I’m been paid, this is it.
Goal: to find objects (in my case VMs) in gcp account which have specific labels but live for too long.
The general algo is simple: query resources, filter based on creation date (specicially, for gcp_compute_instance_info
it’s resources[x].creationTimestamp
), check the age, kill old ones.
The actual maddening reality:
This is google timestamp: 2022-06-18T06:59:15.045-07:00
This is Ansible current date: 2022-06-18T14:34:04Z
If you ever wonder how to feed to_datetime
google-flavored ISO8601, well,…according to specs, it’s impossible. Because there is no field descriptor for milliseconds. Nope.
Moreover, man strptime
does not have anything with sub-second resolution and there is no substitution character for ‘anything’ or ‘any digit’.
(Sigh) So, the true reason I’m paid for is:
Python’s datetime has %f formatter, which is number of microseconds. But Google has milliseconds. But we don’t care. Boom!
- name: Report ages
debug:
msg: "age: {{ansible_date_time.iso8601|to_datetime(ansible_iso8601_fmt) - item.creationTimestamp|to_datetime(google_iso8601_fmt) }}"
loop: "{{ servers.resources }}"
loop_control:
label: "{{ item.name }}"
vars:
google_iso8601_fmt: "%Y-%m-%dT%H:%M:%S.%f%z"
ansible_iso8601_fmt: "%Y-%m-%dT%H:%M:%S%z
… uh, I can’t read it in Medium mess. Anyway, magic is:
ansible_date_time.iso8601|to_datetime(ansible_iso8601_fmt)
and we got Ansible version of datetime (do not forget to gather facts)
item.creationTimestamp|to_datetime(google_iso8601_fmt)
and we got the Google flavor for ISO8601 datetime. Which has totally incorrect microseconds, but, again, we don’t care about milimicroseconds.
Difference between is timedelta, which has trap of its own, but if we are ̶w̶e̶l̶l̶-̶p̶a̶i̶d̶.. experienced, and we know, that it’s not .seconds
, but .total_seconds()
.
So, difference between them is the age (or age in the seconds):
(a-b).total_seconds()
So, full code is:
- name: Get
gcp_compute_instance_info:
filters:
- labels.env=YOUR-FILTER
....
register: servers- name: delete instance
gcp_compute_instance:
state: absent
name: "{{ item.name }}"
...
when: (ansible_date_time.iso8601|to_datetime(ansible_iso8601_fmt) - item.creationTimestamp|to_datetime(google_iso8601_fmt)).total_seconds() > inactivity
loop: "{{ servers.resources }}"
loop_control:
label: "{{ item.name }}"
vars:
google_iso8601_fmt: "%Y-%m-%dT%H:%M:%S.%f%z"
ansible_iso8601_fmt: "%Y-%m-%dT%H:%M:%S%z"
P.S.
Why milliseconds? Why? … May be for job security?