Introduction to AzureRMR

Hong Ooi

AzureRMR is a package for interacting with Azure Resource Manager: authenticate, list subscriptions, manage resource groups, deploy and delete templates and resources. It calls the Resource Manager REST API directly, so you don’t need to have PowerShell or Python installed.

As a general-purpose interface to Azure Resource Manager (ARM), you can use AzureRMR to work with nearly any Azure object that ARM can handle: subscriptions, resource groups, resources, templates and so on. The things you can do include:

Before you begin

To use AzureRMR, you must create and register a service principal with Azure Active Directory. This is a one-time task, and the easiest method is to use the Azure cloud shell.

This will authorise your service principal to work with objects within a single subscription. If you want to add more subscriptions, you can do so via the Portal. Go to the Subscriptions pane, click on the subscription you want to add, then under “Access Control (IAM)”, fill in the details for your service principal and the type of access it to have (typically “Contributor” is good enough).

If you want to allow access at something other than subscription level, you can use the --scopes argument in place of --subscription. For example, to restrict AzureRMR to only the “AnalyticsRG” resource group: az ad sp create-for-rbac --scopes /subscriptions/{your-subscription-ID}/resourceGroups/AnalyticsRG.

Logging in

Let’s look at a sample workflow involving AzureRMR. The first thing to do is authenticate with Azure. AzureRMR supports various ways of authenticating. You can supply a password (which is the default), or if your service principal requires it, you can use the device code flow. With the latter, AzureRMR will display a code, and prompt you to visit a login site in your browser. You then enter the code on the site, which completes the process.

Finally, any authentication arguments can also be supplied in a JSON file, specified via the config_file argument. In particular, the output from the cloud shell command used to create the service principal can be used here.

# authenticate with a password
az <- az_rm$new(tenant="xxx-xxx-xxx",
                app="yyy-yyy-yyy",
                password="{your-password}")

# authenticate with device code: R will display a code to enter in your browser
az2 <- az_rm$new(tenant="xxx-xxx-xxx",
                 app="zzz-zzz-zzz",
                 auth_type="device")

# authenticate with credentials stored in a JSON file
az3 <- az_rm$new(config_file="creds.json")

Subscriptions and resource groups

AzureRMR allows you to work with your subscriptions and resource groups. Note that if you created your service principal via the cloud shell, as described in this vignette, you probably only have access to one subscription. Regardless, you can list all subscriptions that you can work with:

# all subscriptions associated with this app
az$list_subscriptions()
#$`5710aa44-281f-49fe-bfa6-69e66bb55b11`
#<Azure subscription 5710aa44-281f-49fe-bfa6-69e66bb55b11>
#  authorization_source: Legacy
#  name: Visual Studio Ultimate with MSDN
#  policies: list(locationPlacementId, quotaId, spendingLimit)
#  state: Enabled
#---
#  Methods:
#    create_resource_group, delete_resource_group, get_provider_api_version, get_resource_group,
#    list_locations, list_resource_groups, list_resources
#
#$`e26f4a80-370f-4a77-88df-5a8d291cd2f9`
#<Azure subscription e26f4a80-370f-4a77-88df-5a8d291cd2f9>
#  authorization_source: RoleBased
#  name: ADLTrainingMS
#  policies: list(locationPlacementId, quotaId, spendingLimit)
#  state: Enabled
#---
#  Methods:
#    create_resource_group, delete_resource_group, get_provider_api_version, get_resource_group,
#    list_locations, list_resource_groups, list_resources
#
#...

Notice that AzureRMR is based on R6 classes, where methods are part of the object itself (much like objects in C++, C# and Java). Thus list_subscriptions is a member of the az object, and we call it with az$list_subscriptions(). R6 is used because it allows objects to have persistent state; in this case, the objects in R represent corresponding objects in Azure.

The list_subscriptions() call returns a list of subscription objects. You can retrieve the details for a single subscription with get_subscription:

# get a subscription and resource group
(sub1 <- az$get_subscription("5710aa44-281f-49fe-bfa6-69e66bb55b11"))
#<Azure subscription 5710aa44-281f-49fe-bfa6-69e66bb55b11>
#  authorization_source: Legacy
#  name: Visual Studio Ultimate with MSDN
#  policies: list(locationPlacementId, quotaId, spendingLimit)
#  state: Enabled
#---
#  Methods:
#    create_resource_group, delete_resource_group, get_provider_api_version, get_resource_group,
#    list_locations, list_resource_groups, list_resources

A subscription object in turn has methods to get, create and delete resource groups (and also list all resource groups):

(rg <- sub1$get_resource_group("rdev1"))
#<Azure resource group rdev1>
#  id: /subscriptions/5710aa44-281f-49fe-bfa6-69e66bb55b11/resourceGroups/rdev1
#  location: australiaeast
#  managed_by: NULL
#  properties: list(provisioningState)
#  tags: NULL
#---
#  Methods:
#    check, create_resource, delete, delete_resource, delete_template, deploy_template, get_resource,
#    get_template, list_resources, list_templates

# create and delete a resource group
test <- sub1$create_resource_group("test_group")
test$delete(confirm=FALSE)

Resources and templates

Methods for working with resources and templates are exposed as part of the az_resource_group class. You can retrieve an existing resource/template, create a new one, or delete an existing one.

(stor <- rg$get_resource(type="Microsoft.Storage/storageServices", name="rdevstor1"))
#<Azure resource Microsoft.Storage/storageAccounts/rdevstor1>
#  id: /subscriptions/5710aa44-281f-49fe-bfa6-69e66bb55b11/resourceGroups/rdev1/providers/Microsoft.Sto ...
#  identity: NULL
#  is_synced: TRUE
#  kind: Storage
#  location: australiasoutheast
#  managed_by: NULL
#  plan: NULL
#  properties: list(networkAcls, trustedDirectories, supportsHttpsTrafficOnly, encryption,
#    provisioningState, creationTime, primaryEndpoints, primaryLocation, statusOfPrimary)
#  sku: list(name, tier)
#  tags: list()
#---
#  Methods:
#    check, delete, do_operation, set_api_version, sync_fields, update

One benefit of the syntax that AzureRMR uses is that method chaining works. This is the OOP version of pipelines, which most R users will recognise from the tidyverse.

# use method chaining to get a resource without creating a bunch of intermediaries
# same result as above
stor <- az$
    get_subscription("5710aa44-281f-49fe-bfa6-69e66bb55b11")$
    get_resource_group("rdev1")$
    get_resource(type="Microsoft.Storage/storageServices", name="rdevstor1")

Once we have a resource, we can do things with it, via the do_operation() method. In this case, we have a storage account. One of the things we can do with a storage account is retrieve its access keys:

stor$do_operation("listKeys", http_verb="POST")
# $`keys`
# $`keys`[[1]]
# $`keys`[[1]]$`keyName`
# [1] "key1"
# 
# $`keys`[[1]]$value
# [1] "k0gGFi8LirKcDNe73fzwDzhZ2+4oRKzvz+6+Pfn2ZCKO/JLnpyBSpVO7btLxBXQj+j8MZatDTGZ2NXUItye/vA=="
# 
# $`keys`[[1]]$permissions
# [1] "FULL"
#...

Here is another example. If we have a virtual machine, we can start it, execute shell commands, and then shut it down again:

vm <- rg$get_resource(type="Microsoft.Compute/virtualMachines",
    name="myVirtualMachine")

vm$do_operation("start", http_verb="POST") # may take a while
vm$do_operation("runCommand",
    body=list(
        commandId="RunShellScript", # RunPowerShellScript for Windows
        script=as.list("ifconfig > /tmp/ifconfig.out")
    ),
    encode="json",
    http_verb="POST")
vm$do_operation("powerOff", http_verb="POST")

For the types of operations you can carry out on a resource, consult the Azure REST API documentation.

You can also interrogate the fields of a resource object; in particular the properties field can contain arbitrary information about an Azure resource. For example, a storage account’s properties includes the endpoint URIs, and a virtual machine’s properties includes its admin login details.

# file and blob storage endpoint
stor$properties$primaryEndpoints$file
stor$properties$primaryEndpoints$blob

# OS profile for a VM: includes login details
vm$properties$osProfile

In a manner similar to resources, deploying a template is just a matter of calling the resource group object’s deploy_template method. This takes two arguments, template and parameters. Both arguments should be in JSON format: either the name of a JSON file, a character vector containing the JSON data, or a list containing the parsed JSON (via jsonlite::toJSON).

vm_tpl <- rg$deploy_template("myNewVirtualMachine",
    template="vm_template.json",
    parameters=list(
        os="Linux",
        size="Standard_DS2_v2",
        username="ruser",
        publickey=readLines("~/id_rsa.pub")
    ))

Normally, deleting a template doesn’t touch the resources it creates: it only deletes the template itself. However, AzureRMR optionally allows you to free any resources created when you delete a template. This is useful when managing complex objects like VMs, which actually consist of multiple individual resources in Azure (storage account, disk, network interface, etc). When you are done with the VM, deleting the template lets you free all these resources with a single command.

vm_tpl$delete(free_resources=TRUE)

Conclusion

This has been a quick introduction to the features of AzureRMR. Remember that this package is only meant to be a generic mechanism for working with Resource Manager. You can extend it to provide support for service-specific features; examples of packages that do this include AzureVM for virtual machines, and AzureStor for storage accounts. For more information, see the “Extending AzureRMR” vignette.