This commit is contained in:
Hong Ooi 2019-08-28 04:10:17 +10:00
Родитель 05d210bfe3 0e6ac9d977
Коммит a7a9dc6b5f
16 изменённых файлов: 232 добавлений и 31 удалений

Просмотреть файл

@ -20,6 +20,7 @@ Imports:
Suggests:
knitr,
testthat,
AzureKeyVault
AzureKeyVault,
AzureVMmetadata
Roxygen: list(markdown=TRUE)
RoxygenNote: 6.1.1

Просмотреть файл

@ -1,5 +1,7 @@
# AzureVM 2.0.1
* Add methods to retrieve Azure resources used by a VM: `get_disk`, `get_vnet`, `get_nic`, `get_nsg`, `get_public_ip_resource`. These return objects of class `AzureRMR::az_resource`, or `NULL` if not present.
* Add similar methods to retrieve Azure resources used by a scaleset: `get_vnet`, `get_nsg`, `get_public_ip_resource`, `get_load_balancer`, `get_autoscaler`.
* Add `redeploy` and `reimage` methods for VMs, to match those for VM scalesets.
* Fix error in documentation for VMSS public IP address methods: these return `NA`, not `NULL` if the public address is unavailable.

Просмотреть файл

@ -16,6 +16,11 @@
#' - `reimage()`: Reimage the VM.
#' - `get_public_ip_address(nic=1, config=1)`: Get the public IP address of the VM. Returns NA if the VM is shut down, or is not publicly accessible.
#' - `get_private_ip_address(nic=1, config=1)`: Get the private IP address of the VM.
#' - `get_public_ip_resource(nic=1, config=1)`: Get the Azure resource for the VM's public IP address.
#' - `get_nic(nic=1)`: Get the VM's network interface resource.
#' - `get_vnet(nic=1, config=1)`: Get the VM's virtual network resource.
#' - `get_nsg(nic=1, config=1)`: Get the VM's network security group resource. Note that an NSG can be attached to either the VM's network interface or to its virtual network subnet; if there is an NSG attached to both, this method returns a list containing the two NSG resource objects.
#' - `get_disk(disk="os")`: Get a managed disk resource attached to the VM. The `disk` argument can be "os" for the OS disk, or a number indicating the LUN of a data disk. AzureVM only supports managed disks.
#' - `add_extension(publisher, type, version, settings=list(), protected_settings=list(), key_vault_settings=list())`: Add an extension to the VM.
#' - `do_vm_operation(...)`: Carry out an arbitrary operation on the VM resource. See the `do_operation` method of the [AzureRMR::az_resource] class for more details.
#'
@ -128,7 +133,7 @@ public=list(
get_public_ip_address=function(nic=1, config=1)
{
ip <- private$get_ip(nic, config)
ip <- self$get_public_ip_resource(nic, config)
if(is.null(ip) || is.null(ip$properties$ipAddress))
return(NA_character_)
@ -137,10 +142,84 @@ public=list(
get_private_ip_address=function(nic=1, config=1)
{
nic <- private$get_nic(nic)
nic <- self$get_nic(nic)
nic$properties$ipConfigurations[[config]]$properties$privateIPAddress
},
get_public_ip_resource=function(nic=1, config=1)
{
nic <- self$get_nic(nic)
ip_id <- nic$properties$ipConfigurations[[config]]$properties$publicIPAddress$id
if(is_empty(ip_id))
return(NULL)
az_resource$new(self$token, self$subscription, id=ip_id, api_version=self$ip_api_version)
},
get_nic=function(nic=1)
{
nic_id <- self$properties$networkProfile$networkInterfaces[[nic]]$id
if(is_empty(nic_id))
stop("Network interface resource not found", call.=FALSE)
az_resource$new(self$token, self$subscription, id=nic_id, api_version=self$nic_api_version)
},
get_vnet=function(nic=1, config=1)
{
nic <- self$get_nic(nic)
subnet_id <- nic$properties$ipConfigurations[[config]]$properties$subnet$id
vnet_id <- sub("/subnets/[^/]+$", "", subnet_id)
az_resource$new(self$token, self$subscription, id=vnet_id)
},
get_nsg=function(nic=1, config=1)
{
vnet <- self$get_vnet(nic, config)
nic <- self$get_nic(nic)
nic_nsg_id <- nic$properties$networkSecurityGroup$id
nic_nsg <- if(!is.null(nic_nsg_id))
az_resource$new(self$token, self$subscription, id=nic_nsg_id)
else NULL
# go through list of subnets, find the one where this VM is located
found <- FALSE
nic_id <- tolower(nic$id)
for(sn in vnet$properties$subnets)
{
nics <- tolower(unlist(sn$properties$ipConfigurations))
if(any(grepl(nic_id, nics, fixed=TRUE)))
{
found <- TRUE
break
}
}
if(!found)
stop("Error locating subnet for this network configuration", call.=FALSE)
subnet_nsg_id <- sn$properties$networkSecurityGroup$id
subnet_nsg <- if(!is.null(subnet_nsg_id))
az_resource$new(self$token, self$subscription, id=subnet_nsg_id)
else NULL
if(is.null(nic_nsg) && is.null(subnet_nsg))
NULL
else if(is.null(nic_nsg) && !is.null(subnet_nsg))
subnet_nsg
else if(!is.null(nic_nsg) && is.null(subnet_nsg))
nic_nsg
else(list(nic_nsg, subnet_nsg))
},
get_disk=function(disk="os")
{
id <- if(disk == "os")
self$properties$storageProfile$osDisk$managedDisk$id
else if(is.numeric(disk))
self$properties$storageProfile$dataDisks[[disk]]$managedDisk$id
else stop("Invalid disk argument: should be 'os', or the data disk number", call.=FALSE)
az_resource$new(self$token, self$subscription, id=id)
},
add_extension=function(publisher, type, version, settings=list(),
protected_settings=list(), key_vault_settings=list())
{
@ -198,23 +277,6 @@ public=list(
private=list(
get_nic=function(nic=1)
{
nic_id <- self$properties$networkProfile$networkInterfaces[[nic]]$id
if(is_empty(nic_id))
stop("Network interface resource not found", call.=FALSE)
az_resource$new(self$token, self$subscription, id=nic_id, api_version=self$nic_api_version)
},
get_ip=function(nic=1, config=1)
{
nic <- private$get_nic(nic)
ip_id <- nic$properties$ipConfigurations[[config]]$properties$publicIPAddress$id
if(is_empty(ip_id))
return(NULL)
az_resource$new(self$token, self$subscription, id=ip_id, api_version=self$ip_api_version)
},
init_and_deploy=function(...)
{
stop("Do not use 'az_vm_resource' to create a new VM", call.=FALSE)

Просмотреть файл

@ -20,12 +20,17 @@
#' - `reimage()`: Reimage the VM.
#' - `get_public_ip_address(nic=1, config=1)`: Get the public IP address of the VM. Returns NA if the VM is stopped, or is not publicly accessible.
#' - `get_private_ip_address(nic=1, config=1)`: Get the private IP address of the VM.
#' - `get_public_ip_resource(nic=1, config=1)`: Get the Azure resource for the VM's public IP address.
#' - `get_nic(nic=1)`: Get the VM's network interface resource.
#' - `get_vnet(nic=1, config=1)`: Get the VM's virtual network resource.
#' - `get_nsg(nic=1, config=1)`: Get the VM's network security group resource. Note that an NSG can be attached to either the VM's network interface or to its virtual network subnet; if there is an NSG attached to both, this method returns a list containing the two NSG resource objects.
#' - `get_disk(disk="os")`: Get a managed disk resource attached to the VM. The `disk` argument can be "os" for the OS disk, or a number indicating the LUN of a data disk. AzureVM only supports managed disks.
#' - `add_extension(publisher, type, version, settings=list(), protected_settings=list(), key_vault_settings=list())`: Add an extension to the VM.
#' - `do_vm_operation(...)`: Carries out an arbitrary operation on the VM resource. See the `do_operation` method of the [AzureRMR::az_resource] class for more details.
#'
#' @details
#' The VM operations listed above are actually provided by the [az_vm_resource] class, and propagated to the template as active bindings.
#' Many of these methods are actually provided by the [az_vm_resource] class, and propagated to the template as active bindings.
#'
#' @details
#' A single virtual machine in Azure is actually a collection of resources, including any and all of the following.
#' - Network interface (Azure resource type `Microsoft.Network/networkInterfaces`)
#' - Network security group (Azure resource type `Microsoft.Network/networkSecurityGroups`)
@ -160,6 +165,21 @@ active=list(
get_private_ip_address=function()
private$vm$get_private_ip_address,
get_public_ip_resource=function()
private$vm$get_public_ip_resource,
get_nic=function()
private$vm$get_nic,
get_vnet=function()
private$vm$get_vnet,
get_nsg=function()
private$vm$get_nsg,
get_disk=function()
private$vm$get_disk,
redeploy=function()
private$vm$redeploy,

Просмотреть файл

@ -14,6 +14,8 @@
#' - `get_public_ip_address()`: Get the public IP address of the scaleset (technically, of the load balancer). If the scaleset doesn't have a load balancer attached, returns NA.
#' - `get_vm_public_ip_addresses(id=NULL, nic=1, config=1)`: Get the public IP addresses for the instances in the scaleset. Returns NA for the instances that are stopped or not publicly accessible.
#' - `get_vm_private_ip_addresses(id=NULL, nic=1, config=1)`: Get the private IP addresses for the instances in the scaleset.
#' - `get_vnet(nic=1, config=1)`: Get the scaleset's virtual network resource.
#' - `get_nsg(nic=1, config=1)`: Get the scaleset's network security group resource.
#' - `run_deployed_command(command, parameters=NULL, script=NULL, id=NULL)`: Run a PowerShell command on the instances in the scaleset.
#' - `run_script(script, parameters=NULL, id=NULL)`: Run a script on the VM. For a Linux VM, this will be a shell script; for a Windows VM, a PowerShell script. Pass the script as a character vector.
#' - `reimage(id=NULL, datadisks=FALSE)`: Reimage the instances in the scaleset. If `datadisks` is TRUE, reimage any attached data disks as well.
@ -150,6 +152,42 @@ public=list(
unlist(private$vm_map(id, function(vm) vm$get_private_ip_address(nic, config)))
},
get_vnet=function(nic=1, config=1)
{
subnet_id <- self$properties$
virtualMachineProfile$networkProfile$networkInterfaceConfigurations[[nic]]$properties$
ipConfigurations[[config]]$properties$
subnet$id
vnet_id <- sub("/subnets/[^/]+$", "", subnet_id)
az_resource$new(self$token, self$subscription, id=vnet_id)
},
get_nsg=function(nic=1, config=1)
{
vnet <- self$get_vnet(nic, config)
# go through list of subnets, find the one where this scaleset's instances are located
found <- FALSE
vmss_id <- tolower(self$id)
for(sn in vnet$properties$subnets)
{
nics <- tolower(unlist(sn$properties$ipConfigurations))
if(any(grepl(vmss_id, nics, fixed=TRUE)))
{
found <- TRUE
break
}
}
if(!found)
stop("Unable to find subnet for this network configuration", call.=FALSE)
subnet_nsg_id <- sn$properties$networkSecurityGroup$id
if(!is.null(subnet_nsg_id))
az_resource$new(self$token, self$subscription, id=subnet_nsg_id)
else NULL
},
run_deployed_command=function(command, parameters=NULL, script=NULL, id=NULL)
{
private$vm_map(id, function(vm) vm$run_deployed_command(command, parameters, script))

Просмотреть файл

@ -18,6 +18,11 @@
#' - `get_public_ip_address()`: Get the public IP address of the scaleset (technically, of the load balancer). If the scaleset doesn't have a load balancer attached, returns NA.
#' - `get_vm_public_ip_addresses(id=NULL, nic=1, config=1)`: Get the public IP addresses for the instances in the scaleset. Returns NA for the instances that are stopped or not publicly accessible.
#' - `get_vm_private_ip_addresses(id=NULL, nic=1, config=1)`: Get the private IP addresses for the instances in the scaleset.
#' - `get_public_ip_resource()`: Get the Azure resource for the load balancer's public IP address.
#' - `get_vnet(nic=1, config=1)`: Get the scaleset's virtual network resource.
#' - `get_nsg(nic=1, config=1)`: Get the scaleset's network security group resource.
#' - `get_load_balancer()`: Get the scaleset's load balancer resource.
#' - `get_autoscaler()`: Get the scaleset's autoscaler resource.
#' - `run_deployed_command(command, parameters=NULL, script=NULL, id=NULL)`: Run a PowerShell command on the instances in the scaleset.
#' - `run_script(script, parameters=NULL, id=NULL)`: Run a script on the VM. For a Linux VM, this will be a shell script; for a Windows VM, a PowerShell script. Pass the script as a character vector.
#' - `reimage(id=NULL, datadisks=FALSE)`: Reimage the instances in the scaleset. If `datadisks` is TRUE, reimage any attached data disks as well.
@ -26,6 +31,8 @@
#' - `add_extension(publisher, type, version, settings=list(), protected_settings=list(), key_vault_settings=list())`: Add an extension to the scaleset.
#' - `do_vmss_operation(...)` Carry out an arbitrary operation on the scaleset resource (as opposed to the instances in the scaleset).
#'
#' Many of these methods are actually provided by the [az_vmss_resource] class, and propagated to the template as active bindings.
#'
#' @details
#' A virtual machine scaleset in Azure is actually a collection of resources, including any and all of the following.
#' - Network security group (Azure resource type `Microsoft.Network/networkSecurityGroups`)
@ -38,7 +45,6 @@
#' By wrapping the deployment template used to create these resources, the `az_vmss_template` class allows managing them all as a single entity.
#'
#' @section Instance operations:
#' With the exception of `get_public_ip_address`, the scaleset methods listed above are actually provided by the [az_vmss_resource] class, and propagated to the template as active bindings.
#'
#' AzureVM has the ability to parallelise scaleset instance operations using a pool of background processes. This can lead to significant speedups when working with scalesets with high instance counts. The pool is created automatically the first time that it is required, and remains persistent for the session. For more information, see [init_pool].
#'
@ -141,15 +147,38 @@ public=list(
},
get_public_ip_address=function()
{
ip <- self$get_public_ip_resource()
if(!is.null(ip))
ip$properties$ipAddress
else NA_character_
},
get_public_ip_resource=function()
{
outputs <- unlist(self$properties$outputResources)
ip_id <- grep("publicIPAddresses/.+$", outputs, ignore.case=TRUE, value=TRUE)
if(is_empty(ip_id))
return(NA_character_)
ip <- az_resource$new(self$token, self$subscription, id=ip_id)$properties$ipAddress
if(!is.null(ip))
ip
else NA_character_
NULL
else az_resource$new(self$token, self$subscription, id=ip_id)
},
get_load_balancer=function()
{
outputs <- unlist(self$properties$outputResources)
lb_id <- grep("loadBalancers/.+$", outputs, ignore.case=TRUE, value=TRUE)
if(is_empty(lb_id))
NULL
else az_resource$new(self$token, self$subscription, id=lb_id)
},
get_autoscaler=function()
{
outputs <- unlist(self$properties$outputResources)
as_id <- grep("autoscaleSettings/.+$", outputs, ignore.case=TRUE, value=TRUE)
if(is_empty(as_id))
NULL
else az_resource$new(self$token, self$subscription, id=as_id)
}
),
@ -183,6 +212,12 @@ active=list(
get_vm_private_ip_addresses=function()
private$vmss$get_vm_private_ip_addresses,
get_vnet=function()
private$vmss$get_vnet,
get_nsg=function()
private$vmss$get_nsg,
run_deployed_command=function()
private$vmss$run_deployed_command,

Просмотреть файл

@ -25,6 +25,11 @@ sub <- AzureRMR::get_azure_login()$
vm <- sub$create_vm("myubuntuvm", user_config("myname", "~/.ssh/id_rsa.pub"),
location="australiaeast")
# some resources used by the VM
vm$get_vnet()
vm$get_public_ip_resource()
vm$get_disk("os")
# run a shell script or command remotely (will be PowerShell on a Windows VM)
vm$run_script("echo hello world! > /tmp/hello.txt")

Просмотреть файл

@ -26,6 +26,11 @@ The following methods are available, in addition to those provided by the \link[
\item \code{reimage()}: Reimage the VM.
\item \code{get_public_ip_address(nic=1, config=1)}: Get the public IP address of the VM. Returns NA if the VM is shut down, or is not publicly accessible.
\item \code{get_private_ip_address(nic=1, config=1)}: Get the private IP address of the VM.
\item \code{get_public_ip_resource(nic=1, config=1)}: Get the Azure resource for the VM's public IP address.
\item \code{get_nic(nic=1)}: Get the VM's network interface resource.
\item \code{get_vnet(nic=1, config=1)}: Get the VM's virtual network resource.
\item \code{get_nsg(nic=1, config=1)}: Get the VM's network security group resource. Note that an NSG can be attached to either the VM's network interface or to its virtual network subnet; if there is an NSG attached to both, this method returns a list containing the two NSG resource objects.
\item \code{get_disk(disk="os")}: Get a managed disk resource attached to the VM. The \code{disk} argument can be "os" for the OS disk, or a number indicating the LUN of a data disk. AzureVM only supports managed disks.
\item \code{add_extension(publisher, type, version, settings=list(), protected_settings=list(), key_vault_settings=list())}: Add an extension to the VM.
\item \code{do_vm_operation(...)}: Carry out an arbitrary operation on the VM resource. See the \code{do_operation} method of the \link[AzureRMR:az_resource]{AzureRMR::az_resource} class for more details.
}

Просмотреть файл

@ -12,8 +12,6 @@ az_vm_template
Class representing a virtual machine deployment template. This class keeps track of all resources that are created as part of deploying a VM, and exposes methods for managing them.
}
\details{
The VM operations listed above are actually provided by the \link{az_vm_resource} class, and propagated to the template as active bindings.
A single virtual machine in Azure is actually a collection of resources, including any and all of the following.
\itemize{
\item Network interface (Azure resource type \code{Microsoft.Network/networkInterfaces})
@ -49,9 +47,16 @@ The following methods are available, in addition to those provided by the \link[
\item \code{reimage()}: Reimage the VM.
\item \code{get_public_ip_address(nic=1, config=1)}: Get the public IP address of the VM. Returns NA if the VM is stopped, or is not publicly accessible.
\item \code{get_private_ip_address(nic=1, config=1)}: Get the private IP address of the VM.
\item \code{get_public_ip_resource(nic=1, config=1)}: Get the Azure resource for the VM's public IP address.
\item \code{get_nic(nic=1)}: Get the VM's network interface resource.
\item \code{get_vnet(nic=1, config=1)}: Get the VM's virtual network resource.
\item \code{get_nsg(nic=1, config=1)}: Get the VM's network security group resource. Note that an NSG can be attached to either the VM's network interface or to its virtual network subnet; if there is an NSG attached to both, this method returns a list containing the two NSG resource objects.
\item \code{get_disk(disk="os")}: Get a managed disk resource attached to the VM. The \code{disk} argument can be "os" for the OS disk, or a number indicating the LUN of a data disk. AzureVM only supports managed disks.
\item \code{add_extension(publisher, type, version, settings=list(), protected_settings=list(), key_vault_settings=list())}: Add an extension to the VM.
\item \code{do_vm_operation(...)}: Carries out an arbitrary operation on the VM resource. See the \code{do_operation} method of the \link[AzureRMR:az_resource]{AzureRMR::az_resource} class for more details.
}
Many of these methods are actually provided by the \link{az_vm_resource} class, and propagated to the template as active bindings.
}
\examples{

Просмотреть файл

@ -37,6 +37,8 @@ The following methods are available, in addition to those provided by the \link[
\item \code{get_public_ip_address()}: Get the public IP address of the scaleset (technically, of the load balancer). If the scaleset doesn't have a load balancer attached, returns NA.
\item \code{get_vm_public_ip_addresses(id=NULL, nic=1, config=1)}: Get the public IP addresses for the instances in the scaleset. Returns NA for the instances that are stopped or not publicly accessible.
\item \code{get_vm_private_ip_addresses(id=NULL, nic=1, config=1)}: Get the private IP addresses for the instances in the scaleset.
\item \code{get_vnet(nic=1, config=1)}: Get the scaleset's virtual network resource.
\item \code{get_nsg(nic=1, config=1)}: Get the scaleset's network security group resource.
\item \code{run_deployed_command(command, parameters=NULL, script=NULL, id=NULL)}: Run a PowerShell command on the instances in the scaleset.
\item \code{run_script(script, parameters=NULL, id=NULL)}: Run a script on the VM. For a Linux VM, this will be a shell script; for a Windows VM, a PowerShell script. Pass the script as a character vector.
\item \code{reimage(id=NULL, datadisks=FALSE)}: Reimage the instances in the scaleset. If \code{datadisks} is TRUE, reimage any attached data disks as well.

Просмотреть файл

@ -46,6 +46,11 @@ The following methods are available, in addition to those provided by the \link[
\item \code{get_public_ip_address()}: Get the public IP address of the scaleset (technically, of the load balancer). If the scaleset doesn't have a load balancer attached, returns NA.
\item \code{get_vm_public_ip_addresses(id=NULL, nic=1, config=1)}: Get the public IP addresses for the instances in the scaleset. Returns NA for the instances that are stopped or not publicly accessible.
\item \code{get_vm_private_ip_addresses(id=NULL, nic=1, config=1)}: Get the private IP addresses for the instances in the scaleset.
\item \code{get_public_ip_resource()}: Get the Azure resource for the load balancer's public IP address.
\item \code{get_vnet(nic=1, config=1)}: Get the scaleset's virtual network resource.
\item \code{get_nsg(nic=1, config=1)}: Get the scaleset's network security group resource.
\item \code{get_load_balancer()}: Get the scaleset's load balancer resource.
\item \code{get_autoscaler()}: Get the scaleset's autoscaler resource.
\item \code{run_deployed_command(command, parameters=NULL, script=NULL, id=NULL)}: Run a PowerShell command on the instances in the scaleset.
\item \code{run_script(script, parameters=NULL, id=NULL)}: Run a script on the VM. For a Linux VM, this will be a shell script; for a Windows VM, a PowerShell script. Pass the script as a character vector.
\item \code{reimage(id=NULL, datadisks=FALSE)}: Reimage the instances in the scaleset. If \code{datadisks} is TRUE, reimage any attached data disks as well.
@ -54,11 +59,12 @@ The following methods are available, in addition to those provided by the \link[
\item \code{add_extension(publisher, type, version, settings=list(), protected_settings=list(), key_vault_settings=list())}: Add an extension to the scaleset.
\item \code{do_vmss_operation(...)} Carry out an arbitrary operation on the scaleset resource (as opposed to the instances in the scaleset).
}
Many of these methods are actually provided by the \link{az_vmss_resource} class, and propagated to the template as active bindings.
}
\section{Instance operations}{
With the exception of \code{get_public_ip_address}, the scaleset methods listed above are actually provided by the \link{az_vmss_resource} class, and propagated to the template as active bindings.
AzureVM has the ability to parallelise scaleset instance operations using a pool of background processes. This can lead to significant speedups when working with scalesets with high instance counts. The pool is created automatically the first time that it is required, and remains persistent for the session. For more information, see \link{init_pool}.

Просмотреть файл

@ -45,6 +45,12 @@ test_that("VM interaction works",
expect_is(vm$identity, "list")
expect_is(vm$get_public_ip_resource(), "az_resource")
expect_is(vm$get_nic(), "az_resource")
expect_is(vm$get_vnet(), "az_resource")
expect_is(vm$get_nsg(), "az_resource")
expect_is(vm$get_disk("os"), "az_resource")
expect_message(vm$redeploy())
})

Просмотреть файл

@ -43,6 +43,12 @@ test_that("Scaleset interaction works",
expect_is(vm$get_vm_private_ip_addresses(names(inst)[1:2]), "character")
expect_is(vm$get_vm_public_ip_addresses(names(inst)[1:2]), "character")
expect_is(vm$get_public_ip_resource(), "az_resource")
expect_is(vm$get_vnet(), "az_resource")
expect_is(vm$get_nsg(), "az_resource")
expect_is(vm$get_load_balancer(), "az_resource")
expect_is(vm$get_autoscaler(), "az_resource")
expect_is(vm$identity, "list")
})

Просмотреть файл

@ -67,3 +67,4 @@ test_that("Custom resource works",
expect_true(is_empty(rg$list_resources()))
})
rg$delete(confirm=FALSE)

Просмотреть файл

@ -26,6 +26,8 @@ test_that("Custom vnet works",
vnet <- vnet_config(address_space="10.1.0.0/16")
vm <- rg$create_vm(vmname, user, size, vnet=vnet)
expect_is(vm, "az_vm_template")
expect_is(vm$get_vnet(), "az_resource")
})
test_that("Scaleset options work",

Просмотреть файл

@ -26,6 +26,11 @@ sub <- AzureRMR::get_azure_login()$
vm <- sub$create_vm("myubuntuvm", user_config("myname", "~/.ssh/id_rsa.pub"),
location="australiaeast")
# some resources used by the VM
vm$get_vnet()
vm$get_public_ip_resource()
vm$get_disk("os")
# run a shell script or command remotely (will be PowerShell on a Windows VM)
vm$run_script("echo hello world! > /tmp/hello.txt")