Skip to content

Commit 5aa85f3

Browse files
committed
Add option to create edges in parallel
1 parent 44930e6 commit 5aa85f3

File tree

10 files changed

+233
-1
lines changed

10 files changed

+233
-1
lines changed

roles/azure_edges/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ Variables with default values that can be overridden by the user:
4646
- `vbond_port`, `default_vbond_ip`: Default configurations for vBond.
4747
- `az_cedge_vm_size`: Default Azure VM size for cEdge instances.
4848
- `edge_instances`: List of cEdge instance configurations. If not provided, instances will be created based on PnP Portal information.
49+
- `edges_parallel_deployment`: Azure virtual machines are created sequentially by default. Setting this parameter to true enables simultaneous creation of all Edge VMs by using Azure resource manager deployments
4950

5051
### Vars (`vars/main.yml`)
5152

roles/azure_edges/defaults/main.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,3 +78,4 @@ edge_instances: []
7878
# If no edge instances configured, they will be automatically created
7979
# based on the PnP Portal information.
8080
# See `deployment_edges_config` to inspect result
81+
edges_parallel_deployment: false
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
# Copyright 2024 Cisco Systems, Inc. and its affiliates
2+
# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt)
3+
4+
---
5+
6+
- name: "Set vpn0_default_gateway fact from VPN 0 subnet value"
7+
ansible.builtin.set_fact:
8+
vpn0_default_gateway: "{{ vpn0_subnet | ansible.utils.ipaddr('1') | ansible.utils.ipaddr('address') }}"
9+
vpn512_default_gateway: "{{ vpn512_subnet | ansible.utils.ipaddr('1') | ansible.utils.ipaddr('address') }}"
10+
vars:
11+
vpn0_subnet: "{{ az_subnets | json_query('[?VPN==`0` && type!=`cluster`].cidr | [0]') }}"
12+
vpn512_subnet: "{{ az_subnets | json_query('[?VPN==`512` && type!=`cluster`].cidr | [0]') }}"
13+
14+
- name: "Get info about NSG: {{ az_network_security_group }}"
15+
azure.azcollection.azure_rm_securitygroup_info:
16+
resource_group: "{{ az_resource_group }}"
17+
name: "{{ az_network_security_group }}"
18+
register: az_res_gr
19+
20+
- name: "Template userdata file for cedge: {{ hostname }}"
21+
ansible.builtin.template:
22+
src: ./userdata_cedge.j2 # ./bond.j2 ./userdata_cedge.j2
23+
dest: "{{ userdata_cedge_path }}-{{ hostname }}"
24+
mode: "0644"
25+
vars:
26+
hostname: "{{ instance_item.hostname | replace('_', '-') }}"
27+
uuid: "{{ instance_item.uuid }}"
28+
otp: "{{ instance_item.otp }}"
29+
vbond: "{{ instance_item.vbond }}"
30+
system_ip: "{{ instance_item.system_ip }}"
31+
site_id: "{{ instance_item.site_id }}"
32+
loop: "{{ edge_instances }}"
33+
loop_control:
34+
loop_var: instance_item
35+
when: instance_item.hostname not in instances_info or not instances_info[instance_item.hostname]
36+
37+
- name: Create Azure Deployment
38+
azure_rm_deployment:
39+
resource_group: "{{ az_resource_group }}"
40+
name: "{{ az_resources_prefix }}-edges"
41+
location: "{{ az_location }}"
42+
wait_for_deployment_completion: true
43+
template:
44+
$schema: "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#"
45+
contentVersion: "1.0.0.0"
46+
resources: "{{ lookup('template', 'deployment_resources.j2') }}"
47+
outputs: "{{ lookup('template', 'deployment_outputs.j2') }}"
48+
register: azure_deployment
49+
50+
- name: "Extend Network Security Group for machine, NSG: {{ az_network_security_group }}"
51+
azure.azcollection.azure_rm_securitygroup:
52+
resource_group: "{{ az_resource_group }}"
53+
name: "{{ az_network_security_group }}"
54+
rules: "{{ lookup('template', 'nsg_rules.j2') }}"
55+
tags:
56+
Name: "{{ az_network_security_group }}"
57+
Creator: "{{ az_tag_creator }}"
58+
Organization: "{{ organization_name }}"
59+
vars:
60+
deployed_ips: "{{ azure_deployment['deployment']['outputs']['public_ip_addresses']['value'] | map(attribute='ip') }}"
61+
existing_nsgs: "{{ az_res_gr.securitygroups | map(attribute='rules') | flatten | map(attribute='source_address_prefix') | list }}"
62+
when: deployed_ips | difference(existing_nsgs)
63+
64+
- name: Update deployment facts - cedge - that will be consumed by vManage-client in Ansible
65+
ansible.builtin.set_fact:
66+
deployment_facts:
67+
deployed_edge_instances: "{{ deployment_facts.deployed_edge_instances + [instance] }}"
68+
vars:
69+
instance:
70+
hostname: "{{ instance_item['hostname'] }}"
71+
system_ip: "{{ instance_item['system_ip'] }}"
72+
admin_username: "{{ admin_username }}"
73+
admin_password: "{{ admin_password }}"
74+
mgmt_public_ip: "{{ all_public_ips | json_query('[?host==`'~instance_item['hostname']~'` && type==`mgmt`].ip | [0]') }}"
75+
transport_public_ip: "{{ all_public_ips | json_query('[?host==`'~instance_item['hostname']~'` && type==`transport`].ip | [0]') }}"
76+
service_interfaces: "{{ service_interfaces if 'service' in az_subnets | map(attribute='type') else omit }}"
77+
uuid: "{{ instance_item['uuid'] }}"
78+
site_id: "{{ instance_item['site_id'] }}"
79+
all_public_ips: "{{ azure_deployment['deployment']['outputs']['public_ip_addresses']['value'] }}"
80+
service_interfaces: "{{ azure_deployment['deployment']['outputs']['service_interfaces']['value'][instance_item['hostname']] }}"
81+
loop: "{{ edge_instances }}"
82+
loop_control:
83+
loop_var: instance_item
84+
when: instance_item.hostname not in instances_info or not instances_info[instance_item.hostname]

roles/azure_edges/tasks/main.yml

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,14 @@
5757
loop: "{{ edge_instances }}"
5858
loop_control:
5959
loop_var: instance_item
60-
when: edge_instances is defined and (instance_item.hostname not in instances_info or not instances_info[instance_item.hostname])
60+
when:
61+
- not edges_parallel_deployment
62+
- edge_instances is defined
63+
- instance_item.hostname not in instances_info or not instances_info[instance_item.hostname]
64+
65+
- name: Create azure resource manager deployment - cEdge (C8000V)
66+
ansible.builtin.include_tasks: azure_deployment.yml
67+
when: edges_parallel_deployment
6168

6269
- name: Extract deployment facts
6370
ansible.builtin.include_role:
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
- type: "Microsoft.Network/networkInterfaces"
2+
apiVersion: "2024-05-01"
3+
name: "nic-{{ instance_item['hostname'] }}-vpn-{{ subnet_item.VPN }}"
4+
location: "{{ az_location }}"
5+
dependsOn:
6+
- "[resourceId('Microsoft.Network/publicIPAddresses', 'public-ip-{{ instance_item['hostname'] }}-vpn-{{ subnet_item.VPN }}')]"
7+
properties:
8+
ipConfigurations:
9+
- name: "ipconfig-vpn-{{ subnet_item.VPN }}"
10+
properties:
11+
primary: true
12+
privateIPAllocationMethod: "Dynamic"
13+
{% if subnet_item.type in ("mgmt", "transport") %}
14+
publicIPAddress:
15+
id: "[resourceId('Microsoft.Network/publicIPAddresses', 'public-ip-{{ instance_item['hostname'] }}-vpn-{{ subnet_item.VPN }}')]"
16+
{% endif %}
17+
subnet:
18+
id: "{{ (az_virtualnetwork_info['virtualnetworks'][0]['subnets'] | json_query('[?name==`' ~ subnet_item.name ~ '`].id'))[0] }}"
19+
networkSecurityGroup:
20+
id: "{{ az_res_gr['securitygroups'][0]['id'] }}"
21+
tags:
22+
Name: "nic-{{ instance_item['hostname'] }}-vpn-{{ subnet_item.VPN }}"
23+
Creator: "{{ az_tag_creator }}"
24+
Organization: "{{ organization_name }}"
25+
VPN: "{{ subnet_item.VPN }}"
26+
type: "{{ subnet_item.type }}"
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
{% filter from_yaml %}
2+
public_ip_addresses:
3+
type: array
4+
value:
5+
{% for instance in edge_instances if instance.hostname not in instances_info %}
6+
{% for subnet_item in az_subnets if subnet_item.type in ("mgmt", "transport") %}
7+
- name: public-ip-{{ instance.hostname }}-vpn-{{ subnet_item.VPN }}
8+
ip: "[reference('public-ip-{{ instance.hostname }}-vpn-{{ subnet_item.VPN }}').ipAddress]"
9+
type: {{ subnet_item.type }}
10+
host: {{ instance.hostname }}
11+
{% endfor %}
12+
{% endfor %}
13+
service_interfaces:
14+
type: object
15+
value:
16+
{% for instance in edge_instances if instance.hostname not in instances_info %}
17+
{% if "service" in az_subnets | map(attribute='type') %}
18+
{{ instance['hostname'] }}:
19+
{% for subnet_item in az_subnets if subnet_item.type in ("service") %}
20+
addr: "[reference('nic-{{ instance_item['hostname'] }}-vpn-{{ subnet_item.VPN }}').ipConfigurations[0].privateIPAddress]"
21+
index: {{ loop.index0 + 2}}
22+
{% endfor %}
23+
{% else %}
24+
{{ instance['hostname'] }}: {}
25+
{% endif %}
26+
{% endfor %}
27+
{% endfilter %}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
- type: "Microsoft.Network/publicIPAddresses"
2+
apiVersion: "2024-05-01"
3+
name: "public-ip-{{ instance_item['hostname'] }}-vpn-{{ subnet_item.VPN }}"
4+
location: "{{ az_location }}"
5+
properties:
6+
publicIPAllocationMethod: "Static"
7+
tags:
8+
Name: "public-ip-{{ instance_item['hostname'] }}-vpn-{{ subnet_item.VPN }}"
9+
Creator: "{{ az_tag_creator }}"
10+
Machine: "{{ instance_item['hostname'] }}"
11+
VPN: "{{ subnet_item.VPN }}"
12+
Subnet: "{{ subnet_item.name }}"
13+
type: "{{ subnet_item.type }}"
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
{% filter from_yaml %}
2+
{% for instance_item in edge_instances if instance_item.hostname not in instances_info %}
3+
{% for subnet_item in az_subnets %}
4+
{% if subnet_item.type in ("mgmt", "transport", "service") %}
5+
{% include "deployment_public_ip_addresses.j2" %}
6+
7+
{% include "deployment_network_interfaces.j2" %}
8+
9+
{% endif %}
10+
{% endfor %}
11+
{% include "deployment_virtual_machines.j2" %}
12+
13+
{% endfor %}
14+
{% endfilter %}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
- type: "Microsoft.Compute/virtualMachines"
2+
apiVersion: "2024-11-01"
3+
name: "{{ instance_item['hostname'] }}"
4+
location: "{{ az_location }}"
5+
dependsOn:
6+
{% for subnet_item in az_subnets %}
7+
- "[resourceId('Microsoft.Network/networkInterfaces', 'nic-{{ instance_item['hostname'] }}-vpn-{{ subnet_item.VPN }}')]"
8+
{% endfor %}
9+
plan:
10+
name: "{{ az_cedge_image_sku }}"
11+
product: "{{ az_cedge_image_offer }}"
12+
publisher: "{{ az_cedge_image_publisher }}"
13+
properties:
14+
diagnosticsProfile:
15+
bootDiagnostics:
16+
enabled: true
17+
hardwareProfile:
18+
vmSize: "{{ az_cedge_vm_size }}"
19+
osProfile:
20+
adminUsername: "{{ admin_username }}-tmp"
21+
adminPassword: "{{ admin_password }}"
22+
computerName: "{{ instance_item['hostname'] }}"
23+
linuxConfiguration:
24+
disablePasswordAuthentication: false
25+
customData: "{{ lookup('file', userdata_cedge_path ~ '-' ~ instance_item['hostname']) | b64encode }}"
26+
storageProfile:
27+
imageReference:
28+
publisher: "{{ az_cedge_image_publisher }}"
29+
offer: "{{ az_cedge_image_offer }}"
30+
sku: "{{ az_cedge_image_sku }}"
31+
version: "{{ az_cedge_image_version }}"
32+
osDisk:
33+
name: "{{ instance_item['hostname'] }}-os-disk"
34+
createOption: FromImage
35+
diskSizeGB: 30
36+
osType: "Linux"
37+
caching: "ReadWrite"
38+
managedDisk:
39+
storageAccountType: "StandardSSD_ZRS"
40+
networkProfile:
41+
networkInterfaces:
42+
{% for subnet_item in az_subnets %}
43+
- id: "[resourceId('Microsoft.Network/networkInterfaces', 'nic-{{ instance_item['hostname'] }}-vpn-{{ subnet_item.VPN }}')]"
44+
properties:
45+
primary: {{ subnet_item.type == "mgmt" | string }}
46+
{% endfor %}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
{% filter from_yaml %}
2+
---
3+
{% for public_ip in azure_deployment['deployment']['outputs']['public_ip_addresses']['value'] if public_ip['name'] not in az_res_gr.securitygroups | map(attribute='rules') | flatten | map(attribute='name') | list %}
4+
- name: "{{ public_ip['name'] }}"
5+
protocol: "*"
6+
destination_port_range: "*"
7+
source_port_range: "*"
8+
source_address_prefix: "{{ public_ip['ip'] }}"
9+
access: Allow
10+
priority: "{{ 1500 + ((az_res_gr.securitygroups | first).rules | length) + loop.index }}"
11+
direction: Inbound
12+
{% endfor %}
13+
{% endfilter %}

0 commit comments

Comments
 (0)