From cb3ece88a151988658791041515fe4586eb54462 Mon Sep 17 00:00:00 2001 From: msyyc <70930885+msyyc@users.noreply.github.com> Date: Wed, 28 Jul 2021 09:54:08 +0800 Subject: [PATCH] load balancer --- .../CONTRIBUTING.md | 11 + doc/network-manage-loadbalancer/LICENSE | 21 + doc/network-manage-loadbalancer/README.md | 102 ++++ doc/network-manage-loadbalancer/example.py | 426 ++++++++++++++++ .../example_internal_load_balancer.py | 453 +++++++++++++++++ .../example_public_load_balancer.py | 470 ++++++++++++++++++ doc/network-manage-loadbalancer/lb.JPG | Bin 0 -> 36193 bytes .../requirements.txt | 4 + 8 files changed, 1487 insertions(+) create mode 100644 doc/network-manage-loadbalancer/CONTRIBUTING.md create mode 100644 doc/network-manage-loadbalancer/LICENSE create mode 100644 doc/network-manage-loadbalancer/README.md create mode 100644 doc/network-manage-loadbalancer/example.py create mode 100644 doc/network-manage-loadbalancer/example_internal_load_balancer.py create mode 100644 doc/network-manage-loadbalancer/example_public_load_balancer.py create mode 100644 doc/network-manage-loadbalancer/lb.JPG create mode 100644 doc/network-manage-loadbalancer/requirements.txt diff --git a/doc/network-manage-loadbalancer/CONTRIBUTING.md b/doc/network-manage-loadbalancer/CONTRIBUTING.md new file mode 100644 index 0000000..e2abe20 --- /dev/null +++ b/doc/network-manage-loadbalancer/CONTRIBUTING.md @@ -0,0 +1,11 @@ +# Contributing to Azure samples + +Thank you for your interest in contributing to Azure samples! + +## Ways to contribute + +You can contribute to [Azure samples](https://azure.microsoft.com/documentation/samples/) in a few different ways: + +- Submit feedback on [this sample page](https://azure.microsoft.com/documentation/samples/network-python-manage-loadbalancer/) whether it was helpful or not. +- Submit issues through [issue tracker](https://github.com/Azure-Samples/network-python-manage-loadbalancer/issues) on GitHub. We are actively monitoring the issues and improving our samples. +- If you wish to make code changes to samples, or contribute something new, please follow the [GitHub Forks / Pull requests model](https://help.github.com/articles/fork-a-repo/): Fork the sample repo, make the change and propose it back by submitting a pull request. \ No newline at end of file diff --git a/doc/network-manage-loadbalancer/LICENSE b/doc/network-manage-loadbalancer/LICENSE new file mode 100644 index 0000000..d8d98a8 --- /dev/null +++ b/doc/network-manage-loadbalancer/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2015 Microsoft Corporation + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/doc/network-manage-loadbalancer/README.md b/doc/network-manage-loadbalancer/README.md new file mode 100644 index 0000000..d49b48d --- /dev/null +++ b/doc/network-manage-loadbalancer/README.md @@ -0,0 +1,102 @@ +--- +page_type: sample +languages: +- python +products: +- azure +description: "This sample shows how to manage a load balancer using the Azure Resource Manager APIs for Python." +urlFragment: network-python-manage-loadbalancer +--- + +# Getting Started with Azure Resource Manager for load balancers in Python + +This sample shows how to manage a load balancer using the Azure Resource Manager APIs for Python. + +You can use a load balancer to provide high availability for your workloads in Azure. An Azure load balancer is a Layer-4 (TCP, UDP) type load balancer that distributes incoming traffic among healthy service instances in cloud services or virtual machines defined in a load balancer set. + +For a detailed overview of Azure load balancers, see [Azure Load Balancer overview](https://azure.microsoft.com/documentation/articles/load-balancer-overview/). + +![alt tag](./lb.JPG) + +This sample deploys an internet-facing load balancer. It then creates and deploys two Azure virtual machines behind the load balancer. For a detailed overview of internet-facing load balancers, see [Internet-facing load balancer overview](https://azure.microsoft.com/documentation/articles/load-balancer-internet-overview/). + +To deploy an internet-facing load balancer, you'll need to create and configure the following objects. + +- Front end IP configuration - contains public IP addresses for incoming network traffic. +- Back end address pool - contains network interfaces (NICs) for the virtual machines to receive network traffic from the load balancer. +- Load balancing rules - contains rules mapping a public port on the load balancer to port in the back end address pool. +- Inbound NAT rules - contains rules mapping a public port on the load balancer to a port for a specific virtual machine in the back end address pool. +- Probes - contains health probes used to check availability of virtual machines instances in the back end address pool. + +You can get more information about load balancer components with Azure resource manager at [Azure Resource Manager support for Load Balancer](https://azure.microsoft.com/documentation/articles/load-balancer-arm/). + +## Tasks performed in this sample + +The sample performs the following tasks to create the load balancer and the load-balanced virtual machines: + +1. Create a resource group +4. Create a public IP +5. Build the load balancer payload + 1. Build a front-end IP pool + 2. Build a back-end address pool + 3. Build a health probe + 4. Build a load balancer rule + 5. Build inbound NAT rule 1 + 6. Build inbound NAT rule 2 +6. Create the load balancer with the above payload +2. Create a virtual network (vnet) +3. Create a subnet +7. Create NIC 1 +8. Create NIC 2 +9. Find an Ubutnu VM image +10. Create an availability set +11. Create the first VM: Web1 +12. Create the second VM: Web2 +13. Delete the resource group and the resources created in the previous steps + +## Run this sample + +1. If you don't already have a Microsoft Azure subscription, you can register for a [free trial account](http://go.microsoft.com/fwlink/?LinkId=330212). + +1. Install [Python](https://www.python.org/downloads/) if you haven't already. + +2. We recommend using a [virtual environment](https://docs.python.org/3/tutorial/venv.html) to run this example, but it's not mandatory. You can initialize a virtual environment this way: + + pip install virtualenv + virtualenv mytestenv + cd mytestenv + source bin/activate + +3. Clone the sample repository. + + git clone https://github.com/Azure-Samples/network-python-manage-loadbalancer.git + +4. Install the dependencies using pip. + + cd network-python-manage-loadbalancer + pip install -r requirements.txt + +5. Create an Azure service principal, using +[Azure CLI](http://azure.microsoft.com/documentation/articles/resource-group-authenticate-service-principal-cli/), +[PowerShell](http://azure.microsoft.com/documentation/articles/resource-group-authenticate-service-principal/) +or [Azure Portal](http://azure.microsoft.com/documentation/articles/resource-group-create-service-principal-portal/). + +6. Export these environment variables into your current shell. + + export AZURE_TENANT_ID={your tenant ID} + export AZURE_CLIENT_ID={your client ID} + export AZURE_CLIENT_SECRET={your client secret} + export AZURE_SUBSCRIPTION_ID={your subscription ID} + +7. Run the sample for public load balancer. + + python example_public_load_balancer.py + Or + + Run the sample for internal load balancer. + + python example_internal_load_balancer.py + +## More information + +- [Azure SDK for Python](http://github.com/Azure/azure-sdk-for-python) diff --git a/doc/network-manage-loadbalancer/example.py b/doc/network-manage-loadbalancer/example.py new file mode 100644 index 0000000..fe28d3f --- /dev/null +++ b/doc/network-manage-loadbalancer/example.py @@ -0,0 +1,426 @@ +import os +from azure.common.credentials import ServicePrincipalCredentials +from azure.mgmt.resource import ResourceManagementClient +from azure.mgmt.storage import StorageManagementClient +from azure.mgmt.network import NetworkManagementClient +from azure.mgmt.compute import ComputeManagementClient +from haikunator import Haikunator + +haikunator = Haikunator() + +# Azure Datacenter +LOCATION = 'westus' + +# Resource Group +GROUP_NAME = 'azure-sample-group-loadbalancer' + +# Network +VNET_NAME = 'azure-sample-vnet' +SUBNET_NAME = 'azure-sample-subnet' +DOMAIN_LABEL_NAME = 'testdns'+haikunator.haikunate() +PUBLIC_IP_NAME = 'azure-sample-publicip' + +# Load balancer +LB_NAME = 'azure-sample-loadbalancer' +FIP_NAME = 'azure-sample-frontendipname' +ADDRESS_POOL_NAME = 'azure-sample-addr-pool' +PROBE_NAME = 'azure-sample-probe' +LB_RULE_NAME = 'azure-sample-lb-rule' + +NETRULE_NAME_1 = 'azure-sample-netrule1' +NETRULE_NAME_2 = 'azure-sample-netrule2' + +FRONTEND_PORT_1 = 21 +FRONTEND_PORT_2 = 23 +BACKEND_PORT = 22 + +# VM +AVAILABILITY_SET_NAME = 'azure-sample-availabilityset' +OS_DISK_NAME = 'azure-sample-osdisk' +STORAGE_ACCOUNT_NAME = haikunator.haikunate(delimiter='') + +IP_CONFIG_NAME = 'azure-sample-ip-config' +VMS_INFO = { + 1: { + 'name': 'Web1', + 'nic_name': 'azure-sample-nic1', + 'username': 'notadmin1', + 'password': 'Pa$$w0rd91' + }, + 2: { + 'name': 'Web2', + 'nic_name': 'azure-sample-nic2', + 'username': 'notadmin2', + 'password': 'Pa$$w0rd92' + } +} + +# Ubuntu config +PUBLISHER = 'Canonical' +OFFER = 'UbuntuServer' +SKU = '15.10' +VERSION = '15.10.201603150' + +# Windows config +#PUBLISHER = 'microsoftwindowsserver' +#OFFER = 'windowsserver' +#SKU = '2012-r2-datacenter' + +# Manage resources and resource groups - create, update and delete a resource group, +# deploy a solution into a resource group, export an ARM template. Create, read, update +# and delete a resource +# +# This script expects that the following environment vars are set: +# +# AZURE_TENANT_ID: with your Azure Active Directory tenant id or domain +# AZURE_CLIENT_ID: with your Azure Active Directory Application Client ID +# AZURE_CLIENT_SECRET: with your Azure Active Directory Application Secret +# AZURE_SUBSCRIPTION_ID: with your Azure Subscription Id +# + + +def run_example(): + """Resource Group management example.""" + # + # Create all clients with an Application (service principal) token provider + # + subscription_id = os.environ.get( + 'AZURE_SUBSCRIPTION_ID', + '11111111-1111-1111-1111-111111111111') # your Azure Subscription Id + credentials = ServicePrincipalCredentials( + client_id=os.environ['AZURE_CLIENT_ID'], + secret=os.environ['AZURE_CLIENT_SECRET'], + tenant=os.environ['AZURE_TENANT_ID'] + ) + resource_client = ResourceManagementClient(credentials, subscription_id) + compute_client = ComputeManagementClient(credentials, subscription_id) + storage_client = StorageManagementClient(credentials, subscription_id) + network_client = NetworkManagementClient(credentials, subscription_id) + + # Create Resource group + print('Create Resource Group') + resource_client.resource_groups.create_or_update( + GROUP_NAME, {'location': LOCATION}) + + # Create PublicIP + print('Create Public IP') + public_ip_parameters = { + 'location': LOCATION, + 'public_ip_allocation_method': 'static', + 'dns_settings': { + 'domain_name_label': DOMAIN_LABEL_NAME + }, + 'idle_timeout_in_minutes': 4 + } + async_publicip_creation = network_client.public_ip_addresses.create_or_update( + GROUP_NAME, + PUBLIC_IP_NAME, + public_ip_parameters + ) + public_ip_info = async_publicip_creation.result() + + # Building a FrontEndIpPool + print('Create FrontEndIpPool configuration') + frontend_ip_configurations = [{ + 'name': FIP_NAME, + 'private_ip_allocation_method': 'Dynamic', + 'public_ip_address': { + 'id': public_ip_info.id + } + }] + + # Building a BackEnd address pool + print('Create BackEndAddressPool configuration') + backend_address_pools = [{ + 'name': ADDRESS_POOL_NAME + }] + + # Building a HealthProbe + print('Create HealthProbe configuration') + probes = [{ + 'name': PROBE_NAME, + 'protocol': 'Http', + 'port': 80, + 'interval_in_seconds': 15, + 'number_of_probes': 4, + 'request_path': 'healthprobe.aspx' + }] + + # Building a LoadBalancer rule + print('Create LoadBalancerRule configuration') + load_balancing_rules = [{ + 'name': LB_RULE_NAME, + 'protocol': 'tcp', + 'frontend_port': 80, + 'backend_port': 80, + 'idle_timeout_in_minutes': 4, + 'enable_floating_ip': False, + 'load_distribution': 'Default', + 'frontend_ip_configuration': { + 'id': construct_fip_id(subscription_id) + }, + 'backend_address_pool': { + 'id': construct_bap_id(subscription_id) + }, + 'probe': { + 'id': construct_probe_id(subscription_id) + } + }] + + # Building InboundNATRule1 + print('Create InboundNATRule1 configuration') + inbound_nat_rules = [{ + 'name': NETRULE_NAME_1, + 'protocol': 'tcp', + 'frontend_port': FRONTEND_PORT_1, + 'backend_port': BACKEND_PORT, + 'enable_floating_ip': False, + 'idle_timeout_in_minutes': 4, + 'frontend_ip_configuration': { + 'id': construct_fip_id(subscription_id) + } + }] + + # Building InboundNATRule2 + print('Create InboundNATRule2 configuration') + inbound_nat_rules.append({ + 'name': NETRULE_NAME_2, + 'protocol': 'tcp', + 'frontend_port': FRONTEND_PORT_2, + 'backend_port': BACKEND_PORT, + 'enable_floating_ip': False, + 'idle_timeout_in_minutes': 4, + 'frontend_ip_configuration': { + 'id': construct_fip_id(subscription_id) + } + }) + + # Creating Load Balancer + print('Creating Load Balancer') + lb_async_creation = network_client.load_balancers.create_or_update( + GROUP_NAME, + LB_NAME, + { + 'location': LOCATION, + 'frontend_ip_configurations': frontend_ip_configurations, + 'backend_address_pools': backend_address_pools, + 'probes': probes, + 'load_balancing_rules': load_balancing_rules, + 'inbound_nat_rules': inbound_nat_rules + } + ) + lb_info = lb_async_creation.result() + + ############################################################## + # From here, we create the VM and link the LB inside the NIC # + ############################################################## + + # Create VNet + print('Create Vnet') + async_vnet_creation = network_client.virtual_networks.create_or_update( + GROUP_NAME, + VNET_NAME, + { + 'location': LOCATION, + 'address_space': { + 'address_prefixes': ['10.0.0.0/16'] + } + } + ) + async_vnet_creation.wait() + + # Create Subnet + async_subnet_creation = network_client.subnets.create_or_update( + GROUP_NAME, + VNET_NAME, + SUBNET_NAME, + {'address_prefix': '10.0.0.0/24'} + ) + subnet_info = async_subnet_creation.result() + + # Creating NIC + print('Creating NetworkInterface 1') + + back_end_address_pool_id = lb_info.backend_address_pools[0].id + + inbound_nat_rule_1_id = lb_info.inbound_nat_rules[0].id + async_nic1_creation = network_client.network_interfaces.create_or_update( + GROUP_NAME, + VMS_INFO[1]['nic_name'], + create_nic_parameters( + subnet_info.id, back_end_address_pool_id, inbound_nat_rule_1_id) + ) + + inbound_nat_rule_2_id = lb_info.inbound_nat_rules[1].id + print('Creating NetworkInterface 2') + async_nic2_creation = network_client.network_interfaces.create_or_update( + GROUP_NAME, + VMS_INFO[2]['nic_name'], + create_nic_parameters( + subnet_info.id, back_end_address_pool_id, inbound_nat_rule_2_id) + ) + + nic1_info = async_nic1_creation.result() + nic2_info = async_nic2_creation.result() + + # Create availability set + print('Create availability set') + availability_set_info = compute_client.availability_sets.create_or_update( + GROUP_NAME, + AVAILABILITY_SET_NAME, + {'location': LOCATION} + ) + + # Create a storage account + print('Create a storage account') + storage_async_operation = storage_client.storage_accounts.create( + GROUP_NAME, + STORAGE_ACCOUNT_NAME, + { + 'sku': {'name': 'standard_lrs'}, + 'kind': 'storage', + 'location': LOCATION + } + ) + storage_async_operation.wait() + + # Create VMs + print('Creating Virtual Machine 1') + vm_parameters1 = create_vm_parameters( + nic1_info.id, availability_set_info.id, VMS_INFO[1]) + async_vm1_creation = compute_client.virtual_machines.create_or_update( + GROUP_NAME, VMS_INFO[1]['name'], vm_parameters1) + async_vm1_creation.wait() + + print('Creating Virtual Machine 2') + vm_parameters2 = create_vm_parameters( + nic2_info.id, availability_set_info.id, VMS_INFO[2]) + async_vm2_creation = compute_client.virtual_machines.create_or_update( + GROUP_NAME, VMS_INFO[2]['name'], vm_parameters2) + async_vm2_creation.wait() + + provide_vm_login_info_to_user( + 1, public_ip_info, FRONTEND_PORT_1, VMS_INFO[1]) + provide_vm_login_info_to_user( + 2, public_ip_info, FRONTEND_PORT_2, VMS_INFO[2]) + + input("Press enter to delete this Resource Group.") + + # Delete Resource group and everything in it + print('Delete Resource Group') + delete_async_operation = resource_client.resource_groups.delete(GROUP_NAME) + delete_async_operation.wait() + print("\nDeleted: {}".format(GROUP_NAME)) + + +def construct_fip_id(subscription_id): + """Build the future FrontEndId based on components name. + """ + return ('/subscriptions/{}' + '/resourceGroups/{}' + '/providers/Microsoft.Network' + '/loadBalancers/{}' + '/frontendIPConfigurations/{}').format( + subscription_id, GROUP_NAME, LB_NAME, FIP_NAME + ) + + +def construct_bap_id(subscription_id): + """Build the future BackEndId based on components name. + """ + return ('/subscriptions/{}' + '/resourceGroups/{}' + '/providers/Microsoft.Network' + '/loadBalancers/{}' + '/backendAddressPools/{}').format( + subscription_id, GROUP_NAME, LB_NAME, ADDRESS_POOL_NAME + ) + + +def construct_probe_id(subscription_id): + """Build the future ProbeId based on components name. + """ + return ('/subscriptions/{}' + '/resourceGroups/{}' + '/providers/Microsoft.Network' + '/loadBalancers/{}' + '/probes/{}').format( + subscription_id, GROUP_NAME, LB_NAME, PROBE_NAME + ) + + +def provide_vm_login_info_to_user(num, public_ip_info, frontend_port, vm_info): + """Print on the console the connection information for a given VM. + """ + print('\n\nLogin information for the {} VM: {}'.format( + num, vm_info['name'])) + print('-------------------------------------------') + print('ssh to ip:port - {}:{}'.format(public_ip_info.ip_address, frontend_port)) + print('username - {}'.format(vm_info['username'])) + print('password - {}'.format(vm_info['password'])) + + +def create_nic_parameters(subnet_id, address_pool_id, natrule_id): + """Create the NIC parameters structure. + """ + return { + 'location': LOCATION, + 'ip_configurations': [{ + 'name': IP_CONFIG_NAME, + 'subnet': { + 'id': subnet_id + }, + 'load_balancer_backend_address_pools': [{ + 'id': address_pool_id + }], + 'load_balancer_inbound_nat_rules': [{ + 'id': natrule_id + }] + }] + } + + +def create_vm_parameters(nic_id, availset_id, vm_info): + """Create the VM parameters structure. + """ + return { + 'location': LOCATION, + 'os_profile': { + 'computer_name': vm_info['name'], + 'admin_username': vm_info['username'], + 'admin_password': vm_info['password'] + }, + 'hardware_profile': { + 'vm_size': 'Standard_DS1' + }, + 'storage_profile': { + 'image_reference': { + 'publisher': PUBLISHER, + 'offer': OFFER, + 'sku': SKU, + 'version': VERSION + }, + 'os_disk': { + 'name': OS_DISK_NAME, + 'caching': 'None', + 'create_option': 'fromImage', + 'vhd': { + 'uri': 'https://{}.blob.core.windows.net/vhds/{}.vhd'.format( + STORAGE_ACCOUNT_NAME, vm_info['name']) + } + }, + }, + 'network_profile': { + 'network_interfaces': [{ + 'id': nic_id, + 'primary': True + }] + }, + 'availability_set': { + 'id': availset_id + } + } + + +if __name__ == "__main__": + run_example() diff --git a/doc/network-manage-loadbalancer/example_internal_load_balancer.py b/doc/network-manage-loadbalancer/example_internal_load_balancer.py new file mode 100644 index 0000000..064174a --- /dev/null +++ b/doc/network-manage-loadbalancer/example_internal_load_balancer.py @@ -0,0 +1,453 @@ +import os + +from azure.identity import DefaultAzureCredential +from azure.mgmt.resource import ResourceManagementClient +from azure.mgmt.network import NetworkManagementClient +from azure.mgmt.network import models as network_models +from azure.mgmt.compute import ComputeManagementClient + +# Azure Datacenter +LOCATION = 'eastus' +SKU = 'Standard' +# Resource Group +GROUP_NAME = 'myInternalLoadBalancer1' + +# Network +VNET_NAME = 'myVNet' +ADDRESS_PREFIXES = '10.1.0.0/16' +SUBNET_NAME = 'myBackendSubnet' +SUBNET_PREFIXES = '10.1.0.0/24' + +# Nic ip-config +NIC_IP_CONFIG_NAME = 'ipconfig1' + +# Public IP address for the bastion host +BASTION_PUBLIC_IP_NAME = 'myBastionIP' + +# Bastion subnet +IP_CONFIG_NAME = 'myBastionIPConfig' +BASTION_SUBNET_NAME = 'AzureBastionSubnet' +BASTION_SUBNET_PREFIXES = '10.1.1.0/24' + +# Bastion host +BASTION_NAME = 'myBastionHost' + +# Network security group +NSG_NAME = 'myNSG' + +# Network Security Group Rule +NSG_RULE_NAME = 'myNSGRuleHTTP' + +# Network interfaces for the virtual machines +NIC_NAMES = ['myNicVM1', 'myNicVM2', 'myNicVM3'] + +# Virtual machine +VM_NAMES = ['myVM1', 'myVM2', 'myVM3'] +# VN_IMAGE = 'win2019datacenter' +VM_ADMIN_USERNAME = 'azureuser' +VM_ADMIN_PASSEORD = 'P@ssw0rd123' + +# Public IP address - Standard +PUBLIC_IP_NAME = 'myPublicIP' + +# Public Load balancer +LB_NAME = 'myLoadBalancer' +FIP_NAME = 'myFrontEnd' +BP_NAME = 'myBackEndPool' + +# Health probe +LB_PROBE_NAME = 'myHealthProbe' +LB_PROTOCOL = 'tcp' +LB_PORT = 80 + +# Load balancer rule +LB_RELE_NAME = 'myHTTPRule' + +# NIC Test +NIC_TEST_NAME = 'myNicTestVM' + +# VM Test +VM_TEST_NAME = 'myTestVM' +################################# + +# Single IP for the outbound connectivity +PUBLIC_IP_OB_NAME = 'myPublicIPOutbound' + +# Public IP prefix for the outbound connectivity +PUBLIC_IP_PREDIX_OB_NAME = 'myPublicIPPrefixOutbound' +PUBLIC_IP_PREDIX_OB_LENGTH = 28 + +# Outbound frontend IP configuration +FIP_OB_NAME = 'myFrontEndOutbound' + +# Outbound pool +OB_POOL_NAME = 'myBackendPoolOutbound' + +# Oubtbound rule +OB_RULE = 'myOutboundRule' + +# Manage resources and resource groups - create, update and delete a resource group, +# deploy a solution into a resource group, export an ARM template. Create, read, update +# and delete a resource +# +# This script expects that the following environment vars are set: +# +# AZURE_TENANT_ID: with your Azure Active Directory tenant id or domain +# AZURE_CLIENT_ID: with your Azure Active Directory Application Client ID +# AZURE_CLIENT_SECRET: with your Azure Active Directory Application Secret +# AZURE_SUBSCRIPTION_ID: with your Azure Subscription Id + +def run_example(): + import time + start_time = time.time() + """Resource Group management example.""" + # + # Create all clients with an Application (service principal) token provider + # + subscription_id = os.environ.get( + 'AZURE_SUBSCRIPTION_ID', + '11111111-1111-1111-1111-111111111111') # your Azure Subscription Id + + resource_client = ResourceManagementClient( + credential=DefaultAzureCredential(), + subscription_id=subscription_id + ) + network_client = NetworkManagementClient( + credential=DefaultAzureCredential(), + subscription_id=subscription_id + ) + compute_client = ComputeManagementClient( + credential=DefaultAzureCredential(), + subscription_id=subscription_id + ) + + # Create Resource group + rg = resource_client.resource_groups.create_or_update( + GROUP_NAME, {'location': LOCATION}) + print('Create Resource Group:\n{}'.format(rg)) + + # Create VNet + network = network_client.virtual_networks.begin_create_or_update( + GROUP_NAME, + VNET_NAME, + network_models.VirtualNetwork( + location=LOCATION, + address_space=network_models.AddressSpace( + address_prefixes=[ADDRESS_PREFIXES] + ), + subnets=[network_models.Subnet( + name=SUBNET_NAME, + address_prefix=SUBNET_PREFIXES + ), ] + ) + ).result() + print("Create Vnet:\n{}".format(network)) + + # Create PublicIP for the Bastion Host + bastion_public_ip = network_client.public_ip_addresses.begin_create_or_update( + GROUP_NAME, + BASTION_PUBLIC_IP_NAME, + network_models.PublicIPAddress( + location=LOCATION, + public_ip_allocation_method="Static", + sku=network_models.PublicIPPrefixSku(name="Standard") + ) + ).result() + print("Create Public IP for the bastion host:\n{}".format(bastion_public_ip)) + + # Create Bastion Subnet + bastion_subnet = network_client.subnets.begin_create_or_update( + GROUP_NAME, + VNET_NAME, + BASTION_SUBNET_NAME, + {'address_prefix': BASTION_SUBNET_PREFIXES} + ).result() + print("Create a bastion subnet:\n{}".format(bastion_subnet)) + + # Create Bastion Host + ip_configuration = network_models.BastionHostIPConfiguration( + name=NIC_IP_CONFIG_NAME, + subnet=network_models.SubResource(id=bastion_subnet.id), + public_ip_address=network_models.SubResource(id=bastion_public_ip.id) + ) + bastion_parameters = network_models.BastionHost( + location=LOCATION, + ip_configurations=[ip_configuration] + ) + + bastion_host = network_client.bastion_hosts.begin_create_or_update( + GROUP_NAME, + BASTION_NAME, + parameters=bastion_parameters + ).result() + print("Create a bastion host:\n{}".format(bastion_host)) + + # Create Network Security Group + nsg_parameters = network_models.NetworkSecurityGroup(location=LOCATION) + network_security_group = network_client.network_security_groups.begin_create_or_update( + GROUP_NAME, + NSG_NAME, + parameters=nsg_parameters + ).result() + print("Create Network Security Group:\n{}".format(network_security_group)) + + # Create Network Security Group Rule + nsg_rule_parameters = network_models.SecurityRule( + protocol='*', + direction='inbound', + source_address_prefix='*', + source_port_range='*', + destination_address_prefix='*', + destination_port_range=80, + access='allow', + priority=200 + ) + nsg_rule = network_client.security_rules.begin_create_or_update( + GROUP_NAME, + NSG_NAME, + NSG_RULE_NAME, + nsg_rule_parameters + ).result() + print("Create Network Security Group Rule:\n{}".format(nsg_rule)) + + # Create Backend Servers - Standard + # Create Network Interfaces for the VMs + network_interface_parameters = network_models.NetworkInterface( + location=LOCATION, + enable_accelerated_networking=True, + ip_configurations=[network_models.NetworkInterfaceIPConfiguration( + name=IP_CONFIG_NAME, + subnet=network_models.Subnet(id=network.subnets[0].id) + ), + ], + network_security_group=network_models.NetworkSecurityGroup(id=network_security_group.id) + ) + network_interfaces = [] + for nic_name in NIC_NAMES: + network_interface = network_client.network_interfaces.begin_create_or_update( + GROUP_NAME, + nic_name, + network_interface_parameters + ).result() + network_interfaces.append(network_interface) + print("Create Network Interface named {}:\n{}".format(nic_name, network_interface)) + + ############################################################## + # From here, we create the VM and link the LB inside the NIC # + ############################################################## + + # Create VMs + vms = [] + for i in range(3): + vm = compute_client.virtual_machines.begin_create_or_update( + GROUP_NAME, + VM_NAMES[i], + { + "location": LOCATION, + "hardware_profile": { + "vm_size": "Standard_D2_v2" + }, + "storage_profile": { + "image_reference": { + "sku": "2019-Datacenter", + "publisher": "MicrosoftWindowsServer", + "version": "latest", + "offer": "WindowsServer" + }, + "os_disk": { + "caching": "ReadWrite", + "managed_disk": { + "storage_account_type": "Standard_LRS" + }, + "name": "myVMosdisk" + str(i + 1), + "create_option": "FromImage" + }, + "data_disks": [ + { + "disk_size_gb": "1023", + "create_option": "Empty", + "lun": "0" + } + ] + }, + "os_profile": { + "admin_username": VM_ADMIN_USERNAME, + "computer_name": "myVM", + "admin_password": VM_ADMIN_PASSEORD, + "windows_configuration": { + "enable_automatic_updates": True # need automatic update for reimage + } + }, + "network_profile": { + "network_interfaces": [ + { + "id": network_interfaces[i].id, + "properties": { + "primary": True + } + } + ] + } + } + ).result() + vms.append(vm) + print('Create VM{} :\n{}'.format(str(i + 1), vm)) + + # Create Load Balancer + lb_fip_subnets = [network_subnet for network_subnet in network.subnets if network_subnet.name == SUBNET_NAME] + load_balancer_parameters = network_models.LoadBalancer( + location=LOCATION, + sku=network_models.Sku(name=SKU), + frontend_ip_configurations=[ + network_models.FrontendIPConfiguration( + name=FIP_NAME, + subnet=lb_fip_subnets[0] + ) + ], + backend_address_pools=[ + network_models.BackendAddressPool( + name=BP_NAME + ) + ] + ) + + load_balancer = network_client.load_balancers.begin_create_or_update( + GROUP_NAME, + LB_NAME, + load_balancer_parameters + ).result() + print("Create Load Balancer:\n{}".format(load_balancer)) + + # Create Health Probe + load_balancer_parameters.probes = [ + network_models.Probe( + protocol=LB_PROTOCOL, + port=LB_PORT, + name=LB_PROBE_NAME + ) + ] + lb_probe = network_client.load_balancers.begin_create_or_update( + GROUP_NAME, + LB_NAME, + load_balancer_parameters + ).result().probes + print("Create Health Probe: \n{}".format(eval(str(lb_probe[0])))) + + # Create Load Balancer Rule + load_balancer_parameters.load_balancing_rules = [ + network_models.LoadBalancingRule( + name=LB_RELE_NAME, + protocol='tcp', + frontend_port=80, + backend_port=80, + frontend_ip_configuration=network_models.SubResource(id=load_balancer.frontend_ip_configurations[0].id), + backend_address_pool=network_models.SubResource(id=load_balancer.backend_address_pools[0].id), + probe=network_models.SubResource(id=lb_probe[0].id), + idle_timeout_in_minutes=15, + enable_floating_ip=True + ) + ] + lb_rule = network_client.load_balancers.begin_create_or_update( + GROUP_NAME, + LB_NAME, + load_balancer_parameters + ).result().load_balancing_rules + print("Create Load Balancer Rule: \n{}".format(lb_rule[0])) + + # Add VMs to Load Balancer Backend Pool + for i in range(3): + for nic_ipconf in network_interfaces[i].ip_configurations: + if nic_ipconf.name == NIC_IP_CONFIG_NAME: + nic_ipconf.load_balancer_backend_address_pools = [load_balancer.backend_address_pools[0], + ] + add_vm_to_lb_bp = network_client.network_interfaces.begin_create_or_update( + GROUP_NAME, + NIC_NAMES[i], + network_interfaces[i] + ).result().ip_configurations + print("Add {} to Load Balancer Backend Pool: \n{}".format(NIC_NAMES[i], add_vm_to_lb_bp)) + + # Test Load Balancer + # Create NIC for VM to test + nic_test_parameters = network_models.NetworkInterface( + location=LOCATION, + # enable_accelerated_networking=True, + ip_configurations=[network_models.NetworkInterfaceIPConfiguration( + name=NIC_IP_CONFIG_NAME, + subnet=network_models.Subnet(id=network.subnets[0].id) + ), + ], + network_security_group=network_models.NetworkSecurityGroup(id=network_security_group.id) + ) + nic_test = network_client.network_interfaces.begin_create_or_update( + GROUP_NAME, + NIC_TEST_NAME, + nic_test_parameters + ).result() + print("Create Network Interface:\n{}".format(nic_test)) + + # Create VM for test + vm_test_parameters = { + "location": LOCATION, + "hardware_profile": { + "vm_size": "Standard_D2_v2" + }, + "storage_profile": { + "image_reference": { + "sku": "2019-Datacenter", + "publisher": "MicrosoftWindowsServer", + "version": "latest", + "offer": "WindowsServer" + }, + "os_disk": { + "caching": "ReadWrite", + "managed_disk": { + "storage_account_type": "Standard_LRS" + }, + "name": "myVMosdisk", + "create_option": "FromImage" + }, + "data_disks": [ + { + "disk_size_gb": "1023", + "create_option": "Empty", + "lun": "0" + } + ] + }, + "os_profile": { + "admin_username": VM_ADMIN_USERNAME, + "computer_name": "myVM", + "admin_password": VM_ADMIN_PASSEORD, + "windows_configuration": { + "enable_automatic_updates": True # need automatic update for reimage + } + }, + "network_profile": { + "network_interfaces": [ + { + "id": nic_test.id, + "properties": { + "primary": True + } + } + ] + } + } + vm_test = compute_client.virtual_machines.begin_create_or_update( + GROUP_NAME, + VM_TEST_NAME, + vm_test_parameters + ).result() + print('Create VM for test:\n{}'.format(vm_test)) + print("Running time: {}".format(time.time() - start_time)) + + # Delete Resource group and everything in it + input("Press enter to delete this Resource Group.") + print('Delete Resource Group') + delete_group = resource_client.resource_groups.begin_delete(GROUP_NAME) + print("\nDeleted: {}".format(GROUP_NAME)) + + +if __name__ == "__main__": + run_example() diff --git a/doc/network-manage-loadbalancer/example_public_load_balancer.py b/doc/network-manage-loadbalancer/example_public_load_balancer.py new file mode 100644 index 0000000..7472717 --- /dev/null +++ b/doc/network-manage-loadbalancer/example_public_load_balancer.py @@ -0,0 +1,470 @@ +import os + +from azure.identity import DefaultAzureCredential +from azure.mgmt.resource import ResourceManagementClient +from azure.mgmt.network import NetworkManagementClient +from azure.mgmt.network import models as network_models +from azure.mgmt.compute import ComputeManagementClient + +# Azure Datacenter +LOCATION = 'eastus' +SKU = 'Standard' +# Resource Group +GROUP_NAME = 'myPublicLoadBalancer1' + +# Network +VNET_NAME = 'myVNet' +ADDRESS_PREFIXES = '10.1.0.0/16' +SUBNET_NAME = 'myBackendSubnet' +SUBNET_PREFIXES = '10.1.0.0/24' + +# Nic ip-config +NIC_IP_CONFIG_NAME = 'ipconfig1' + +# Public IP address for the bastion host +BASTION_PUBLIC_IP_NAME = 'myBastionIP' + +# Bastion subnet +IP_CONFIG_NAME = 'myBastionIPConfig' +BASTION_SUBNET_NAME = 'AzureBastionSubnet' +BASTION_SUBNET_PREFIXES = '10.1.1.0/24' + +# Bastion host +BASTION_NAME = 'myBastionHost' + +# Network security group +NSG_NAME = 'myNSG' + +# Network Security Group Rule +NSG_RULE_NAME = 'myNSGRuleHTTP' + +# Network interfaces for the virtual machines +NIC_NAMES = ['myNicVM1', 'myNicVM2', 'myNicVM3'] + +# Virtual machine +VM_NAMES = ['myVM1', 'myVM2', 'myVM3'] +# VN_IMAGE = 'win2019datacenter' +VM_ADMIN_USERNAME = 'azureuser' +VM_ADMIN_PASSEORD = 'P@ssw0rd123' + +# Public IP address - Standard +PUBLIC_IP_NAME = 'myPublicIP' + +# Public Load balancer +LB_NAME = 'myLoadBalancer' +FIP_NAME = 'myFrontEnd' +BP_NAME = 'myBackEndPool' + +# Health probe +LB_PROBE_NAME = 'myHealthProbe' +LB_PROTOCOL = 'tcp' +LB_PORT = 80 + +# Load balancer rule +LB_RELE_NAME = 'myHTTPRule' + +# Single IP for the outbound connectivity +PUBLIC_IP_OB_NAME = 'myPublicIPOutbound' + +# Public IP prefix for the outbound connectivity +PUBLIC_IP_PREDIX_OB_NAME = 'myPublicIPPrefixOutbound' +PUBLIC_IP_PREDIX_OB_LENGTH = 28 + +# Outbound frontend IP configuration +FIP_OB_NAME = 'myFrontEndOutbound' + +# Outbound pool +OB_POOL_NAME = 'myBackendPoolOutbound' + +# Oubtbound rule +OB_RULE = 'myOutboundRule' + +# Manage resources and resource groups - create, update and delete a resource group, +# deploy a solution into a resource group, export an ARM template. Create, read, update +# and delete a resource +# +# This script expects that the following environment vars are set: +# +# AZURE_TENANT_ID: with your Azure Active Directory tenant id or domain +# AZURE_CLIENT_ID: with your Azure Active Directory Application Client ID +# AZURE_CLIENT_SECRET: with your Azure Active Directory Application Secret +# AZURE_SUBSCRIPTION_ID: with your Azure Subscription Id + +def run_example(): + import time + start_time = time.time() + """Resource Group management example.""" + # + # Create all clients with an Application (service principal) token provider + # + subscription_id = os.environ.get( + 'AZURE_SUBSCRIPTION_ID', + '11111111-1111-1111-1111-111111111111') # your Azure Subscription Id + + resource_client = ResourceManagementClient( + credential=DefaultAzureCredential(), + subscription_id=subscription_id + ) + network_client = NetworkManagementClient( + credential=DefaultAzureCredential(), + subscription_id=subscription_id + ) + compute_client = ComputeManagementClient( + credential=DefaultAzureCredential(), + subscription_id=subscription_id + ) + + # Create Resource group + rg = resource_client.resource_groups.create_or_update( + GROUP_NAME, {'location': LOCATION}) + print('Create Resource Group:\n{}'.format(rg)) + + # Create VNet + network = network_client.virtual_networks.begin_create_or_update( + GROUP_NAME, + VNET_NAME, + network_models.VirtualNetwork( + location=LOCATION, + address_space=network_models.AddressSpace( + address_prefixes=[ADDRESS_PREFIXES] + ), + subnets=[network_models.Subnet( + name=SUBNET_NAME, + address_prefix=SUBNET_PREFIXES + ), ] + ) + ).result() + print("Create Vnet:\n{}".format(network)) + + # Create PublicIP for the Bastion Host + bastion_public_ip = network_client.public_ip_addresses.begin_create_or_update( + GROUP_NAME, + BASTION_PUBLIC_IP_NAME, + network_models.PublicIPAddress( + location=LOCATION, + public_ip_allocation_method="Static", + sku=network_models.PublicIPPrefixSku(name="Standard") + ) + ).result() + print("Create Public IP for the bastion host:\n{}".format(bastion_public_ip)) + + # Create Bastion Subnet + bastion_subnet = network_client.subnets.begin_create_or_update( + GROUP_NAME, + VNET_NAME, + BASTION_SUBNET_NAME, + {'address_prefix': BASTION_SUBNET_PREFIXES} + ).result() + print("Create a bastion subnet:\n{}".format(bastion_subnet)) + + # Create Bastion Host + ip_configuration = network_models.BastionHostIPConfiguration( + name=NIC_IP_CONFIG_NAME, + subnet=network_models.SubResource(id=bastion_subnet.id), + public_ip_address=network_models.SubResource(id=bastion_public_ip.id) + ) + bastion_parameters = network_models.BastionHost( + location=LOCATION, + ip_configurations=[ip_configuration] + ) + + bastion_host = network_client.bastion_hosts.begin_create_or_update( + GROUP_NAME, + BASTION_NAME, + parameters=bastion_parameters + ).result() + print("Create a bastion host:\n{}".format(bastion_host)) + + # Create Network Security Group + nsg_parameters = network_models.NetworkSecurityGroup(location=LOCATION) + network_security_group = network_client.network_security_groups.begin_create_or_update( + GROUP_NAME, + NSG_NAME, + parameters=nsg_parameters + ).result() + print("Create Network Security Group:\n{}".format(network_security_group)) + + # Create Network Security Group Rule + nsg_rule_parameters = network_models.SecurityRule( + protocol='*', + direction='inbound', + source_address_prefix='*', + source_port_range='*', + destination_address_prefix='*', + destination_port_range=80, + access='allow', + priority=200 + ) + nsg_rule = network_client.security_rules.begin_create_or_update( + GROUP_NAME, + NSG_NAME, + NSG_RULE_NAME, + nsg_rule_parameters + ).result() + print("Create Network Security Group Rule:\n{}".format(nsg_rule)) + + # Create Backend Servers - Standard + # Create Network Interfaces for the VMs + network_interface_parameters = network_models.NetworkInterface( + location=LOCATION, + enable_accelerated_networking=True, + ip_configurations=[network_models.NetworkInterfaceIPConfiguration( + name=NIC_IP_CONFIG_NAME, + subnet=network_models.Subnet(id=network.subnets[0].id) + ), + ], + network_security_group=network_models.NetworkSecurityGroup(id=network_security_group.id) + ) + network_interfaces = [] + for nic_name in NIC_NAMES: + network_interface = network_client.network_interfaces.begin_create_or_update( + GROUP_NAME, + nic_name, + network_interface_parameters + ).result() + network_interfaces.append(network_interface) + print("Create Network Interface named {}:\n{}".format(nic_name, network_interface)) + + ############################################################## + # From here, we create the VM and link the LB inside the NIC # + ############################################################## + + # Create VMs + vms = [] + for i in range(3): + vm = compute_client.virtual_machines.begin_create_or_update( + GROUP_NAME, + VM_NAMES[i], + { + "location": LOCATION, + "hardware_profile": { + "vm_size": "Standard_D2_v2" + }, + "storage_profile": { + "image_reference": { + "sku": "2019-Datacenter", + "publisher": "MicrosoftWindowsServer", + "version": "latest", + "offer": "WindowsServer" + }, + "os_disk": { + "caching": "ReadWrite", + "managed_disk": { + "storage_account_type": "Standard_LRS" + }, + "name": "myVMosdisk"+str(i+1), + "create_option": "FromImage" + }, + "data_disks": [ + { + "disk_size_gb": "1023", + "create_option": "Empty", + "lun": "0" + } + ] + }, + "os_profile": { + "admin_username": VM_ADMIN_USERNAME, + "computer_name": "myVM", + "admin_password": VM_ADMIN_PASSEORD, + "windows_configuration": { + "enable_automatic_updates": True # need automatic update for reimage + } + }, + "network_profile": { + "network_interfaces": [ + { + "id": network_interfaces[i].id, + "properties": { + "primary": True + } + } + ] + } + } + ).result() + vms.append(vm) + print('Create VM{} :\n{}'.format(str(i+1), vm)) + + # Create PublicIP for the Load Balancer + public_ip = network_client.public_ip_addresses.begin_create_or_update( + GROUP_NAME, + PUBLIC_IP_NAME, + network_models.PublicIPAddress( + location=LOCATION, + public_ip_allocation_method="Static", + sku=network_models.PublicIPPrefixSku(name="Standard") + ) + ).result() + print("Create PublicIP for the Load Balancer:\n{}".format(public_ip)) + + # Create Load Balancer + load_balancer_parameters = network_models.LoadBalancer( + location=LOCATION, + sku=network_models.Sku(name=SKU), + frontend_ip_configurations=[ + network_models.FrontendIPConfiguration( + name=FIP_NAME, + public_ip_address=network_models.PublicIPAddress( + id=public_ip.id + ) + ) + ], + backend_address_pools=[ + network_models.BackendAddressPool( + name=BP_NAME + ) + ] + ) + + load_balancer = network_client.load_balancers.begin_create_or_update( + GROUP_NAME, + LB_NAME, + load_balancer_parameters + ).result() + print("Create Load Balancer:\n{}".format(load_balancer)) + + # Create Health Probe + load_balancer_parameters.probes = [ + network_models.Probe( + protocol=LB_PROTOCOL, + port=LB_PORT, + name=LB_PROBE_NAME + ) + ] + lb_probe = network_client.load_balancers.begin_create_or_update( + GROUP_NAME, + LB_NAME, + load_balancer_parameters + ).result().probes + print("Create Health Probe: \n{}".format(eval(str(lb_probe[0])))) + + # Create Load Balancer Rule + load_balancer_parameters.load_balancing_rules = [ + network_models.LoadBalancingRule( + name=LB_RELE_NAME, + protocol='tcp', + frontend_port=80, + backend_port=80, + frontend_ip_configuration=network_models.SubResource(id=load_balancer.frontend_ip_configurations[0].id), + backend_address_pool=network_models.SubResource(id=load_balancer.backend_address_pools[0].id), + probe=network_models.SubResource(id=lb_probe[0].id), + disable_outbound_snat=True, + idle_timeout_in_minutes=15, + enable_floating_ip=True + ) + ] + lb_rule = network_client.load_balancers.begin_create_or_update( + GROUP_NAME, + LB_NAME, + load_balancer_parameters + ).result().load_balancing_rules + print("Create Load Balancer Rule: \n{}".format(lb_rule[0])) + + # Add VMs to Load Balancer Backend Pool + for i in range(3): + for nic_ipconf in network_interfaces[i].ip_configurations: + if nic_ipconf.name == NIC_IP_CONFIG_NAME: + nic_ipconf.load_balancer_backend_address_pools = [load_balancer.backend_address_pools[0], + ] + add_vm_to_lb_bp = network_client.network_interfaces.begin_create_or_update( + GROUP_NAME, + NIC_NAMES[i], + network_interfaces[i] + ).result().ip_configurations + print("Add {} to Load Balancer Backend Pool: \n{}".format(NIC_NAMES[i], add_vm_to_lb_bp)) + + # Create Public IP for the Outbound Connectivity + outbound_rule_ip = network_client.public_ip_addresses.begin_create_or_update( + GROUP_NAME, + PUBLIC_IP_OB_NAME, + network_models.PublicIPAddress( + location=LOCATION, + public_ip_allocation_method="Static", + sku=network_models.PublicIPPrefixSku(name="Standard") + ) + ).result() + print("Create Public IP for the Outbound Connectivity:\n{}".format(outbound_rule_ip)) + + # Create Frontend IP Configuration + load_balancer_parameters.frontend_ip_configurations.append( + network_models.FrontendIPConfiguration( + name=FIP_OB_NAME, + public_ip_address=outbound_rule_ip + ) + ) + lb_fip_config = network_client.load_balancers.begin_create_or_update( + GROUP_NAME, + LB_NAME, + load_balancer_parameters + ).result().frontend_ip_configurations + print("Create Frontend IP Configuration:\n{}".format(lb_fip_config[-1])) + + # Create Outbound Pool + load_balancer_parameters.backend_address_pools.append( + network_models.BackendAddressPool( + name=OB_POOL_NAME, + ) + ) + lb_ob_pool = network_client.load_balancers.begin_create_or_update( + GROUP_NAME, + LB_NAME, + load_balancer_parameters + ).result().backend_address_pools + print("Create Outbound Pool:\n{}".format(lb_ob_pool[-1])) + + # Create Outbound Rule for the Outbound Backend Pool + load_balancer_parameters.outbound_rules = [ + network_models.OutboundRule( + name=OB_RULE, + frontend_ip_configurations=[network_models.SubResource(id=lb_fip_config[-1].id)], + protocol='All', + idle_timeout_in_minutes=15, + allocated_outbound_ports=10000, + backend_address_pool=network_models.SubResource(id=lb_ob_pool[-1].id) + ) + ] + lb_ob_rule = network_client.load_balancers.begin_create_or_update( + GROUP_NAME, + LB_NAME, + load_balancer_parameters + ).result().outbound_rules + print("Create Outbound Rule for the Outbound Backend Pool:\n{}".format(lb_ob_rule[-1])) + + # Add VMs to the Outbound Pool + ob_pool_info = network_client.load_balancer_backend_address_pools.get( + GROUP_NAME, + LB_NAME, + OB_POOL_NAME + ) + for i in range(3): + vmnic_info = network_client.network_interfaces.get( + GROUP_NAME, NIC_NAMES[i] + ) + for ip_conf in vmnic_info.ip_configurations: + if ip_conf.name == NIC_IP_CONFIG_NAME: + ip_conf.load_balancer_backend_address_pools.append(ob_pool_info) + + add_vm_to_lb_op = network_client.network_interfaces.begin_create_or_update( + GROUP_NAME, + NIC_NAMES[i], + vmnic_info + ).result().ip_configurations + print("Add {} to Load Balancer Outbound Pool: \n{}".format(NIC_NAMES[i], add_vm_to_lb_op)) + + # Get the Public IP Address of the Load Balancer + network_public_ip_info = network_client.public_ip_addresses.get( + GROUP_NAME, PUBLIC_IP_NAME + ) + print("Public IP Address:\n{}".format(network_public_ip_info.ip_address)) + print("Running time: {}".format(time.time()-start_time)) + + # Delete Resource group and everything in it + input("Press enter to delete this Resource Group.") + print('Delete Resource Group') + delete_group = resource_client.resource_groups.begin_delete(GROUP_NAME) + print("\nDeleted: {}".format(GROUP_NAME)) + + +if __name__ == "__main__": + run_example() diff --git a/doc/network-manage-loadbalancer/lb.JPG b/doc/network-manage-loadbalancer/lb.JPG new file mode 100644 index 0000000000000000000000000000000000000000..70ff2d3607ec51cea86bbd1f9c7a140bd44837d9 GIT binary patch literal 36193 zcmeFa2Ut{D)-HSy1PO}d9F!z%Q9wWtL5Y$jXG*e&Smc~@ z&Y^&!>K?midV2bs{_mat&L8gcb@A+~U8m03VePe7c-PvB8O6*3*OlZHke=UtPz1|}1Hknk>+}E~ zcn!PLKrRm;NH!Q!?h2Sny7ft0tTx1+P8mAe_Ux8qYMH%V{l zo4>R!3D$pJ=D#T;ldU)7bN?My)i<(&WDTZ)ScN(fmCn&13e_m&pF_3rH9`t+B+EiL%1o?1CtIk~%m z)DYyq$^Yx1|5JT}B>Jt>e@T9Dj^I6#4_vLx+^rshMds)7@(PIY3W;d_eaZO*1%;*f z|8Soa|4(B4ZlM3!k^e7IOGe7lLek>r*rBe!cCTsW^1rv*PwixWXHNe*N$}dQ6|i-X z_3-iWrTBl}@qeYnFIPa$1E2eiPr)ad|6h3h)ycm_smR12Cf%q$zmpe2LRsX%ea?u@Nh5VUctk=LO?t`Oi8kP{M; zbJ0`NbN$;d%ol*<3f90SUu>+Kz$FqaY!WO?8^8p{A}@o{%bx+vzrC<7VdGrJ#k+z} zKnUJYc^$Zfg^hg)2mA76958f=6#)JY;E-G$jQxVO}KQye{G3VB_HZ zoEO$5FR);f;9R~Th)a4;9nZ{#?55DOE9CcMKbAJ*vj}VKQkc8;5m2&<%(3nLoZ2rl z`(K+_@c*ru{Wh_G%xfGV!o~s@51Ryl0B3UHoF6XzcPOz_7II!s@-unbX0bMujY`^9 z`JDo39AfPvSSCfQ37Mv?hzOry0IaFIH0A#0yM?-{`6uQ29p_As!~4dk)E*o>8<=!4 zZY&z4swy=aSBk$U^dkDDF(pskk3U@7{}+TODuTA1$-j__*?I>r56JXNI?oN5 za7nMbCbL_Zj?`}=!2loNXk}##(5Cw?a1gf7F^T~u)GlbQ`hPSSC*WG!SXo)M@~PT9 zM%SnN!&-WFV=gXZfPDi~^v#$*JpbiTqfrL2g8_o>Xl*y`AUS53cFX-)Fu*++DlrKI zyv#&XLZ8D{`7uCTKL*&N*p((XNw+z{0AC3I4}QQ2$&HpLHYMq( zOP1?$yi)-)yK24moEfEJ1e_T`|MRjoTncS4o4XJVpSBXatg2K;TJSda%O}FxBLr! z_@8dh=tkR&AgLERyW(M1$erxAGwIT>`4+=uvx%3}cP9l+l8eIwVC_jJLc{L-ga)gz z6SjNJA%4qYue%sGuciW$nxg!t{3#q4!5kQ%H=pXA;qFRX45_^U()96=qX*}f|0_pE zW}(=vCtd<9DZuD1$aoA89m?bCy{7cME;qI}iN)eLX@ZHyt)}bR(YG=gG;bknp;F zPkN{azW<#$?zdZ!2i=A2MV}~HIO!8tq&>q3k&p3=trmK&ohvoL^=(3*QnR&DQEt(H zZL`wtX1VRu+9)(JPx(wH>C=odZ+nK_GlT6r^)}%O+D#keW~odD%cy%9$Q)_6cCT?F zBKT8E6Xi_4QxbA~|As?n;b33dl`Rz0JY4~dTFHG&J1pDE@#?3c;yC?9OIJP8YXHsK zU4}Log_I~y+`|%o4lUAlY<&gRy88-KqzgjVgk#5xU@eYTzSB%eiuFMg>nFrl^fThW zo98P&#+xz=c|W9Ot2?v%+5PH+&5+G1U&CfrIREzKv(O_{K}x?ATk(XwBzgR(P$=Ov?*vxg5~raMj_}fK4E}GwNeaF zm3}5fdwRbq_aetJyLvYu{k@;`@D}nQQLy^t_2GEI*-Ey5skWvpliE=HRij4OLvnRl zOM5@ZlMsJypFJ{@U4O~TP4Db1G6@HVZ`Rfbjn`B~JMQl!WC|vlXF1{#3EW$*F;oll zjr#6uq-lR9o0eU8mrrDiZ`lXugsW9>_POB4_>31GT`W2FrZ3?nB@L#z>4Y;5CbWC(C5**&#UXZ3GQEjblCXVc=#k0_ z6|O)V-z>{hw{T$PaOcHHbs$~ihzEo2qrSpI=#O;BamY7%mFhe9<>|`3W-rO%GXp9n zd!5fJVu+Bid+-6&J*bCFW-i;{Yk_y}g~o3x^h597#gl(B$tbDqsMhg$eTKN?@ZBd% zV~z7Rl|qHR57$F&la+!EJ-x&qx$h{>LrHDXH+Q{WJeh*wmSpM&gk}h^7=90yd(xsZ z_hzo{Da2$EyKt8{_z-d38+yN{9|f_RzcqcPfVzL;)!#Dy)bQE;k8F=_Mc#ql=$MsP zuUIl!O{3XG1TXFpQIa5orR5E3D*8iF19HLrd~rf;eWkHwlBrk|>`BUd!;xsl-J*me zbnVBUxv|C9#W7I&S6;OzKDBm_v)=MNf4xA>60DOo+;n4AMy!A5sg$xqKxT)>E73db z12>{)<;p&hKK$0h#2Phm&}BUzBp}0z^itd13D2Zub{`Ps<`kt<$cp!qrSGaYb3)z* z&Ma8d9O8=OJJYyg+Nasi9kc7lM<)#1ZLDx&YWu0*aBWME?yJ>yiuUwk88#7MfY_F9 z^f+v_s*r1HR~HpcX?i?>0c0!fl##JVavrc3{0|Ok!#N9k{-@G0WxG_aU!ht3o;Am3 zidN*nykmNpwF4dX@IHz-*==7Qy?1n6Ot90Q2H9hH-q&p7{B)bVfY8t6!|~O~k=zHo zMLJxr73Sw@R{r0jZb``P$8Fx}V3Zz`(k;LMR^EO;qDOq9NXcHLo~3#gITFv7rd)p4 zMpZ-~(-nTL;K*XS3Qd6&u{|?A&dIjjvlk|%urd-+T#IfS$6{aphL37n?=PaXk4mYSiZNZS3(h(k2$__q4Gq zF;mcFi8^Y3I&Hh|*o%`>#%B5m9tTz%R|%rrL0S+0Znp(fQsb{CD&}j7TjZg5i`)+s zkO}j~>{b@OBeB>AvMvWsDBp0l*b()*xEgt>4@)*w7OVN(iMw9WhZunBu7=>T!)PbM zX(ditcTiW;gv~%RTO7YYcp_Ve;z=%^J17yXZOL_Xisn^>A2yU%4dx0edZUdXx0uu2 z#w+bpS>qgSyEGykIr0g(89Uo0b+Y(--Z#ItTZ{<4j>@u;I9eMowll~suFR2zJ=r`y zAj%X<;Mf(_$dy1TwRL2%?bauOs`Ps=_y+t^3Ju}c-yZE{>FIU(xt6}N9$$|jB@1%( zy|`?D&j;$hpWU$ct+%S{k^mcB?-^~a<{J%1657~!J0W|{!cqTwxoRannX)oavq*)t zkVrqq=jR%cR@`GxZz~B_PA?~rt7|+~mn8>&SFpa=o9>&6sGZ}eVStaiFeBV-48V5q z5CeP$%Nd31GzWZuxQ&TQw%9un1E{7Ak58_79-r*c@R=dHu1mNY(tCX%HX3q&$Ka+C z*Q#AjMOpURgq;<)8OQzPQc?c%$N2*J0>CEscaaNCBN(Zj%X&3gyDOR|#o?tm1*5H1 zE5#}uQ=&u4Zc{c5ln^n8xNd51aM82fquR5RHg~z!Vp;ejD?6@$_XlE+jBrlicLloz z1K2}O$u?nIx#-BSrpG04l-aB?N5}4jY*BKg=Xq6@pIFsa?(1)ECvx0xFhE$qt~~0z z2Lt%u!vGx{P)~JTKiE5=lS~dP_$d=bpQ$~pRR+m|4p_zjP0Scz!Tk^4J)}OPpB&1ZG6Vxe_5JaCH}NtGJ0&0{e6^$!GMDZTTEj92zpAW1e7$Xk znhA1KE8R1uIL<{0?*v0urlIHa#AtE(fBwb;dAEDb?pTI9qiOJu^I82b7nWWe1Y-5b zbhdlc&z79h^T0tmMcALsplME;nGSZuFZS>-09|hLE?INc08dqy8&SlGi6Ft}twDL+ zYYJUT=VUTIvIUIEvgA6r&9dZ=vHq;+HSrHeKbte0IArOGmXb}|^romZl5elcO8P=} z`UDj(w-s~OA(!yVV9Awk>pnzy>c{)8(QCr5kfw82Q1SsT#SRh2FEis8b#EWAt}7l< zY`u)24UM}0X%+ZF(c;gTMk7U3Djy?sD^>A`gXOSzzs^mvJnz*TtFk_pB;M>RW|^GZ zM`p4Qyu6@hc5FS11w?{;D_#_PN(p$`Er_SqU;#Z|DaK#ETZ4wt7unNkQs5 z2`k^|)+Rykd<9Af@t9)ucT=IokRQ|C$fFXbg0tyTw~`IAb=?X7wP*$PmY925+}i?r zR$(9VjyBf)WyDGML?_SO4+*%{)OMH4^FIXKc~o1Y*%vDzs&k^+Fkrp!L8$MTh2D$^ zU(;q@`j(b^Cs&lwy5gz~dPRBgMq^oQMj9niVeVlGtWSo`+fTE!+Tk6tsCY^~nJAgg z5H2lfdZ*7w@B3vQ1EVw1A%?e70Y)tTb-8`%`pqs^2k#r&Y1kspT(~rWE@MY)=87QhRH~F9%1C$t? z4Zre&&G(Q!uHHvQu)FasH!r$8oBmW1Jn4To!1TN6=E33L~|j%8h`|v`Df% zAm`6t-!zX{nxMC-zkUa6qS4Oo?CMrk>HM8!e>lH7%hy)76G23-=sW1_mK-smZ3Ox2 z&H~%TE@}>USF$1eLz#*tjVQ%hm7E!Vbo{Bw2)W&G?qzEBIB<9OCoMRP4mLRY$@O~> zb{DA@PTyFg?j=|N9LN`K>$U6UKYIl~Aly;?*aBW_{g7FD| z_yZf-XqAD+!Y#j@g9|09>NKta5#eGL4+qJPCjVhV+}_e7X2sMvyh_^ia3{8*!}B|a zqwenv>!B6ATi^Xc(odI#?&84>4Bs(P*!waavrSTZ?$w%~&K!f{rgwA(tpwX8i${Zx_+!k*;}$fA8>9=@de@Vj*TsCFXG}_dx#?{weGQ8_ zL~DN6I@4}$O2E)Kb3Mg!+56%1x4XXWX*Hd|(3*RXh3W89j$z&ppDPBI$O>J0mMhAx zrOrMfFs(J#G?;-Wz^^u0TpX+p^iMVH3^ZW?mYY8iI?!-~GTDNg3Ow`Hu(FT@1YzXy zQRWx1x}agvYDZZj#lRNZ_RqMQ(Y1)~!{V?3x%wBKbz#M5(=jJri&p|OVoOqs+5uFG zgNJG)_J+J4lhoif2W``yj54?BTo5ux8pYZ8vZA}4)yhV1dtFj32awq_#T^$Hi@t&B zE&lW-&0)T{WO2RELU$3FYHjfNIGy|3Z@W8I2=&N=ln||clzK5}QnF2D zC*zkGq&LY{Zi{^ z5Z}LM>}8-ovnR~wujt`bGP#ym*B+hB5S-ub;!IxAPm;bhv``v9LDN$j`7WsxVK>q{R`xUCVLWTEc&vYMTO!Pp_&2mals`Q(11<40%uPDV`zTAUo96pdx8Y&s z!MgnWAe$r*bg1#wq)^@>DdU2Te#uG2yekk7R^{{bTVlIYJ{v~I|7<0B9b!ETnA2+9 z(>)%mcZY7C^7y|FioA{I86YRAg{IzJst$9%<0wN~E<&J%Si-UC;z$i}F#ns)_jlXx zfAf$-iZ zG0%M0J1hHDgvNGVnuv2vgRo0$m&9=Z(Ux0h+NC{;l=1ayaiK4Cp6$`HIOhvRPkhp^ zV1SkPh$T^@!3N>oPWeIBvO%cRlbRU1*I!o{&Uv-a-;pXHh^L4Fb{5l7DxMlq)N+Ft z`6lvgiaMz!nq%V29Lc*eXrD>6re;PBQjxsiX8Ua}S8SfFK&|w#bbR>gEyx8b9s|6} z?acD$NYsuJRjd~L^1Te}G@*ztw9?~If4aRa>^jP*&M?+-PGY{Y^yOtm+8c>yw^q4z zTgS)!ReE<01AM1h0&q+$g*$2>>Z@+y9eYeI%1EaM3_zIBSo-=>xFucE-l}|~9nwny z1B6b0r2zyh;v~y;WnI-S;n4ng@U+@tm14@DZD?@-Wu5pgCf+wp%;?DM zE96Iw!CD}b+}1(_zJ>Ah0~&>6Y)}Im)eO;?w%DK3)8)HeqI^)=#ZA1=^twb``dCg9Q2BD z7Q%j8H1*#W3>eJ-k*~k4n*2XF0^2;i^Y2{2^mlIfa5em2wI1}}r|nF$Poj&_Mbs*p zQuIUXzq;Um5X1X15onT>1?Wp2mYJoT?lD z%J$N`keP@f{ZXz<-&Fx@){!D4Vara&nCRB}R(*{L`B7AWOiqOe1b0o64F5(X!Wptu z(GYvca2Yxh@^(3bgvm;IZv8y%*f^mBmE^l<%I*T8RcX$GV@cj4bmlSV2df01c<(QfzSSSv10u7jxw}S@ zt1TK}@MP4~J4r2lu0p5V`a$WrWTbQP2huT=Ls0Ri9WBGii;w+VJELmHxq91r=Hf}V zU(XnU;`=*_O=a-7Z}Veqd%;T2QlE9POi-*mF{XBt6W4XzI8BR|6wU3rb<89G`1ahZxKK+v8^5*AhMh9EyaeCV_5=jE zAY@Y1)GUt4+ipD)!HWMgz~Nt9$D`QO)=|SB&-`TNs5(f&!W<*&@X3)(aS}GK z5AKgZDirryBsi9vMd=rzys$(25!)H>-pfpzDjeu%iLjG7SWC?B>Lu!TY5G^s9zE{j zIJQdvnhhW1H%nLAeTAy3PgAha>sO@ta_?DJiTfUJSNU$!M~U^%=_4^4CfB*wU1~G5xuZjC zYwH%nk7E9kxvDq`c3Y*-lQk2mZpa~rQxvb+hoYgfi^3jZHK=Xp%h69b;-A}{i6&A% zKd!y~WtBTxBvH^rH|pJHlktzPA#ZUjJ7c~bG|<RBVk7O|j$}Yl=ybB9 z+cBNya$5;H+b zT=@7+rpy`zto$itrDX(-DnV*s0P9g0BDCb<)O5E%L`N={Z0?hJ$b3nJ#+827ecnK= z$9Qs^+*QTGtuy;NQid47h!+yCYjgK9x%$6VXni@()?iaiKdKz)KpfMU|2*?_xaUvV zmm0Vh}<-vJ7abCM2 zUkC9{a^0S&aq4hMvn9%vc;cB#&zL|u_N5x(UHZ&5pRGFHgj;ONFp z$y1Ykzw{LYOk-#Bd$yhwD={dr3fxe|$IE6kzjBgfoIZ`9z>y3nyxv1Dcv*2Qm!Qm8ROHY6*`SPBvT> zxffLrjkt*4P-WCL{h97PT6PbQ9bWZI$g2>FO=5y-L^@=KJ3#5I( zfN0~Dq)GC3#ZP#1!l*oQ?WU9HhxoqHv(#K-rDEe(c^dd#98g|{7+qw>z1{3&oa-KU zj6h)5Sf^gz>KfJ)LU){_Vy1bIipNN?mMgtiG6##ab$fjxjNcsV98BGlDh-R9j3qW-PanPV;@heZ+q9usA;;BW<-R13hnM}3XV!4Ro8{76ycz5`;1+XPb(POJb@02e znOk7|Cv%F}+wg5s2~Sq|ie=(HA3a$!MX>+nxgadDhqzK?cihf~``0`jaw>zr$b9<} z!svbbcCJe9_~Zj3&4;uSGzOyRH3n{bk6dLXH#;9#>)XLh+PWY3a0t?Z2uawA75t8r z`jFAj5?w)z<^7~o-CX%vCgN$#aCKIBu;JI@tVo)<%NDThkl~k`v*E|e6_NN$SjHE3 z*9-z&8{x0`8!3H8&2G7bipJ1%Gauok>I7(Z+jt+wN{1!{rM zdWMFwBF=3T9OnI4sE0=)1KDHm1?-jq$Gd=hnndo=w-YpL(+S$_NJ$J$AGm|Wy|qgf zMnzZna?)8CoM#^fxIz^s?kL9LLerTxhW4nJj%w@*>bVXr|7;5%V>VAH{K+b|%{31> zOD1n^DQ_fzzR%*XEixT!LtHVyjViIkx`6z#(Tq-VN;oK6; zbt&_lE!{Fw9q408&6@*`%;j;zocEh=nXeLS_>KtM)mLGFq91QkbQEERlteGD3wjXv zig}Ar)lSIm(t2;UMA9r2X5(lL57nYj2vBfL(Mfu+qLu&VqWmH)l!??QZ&HWFyL zithX%{WsXX@xu-0bL|bfp5qNv_)WKPl)m}Jq}3-^oEt`Xe@MCBcfUE)bUU^`kW?h`X!2K)ohX@1GA6IrP>lMDF zX%p;BKI_$)-ir7s5LBJNY)ME+a~_a&&op|%{G_z5j~W_gtr6YRnTt?>fbzhufAdH3 zMfxIf*#e`9cLyjBY8ua<>hl#ueaH3wDGojcC(^zAO0)bitz&%U>p{lVV^3nLb5^fx z2MNYgep&$=Sp}oGL(32`(R*j|bt!=H5Lk4QzqSb(egHYzBB)2m0IRaL1(_ zW26OKxfBbFw%LRAGl`D3>R2uYt9A zR6N}WLH6?0`Ik?Nww6G%f#Bq7o#w^D&*wN}382@qVLv7F#|M;;iSMf!6sB0E`udG# zF&oNw$*0xc7AadBE+21)^4!RHo)-nH)6Ir>{uGl>%EAcraHVm5`)WbiERGc?+#}1D zN@m>Z#%h)mA_HnoFKN3NGyF7%x1C9DB7ypEJ+Lc((#AeKte-u&pEK)yF^v{Bw+GBO zC4SOD3$(*;gn|n8KczIa{Z_B`yldk#7_EZ%KEKp(J`|ptPsl!CMf;J^p<`e5&K_bo zpNW(mM#%fAihxD4mOJo+>Gn0aO(@Y8ex{`~@(;+uVyX3^2A1rhk>3 zQf^^@jXl^QUM3#YvSj5fIZvXmju@$L070G2z-B-kfBvV>oRA5^XGJF$=W1xKhHv4^ z=w8z<ox$JvjRQQgAI^%0|&sE9GH}- z1A=cd)u3k%LFONDasJZoi>kcI!o2a(ElTKC6 zpuLiYT?z%mm#Cs_vebuXw ztzcr_XFuczhf+$cST*%p*&5`ilke$$bL5g1952*NYHMc-)dTq?E*MNNyej>7mr*n- z16G`L(TCcw{_{M?t`V6{h^E2Nuf}|kknP{tkE`mVl;^OJvIwzrL}W)qO|?vd^@oPI zWo~&t&P2P;DLKavXi;@!tPoPa(_iQIt^%`#u>0Y~#7NKx++U|_S7B1Xe_K9xd%6L) zVY1cMAJH%enHxSbeXTA_vBYHS@!B8KP$T&iKYtBGR<$aqJUw~#U$JS>5!Q4rg|S@$ zYF0Lk3S%2IDqJ&JK5~6)y{xc)rR34D#|H7WuGuNYiY}<=9Yo5XXdx2IuZZ)#FD_)Ia2eB*PE8Jh+Yd zAg{#JuBC8$lN1h58{WN?V>P}kJZf1*a5!6Hp(VIbbr6t zay|QD4aZV5#4qMY?igztd}!04Q!73yBhHb-tGIM|D`$<~I_g7C;j`>vk*PcG-8c?D zEZea$=bVMw@=U^JJ{!#)q3Nw#z6b5P20$3K6VH^!vRyVIk>N`MWeiZE_k<`u?Xt-( zamexzr74NAzOjj2ie=^n?GG}ZYBwU1>i|7Jb2($s`5td*$tw>G5b@fcHaf89HoUHOZ5c3>cY63m`dJDsh-`k`*jbnKXm+BJZbJ3>~1d+~0|y2Hk*(hr(# z(LJDGOe4HYzeE9A+ScPR#O2I$v7c=L|87e^er<_Sb8hF9n-Nq%#gyq?`D(8q`@BEt zHI4yRi4CS{%c`J}fkF>R6Ab;Nh}9B4Asg**7)dH^Ev|H&;>zbHv6;O@lSi)m6DqF}#zVz1SzY1Mz7u~0yDypfa`24fd z0(4r2$9<-`^_>_x(lL)vBF;JL`bp) zNt1Ki>%dj|XI+Q+m5_}AROfcopp>|o-JG(tDz6DXdy1k~5Zf60Ivip@HUV8VYNjM&HkhqDDfB4(sFHD27t^74a2@`tQy< zw|(aRx)Gv@bkON{_q&sv<51&abBDP$e2Pu)dbAQqr!+agYwuMUH{w3qxjIbo4R^MW z7r)Q4BXuyRY!lp$eSVjuCYF(U_I>SF>?SoO6aLbH!>xd#isq&KwlMF9X-|TU{P)6k zLOL~n$m%@oqcsezX&Cg3%b^(_!k6~KeZVn*BW}?tr8XaB&tQKxRFnwi>hHg!9XA^z zWL$eXLDPKuNLsRwy;kpzUVBD3Hz{x^x>bjVitx3$@RbD*AQ0@a^o~@mGVSxOr5~+P zp@Xsh32U1Au z4Bm*I?@-98ad3ZXtsRih*ntd`=4xkU6Cp7-9>4aREh(8`Ts_6@1#S%tqvXEjN<6B+6oNR_VZf zC{-7J#DvtSo;f%Nr5g;CP*Fn#ra^V@$A#r#wwF>F2E@U{v10zsv&NC>0H!lU5c*`& zhmB&>bQfU&zrf*v?;L=JdmUshtrB*2MISb^@=G?I&Cqren5m?{%QSr+!;sM!fu`Be z1(zr^=>iS=CE0Db1dLpO#~n}@;AfWi&-R%%WU$X?Tox*HOJS|j_Mjbm9W?IX2rz{Y z6s}>uL!kV)VFeBo3ML^CNAFOwqxVrYE2UjGSWn!vM?I zPfWdGg-GI^fX?W_-^uflA`I|{-q!X45#w!|tP!8|;v%W7Z9u#7>H6BNy_{WD(*Z3? z@!5Nt`%)uzMGY~^ji8lH=Yj#u7hr3m-jL>!Q|=V;i)sweN2=RPyY(go+I%6`;abF7 z70Sc+cuCRF^_uWRI5@)D5mZ7C9U7F2tFO2p>D0XRMdv2P*(J>XBJv%PUKJ~6 zPCw&Q@(P13mU|=6jhpa8svHy;9*&h6LBl~aR<=ve91_YRnT{>gL;(8^MUTR^lm?NY zTW~WV_W}lH6~>jJfBRuaN@eaHgu(yqW&*ghnxa%( zV)8wMx}augc?WU?3cU_HIfnc^^`jZc1j5TxYG^cwD7Wc~AN!(VUs^{8H@zz)V zpH#jqRbbH@tkxiZVzXcTO(cQVNxUg%(C(X%W4tE2nh@UoCG1;t&z1t#jwm`4j`aik z&;@2Q>5tqDihjKKJR$LrQvG4M$Q(HqcWTlJdv5-?*BGq)2^!Hk=1I)WG*uw7v?nM( z2g)|BH$TI5|EYM6){$J9v6yB)r-O-jFg`-c{iGnl{hPB}7iLA?c7JaqoV`Qu_ zQeVh%f5c|0lS#?rX6h%24tX^tgSgQz=|z&b0^cQAkw(Eq#S;J+sd zV}Fqf*fVUG4A`!mGgej|&}Lw*63TMLwVhJ9CWP$L!ENYnLEo(1&3(n|Q9zxM=;wG& z`b6pd*T*Y3jFEmL6{vvSqzRD%7@2{5a^c?9VLZK8r-r*0F-WRPZ|Q{8vnUj$r%N(N zO{{qo-kvZ$*6B#Z%atf&(~oC?>PH5nbS<~oi`Z5iVb~+k2FH0~dL+}NeqfijM&?a)*I_YA93470blf*~S)*3y?I2GR_-@(B* zr168O9U6@UrTqlzacQa~)OAqhJ$U_Rd;Xw^_W0_Zc|>3HH-WOTw>pk2c}T-~6%J5Djl(CX%qI~0{tcO8 zTlELMOzI}p+4jehQ%U28T@6S=3gXfvR*&_|{$n|#YWen_$6^t64zDh8o}I|F76shO zTKjB!rc#w|FG$f~hIMqrF`1g)k&Aa*V*l{|NA{sQDsZ|xl9&E)0PUKeHU@b8CjA~N zKihB!w#dfO3**ZBHEbkgGe%hZfPIML2@UU-T8@&@{pIVlcXMqyg8eiNUv0|UaHjpZ z^^h0v!24#^Z2DB|=xTxLaB1Z{k6XgU{Kv0&ql1IWo+M*n7)rqmj6LF}y+YTSp2!~* zrF8T`MwHR3Xpizg4^UZdqu71{slpx&hs`CGJ<;_`wqZ|1wpQN@tw3eJ_%x{YBD z5%SUFvlB|A6Pz>?Jz8G6?7B;y97bDorSNE2H4pv5sddi7RJ?1FhI8X z@bD`Pz}OFiUvOe8{edc%!k5rDHoQ{sLY(;BSMX&Hql_ZACS6kY)R1~6JfIF(LM+1P zOmfJ03c_=@ZuT46`*=5eOQiIVQz>7qKc@>&Q>`g&j8ufW(aGLqT$j7*J<fF}1`VWfi)JtzquCaJ5yEwaGvYYf#d_F4kT2!r? znmTAO%>CLX)6X{TE<#PfI6eyYbsjz0Ixz=(ahk5!XDSB!(@`*uf{cy&kkU3L2u46M%Lt_q+SY9)Cy+}iJ9 zIiRrGx;*GYp)HZ~PMR;AvxNSr#mc4CK*Bw4ryVNyRYKLr>H%p}t9P*y}X#Nl@t41bcD!!VGy2Svz0(osMGZUEz5LIqe0z0Gq5MRessW_9_25e zJJ#u7QJ{iD63J>yetBmN)YrdXA1!a+MhVUX{!UaV(FQSvlP(gLeE6QC!=HceGN|VL zxenIjP6t}=$Szx44gwa@9%Ca325&wMx-Zp9e-pJZNXcV(3;J`hpMHO|1z`{0Cyif) zBxn`*mY|+zoe?i-|9XHVN2z$Xu5E%ok6`o%agj{sd+n`7eL8cY*Wa%RNV};xaeSW8 zTMi$V*tR;z(QfUkri&@&vM;e9e?0ntp(0E#0g$(z)bm|w)XOj|mA3>H@taG?AY(V&G`Xz&jy0oeVHHb1j2uv$^z#)4&X)^+O=&Mz<8o2)=56^C;78fncRI zWpdncfxC+uN7DU?4{jbc)4!xH_~>@>pW>~~9F3b^;OOR$B>206x+*XVgpRU7 zddT|fo1QPqz~ZGg2QGfVMzp-QaAwsNX525hcZfso*rFL_DH00D;jcutgbd$4?*fPG zXSV9w2Zlh|pb%e0m1&4up&!u-B#}6DW9Z%MaNv0mrJz|rz%Td z6Mr}<;UX*Gk{S2l-8WtIEf3`!J{HJ@y#r;1F8Vr{3iBd>CVsj>d77p{p_pUy)QyyJ@TNqvJ|}0?7(1 zo%gyK>q(~+l8>|XHS!eg&&1KzvRheo0jOgyY|@FZ7S7W5nm=)aae#eE2guPmKl-@? zW22<2YjFH}3}2R(^?aT1WFP_TYq|#pFa_!Kp~zR%2hpr{O12H(*n=NZl*pAl{|=j8 zSr1q?Mz0ay1?`}q?cbk)zrCf4zONC0x1XN?{fA}nOAZJHLvxg4ws2G*4qJzCY_xaY zt+-MJ;~}C@t=Az1zgPqhavRIndPT!Gt2l`qs-5uq3kSu@8jfSTS$VPR7TZR@ox5oM zidKW``^%}i|Crye+n8d@%c$&N;c;_;1UqVSC_H%Am` zQ!?-w3#$$~ZgmL~)>M;sb#<YTTE;jZVQs3BMDvy&BfW!`j_tLBU-M62P(ymC5t zJecq{iXodV)3RH{(|c5~xof^Yon)=b*XBj>jz|fyp7GTEcbU(}^QI6|SZN8f3tSor zfd-%b`>Xm*`5#O-4;0YS59SonT_hbG$#~W`7;ZT^e7-~&5zjZd;~0@Hyg z&99PzQ5StmoW6*#1X*_$(eMlJ?w3TH?i2UHH!9#~S4y-?xR6VrKEI$t*DHg2ApEcl ze)82H1F-vyfo*_D>ZiSNx%1pL<$H^|(@eM^5=!=!YW$i4*!M%oa3M-~uPJHnQ*oiF zhZ)7>GgPlQ*Ip#anzmyTyD6cvpI;-H(jeoNHuWwS+?8=jf~|(jdGK)PHksybVzPq+ zy^nroMTeoZjQy@do<@tL$H(pBeC67m-le>7ZCk{20PVhT1~MsQ%>*w(B_d#IW1_){ zEU1>}Hpl1)_UwJU7?FFi7=TIHqO5(kVR=b z^L9$u21N-Yy5opONNMPw4aUbm)~#3N6HpHznbnGWGnu607xT~J;x_WuPrzd2B2XM1 zT)8^5n;dgKd7;+O4WGKP3Mz4DhUVYp72-+fV}P$pY9G+r8b#}WwZ;)sqNI~7W#E#({%JM-rvhD#hgaRK_t?6}%PmNAwU-OErPZI#sJyX%N;(m> z7$=BekY4||chhFKY&?<^X9c^Yh*wnX<=@=v|0nGRP6_7djJWV)1kpI7(B92RzFL2{ zq5`P-o)5Ia4;kSgc(Ysw!8RH*S*1#pd=XcYQ#!~y))G8QU#w>0r#bB?cGjva-oa`t zu8Qs*e~YWbH}+uXeS@!cL#N2U~t z1@N)&!{XQVS}$#lo(G*GJ~jKNXZvhdkb8%ylWdJ0=Xq|eMXgX5?jAf}+HM)AH8+!x zpMHPD*(Xae>CCvWtBHPiUUG(lUR-wQEBNt8P3@0sfj)s~9un1G^fNvK4_IMMf*b6& z{7bj-zuV(n(;#JU+>!}7)mHi?|DNm4Gde>BjyvX@4^kJf=?^rt+{)M*qHgZUYUtnn zA)j*#++H^a`p2bZa7qJ?*MsCHsx1Tjz;Ln!kFeeYwhC*`WUPnW6`u|}?Mqcn$!aop z3;yF8T6>T^e7Zx?iP_=h2u+lxk5d5G&^;fvHl66>$24$?yny$DDbkzNG_q)HVCAjEH@=N#YnuKV6~zi*xI z{&Cm)$6m>k{p_dAGkY>KznKBzQ)6Lr^Vme3ynhfsIKX%O%gzw=MD^4CjW29;$#{q& zIK{RZ-zg^#88%ex2M9A95*DB#s?5p2uiL3`9iq2suJ2*6ih_DpN)%f=8U~KB_&(_V zr|wKUxz%zfMDqY6s$!|9R_B;&#;Zj~vk)rr#3k`PvbJ2K^syZ+9F@ClQ71{6{@F1v z&28Us#bVJuP4+StdjXE`l^(y5x=D>HSOm;)mDP}aa^UT4d49?Pn9nR(z~AR>z)Pux zWowMVg~q<6mkxMB-b>;sgl{5{fYarFP#~>S+MDUPut#fXF9e|(zfU4$Ba9SdT!+j0 z1vTKdeKL@P^^~^i0rq3q%|C|2o@ng=vf@`8c)QNqWvVDY=x$9?_Izn{`hAS@9c2V7 zyZyH=)66_AFrwhtnr(93s$6(Ncp*U|_DC1XbcW{!#K8l`$EEc^_D>(>+G$3VtoHgw zL@iWRxPu76#hHvzTG#c{WgZphSzx->|zg#c67t z;11FEVU?cQ{27s2B{TM0o_dd~?r2gJUZvxD{h;>0Ao$$+^uyum)Mv}#s^cGtt3A#Z z2+a)CGAK=E{56^sBH%ipRHw5AGPg33RR|c7prNt8`Az!Rs$9TDoQE0W( zfIfV-pYd50XhY81VZYku&-~MS{2^FMa+FJ8hL{6G>~}e{U8td$rAv9}s`Ajq9I}cN zl(M@cQVLA%C)V6z%}8@evya&MG*{a5B4F*S#m`H*}}t{`@ts1^LCZb&KQpro(9IJRqQIoVXUL;2esBql8w`025 z88e_zC0cEvSEMb~|9#R<=SrEns=MX z)Ve74E;+4cdR(n_ZM1ur^f_6$%?R53hN>ZEGrn7hj+h~H<#L@vhQ+Or$ew4p#tqrU zvRMQRgzU@PP+u%%j0mw>>c`vb$M+E~)-O<#vGV?)1VS$(pO2U3Ez#k`g{(2wFYWc{ z=x%Dtub^${cMX`Awq54e_C%8|N_y!Sw)7teM|@BmcPnN~6`|!|v$3^2`iUr! z$O8=_ol%#sv!Qcj#N5S56d{Z^jI9ePab4rI=Dnj+4Ax& zXV+?lm{kYrbZ>UwR=gl6<6O3(KQp2shW&;`l`q{w1L%2(JY2zv+hK0K<-EyUSRcxT28!j0Unv@`6DX(r3_oRb>M$#_$nOs}-1 z?p0#1!rEp?fU$IA~vtvZr2woc|!9MCHwPq&^5~0nVXGw zHa%FLH;6I$gwStLjH`@&*fIo#N=13)iL)-%Qr&8IDQHH7{Pw#1#$!xUemcYi?dFMJ zf4laD#b2CjTdM#iT~^tD82!MM6hMdl7)Jn1M)W=3jrSZ)%Nb6OmMeNg0!I%_HNW#6 zdNWNOedlfaV)X-b*(9IuX_VY0K=$Tl0)i7)3s9y0NcFLC{44S7UzZI16>>3-{)NwE zlBE1uMKQl9_4?~RANk8=40}TJvEwKM_!@S=e(x-8%Xbl@l8IdTFs8V0XYjLaZ*9MM zh96@P=V+8?<{}-K%<2CQp8ON0{O^2TK%bZlIF6r0KF!R)D6w@-upa@X2+V5SKE+bP zv>h>(z19U9OEsxN+Y}@Y0S@tx&5`+e#v3#tcB7la3*fdxS$~$Sg`%}Nx}p74WZlSD zmMDAkyglQ^kpvHO;UZ-U*t|s=sZ({H1Y1ezMA^YN{-*1!9{%~A{VYZN&6MPt{EY!; zTygP>$)DNkZc?#nhBkJ~B?Z`F!i8P#9$8qd?W(zht~oHrNjeZ_bS3&bE1L^y zNO-T}ze;!z3$jc~m3YsUEuP|$ELw{R!A&uSCdBe0F|AjSyHB7_fnsQyixj^6&&c?; zg%Sj6TVNliIz4s+#2O=2x#{m#(yTb!UI@`MzgZjRttKOHX$t$$?U`Fy*E_AHizChy zWiqNPE#lk0D zhIm~slng)We>5VJF3pt5gPERCf1usDCLD{8FQwlJ_^3{vBzIEIM}rDkiYCR z=dM%-*0+nt`W6yQ7cOMptUbCfBW7Y8p6>wePVl0;ADTZI)f8FLRq*&yCP)U~bF?6z z7ISz0>Db-WCwWtiSVFn~%pXyr(SEM!ycCN3+WO53z?t{a!=`!b{{F9!uQnRY4W>?lr>bKPX* zFI3Zb`p--{$A8JAztS~DN`HkiIpVVYp?qD)Y;w-4_Ogoa_2}x1`>ZvdU%+=g9S%W^ zhg9{=`)bs8e>MP*^(MD}Rj;2G^XV4P%hkU9P*YPv_CM$`u-!p!`N&*b!U8>cum<(J zv&t1LycZ}}pmW%talFkAR44$8{QKwsEi|G0%iWge2cxZyHi^}R{RP~8_!GDr+0ZIj zF@Qgyp3P2TE*F1uFd$Nw-r=I_SZbqIcxU9+=Ox@7}bcv#;x* zY?5}XV8xYMu6jFpqAX2iap83*tL#l$Gk2N7v72Fk#{T{P`h>XK&Cdp)#V9Oav9ih zDcRbqyWTUZP&D5eKibGsipcI3c^GTjNAdgt_~qtNn!O52O_gYTc5%9mX@rR{lQjGX zNWDVI$aKX0FML;$lQw);(k&{%Qdl~ z?qWFPjUH92oqBPB!FrG#EIG22v}x_tHBs*yRq7FhUo}%wqEH_c|5>#cn^+3Jv`%bm zeEc*>>{t`2^|?928)~6$`V^3T4ZERE5X#*Y!|%+%`WbRlNf!NmZA`T zQ+YWbkF;qByd*fUW*@CS#9_~%$sgdQhBR!B7+{zNwpiMd<>p1Tcl&J#iSBLvXbOOK zlBL;eiaNaW_RQonqz?`^AgpE1#Ob2V{nZAr?aUg{1$&lF5*lev308-lJm*OxZM7TS zgWiJp(;knuhtHWq7>?v9+L>$f@R6xjSC6xKhp*D5958Zybkm^%xh3|KcDWR_WmM<9 z(OvHvmCsh_OqvG%)=0!UgRWtGwZB-ZD)W_Qf?Sb{9D^76M%Pn*@H2$9k?>EpyIP(m zKSdzxuf>lViD|V+R0zUG6*8Pgd>>5_Jdmj*-t+i7y{-90R?Uv!?WRWd^E(ehcN<0Dh7?q1Ga0YAv%vr534 z3g2^hs#rJejJQ7V70GxK<(3Wv_ zaVH!P^L$46ZNFPAKfrXDZS@G3x9b0ru<0<;0@{LHZ z+S&2^2-h;VKslI4(QWGn@8i+k3`N8g>S}ufqy1b6tv^anh}Tv>E@;+|85`OlN9GTR zie1voLk|cmB|dMugR;(eBbT<$>(82EUp`_Zm-BV{%=Q9gk`IpjB#SzC?XX#|k31JP zRG;*_zgQJ2_q*>`lFIZ{Qt7Zkcu7@T>KGDb6Yr*@c9mgyEgLVozQa zFf}1LPOLDvb+Sog{#u>L7IvUSMAVkR(=7J5APCy<#uKw3G*iSLTasZ$6_B|2@&gdG z(C%|?qWxXjpyyF1FK}5&n;qYD@e8a)K{;^v1)@oUINq?cdP?dJ$zOc*YB2-KPv92jOOR@&N0g?IMs7P{vuuKX1^zm&n1D=$5Sp zMgtKlC=b=r((eE4Mo0&igzNl#@_b?(R#Gj!4Q0^z%Kl*j(u+W^f8GG*_YU63$e%Yr zaVksR!d4FAE92)I!g+-=2o;T~`(q^LYdOE~fjkL?t#BR^$R+{{a`|(qKPPr3vD z%~kW@U6T&#$TTIG)BY;#mirU4wEb^z-~BzoQ-P zn-Tkz_p55mF)1 z2JeqWsv*2lz0M(gEF7Z+Wtx1)Xg@c#2gfP&mQU}a_8TQot``RR?|6Kve9Yp@Xqa1z z+_6w}7S3|0>v>A_rDD9EYid!Jc;~DqPTH{Y&2W;$B!N)I-PYo{H&~G&8af&ygZRFz zLE4_vb-VEBysg*C%}0Sz2sWLV+>zkz#c#rvZv)hgl;_ksO>mDLmRuT}#cY^L72W*Y z=R}*U9~jT%rAWRFAmACVFV#KKP;9GBo-kT-W)MI~5&LM15iABj__!rtN-uSFH}MO? zcrBh%D^PFo=~HDX;&yX>a5U^`(%tx2wfsH5Z$Yh}XiklaEMbzig1{(ds^Zby z&*GFNgJ2!zS1qVA^ef*WIS@-87*?@tXOV)2GNA#gBDNd47O4 zXXZoN=j^d*3&g}+ERXKxJxddV zIlEZqpGr*2w&vx%64UT)QGaK6qe#_L@)J%3BI)RGZxzvgRXvFi)wU0mm zq>2k3R506)yyDO?!|`c`X~3-t0f_F5b{_oN>HDZhvBsAhR(qyk&2(Bm+4`{Wgg1v; zEmB(fz7dTVZjM^&H%qQI&98co>L@+P&ppS!{~uE)a+$AXGL?cny^TyNLK@_5iSl6} zU*s9nsK@VHZpHS+JUbgY)+S_E@=3k=J!dcH9#Cv6SRbc%$lSgYyLwtM+4_+w>EBQP zNwqsXE}cUS0<-x`gWzIHu z+!42WY4NqtzTbbJkb%W;(3I?ZaC}Ei>}%mNF4$q0Dh_Fv0Pcoq9t-&`H&@I^+H`7XbDK*>}N?2*flCKl3#oql|bIzH{ zKgqe0wC%nWQ)&~_P=#)Zguvav?YME3yz;Wu@sm@XjxILnr#v$y3bJ}Y>B8SLLWE15 zBY+7Ry^%G0Z_3s1+$cYl+^^R`yn^e>q*W*D%r-ZRkDgwHbcWG)1kz zvvXfUlB?wRkA)mdtEj4fAi_g|-}vk>K5i!ND(Am;X`bV-|GxfBga1Ju!2L1xe*kA$ B3_t(? literal 0 HcmV?d00001 diff --git a/doc/network-manage-loadbalancer/requirements.txt b/doc/network-manage-loadbalancer/requirements.txt new file mode 100644 index 0000000..c501f74 --- /dev/null +++ b/doc/network-manage-loadbalancer/requirements.txt @@ -0,0 +1,4 @@ +azure-identity +azure-mgmt-resource==18.0.0 +azure-mgmt-network==19.0.0 +azure-mgmt-compute==22.0.0 \ No newline at end of file