I am deploying any number of instances using ansible in Azure Cloud based on a instancesCount
variable and iterating over the creation tasks for each resource (NIC, managed disk, VM, etc) using with_sequence: count={{ instancesCount }}
. The instances, and their associated resources (managed disks, os disk, NICs) are created in the same name format:
{{ env }}-xxx-{{ vmName }}-{{ count }}:
say instancesCount is 3:
dev-xxx-myvm-1
dev-xxx-myvm-1-nic
dev-xxx-myvm--1-osDisk
dev-xxx-myvm-2
dev-xxx-myvm-2-nic
dev-xxx-myvm-2-osDisk
dev-xxx-myvm-3
dev-xxx-myvm-3-nic
dev-xxx-myvm-3-osDisk
I am looking for a way to scale down the number of instances when the variable instancesCount
changes to a lower integer number, say from 3 to 1, by removing the newest instances first: dev-xxx-myvm-3
, dev-xxx-myvm-2
, and their associated resources, leaving just dev-xxx-myvm-1
.
The logic I am thinking is first gather info from Azure using Ansible modules for each resource (azure_rm_virtualmachine_info
, azure_rm_networkinterface_info
, azure_rm_manageddisk_info
, etc). Save each of that in a variable of its own, and using that, and instancesCount, remove those resources that exceed, but I am not sure how to proceed..
Using jinja2 I can easily get the vm names to be removed, but cant convert this code to Ansible:
{% set to_remove = existing_vms.vms | length - instancesCount | int %}
{% for item in existing_vms.vms[-to_remove:] %}
{{ item.name }}
{% endfor %}
Was able to convert successfully:
- name: Print name of vms to be removed
debug:
var: item.name
loop: "{{ existing_vms.vms[-(to_remove|int):] }}"
Yet, one last issue: the list is not sorted. Say we have 10 instances, the existing_vms.vms.*.name
looks like this, as its pulled from Azure:
dev-xxx-myvm-1
dev-xxx-myvm-10
dev-xxx-myvm-2
dev-xxx-myvm-3
dev-xxx-myvm-4
dev-xxx-myvm-5
dev-xxx-myvm-6
dev-xxx-myvm-7
dev-xxx-myvm-8
dev-xxx-myvm-9
How would I be able to sort the list by the trailing number in the name, ascending, before passing it to the slice operator - [-(to_remove)|int:]
?
Correct solution is to look for what VMs are already deployed using azure_rm_virtualmachine_info
, save that in a variable and sanitize the variable, then pass it to azure_rm_virtualmachine
while specifying remove_on_absent
. There is no need to get managed disk, nic or any other resource info as this will remove dependent resources.
- name: "Getting deployment state"
block:
- name: "Getting deployment state"
azure.azcollection.azure_rm_virtualmachine_info:
resource_group: myRG
register: existing_vms
- name: Saving all VM names in vm_names
ansible.builtin.set_fact:
vm_names: "{{ vm_names | default([]) + [item.name] }}"
loop: "{{ existing_vms.vms }}"
- name: Sorting the VM names in vm_names_sorted
ansible.builtin.set_fact:
vm_names_sorted: "{{ vm_names | community.general.version_sort }}"
ignore_errors: true
This will sort the list properly:
FROM:
dev-xxx-myvm-1
dev-xxx-myvm-10
dev-xxx-myvm-2
dev-xxx-myvm-3
dev-xxx-myvm-4
dev-xxx-myvm-5
dev-xxx-myvm-6
dev-xxx-myvm-7
dev-xxx-myvm-8
dev-xxx-myvm-9
TO:
dev-xxx-myvm-1
dev-xxx-myvm-2
dev-xxx-myvm-3
dev-xxx-myvm-4
dev-xxx-myvm-5
dev-xxx-myvm-6
dev-xxx-myvm-7
dev-xxx-myvm-8
dev-xxx-myvm-9
dev-xxx-myvm-10
- name: "Setting scale down value if instancesCount < currrent deployment"
ansible.builtin.set_fact:
to_remove: "{{ vm_names_sorted | length - instancesCount | int }}"
when: vm_names_sorted is defined and vm_names_sorted | length | int > instancesCount | int and instancesCount | int != 0
azure_rm_virtualmachine
to remove to_remove number of VMs, starting with the newest (dev-xxx-myvm-10, dev-xxx-myvm-9, etc):
- name: "Scaling down deployment to {{ instancesCount }}"
azure.azcollection.azure_rm_virtualmachine:
resource_group: myRG
name: "{{ item }}"
remove_on_absent: ['network_interfaces', 'virtual_storage', 'public_ips']
state: absent
loop: "{{ vm_names_sorted[-(to_remove|int):] }}"
when: to_remove is defined