Creating an Azure VM Scale Set with the azurerm Python library

There are various ways to create an Azure VM Scale Set. The easiest methods are: directly in the Azure portal, using the CLI quick-create command, and by deploying an Azure template. If instead of deploying a template you want to create a VMSS programmatically and imperatively – that is by creating each resource one call at a time, here’s how to do it using the azurerm library of REST wrapper functions.

Before using this library you need to create a service principal. These steps are covered here.

The azurerm library added a create_vmss() function in version 0.6.12. The initial implementation has some limitations, notably:

  • Doesn’t support creating VMs with certificates. Only user/password.
  • Expects a load balancer with an inbound NAT pool to be created and its ID to be provided as a function argument.
  • Only supports VM platform images, not custom images.
  • These are easy to fix. Let me know if you need one of these features.

    Here’s an example program which creates a resource group, VNet, public ip address, load balancer, storage accounts, NSG, and uses them to create a scale set. You can find a similar example program in the azure examples folder here: You can also see how the azurerm unit tests create a VM and a VMSS in the same VNet here:

    # simple program to do an imperative VMSS quick create from a platform image
    # Arguments:
    # -name [resource names are defaulted from this]
    # -image
    # -location [same location used for all resources]
    import argparse
    import azurerm
    import json
    from random import choice
    from string import ascii_lowercase
    from haikunator import Haikunator
    # validate command line arguments
    argParser = argparse.ArgumentParser()
    argParser.add_argument('--name', '-n', required=True, action='store', help='Name of vmss')
    argParser.add_argument('--capacity', '-c', required=True, action='store',
                           help='Number of VMs')
    argParser.add_argument('--location', '-l', action='store', help='Location, e.g. eastus')
    argParser.add_argument('--verbose', '-v', action='store_true', default=False, help='Print operational details')
    args = argParser.parse_args()
    name =
    location = args.location
    capacity = args.capacity
    tenant_id = 'put your tenant id here'
    app_id = 'put your app id here'
    app_secret = 'put your app secret here'
    subscription_id = 'put your subscription id here'
    # authenticate
    access_token = azurerm.get_access_token(tenant_id, app_id, app_secret)
    # create resource group
    print('Creating resource group: ' + name)
    rmreturn = azurerm.create_resource_group(access_token, subscription_id, name, location)
    # create NSG - not strictly necessary
    nsg_name = name + 'nsg'
    print('Creating NSG: ' + nsg_name)
    rmreturn = azurerm.create_nsg(access_token, subscription_id, name, nsg_name, location)
    nsg_id = rmreturn.json()['id']
    print('nsg_id = ' + nsg_id)
    # create NSG rule
    nsg_rule = 'ssh'
    print('Creating NSG rule: ' + nsg_rule)
    rmreturn = azurerm.create_nsg_rule(access_token, subscription_id, name, nsg_name, nsg_rule, \
        description='ssh rule', destination_range='22')
    # create set of storage accounts, and construct container array
    print('Creating storage accounts')
    container_list = []
    for count in range(5):
        sa_name = ''.join(choice(ascii_lowercase) for i in range(10))
        rmreturn = azurerm.create_storage_account(access_token, subscription_id, name, sa_name, \
            location, storage_type='Standard_LRS')
        if rmreturn.status_code == 202:
            container = 'https://' + sa_name + '' + name + 'vhd'
            print('Error ' + str(rmreturn.status_code) + ' creating storage account ' + sa_name)
    # create VNET
    vnetname = name + 'vnet'
    print('Creating VNet: ' + vnetname)
    rmreturn = azurerm.create_vnet(access_token, subscription_id, name, vnetname, location, \
    subnet_id = rmreturn.json()['properties']['subnets'][0]['id']
    print('subnet_id = ' + subnet_id)
    # create public IP address
    public_ip_name = name + 'ip'
    dns_label = name + 'ip'
    print('Creating public IP address: ' + public_ip_name)
    rmreturn = azurerm.create_public_ip(access_token, subscription_id, name, public_ip_name, \
        dns_label, location)
    ip_id = rmreturn.json()['id']
    print('ip_id = ' + ip_id)
    # create load balancer with nat pool
    lb_name = vnetname + 'lb'
    print('Creating load balancer with nat pool: ' + lb_name)
    rmreturn = azurerm.create_lb_with_nat_pool(access_token, subscription_id, name, lb_name, ip_id, \
        '50000', '50100', '22', location)
    be_pool_id = rmreturn.json()['properties']['backendAddressPools'][0]['id']
    lb_pool_id = rmreturn.json()['properties']['inboundNatPools'][0]['id']
    # create VMSS
    vmss_name = name
    vm_size = 'Standard_A1'
    publisher = 'Canonical'
    offer = 'UbuntuServer'
    sku = '16.04.0-LTS'
    version = 'latest'
    username = 'azure'
    # this example creates a random password. You might want to change this or at
    # least save the random password that gets created somewhere
    password = Haikunator.haikunate(delimiter=',') 
    print('Creating VMSS: ' + vmss_name)
    rmreturn = azurerm.create_vmss(access_token, subscription_id, name, vmss_name, vm_size, capacity, \
        publisher, offer, sku, version, container_list, subnet_id, \
        be_pool_id, lb_pool_id, location, username=username, password=password)
    print(json.dumps(rmreturn.json(), sort_keys=False, indent=2, separators=(',', ': ')))

    Next steps

    Next on my to do list is:

    – a VMSS create example using the official Azure Python SDK.

    – Add Azure ACS wrappers to the azurerm library.

    – Make the azurerm create_vmss() and create_vm() functions support certificates.

    This entry was posted in Cloud, Computers and Internet, Python, VM Scale Sets and tagged , , . Bookmark the permalink.

    Leave a Reply

    Fill in your details below or click an icon to log in: Logo

    You are commenting using your account. Log Out / Change )

    Twitter picture

    You are commenting using your Twitter account. Log Out / Change )

    Facebook photo

    You are commenting using your Facebook account. Log Out / Change )

    Google+ photo

    You are commenting using your Google+ account. Log Out / Change )

    Connecting to %s