ansible-collections / azure

Development area for Azure Collections
https://galaxy.ansible.com/azure/azcollection
GNU General Public License v3.0
248 stars 332 forks source link

Allow Backend Address Members to be added to Pool in azure_rm_loadbalancer #866

Open mike-andretta opened 2 years ago

mike-andretta commented 2 years ago

I have not seen this mentioned so if It has I apologize.

SUMMARY

I've found myself writing Azure CLI tasks to add members to pool, the pool has the ability in azure_rm_loadbalancer module to be created but I do not see any ability to add pool members.

ISSUE TYPE
COMPONENT NAME

azure_rm_loadbalancer

ADDITIONAL INFORMATION

This feature would allow for a single module to be used with the ability to add/remove pool members within the same module. Currently if the azure_rm_loadbalancer module is used then another separate task with some Azure CLI needs to be written to allow the full deployment of a LB with pool members included. Basically adding in a function like the same code below.

- name: Create Load Balancer
  azure_rm_loadbalancer:
    resource_group: rg-sample
    name: lb-sample
    location: eastus
    sku: Standard
    frontend_ip_configurations:
      - name: fw-ip
        subnet: sn-subnet-name
        private_ip_allocation_method: Dynamic
    backend_address_pools:
      - name: be-pool-web
        members: # New feature
          - server: server1 # New feature
            ip: 10.0.0.10 # New feature
          - server: server2 # New feature
            ip: 10.0.0.11 # New feature
      - name: be-pool-sftp
        members: # New feature
          - server: server3 # New feature
            ip: 10.0.0.12 # New feature
          - server: server4 # New feature
            ip: 10.0.0.13 # New feature
    load_balancing_rules:
      - name: rule-web
        frontend_ip_configuration: fw-ip
        backend_address_pool: be-pool-web
        frontend_port: 443
        backend_port: 443
        probe: tcp-443
        idle_timeout: 30
        enable_floating_ip: false
        protocol: Tcp
        load_distribution: Default
      - name: rule-sftp
        frontend_ip_configuration: fw-ip
        backend_address_pool: be-pool-sftp
        frontend_port: 22
        backend_port: 22
        probe: tcp-22
        idle_timeout: 30
        enable_floating_ip: false
        protocol: Tcp
        load_distribution: Default
    probes:
      - name: tcp-443
        port: 443
        protocol: Tcp
      - name: tcp-22
        port: 22
        protocol: Tcp
    state: present
sean-freeman commented 1 year ago

@Fred-sun This is a significant bug, can you please add bug label and amend to high_priority label?

To workaround this I had to provision the LB before the VM NIC and VM, so that I could preallocate the VM NIC at provision-time to the LB Backend Pool. This is a very ineffective method and because the hosts were yet to be provisioned (and dynamically added to Ansible Inventory), it required a large amount of additional code (around 1050 lines instead of about 200 if I could loop over existing hosts and append to the LB).

michael-andretta commented 1 year ago

@Fred-sun This is a significant bug, can you please add bug label and amend to high_priority label?

To workaround this I had to provision the LB before the VM NIC and VM, so that I could preallocate the VM NIC at provision-time to the LB Backend Pool. This is a very ineffective method and because the hosts were yet to be provisioned (and dynamically added to Ansible Inventory), it required a large amount of additional code (around 1050 lines instead of about 200 if I could loop over existing hosts and append to the LB).

@sean-freeman this is how I got around this for now and to stop failures when a NIC is not present. Its not the best but it works for now and solves two problems.

  1. NIC/VM is not present and a LB should be provisioned
  2. NIC/VM is deleted and the LB is not removed prior to the VM being deleted
- name: Get NIC Facts of VMs in RG
  azure_rm_virtualmachine_info:
    resource_group: '{{ lb_resource_group }}'
  register: vm_info_output

- name: Set fact of NIC names
  set_fact:
    rg_nic_names: "{{ vm_info_output | json_query('vms[*].network_interface_names[*]') | flatten }}" 

This will go to the RG where the LB and NIC should live. It registers all the NIC names. I then use them in a when condition for the addition of the NIC to the LB via the 'az network nic ip-config address-pool add' cli command. Below is the condition I use (I know with_items shouldnt be used anymore but I havent rewritten it with loop).

  with_items: '{{ be_members|default([]) }}'
  when: item is defined and item.state == 'present' and item.region == short_location and item.nic_name in rg_nic_names

Again not the most beautiful thing but it has worked for me.

Fred-sun commented 1 year ago

@mike-andretta I will arrange some time to solve this problem next week, thank you!

michael-andretta commented 1 year ago

Thanks @Fred-sun , below are some highlights I've observed that hopefully will help you with this.

I've struggled with the fact that the azure CLI wants '--ip-config-name'. In some cases on a NIC it will be 'default', others its 'ifconfig', and just yesterday I have seen it be 'primary'. I've been unable to find any logic as to why in some situations it is different names.

Also in the example I gave above, the IP address is not needed, its dependent on the NIC name, at least with Azure CLI. My roles (LB task and vars) have the ability to handle multiple regions. Below is an example of how I'm handling the NIC add (I also have a task with conditions to remove the NIC if absent) and using the be_members section with a region parameter on the NIC to drive the conditional add of that member to an EUS2 or CUS LB in this example.

Another struggle, as we have adopted more load balancers (which drove the search for the NIC in the RG), was that a VM (and NIC) were deleted yet the LB was never cleaned up and made absent. This initially caused our pipelines to fail while attempting to add the NIC with state 'present' however the search using module 'azure_rm_virtualmachine_info' and json_query allows us to keep the pipeline from failing if the VM has been terminated.

Example NIC add to Pool

- name: Add Members to Pool by NIC
  shell: >
    az network nic ip-config address-pool add
    --resource-group '{{ lb_resource_group }}'
    --address-pool '{{ item.pool_name }}'
    --nic-name '{{ item.nic_name }}'
    --ip-config-name "{{ item.ip_config }}"
    --lb-name 'lb-{{ short_subscription_name }}-{{ short_location }}-{{ lb_shortname }}'
    --subscription '{{ subscription_id }}'
  with_items: '{{ be_members|default([]) }}'
  when: item is defined and item.state == 'present' and item.region == short_location and item.nic_name in rg_nic_names and lb_state == 'present'

Inside my vars file I have a section called be_member which looks like this.

be_members:
# EUS2 Servers
  - nic_name: server1e2-nic01
    pool_name: '{{ lb_shortname }}-backend1'
    region: eus2
    ip_config: default
    state: present

  - nic_name: server2e2-nic01
    pool_name: '{{ lb_shortname }}-backend1'
    region: eus2
    ip_config: default
    state: present

# CUS Servers
  - nic_name: server1cus-nic01
    pool_name: '{{ lb_shortname }}-backend1'
    region: cus
    ip_config: default
    state: present

  - nic_name: server2cus-nic01
    pool_name: '{{ lb_shortname }}-backend1'
    region: cus
    ip_config: default
    state: present