* closes #1 
* closes #3
This commit is contained in:
Hong Ooi 2019-06-14 11:04:22 +10:00 коммит произвёл GitHub
Родитель 7266697d3b
Коммит f5a7c3adf5
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
82 изменённых файлов: 4971 добавлений и 2983 удалений

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

@ -8,3 +8,5 @@ CONTRIBUTING.md
drat.sh drat.sh
.travis.yml .travis.yml
^LICENSE\.md$ ^LICENSE\.md$
azure-pipelines.yml
^tpl$

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

@ -1,13 +1,12 @@
Package: AzureVM Package: AzureVM
Title: Virtual Machines in 'Azure' Title: Virtual Machines in 'Azure'
Version: 1.0.1 Version: 2.0.0
Authors@R: c( Authors@R: c(
person("Hong", "Ooi", , "hongooi@microsoft.com", role = c("aut", "cre")), person("Hong", "Ooi", , "hongooi@microsoft.com", role = c("aut", "cre")),
person("Data Science Virtual Machine team", role="ctb", comment="DSVM template provider"),
person("Microsoft", role="cph") person("Microsoft", role="cph")
) )
Description: Functionality for working with virtual machines (VMs) in Microsoft's 'Azure' cloud: <https://azure.microsoft.com/en-us/services/virtual-machines/>. Includes facilities to create, startup, shutdown, and cleanly delete VMs and VM clusters. With a running VM, execute scripts and install optional extensions. A selection of VM templates based on the 'Data Science Virtual Machine' (DSVM) is supplied; this allows fast and easy provisioning of a VM preinstalled with several software packages useful for data science. Alternatively, users can provide VM templates of their own. Description: Functionality for working with virtual machines (VMs) in Microsoft's 'Azure' cloud: <https://azure.microsoft.com/en-us/services/virtual-machines/>. Includes facilities to deploy, startup, shutdown, and cleanly delete VMs and VM clusters. Deployment configurations can be highly customised, and can make use of existing resources as well as creating new ones. A selection of predefined configurations is provided to allow easy deployment of commonly used Linux and Windows images, including Data Science Virtual Machines. With a running VM, execute scripts and install optional extensions. Part of the 'AzureR' family of packages.
URL: https://github.com/Azure/AzureVM URL: https://github.com/Azure/AzureVM https://github.com/Azure/AzureR
BugReports: https://github.com/Azure/AzureVM/issues BugReports: https://github.com/Azure/AzureVM/issues
License: MIT + file LICENSE License: MIT + file LICENSE
VignetteBuilder: knitr VignetteBuilder: knitr
@ -15,9 +14,11 @@ Depends:
R (>= 3.3), R (>= 3.3),
Imports: Imports:
R6, R6,
AzureRMR AzureRMR (>= 2.1.2),
jsonlite
Suggests: Suggests:
knitr, knitr,
testthat testthat,
AzureKeyVault
Roxygen: list(markdown=TRUE) Roxygen: list(markdown=TRUE)
RoxygenNote: 6.1.0.9000 RoxygenNote: 6.1.1

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

@ -1,6 +1,79 @@
# Generated by roxygen2: do not edit by hand # Generated by roxygen2: do not edit by hand
S3method(build_template_definition,vm_config)
S3method(build_template_definition,vmss_config)
S3method(build_template_parameters,vm_config)
S3method(build_template_parameters,vmss_config)
export(autoscaler_config)
export(autoscaler_profile)
export(az_vm_resource) export(az_vm_resource)
export(az_vm_template) export(az_vm_template)
export(az_vmss_resource)
export(az_vmss_template)
export(build_template_definition)
export(build_template_parameters)
export(datadisk_config)
export(debian_9_backports)
export(debian_9_backports_ss)
export(image_config)
export(ip_config)
export(is_vm)
export(is_vm_resource)
export(is_vm_scaleset)
export(is_vm_scaleset_resource)
export(is_vm_scaleset_template)
export(is_vm_template) export(is_vm_template)
export(lb_config)
export(lb_probe)
export(lb_probe_http)
export(lb_probe_https)
export(lb_probe_jupyter)
export(lb_probe_mssql)
export(lb_probe_mssql_browser)
export(lb_probe_rdp)
export(lb_probe_rstudio)
export(lb_probe_ssh)
export(lb_rule)
export(lb_rule_http)
export(lb_rule_https)
export(lb_rule_jupyter)
export(lb_rule_mssql)
export(lb_rule_mssql_browser)
export(lb_rule_rdp)
export(lb_rule_rstudio)
export(lb_rule_ssh)
export(nic_config)
export(nic_ip_config)
export(nsg_config)
export(nsg_rule)
export(nsg_rule_allow_http)
export(nsg_rule_allow_https)
export(nsg_rule_allow_jupyter)
export(nsg_rule_allow_mssql)
export(nsg_rule_allow_mssql_browser)
export(nsg_rule_allow_rdp)
export(nsg_rule_allow_rstudio)
export(nsg_rule_allow_ssh)
export(rhel_7.6)
export(rhel_7.6_ss)
export(rhel_8)
export(rhel_8_ss)
export(scaleset_options)
export(subnet_config)
export(ubuntu_16.04)
export(ubuntu_16.04_ss)
export(ubuntu_18.04)
export(ubuntu_18.04_ss)
export(ubuntu_dsvm)
export(ubuntu_dsvm_ss)
export(user_config)
export(vm_config)
export(vmss_config)
export(vnet_config)
export(windows_2016)
export(windows_2016_ss)
export(windows_2019)
export(windows_2019_ss)
export(windows_dsvm)
export(windows_dsvm_ss)
import(AzureRMR) import(AzureRMR)

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

@ -1,3 +1,12 @@
# AzureVM 2.0.0
* Complete rewrite of package, to be less DSVM-centric and more flexible:
* Separate out deployment of VMs and VM clusters; the latter are implemented as single scaleset resources, rather than simple arrays of individual VMs.
* `vm_config` and `vmss_config` functions to fine-tune the deployment options, including specifying the base VM image; networking details like security rules, load balancers and autoscaling; datadisks to attach; use of low-priority VMs for scalesets; etc.
* Several predefined configurations supplied to allow quick deployment of commonly used images (Ubuntu, Windows Server, RHEL, Debian).
* Allow referring to existing resources in a deployment, by supplying `AzureRMR::az_resource` objects as arguments.
* See the README and/or the vignette for more information.
# AzureVM 1.0.1 # AzureVM 1.0.1
* Allow resource group and subscription accessor methods to work without AzureVM on the search path. * Allow resource group and subscription accessor methods to work without AzureVM on the search path.

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

@ -1,4 +1,11 @@
#' @import AzureRMR #' @import AzureRMR
NULL NULL
#' @export
AzureRMR::build_template_definition
#' @export
AzureRMR::build_template_parameters
globalVariables("self", "AzureVM") globalVariables("self", "AzureVM")

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

@ -25,8 +25,7 @@
#' @examples #' @examples
#' \dontrun{ #' \dontrun{
#' #'
#' sub <- AzureRMR::az_rm$ #' sub <- AzureRMR::get_azure_login$
#' new(tenant="myaadtenant.onmicrosoft.com", app="app_id", password="password")$
#' get_subscription("subscription_id") #' get_subscription("subscription_id")
#' #'
#' sub$list_vm_sizes("australiaeast") #' sub$list_vm_sizes("australiaeast")
@ -55,156 +54,204 @@ NULL
#' get_vm(name) #' get_vm(name)
#' #'
#' ## R6 method for class 'az_subscription' #' ## R6 method for class 'az_subscription'
#' get_vm_cluster(name, resource_group = name) #' get_vm_scaleset(name, resource_group = name)
#' #'
#' ## R6 method for class 'az_resource_group' #' ## R6 method for class 'az_resource_group'
#' get_vm_cluster(name) #' get_vm_scaleset(name)
#' #'
#' ## R6 method for class 'az_resource_group' #' ## R6 method for class 'az_resource_group')
#' ## R6 method for class 'az_subscription' #' get_vm_resource(name)
#' list_vms() #' get_vm_scaleset_resource(name)
#' ``` #' ```
#' @section Arguments: #' @section Arguments:
#' - `name`: The name of the VM or cluster. #' - `name`: The name of the VM or scaleset.
#' - `resource_group`: For the `az_subscription` method, the resource group in which `get_vm()` will look for the VM. Defaults to the VM name. #' - `resource_group`: For the `az_subscription` methods, the resource group in which `get_vm()` and `get_vm_scaleset()` will look for the VM or scaleset. Defaults to the VM name.
#'
#' @section Details:
#' Despite the names, `get_vm` and `get_vm_cluster` can both be used to retrieve individual VMs and clusters. The main difference is in their behaviour if a deployment template is not found. In the case of `get_vm`, it also searches for a raw VM resource of the given name, whereas `get_vm_cluster` will throw an error immediately.
#' #'
#' @section Value: #' @section Value:
#' For `get_vm()`, an object representing the VM, either of class `az_vm_template` or `az_vm_resource`. #' For `get_vm()`, an object representing the VM deployment. This will include other resources besides the VM itself, such as the network interface, virtual network, etc.
#' #'
#' For `list_vms()`, a list of such objects. #' For `get_vm_scaleset()`, an object representing the scaleset deployment. Similarly to `get_vm()`, this includes other resources besides the scaleset.
#' #'
#' For `get_vm_cluster()`, an object representing the cluster. #' For `get_vm_resource()` and `get_vm_scaleset_resource()`, the VM or scaleset resource itself.
#' #'
#' @seealso #' @seealso
#' [az_vm_template], [az_vm_resource], #' [az_vm_template], [az_vm_resource], [az_vmss_template], [az_vmss_resource] for the methods available for working with VMs and VM scalesets.
#'
#' [AzureRMR::az_subscription], [AzureRMR::az_resource_group] #' [AzureRMR::az_subscription], [AzureRMR::az_resource_group]
#' #'
#' @examples #' @examples
#' \dontrun{ #' \dontrun{
#' #'
#' sub <- AzureRMR::az_rm$ #' sub <- AzureRMR::get_azure_login()$
#' new(tenant="myaadtenant.onmicrosoft.com", app="app_id", password="password")$
#' get_subscription("subscription_id") #' get_subscription("subscription_id")
#' #'
#' sub$list_vms() #' sub$get_vm("myvirtualmachine")
#' sub$get_vm("myVirtualMachine") #' sub$get_vm_scaleset("myscaleset")
#' #'
#' rg <- sub$get_resource_group("rgname") #' rg <- sub$get_resource_group("rgname")
#' rg$get_vm("myOtherVirtualMachine") #' rg$get_vm("myothervirtualmachine")
#' #' rg$get_vm_scaleset("myotherscaleset")
#'
#' } #' }
#' @rdname get_vm #' @rdname get_vm
#' @aliases get_vm get_vm_cluster list_vms #' @aliases get_vm get_vm_scaleset get_vm_resource get_vm_scaleset_resource
#' @name get_vm #' @name get_vm
NULL NULL
#' Create a new virtual machine or cluster of virtual machines #' Create a new virtual machine or scaleset of virtual machines
#' #'
#' Method for the [AzureRMR::az_subscription] and [AzureRMR::az_resource_group] classes. #' Method for the [AzureRMR::az_subscription] and [AzureRMR::az_resource_group] classes.
#' #'
#' @section Usage: #' @section Usage:
#' ``` #' ```
#' ## R6 method for class 'az_resource_group' #' ## R6 method for class 'az_resource_group'
#' create_vm(name, os = c("Windows", "Ubuntu"), size = "Standard_DS3_v2", #' create_vm(name, login_user, size = "Standard_DS3_v2", config = "ubuntu_dsvm",
#' username, passkey, userauth_type = c("password", "key"), #' managed = TRUE, datadisks = numeric(0), ...,
#' ext_file_uris = NULL, inst_command = NULL, #' template, parameters, mode = "Incremental", wait = TRUE)
#' template, parameters, ..., wait = TRUE)
#' #'
#' ## R6 method for class 'az_subscription' #' ## R6 method for class 'az_subscription'
#' create_vm(name, location, os = c("Windows", "Ubuntu"), size = "Standard_DS3_v2", #' create_vm(name, ..., resource_group = name, location)
#' username, passkey, userauth_type = c("password", "key"),
#' ext_file_uris = NULL, inst_command = NULL,
#' template, parameters, ..., wait = TRUE)
#' #'
#' ## R6 method for class 'az_resource_group' #' ## R6 method for class 'az_resource_group'
#' create_vm_cluster(name, os = c("Windows", "Ubuntu"), size = "Standard_DS3_v2", #' create_vm_scaleset(name, login_user, instances, size = "Standard_DS1_v2",
#' username, passkey, userauth_type = c("password", "key"), #' config = "ubuntu_dsvm_ss", ...,
#' ext_file_uris = NULL, inst_command = NULL, clust_size, #' template, parameters, mode = "Incremental", wait = TRUE)
#' template, parameters, ..., wait = TRUE)
#' #'
#' ## R6 method for class 'az_subscription' #' ## R6 method for class 'az_subscription'
#' create_vm_cluster(name, location, os = c("Windows", "Ubuntu"), size = "Standard_DS3_v2", #' create_vm_scaleset(name, ..., resource_group = name, location)
#' username, passkey, userauth_type = c("password", "key"),
#' ext_file_uris = NULL, inst_command = NULL, clust_size,
#' template, parameters, ..., wait = TRUE)
#' ``` #' ```
#' @section Arguments: #' @section Arguments:
#' - `name`: The name of the VM or cluster. #' - `name`: The name of the VM or scaleset.
#' - `location`: For the subscription class methods, the location for the VM. Use the `list_locations()` method of the `AzureRMR::az_subscription` class to see what locations are available. #' - `location`: For the subscription methods, the location for the VM or scaleset. Use the `list_locations()` method of the `AzureRMR::az_subscription` class to see what locations are available.
#' - `os`: The operating system for the VM. #' - `resource_group`: For the subscription methods, the resource group in which to place the VM or scaleset. Defaults to a new resource group with the same name as the VM.
#' - `size`: The VM size. Use the `list_vm_sizes()` method of the `AzureRMR::az_subscription` class to see what sizes are available. #' - `login_user`: The details for the admin login account. An object of class `user_config`, obtained by a call to the `user_config` function.
#' - `username`: The login username for the VM. #' - `size`: The VM (instance) size. Use the [list_vm_sizes] method to see what sizes are available.
#' - `passkey`: The login password or public key. #' - `config`: The VM or scaleset configuration. See 'Details' below for how to specify this. The default is to use an Ubuntu Data Science Virtual Machine.
#' - `userauth_type`: The type of login authentication to use. Only has an effect for Linux-based VMs; Windows VMs will always use `"password"`. #' - `managed`: For `create_vm`, whether the VM should have a managed identity attached.
#' - `ext_file_uris`: Optional link to download extension packages. #' - `datadisks`: For `create_vm`, any data disks to attach to the VM. See 'Details' below.
#' - `inst_command`: If `ext_file_uris` is supplied, the install script to run. Defaults to `install.sh` for an Ubuntu VM, or `install.ps1` for a Windows VM. #' - `instances`: For `create_vm_scaleset`, the initial number of instances in the scaleset.
#' - `clust_size`: For a cluster, the number of nodes to create. #' - `...` For the subscription methods, any of the other arguments listed here, which will be passed to the resource group method. For the resource group method, additional arguments to pass to the VM/scaleset configuration functions [vm_config] and [vmss_config]. See the examples below.
#' - `template`: Optional: the VM template to deploy. By default, this is determined by the values of the other arguments; see 'Details' below. #' - `template,parameters`: The template definition and parameters to deploy. By default, these are constructed from the values of the other arguments, but you can supply your own template and/or parameters as well.
#' - `parameters`: Optional: other parameters to pass to the deployment.
#' - `wait`: Whether to wait until the deployment is complete. #' - `wait`: Whether to wait until the deployment is complete.
#' - `...`: Other arguments to lower-level methods. #' - `mode`: The template deployment mode. If "Complete", any existing resources in the resource group will be deleted.
#' #'
#' @section Details: #' @section Details:
#' This method deploys a template to create a new virtual machine or cluster of VMs. Currently, seven templates are supplied with this package, based on the Azure Data Science Virtual Machine: #' These methods deploy a template to create a new virtual machine or scaleset.
#' - Ubuntu DSVM
#' - Ubuntu DSVM using public key authentication
#' - Ubuntu DSVM with extensions
#' - Ubuntu DSVM cluster
#' - Ubuntu DSVM cluster with extensions
#' - Windows Server 2016 DSVM
#' - Windows Server 2016 DSVM cluster with extensions
#' #'
#' An individual virtual machine is treated as a cluster containing only a single node. #' The `config` argument can be specified in the following ways:
#' - As the name of a supplied VM or scaleset configuration, like "ubuntu_dsvm" or "ubuntu_dsvm_ss". AzureVM comes with a number of supplied configurations to deploy commonly used images, which can be seen at [vm_config] and [vmss_config]. Any arguments in `...` will be passed to the configuration, allowing you to customise the deployment.
#' - As a call to the `vm_config` or `vmss_config` functions, to deploy a custom VM image.
#' - As an object of class `vm_config` or `vmss_config`.
#' #'
#' You can also supply your own VM template for deployment, via the `template` argument. See [AzureRMR::az_template] for information how to supply templates. Note that if you do this, you may also have to supply a `parameters` argument, as the standard parameters for this method are customised for the DSVM. #' The data disks for the VM can be specified as either a vector of numeric disk sizes in GB, or as a list of `datadisk_config` objects, created via calls to the `datadisk_config` function. Currently, AzureVM only supports creating data disks at deployment time for single VMs, not scalesets.
#' #'
#' For the `AzureRMR::az_subscription` method, this will by default create the VM in _exclusive_ mode, meaning a new resource group is created solely to hold the VM. This simplifies managing the VM considerably, in particular deleting the resource group will also automatically delete all the VM's resources. #' You can also supply your own template definition and parameters for deployment, via the `template` and `parameters` arguments. See [AzureRMR::az_template] for information how to create templates.
#'
#' The `AzureRMR::az_subscription` methods will by default create the VM in _exclusive_ mode, meaning a new resource group is created solely to hold the VM or scaleset. This simplifies managing the VM considerably; in particular deleting the resource group will also automatically delete all the deployed resources.
#' #'
#' @section Value: #' @section Value:
#' An object of class `az_vm_template` representing the created VM. #' For `create_vm`, an object of class `az_vm_template` representing the created VM. For `create_vm_scaleset`, an object of class `az_vmss_template` representing the scaleset.
#' #'
#' @seealso #' @seealso
#' [az_vm_template], #' [az_vm_template], [az_vmss_template]
#'
#' [vm_config], [vmss_config], [user_config], [datadisk_config]
#'
#' [AzureRMR::az_subscription], [AzureRMR::az_resource_group], #' [AzureRMR::az_subscription], [AzureRMR::az_resource_group],
#' [Data Science Virtual Machine](https://azure.microsoft.com/en-us/services/virtual-machines/data-science-virtual-machines/) #' [Data Science Virtual Machine](https://azure.microsoft.com/en-us/services/virtual-machines/data-science-virtual-machines/)
#' #'
#' @examples #' @examples
#' \dontrun{ #' \dontrun{
#' #'
#' sub <- AzureRMR::az_rm$ #' sub <- AzureRMR::get_azure_login()$
#' new(tenant="myaadtenant.onmicrosoft.com", app="app_id", password="password")$
#' get_subscription("subscription_id") #' get_subscription("subscription_id")
#' #'
#' # default Windows Server DSVM: make sure to use a strong password! #' # default Ubuntu 18.04 VM:
#' sub$create_vm("myWindowsDSVM", #' # SSH key login, Standard_DS3_v2, publicly accessible via SSH
#' location="australiaeast", #' sub$create_vm("myubuntuvm", user_config("myname", "~/.ssh/id_rsa.pub"),
#' username="ds", #' location="australiaeast")
#' passkey="Password123!")
#' #'
#' # upsized Linux (Ubuntu) DSVM #' # Windows Server 2019, with a 500GB datadisk attached, not publicly accessible
#' sub$create_vm("myLinuxDSVM", #' sub$create_vm("mywinvm", user_config("myname", password="Use-strong-passwords!"),
#' location="australiaeast", #' size="Standard_DS4_v2", config="windows_2019", datadisks=500, ip=NULL,
#' os="Linux", #' location="australiaeast")
#' username="ds",
#' passkey=readLines("~/id_rsa.pub"),
#' size="Standard_DS13_v2")
#' #'
#" # Linux cluster with 5 nodes #' # Ubuntu DSVM, GPU-enabled
#' sub$create_vm_cluster("myLinuxCluster", #' sub$create_vm("mydsvm", user_config("myname", "~/.ssh/id_rsa.pub"), size="Standard_NC12",
#' location="australiaeast", #' config="ubuntu_dsvm_ss",
#' os="Linux", #' location="australiaeast")
#' username="ds", #'
#' passkey=readLines("~/id_rsa.pub"), #' ## custom VM configuration: Windows 10 Pro 1903 with data disks
#' clust_size=5) #' ## this assumes you have a valid Win10 desktop license
#' user <- user_config("myname", password="Use-strong-passwords!")
#' image <- image_config(
#' publisher="MicrosoftWindowsDesktop",
#' offer="Windows-10",
#' sku="19h1-pro"
#' )
#' datadisks <- list(
#' datadisk_config(250, type="Premium_LRS"),
#' datadisk_config(1000, type="Standard_LRS")
#' )
#' nsg <- nsg_config(
#' list(nsg_rule_allow_rdp)
#' )
#' config <- vm_config(
#' image=image,
#' keylogin=FALSE,
#' datadisks=datadisks,
#' nsg=nsg,
#' properties=list(licenseType="Windows_Client")
#' )
#' sub$create_vm("mywin10vm", user, size="Standard_DS2_v2", config=config,
#' location="australiaeast")
#'
#'
#' # default Ubuntu scaleset:
#' # load balancer and autoscaler enabled, Standard_DS1_v2
#' sub$create_vm_scaleset("mydsvmss", user_config("myname", "~/.ssh/id_rsa.pub"),
#' instances=5,
#' location="australiaeast"))
#'
#' # Ubuntu DSVM scaleset with public GPU-enabled instances, no load balancer or autoscaler
#' sub$create_vm_scaleset("mydsvmss", user_config("myname", "~/.ssh/id_rsa.pub"),
#' instances=5, size="Standard_NC12", config="ubuntu_dsvm_ss",
#' options=scaleset_options(public=TRUE),
#' load_balancer=NULL, autoscaler=NULL,
#' location="australiaeast")
#'
#' # RHEL scaleset, allow http/https access
#' sub$create_vm_scaleset("myrhelss", user_config("myname", "~/.ssh/id_rsa.pub"),
#' instances=5, config="rhel_8_ss",
#' nsg=nsg_config(list(nsg_rule_allow_http, nsg_rule_allow_https)),
#' location="australiaeast")
#'
#' # Large Debian scaleset, using low-priority VMs
#' # need to set the instance size to something that supports low-pri
#' sub$create_vm_scaleset("mydebss", user_config("myname", "~/.ssh/id_rsa.pub"),
#' instances=50, size="Standard_DS3_v2", config="debian_9_backports_ss",
#' options=scaleset_options(low_priority=TRUE, large_scaleset=TRUE),
#' location="australiaeast")
#'
#'
#' ## VM and scaleset in the same resource group and virtual network
#' # first, create the resgroup
#' rg <- sub$create_resource_group("rgname", "australiaeast")
#'
#' # create the master
#' rg$create_vm("mastervm", user_config("myname", "~/.ssh/id_rsa.pub"))
#'
#' # get the vnet resource
#' vnet <- rg$get_resource(type="Microsoft.Network/virtualNetworks", name="mastervm-vnet")
#'
#' # create the scaleset
#' rg$create_vm_scaleset("slavess", user_config("myname", "~/.ssh/id_rsa.pub"),
#' instances=5, vnet=vnet, nsg=NULL, load_balancer=NULL, autoscaler=NULL)
#' #'
#' } #' }
#' @rdname create_vm #' @rdname create_vm
#' @aliases create_vm create_vm_cluster #' @aliases create_vm create_vm_scaleset
#' @name create_vm #' @name create_vm
NULL NULL
@ -224,22 +271,17 @@ NULL
#' resource_group = name) #' resource_group = name)
#' #'
#' ## R6 method for class 'az_resource_group' #' ## R6 method for class 'az_resource_group'
#' delete_vm_cluster(name, confirm = TRUE, free_resources = TRUE) #' delete_vm_scaleset(name, confirm = TRUE, free_resources = TRUE)
#' #'
#' ## R6 method for class 'az_subscription' #' ## R6 method for class 'az_subscription'
#' delete_vm_cluster(name, confirm = TRUE, free_resources = TRUE, #' delete_vm_scaleset(name, confirm = TRUE, free_resources = TRUE,
#' resource_group = name) #' resource_group = name)
#' ``` #' ```
#' @section Arguments: #' @section Arguments:
#' - `name`: The name of the VM or cluster. #' - `name`: The name of the VM or scaleset.
#' - `confirm`: Whether to confirm the delete. #' - `confirm`: Whether to confirm the delete.
#' - `free_resources`: If this was a deployed template, whether to free all resources created during the deployment process. #' - `free_resources`: If this was a deployed template, whether to free all resources created during the deployment process.
#' - `resource_group`: For the `AzureRMR::az_subscription` method, the resource group containing the VM or cluster. #' - `resource_group`: For the `AzureRMR::az_subscription` method, the resource group containing the VM or scaleset.
#'
#' @section Details:
#' If the VM or cluster is of class [az_vm_template] and was created in exclusive mode, this method deletes the entire resource group that it occupies. This automatically frees all resources that were created during the deployment process. Otherwise, if `free_resources=TRUE`, it manually deletes each individual resource in turn. This is done synchronously (the method does not return until the deletion is complete) to allow for dependencies.
#'
#' If the VM is of class [az_vm_resource], this method only deletes the VM resource itself, not any other resources it may depend on.
#' #'
#' @seealso #' @seealso
#' [create_vm], [az_vm_template], [az_vm_resource], #' [create_vm], [az_vm_template], [az_vm_resource],
@ -248,16 +290,15 @@ NULL
#' @examples #' @examples
#' \dontrun{ #' \dontrun{
#' #'
#' sub <- AzureRMR::az_rm$ #' sub <- AzureRMR::get_azure_login()$
#' new(tenant="myaadtenant.onmicrosoft.com", app="app_id", password="password")$
#' get_subscription("subscription_id") #' get_subscription("subscription_id")
#' #'
#' sub$delete_vm("myWindowsDSVM") #' sub$delete_vm("myvm")
#' sub$delete_vm("myLinuxDSVM") #' sub$delete_vm_scaleset("myscaleset")
#' #'
#' } #' }
#' @rdname delete_vm #' @rdname delete_vm
#' @aliases delete_vm delete_vm_cluster #' @aliases delete_vm delete_vm_scaleset
#' @name delete_vm #' @name delete_vm
NULL NULL
@ -267,6 +308,7 @@ NULL
{ {
add_sub_methods() add_sub_methods()
add_rg_methods() add_rg_methods()
add_defunct_methods()
} }
@ -288,20 +330,8 @@ add_sub_methods <- function()
else sapply(res$value, `[[`, "name") else sapply(res$value, `[[`, "name")
}) })
az_subscription$set("public", "create_vm", overwrite=TRUE,
az_subscription$set("public", "create_vm", overwrite=TRUE, function(...) function(name, ..., resource_group=name, location)
{
self$create_vm_cluster(..., clust_size=1)
})
az_subscription$set("public", "create_vm_cluster", overwrite=TRUE,
function(name, location, resource_group=name,
os=c("Windows", "Ubuntu"), size="Standard_DS3_v2",
username, passkey, userauth_type=c("password", "key"),
ext_file_uris=NULL, inst_command=NULL,
clust_size, template, parameters,
..., wait=TRUE)
{ {
if(!is_resource_group(resource_group)) if(!is_resource_group(resource_group))
{ {
@ -320,11 +350,7 @@ add_sub_methods <- function()
} }
else mode <- "Incremental" # if passed a resource group object, assume it already exists in Azure else mode <- "Incremental" # if passed a resource group object, assume it already exists in Azure
res <- try(resource_group$create_vm_cluster(name, os=os, size=size, res <- try(resource_group$create_vm(name, ..., mode=mode))
username=username, passkey=passkey, userauth_type=userauth_type,
ext_file_uris=ext_file_uris, inst_command=inst_command,
clust_size=clust_size, template=template, parameters=parameters,
..., wait=wait, mode=mode))
if(inherits(res, "try-error") && mode == "Complete") if(inherits(res, "try-error") && mode == "Complete")
{ {
@ -334,6 +360,35 @@ add_sub_methods <- function()
res res
}) })
az_subscription$set("public", "create_vm_scaleset", overwrite=TRUE,
function(name, ..., resource_group=name, location)
{
if(!is_resource_group(resource_group))
{
rgnames <- names(self$list_resource_groups())
if(resource_group %in% rgnames)
{
resource_group <- self$get_resource_group(resource_group)
mode <- "Incremental"
}
else
{
message("Creating resource group '", resource_group, "'")
resource_group <- self$create_resource_group(resource_group, location=location)
mode <- "Complete"
}
}
else mode <- "Incremental" # if passed a resource group object, assume it already exists in Azure
res <- try(resource_group$create_vm_scaleset(name, ..., mode=mode))
if(inherits(res, "try-error") && mode == "Complete")
{
resource_group$delete(confirm=FALSE)
stop("Unable to create VM scaleset", call.=FALSE)
}
res
})
az_subscription$set("public", "get_vm", overwrite=TRUE, az_subscription$set("public", "get_vm", overwrite=TRUE,
function(name, resource_group=name) function(name, resource_group=name)
@ -344,14 +399,13 @@ add_sub_methods <- function()
resource_group$get_vm(name) resource_group$get_vm(name)
}) })
az_subscription$set("public", "get_vm_scaleset", overwrite=TRUE,
az_subscription$set("public", "get_vm_cluster", overwrite=TRUE,
function(name, resource_group=name) function(name, resource_group=name)
{ {
if(!is_resource_group(resource_group)) if(!is_resource_group(resource_group))
resource_group <- self$get_resource_group(resource_group) resource_group <- self$get_resource_group(resource_group)
resource_group$get_vm_cluster(name) resource_group$get_vm_scaleset(name)
}) })
az_subscription$set("public", "delete_vm", overwrite=TRUE, az_subscription$set("public", "delete_vm", overwrite=TRUE,
@ -363,41 +417,13 @@ add_sub_methods <- function()
resource_group$delete_vm(name, confirm=confirm, free_resources=free_resources) resource_group$delete_vm(name, confirm=confirm, free_resources=free_resources)
}) })
az_subscription$set("public", "delete_vm_scaleset", overwrite=TRUE,
az_subscription$set("public", "delete_vm_cluster", overwrite=TRUE,
function(name, confirm=TRUE, free_resources=TRUE, resource_group=name) function(name, confirm=TRUE, free_resources=TRUE, resource_group=name)
{ {
if(!is_resource_group(resource_group)) if(!is_resource_group(resource_group))
resource_group <- self$get_resource_group(resource_group) resource_group <- self$get_resource_group(resource_group)
resource_group$delete_vm_cluster(name, confirm=confirm, free_resources=free_resources) resource_group$delete_vm_scaleset(name, confirm=confirm, free_resources=free_resources)
})
az_subscription$set("public", "list_vms", overwrite=TRUE, function()
{
provider <- "Microsoft.Compute"
path <- "virtualMachines"
api_version <- self$get_provider_api_version(provider, path)
op <- file.path("providers", provider, path)
cont <- call_azure_rm(self$token, self$id, op, api_version=api_version)
lst <- lapply(cont$value,
function(parms) AzureVM::az_vm_resource$new(self$token, self$id, deployed_properties=parms))
# keep going until paging is complete
while(!is_empty(cont$nextLink))
{
cont <- call_azure_url(self$token, cont$nextLink)
lst <- lapply(cont$value,
function(parms) AzureVM::az_vm_resource$new(self$token, self$id, deployed_properties=parms))
}
# namespace shenanigans: get unexported function from AzureVM
convert_to_vm_template <- get("convert_to_vm_template", loadNamespace("AzureVM"))
# get templates corresponding to raw VMs (if possible)
lapply(named_list(lst), convert_to_vm_template)
}) })
} }
@ -405,138 +431,146 @@ add_sub_methods <- function()
# extend resource group methods # extend resource group methods
add_rg_methods <- function() add_rg_methods <- function()
{ {
az_resource_group$set("public", "create_vm", overwrite=TRUE, function(...) az_resource_group$set("public", "create_vm", overwrite=TRUE,
function(name, login_user, size="Standard_DS3_v2", config="ubuntu_18.04", managed=TRUE, datadisks=numeric(0),
..., template, parameters, mode="Incremental", wait=TRUE)
{ {
self$create_vm_cluster(..., clust_size=1) stopifnot(inherits(login_user, "user_config"))
})
if(is.character(config))
config <- get(config, getNamespace("AzureVM"))
if(is.function(config))
config <- config(!is_empty(login_user$key), managed, datadisks, ...)
az_resource_group$set("public", "create_vm_cluster", overwrite=TRUE, stopifnot(inherits(config, "vm_config"))
function(name, os=c("Windows", "Ubuntu"), size="Standard_DS3_v2",
username, passkey, userauth_type=c("password", "key"),
ext_file_uris=NULL, inst_command=NULL,
clust_size, template, parameters,
..., wait=TRUE)
{
# namespace shenanigans: get unexported functions from AzureVM
get_dsvm_template <- get("get_dsvm_template", loadNamespace("AzureVM"))
make_dsvm_param_list <- get("make_dsvm_param_list", loadNamespace("AzureVM"))
os <- match.arg(os)
userauth_type <- match.arg(userauth_type)
if(missing(parameters) && (missing(username) || missing(passkey)))
stop("Must supply login username and password/private key", call.=FALSE)
# find template given input args
if(missing(template)) if(missing(template))
template <- get_dsvm_template(os, userauth_type, clust_size, ext_file_uris, inst_command) template <- build_template_definition(config)
# convert input args into parameter list for template
if(missing(parameters)) if(missing(parameters))
parameters <- make_dsvm_param_list(name=name, size=size, parameters <- build_template_parameters(config, name, login_user, size)
username=username, userauth_type=userauth_type, passkey=passkey,
ext_file_uris=ext_file_uris, inst_command=inst_command,
clust_size=clust_size, template=template)
AzureVM::az_vm_template$new(self$token, self$subscription, self$name, name, az_vm_template$new(self$token, self$subscription, self$name, name,
template=template, parameters=parameters, ..., wait=wait) template=template, parameters=parameters, mode=mode, wait=wait)
}) })
az_resource_group$set("public", "create_vm_scaleset", overwrite=TRUE,
function(name, login_user, instances, size="Standard_DS1_v2", config="ubuntu_18.04_ss",
..., template, parameters, mode="Incremental", wait=TRUE)
{
stopifnot(inherits(login_user, "user_config"))
if(is.character(config))
config <- get(config, getNamespace("AzureVM"))
if(is.function(config))
config <- config(...)
stopifnot(inherits(config, "vmss_config"))
if(missing(template))
template <- build_template_definition(config)
if(missing(parameters))
parameters <- build_template_parameters(config, name, login_user, size, instances)
az_vmss_template$new(self$token, self$subscription, self$name, name,
template=template, parameters=parameters, mode=mode, wait=wait)
})
az_resource_group$set("public", "get_vm", overwrite=TRUE, az_resource_group$set("public", "get_vm", overwrite=TRUE,
function(name) function(name)
{ {
res <- try(AzureVM::az_vm_template$new(self$token, self$subscription, self$name, name), silent=TRUE) az_vm_template$new(self$token, self$subscription, self$name, name)
# if we couldn't find a VM deployment template, get the raw VM resource
if(inherits(res, "try-error"))
{
warning("No deployment template found for VM '", name, "'", call.=FALSE)
res <- AzureVM::az_vm_resource$new(self$token, self$subscription, self$name,
type="Microsoft.Compute/virtualMachines", name=name)
}
res
}) })
az_resource_group$set("public", "get_vm_scaleset", overwrite=TRUE,
az_resource_group$set("public", "get_vm_cluster", overwrite=TRUE,
function(name) function(name)
{ {
AzureVM::az_vm_template$new(self$token, self$subscription, self$name, name) az_vmss_template$new(self$token, self$subscription, self$name, name)
}) })
az_resource_group$set("public", "delete_vm", overwrite=TRUE, az_resource_group$set("public", "delete_vm", overwrite=TRUE,
function(name, confirm=TRUE, free_resources=TRUE) function(name, confirm=TRUE, free_resources=TRUE)
{ {
vm <- self$get_vm(name) self$get_vm(name)$delete(confirm=confirm, free_resources=free_resources)
if(is_vm_template(vm))
vm$delete(confirm=confirm, free_resources=free_resources)
else vm$delete(confirm=confirm)
}) })
az_resource_group$set("public", "delete_vm_scaleset", overwrite=TRUE,
az_resource_group$set("public", "delete_vm_cluster", overwrite=TRUE,
function(name, confirm=TRUE, free_resources=TRUE) function(name, confirm=TRUE, free_resources=TRUE)
{ {
self$get_vm_cluster(name)$delete(confirm=confirm, free_resources=free_resources) self$get_vm_scaleset(name)$delete(confirm=confirm, free_resources=free_resources)
}) })
az_resource_group$set("public", "list_vms", overwrite=TRUE, function()
{
provider <- "Microsoft.Compute"
path <- "virtualMachines"
api_version <- az_subscription$
new(self$token, self$subscription)$
get_provider_api_version(provider, path)
op <- file.path("resourceGroups", self$name, "providers", provider, path)
cont <- call_azure_rm(self$token, self$subscription, op, api_version=api_version)
lst <- lapply(cont$value,
function(parms) AzureVM::az_vm_resource$new(self$token, self$subscription, deployed_properties=parms))
# keep going until paging is complete
while(!is_empty(cont$nextLink))
{
cont <- call_azure_url(self$token, cont$nextLink)
lst <- lapply(cont$value,
function(parms) AzureVM::az_vm_resource$new(self$token, self$subscription, deployed_properties=parms))
}
# namespace shenanigans: get unexported function from AzureVM
convert_to_vm_template <- get("convert_to_vm_template", loadNamespace("AzureVM"))
# get templates corresponding to raw VMs (if possible)
lapply(named_list(lst), convert_to_vm_template)
})
az_resource_group$set("public", "list_vm_sizes", overwrite=TRUE, az_resource_group$set("public", "list_vm_sizes", overwrite=TRUE,
function(name_only=FALSE) function(name_only=FALSE)
{ {
az_subscription$ az_subscription$
new(self$token, self$subscription)$ new(self$token, parms=list(subscriptionId=self$subscription))$
list_vm_sizes(self$location, name_only=name_only) list_vm_sizes(self$location, name_only=name_only)
}) })
az_resource_group$set("public", "get_vm_resource", overwrite=TRUE,
function(name)
{
az_vm_resource$new(self$token, self$subscription, self$name,
type="Microsoft.Compute/virtualMachines", name=name)
})
az_resource_group$set("public", "get_vm_scaleset_resource", overwrite=TRUE,
function(name)
{
az_vmss_resource$new(self$token, self$subscription, self$name,
type="Microsoft.Compute/virtualMachineScalesets", name=name)
})
} }
convert_to_vm_template <- function(vm_resource)
{
token <- vm_resource$token
subscription <- vm_resource$subscription
resource_group <- vm_resource$resource_group
name <- vm_resource$name
tpl <- try(AzureVM::az_vm_template$new(token, subscription, resource_group, name), silent=TRUE) #' Defunct methods
if(!inherits(tpl, "try-error") && #'
!is_empty(tpl$properties$outputResources) && #' @section Usage:
grepl(sprintf("providers/Microsoft.Compute/virtualMachines/%s$", name), #' ```
tpl$properties$outputResources[[1]]$id, ignore.case=TRUE)) #' get_vm_cluster(...)
tpl #' create_vm_cluster(...)
else vm_resource #' delete_vm_cluster(...)
#' ```
#' These methods for the `az_subscription` and `az_resource_group` classes are defunct in AzureVM 2.0. To work with virtual machine clusters, call the [get_vm_scaleset], [create_vm_scaleset] and [delete_vm_scaleset] methods instead.
#' @rdname defunct
#' @name defunct
#' @aliases get_vm_cluster create_vm_cluster delete_vm_cluster
NULL
add_defunct_methods <- function()
{
az_subscription$set("public", "get_vm_cluster", overwrite=TRUE, function(...)
{
.Defunct(msg="The 'get_vm_cluster' method is defunct.\nUse 'get_vm_scaleset' instead.")
})
az_subscription$set("public", "create_vm_cluster", overwrite=TRUE, function(...)
{
.Defunct(msg="The 'create_vm_cluster' method is defunct.\nUse 'create_vm_scaleset' instead.")
})
az_subscription$set("public", "delete_vm_cluster", overwrite=TRUE, function(...)
{
.Defunct(msg="The 'delete_vm_cluster' method is defunct.\nUse 'delete_vm_scaleset' instead.")
})
az_resource_group$set("public", "get_vm_cluster", overwrite=TRUE, function(...)
{
.Defunct(msg="The 'get_vm_cluster' method is defunct.\nUse 'get_vm_scaleset' instead.")
})
az_resource_group$set("public", "create_vm_cluster", overwrite=TRUE, function(...)
{
.Defunct(msg="The 'create_vm_cluster' method is defunct.\nUse 'create_vm_scaleset' instead.")
})
az_resource_group$set("public", "delete_vm_cluster", overwrite=TRUE, function(...)
{
.Defunct(msg="The 'delete_vm_cluster' method is defunct.\nUse 'delete_vm_scaleset' instead.")
})
} }

81
R/autoscaler_config.R Normal file
Просмотреть файл

@ -0,0 +1,81 @@
#' Autoscaler configuration
#'
#' @param profiles A list of autoscaling profiles, each obtained via a call to `autoscaler_profile`.
#' @param ... Other named arguments that will be treated as resource properties.
#' @param name For `autoscaler_profile`, a name for the profile.
#' @param minsize,maxsize,default For `autoscaler_profile`, the minimum, maximum and default number of instances.
#' @param scale_out,scale_in For `autoscaler_profile`, the percentage CPU at which to scale out and in, respectively.
#' @param interval For `autoscaler_profile`, The interval between samples, in ISO 8601 format. The default is 1 minute.
#' @param window For `autoscaler_profile`, the window width over which to compute the percentage CPU. The default is 5 minutes.
#'
#' @seealso
#' [create_vm_scaleset], [vmss_config]
#' @export
autoscaler_config <- function(profiles=list(autoscaler_profile()), ...)
{
props <- list(profiles=profiles, ...)
structure(list(properties=props), class="as_config")
}
build_resource_fields.as_config <- function(config, ...)
{
config$properties$profiles <- lapply(config$properties$profiles, unclass)
utils::modifyList(as_default, config)
}
add_template_variables.as_config <- function(config, ...)
{
name <- "[concat(parameters('vmName'), '-as')]"
id <- "[resourceId('Microsoft.Insights/autoscaleSettings', variables('asName'))]"
ref <- "[concat('Microsoft.Insights/autoscaleSettings/', variables('asName'))]"
capacity <- "[mul(int(parameters('instanceCount')), 10)]"
scaleval <- "[max(div(int(parameters('instanceCount')), 5), 1)]"
list(asName=name, asId=id, asRef=ref, asMaxCapacity=capacity, asScaleValue=scaleval)
}
#' @rdname autoscaler_config
#' @export
autoscaler_profile <- function(name="Profile", minsize=1, maxsize=NA, default=NA, scale_out=0.75, scale_in=0.25,
interval="PT1M", window="PT5M")
{
if(is.na(maxsize))
maxsize <- "[variables('asMaxCapacity')]"
if(is.na(default))
default <- "[parameters('instanceCount')]"
capacity <- list(minimum=minsize, maximum=maxsize, default=default)
trigger <- list(
metricName="Percentage CPU",
metricNamespace="",
metricResourceUri="[variables('vmId')]",
timeGrain=interval,
timeWindow=window,
statistic="Average",
timeAggregation="Average"
)
action <- list(
type="ChangeCount",
value="[variables('asScaleValue')]",
cooldown=interval
)
rule_out <- list(metricTrigger=trigger, scaleAction=action)
rule_out$metricTrigger$operator <- "GreaterThan"
rule_out$metricTrigger$threshold <- round(scale_out * 100)
rule_out$scaleAction$direction <- "Increase"
rule_in <- list(metricTrigger=trigger, scaleAction=action)
rule_in$metricTrigger$operator <- "LessThan"
rule_in$metricTrigger$threshold <- round(scale_in * 100)
rule_in$scaleAction$direction <- "Decrease"
prof <- list(
name=name,
capacity=capacity,
rules=list(rule_out, rule_in)
)
structure(prof, class="as_profile_config")
}

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

@ -5,25 +5,29 @@
#' @docType class #' @docType class
#' @section Methods: #' @section Methods:
#' The following methods are available, in addition to those provided by the [AzureRMR::az_resource] class: #' The following methods are available, in addition to those provided by the [AzureRMR::az_resource] class:
#' - `new(...)`: Initialize a new VM object.
#' - `start(wait=TRUE)`: Start the VM. By default, wait until the startup process is complete. #' - `start(wait=TRUE)`: Start the VM. By default, wait until the startup process is complete.
#' - `stop(deallocate=TRUE, wait=FALSE)`: Stop the VM. By default, deallocate it as well. #' - `stop(deallocate=TRUE, wait=FALSE)`: Stop the VM. By default, deallocate it as well.
#' - `restart(wait=TRUE)`: Restart the VM. #' - `restart(wait=TRUE)`: Restart the VM.
#' - `run_deployed_command(command, parameters, script)`: Run a PowerShell command on the VM. #' - `run_deployed_command(command, parameters, script)`: Run a PowerShell command on the VM.
#' - `run_script(script, parameters)`: 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. #' - `run_script(script, parameters)`: 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.
#' - `sync_vm_status()`: Update the VM status fields in this object with information from the host. #' - `sync_vm_status()`: Check the status of the VM.
#' - `resize(size, deallocate=FALSE, wait=FALSE)`: Resize the VM. Optionally deallocate it first (may sometimes be necessary). #' - `resize(size, deallocate=FALSE, wait=FALSE)`: Resize the VM. Optionally stop and deallocate it first (may sometimes be necessary).
#' - `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.
#' - `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.
#' #'
#' @seealso #' @seealso
#' [AzureRMR::az_resource], #' [AzureRMR::az_resource], [get_vm_resource], [az_vm_template]
#'
#' [VM API reference](https://docs.microsoft.com/en-us/rest/api/compute/virtualmachines) #' [VM API reference](https://docs.microsoft.com/en-us/rest/api/compute/virtualmachines)
#' @format An R6 object of class `az_vm_resource`, inheriting from `AzureRMR::az_resource`. #' @format An R6 object of class `az_vm_resource`, inheriting from `AzureRMR::az_resource`.
#' @export #' @export
az_vm_resource <- R6::R6Class("az_vm_resource", inherit=AzureRMR::az_resource, az_vm_resource <- R6::R6Class("az_vm_resource", inherit=AzureRMR::az_resource,
public=list( public=list(
disks=NULL,
status=NULL, status=NULL,
nic_api_version="2019-04-01", # need to record this since AzureRMR can't currently get API versions for subresources
sync_vm_status=function() sync_vm_status=function()
{ {
@ -36,30 +40,26 @@ public=list(
self$sync_fields() self$sync_fields()
res <- self$do_operation("instanceView", http_verb="GET") res <- self$do_operation("instanceView")
self$status <- get_status(res$statuses) self$status <- get_status(res$statuses)
disks <- named_list(res$disks) self$status
self$disks <- lapply(disks, function(d) get_status(d$status))
invisible(NULL)
}, },
start=function(wait=TRUE) start=function(wait=TRUE)
{ {
message("Starting VM '", self$name, "'")
self$do_operation("start", http_verb="POST") self$do_operation("start", http_verb="POST")
Sys.sleep(2) # Sys.sleep(2)
if(wait) if(wait)
{ {
for(i in 1:100) for(i in 1:100)
{ {
Sys.sleep(5)
self$sync_vm_status() self$sync_vm_status()
if(length(self$status) == 2 && if(length(self$status) == 2 &&
self$status[1] == "succeeded" && self$status[1] == "succeeded" &&
self$status[2] == "running") self$status[2] == "running")
break break
Sys.sleep(5)
} }
if(length(self$status) < 2 || if(length(self$status) < 2 ||
self$status[1] != "succeeded" || self$status[1] != "succeeded" ||
@ -70,19 +70,18 @@ public=list(
restart=function(wait=TRUE) restart=function(wait=TRUE)
{ {
message("Restarting VM '", self$name, "'")
self$do_operation("restart", http_verb="POST") self$do_operation("restart", http_verb="POST")
Sys.sleep(2) # Sys.sleep(2)
if(wait) if(wait)
{ {
for(i in 1:100) for(i in 1:100)
{ {
Sys.sleep(5)
self$sync_vm_status() self$sync_vm_status()
if(length(self$status) == 2 && if(length(self$status) == 2 &&
self$status[1] == "succeeded" && self$status[1] == "succeeded" &&
self$status[2] == "running") self$status[2] == "running")
break break
Sys.sleep(5)
} }
if(length(self$status) < 2 || if(length(self$status) < 2 ||
self$status[1] != "succeeded" || self$status[1] != "succeeded" ||
@ -93,12 +92,6 @@ public=list(
stop=function(deallocate=TRUE, wait=FALSE) stop=function(deallocate=TRUE, wait=FALSE)
{ {
msg <- "Shutting down"
if(deallocate)
msg <- paste(msg, "and deallocating")
msg <- paste0(msg, " VM '", self$name, "'")
message(msg)
self$do_operation("powerOff", http_verb="POST") self$do_operation("powerOff", http_verb="POST")
if(deallocate) if(deallocate)
self$do_operation("deallocate", http_verb="POST") self$do_operation("deallocate", http_verb="POST")
@ -106,21 +99,16 @@ public=list(
{ {
for(i in 1:100) for(i in 1:100)
{ {
Sys.sleep(5)
self$sync_vm_status() self$sync_vm_status()
if(length(self$status) < 2 || self$status[2] %in% c("stopped", "deallocated")) if(length(self$status) < 2 || self$status[2] %in% c("stopped", "deallocated"))
break break
Sys.sleep(5)
} }
if(length(self$status) == 2 && !(self$status[2] %in% c("stopped", "deallocated"))) if(length(self$status) == 2 && !(self$status[2] %in% c("stopped", "deallocated")))
stop("Unable to shut down VM", call.=FALSE) stop("Unable to shut down VM", call.=FALSE)
} }
}, },
add_extension=function(...)
{
stop("This function is not yet implemented", call.=FALSE)
},
resize=function(size, deallocate=FALSE, wait=FALSE) resize=function(size, deallocate=FALSE, wait=FALSE)
{ {
if(deallocate) if(deallocate)
@ -144,15 +132,13 @@ public=list(
} }
}, },
run_deployed_command=function(command=NULL, parameters=NULL, script=NULL) run_deployed_command=function(command, parameters=NULL, script=NULL)
{ {
if(is_empty(command))
stop("Must supply a command to run", call.=FALSE)
body <- list(commandId=command, parameters=parameters, script=script) body <- list(commandId=command, parameters=parameters, script=script)
self$do_operation("runCommand", body=body, encode="json", http_verb="POST") self$do_operation("runCommand", body=body, encode="json", http_verb="POST")
}, },
run_script=function(script=NULL, parameters=NULL) run_script=function(script, parameters=NULL)
{ {
os_prof_names <- names(self$properties$osProfile) os_prof_names <- names(self$properties$osProfile)
windows <- any(grepl("windows", os_prof_names, ignore.case=TRUE)) windows <- any(grepl("windows", os_prof_names, ignore.case=TRUE))
@ -164,6 +150,45 @@ public=list(
self$run_deployed_command(cmd, as.list(parameters), as.list(script)) self$run_deployed_command(cmd, as.list(parameters), as.list(script))
}, },
get_public_ip_address=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(NA_character_)
ip <- az_resource$new(self$token, self$subscription, id=ip_id)$properties$ipAddress
if(is.null(ip))
NA_character_
else ip
},
get_private_ip_address=function(nic=1, config=1)
{
nic <- private$get_nic(nic)
nic$properties$ipConfigurations[[config]]$properties$privateIPAddress
},
add_extension=function(publisher, type, version, settings=list(),
protected_settings=list(), key_vault_settings=list())
{
name <- gsub("[[:punct:]]", "", type)
op <- file.path("extensions", name)
props <- list(
publisher=publisher,
type=type,
typeHandlerVersion=version,
autoUpgradeMinorVersion=TRUE,
settings=settings
)
if(!is_empty(protected_settings))
props$protectedSettings <- protected_settings
if(!is_empty(key_vault_settings))
props$protectedSettingsFromKeyVault <- key_vault_settings
self$do_operation(op, body=list(properties=props), http_verb="PUT")
},
print=function(...) print=function(...)
{ {
cat("<Azure virtual machine resource ", self$name, ">\n", sep="") cat("<Azure virtual machine resource ", self$name, ">\n", sep="")
@ -179,41 +204,22 @@ public=list(
cat("---\n") cat("---\n")
cat(AzureRMR::format_public_fields(self, cat(AzureRMR::format_public_fields(self,
exclude=c("subscription", "resource_group", "type", "name", "status", "is_synced"))) exclude=c("subscription", "resource_group", "type", "name", "status", "is_synced", "nic_api_version")))
cat(AzureRMR::format_public_methods(self)) cat(AzureRMR::format_public_methods(self))
invisible(NULL) invisible(NULL)
},
# add custom deletion method to handle managed disks
delete=function(..., confirm=TRUE, wait=TRUE)
{
managed_disks <- c(
self$properties$storageProfile$osDisk$managedDisk$id,
lapply(self$properties$storageProfile$dataDisks,
function(x) x$managedDisk$id)
)
super$delete(..., confirm=confirm, wait=wait)
if(!is_empty(managed_disks))
{
md_api_ver <- named_list(
call_azure_rm(self$token, self$subscription, "providers/Microsoft.Compute")$
resourceTypes, "resourceType"
)$
disks$
apiVersions[[1]]
lapply(managed_disks, function(id)
az_resource$
new(self$token, self$subscription, id=id, deployed_properties=list(NULL))$
delete(confirm=confirm, wait=wait)
)
}
} }
), ),
private=list( private=list(
get_nic=function(n=1)
{
nic_id <- self$properties$networkProfile$networkInterfaces[[n]]$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)
},
init_and_deploy=function(...) init_and_deploy=function(...)
{ {
stop("Do not use 'az_vm_resource' to create a new VM", call.=FALSE) stop("Do not use 'az_vm_resource' to create a new VM", call.=FALSE)

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

@ -1,55 +1,45 @@
#' Virtual machine cluster template class #' Virtual machine template class
#' #'
#' Class representing a virtual machine template. This class keeps track of all resources that are created as part of deploying a VM or cluster of VMs, and exposes methods for managing them. In this page, "VM" refers to both a cluster of virtual machines, as well as a single virtual machine (which is treated as the special case of a cluster containing a single node). #' 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.
#' #'
#' @docType class #' @docType class
#' @section Methods: #' @section Methods:
#' The following methods are available, in addition to those provided by the [AzureRMR::az_template] class: #' The following methods are available, in addition to those provided by the [AzureRMR::az_template] class.
#' - `new(...)`: Initialize a new VM object. See 'Initialization' for more details.
#' - `start(wait=TRUE)`: Start the VM. By default, wait until the startup process is complete. #' - `start(wait=TRUE)`: Start the VM. By default, wait until the startup process is complete.
#' - `stop(deallocate=TRUE, wait=FALSE)`: Stop the VM. By default, deallocate it as well. #' - `stop(deallocate=TRUE, wait=FALSE)`: Stop the VM. By default, deallocate it as well.
#' - `restart(wait=TRUE)`: Restart the VM. #' - `restart(wait=TRUE)`: Restart the VM.
#' - `run_deployed_command(command, parameters, script)`: Run a PowerShell command on the VM. #' - `run_deployed_command(command, parameters, script)`: Run a PowerShell command on the VM.
#' - `run_script(script, parameters)`: 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. #' - `run_script(script, parameters)`: 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.
#' - `sync_vm_status()`: Update the VM status fields in this object with information from the host. #' - `sync_vm_status()`: Check the status of the VM.
#' - `resize(size, deallocate=FALSE, wait=FALSE)`: Resize the VM. Optionally deallocate it first (may sometimes be necessary). #' - `resize(size, deallocate=FALSE, wait=FALSE)`: Resize the VM. Optionally stop and deallocate it first (may sometimes be necessary).
#' #' - `get_public_ip_address(nic=1, config=1)`: Get the public IP address of the VM. Returns NULL if the VM is stopped, or is not publicly accessible.
#' @section Fields: #' - `get_private_ip_address(nic=1, config=1)`: Get the private IP address of the VM.
#' The following fields are available, in addition to those provided by the `AzureRMR::az_template` class. Each is a list with one element per node in the cluster. #' - `add_extension(publisher, type, version, settings=list(), protected_settings=list(), key_vault_settings=list())`: Add an extension to the VM.
#' - `disks`: The status of any attached disks. #' - `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.
#' - `ip_address`: The IP address. NULL if the node is currently deallocated.
#' - `dns_name`: The fully qualified domain name.
#' - `status`: The status of the node, giving the provisioning state and power state.
#' #'
#' @details #' @details
#' A single virtual machine in Azure is actually a collection of resources, including any and all of the following. A cluster can share a storage account and virtual network, but each individual node will still have its own IP address and network interface. #' The VM operations listed above are actually provided by the [az_vm_resource] class, and propagated to the template as active bindings.
#' - Storage account #'
#' - Network interface #' A single virtual machine in Azure is actually a collection of resources, including any and all of the following.
#' - Network security group #' - Network interface (Azure resource type `Microsoft.Network/networkInterfaces`)
#' - Virtual network #' - Network security group (Azure resource type `Microsoft.Network/networkSecurityGroups`)
#' - IP address #' - Virtual network (Azure resource type `Microsoft.Network/virtualNetworks`)
#' - The VM itself #' - Public IP address (Azure resource type `Microsoft.Network/publicIPAddresses`)
#' - The VM itself (Azure resource type `Microsoft.Compute/virtualMachines`)
#' #'
#' By wrapping the deployment template used to create these resources, the `az_vm_template` class allows managing them all as a single entity. #' By wrapping the deployment template used to create these resources, the `az_vm_template` class allows managing them all as a single entity.
#' #'
#' @section Initialization:
#' Initializing a new object of this class can either retrieve an existing VM template, or deploy a new VM template on the host. Generally, the best way to initialize an object is via the VM-related methods of the [az_subscription] and [az_resource_group] class, which handle the details automatically.
#'
#' A new VM can be created in _exclusive_ mode, meaning a new resource group is created solely to hold the VM. This simplifies deleting a VM considerably, as deleting the resource group will also automatically delete all the VM's resources. This can be done asynchronously, meaning that the `delete()` method returns immediately while the process continues on the host. Otherwise, deleting a VM will explicitly delete each of its resources, a task that must be done synchronously to allow for dependencies.
#'
#' @seealso #' @seealso
#' [AzureRMR::az_resource], [create_vm], [create_vm_cluster], [get_vm], [get_vm_cluster], [list_vms], #' [AzureRMR::az_template], [create_vm], [get_vm], [delete_vm]
#' [delete_vm], [delete_vm_cluster], #'
#' [VM API reference](https://docs.microsoft.com/en-us/rest/api/compute/virtualmachines) #' [VM API reference](https://docs.microsoft.com/en-us/rest/api/compute/virtualmachines)
#' #'
#' @examples #' @examples
#' \dontrun{ #' \dontrun{
#' #'
#' # recommended way to retrieve a VM: via a resource group or subscription object #' sub <- AzureRMR::get_azure_login()$
#' sub <- AzureRMR::az_rm$
#' new(tenant="myaadtenant.onmicrosoft.com", app="app_id", password="password")$
#' get_subscription("subscription_id") #' get_subscription("subscription_id")
#' #'
#' vm <- sub$get_vm("myLinuxDSVM") #' vm <- sub$get_vm("myLinuxDSVM")
#' #'
#' # start the VM #' # start the VM
@ -73,278 +63,129 @@
az_vm_template <- R6::R6Class("az_vm_template", inherit=az_template, az_vm_template <- R6::R6Class("az_vm_template", inherit=az_template,
public=list( public=list(
disks=NULL,
status=NULL,
ip_address=NULL,
dns_name=NULL, dns_name=NULL,
clust_size=NULL,
initialize=function(token, subscription, resource_group, name, ..., wait=TRUE) initialize=function(token, subscription, resource_group, name, ..., wait=TRUE)
{ {
super$initialize(token, subscription, resource_group, name, ..., wait=wait) super$initialize(token, subscription, resource_group, name, ..., wait=wait)
# fill in fields that don't require querying the host
num_instances <- self$properties$outputs$numInstances
if(is_empty(num_instances))
{
self$clust_size <- 1
vmnames <- self$name
}
else
{
self$clust_size <- as.numeric(num_instances$value)
vmnames <- paste0(self$name, seq_len(self$clust_size) - 1)
}
if(wait) if(wait)
{ {
private$vm <- sapply(vmnames, function(name) private$vm <- az_vm_resource$new(self$token, self$subscription, id=self$properties$outputs$vmResource$value)
{
az_vm_resource$new(self$token, self$subscription, self$resource_group,
type="Microsoft.Compute/virtualMachines", name=name)
}, simplify=FALSE)
# get the hostname/IP address for the VM # get the hostname/IP address for the VM
outputs <- unlist(self$properties$outputResources) outputs <- unlist(self$properties$outputResources)
ip_id <- grep("publicIPAddresses/.+$", outputs, ignore.case=TRUE, value=TRUE) ip_id <- grep("publicIPAddresses/.+$", outputs, ignore.case=TRUE, value=TRUE)
ip <- lapply(ip_id, function(id)
az_resource$new(self$token, self$subscription, id=id)$properties)
self$ip_address <- sapply(ip, function(x) x$ipAddress) if(!is_empty(ip_id))
self$dns_name <- sapply(ip, function(x) x$dnsSettings$fqdn)
lapply(private$vm, function(obj) obj$sync_vm_status())
self$disks <- lapply(private$vm, "[[", "disks")
self$status <- lapply(private$vm, "[[", "status")
NULL
}
else message("Deployment started. Call the sync_vm_status() method to track the status of the deployment.")
NULL
},
sync_vm_status=function()
{
if(is_empty(private$vm) || is_empty(self$status) || tolower(self$status[[1]][1]) != "succeeded")
{
res <- try(self$initialize(self$token, self$subscription, self$resource_group, self$name), silent=TRUE)
if(inherits(res, "try-error"))
{ {
message("VM deployment in progress") ip <- az_resource$new(self$token, self$subscription, id=ip_id)
return(invisible(NULL)) self$dns_name <- ip$properties$dnsSettings$fqdn
} }
} }
else message("Deployment started. Call the sync_vm_status() method to track the status of the deployment.")
lapply(private$vm, function(obj) obj$sync_vm_status())
self$disks <- lapply(private$vm, "[[", "disks")
self$status <- lapply(private$vm, "[[", "status")
self$status
},
start=function(wait=TRUE)
{
lapply(private$get_vm(), function(obj) obj$start(wait=wait))
self$sync_vm_status()
},
stop=function(deallocate=TRUE, wait=TRUE)
{
lapply(private$get_vm(), function(obj) obj$stop(deallocate=deallocate, wait=wait))
self$sync_vm_status()
},
restart=function(wait=TRUE)
{
lapply(private$get_vm(), function(obj) obj$restart(wait=wait))
self$sync_vm_status()
},
add_extension=function(...)
{
lapply(private$get_vm(), function(obj) obj$add_extension(...))
invisible(NULL)
},
resize=function(size, deallocate=FALSE, wait=FALSE)
{
lapply(private$get_vm(), function(obj) obj$resize(size, deallocate=deallocate, wait=wait))
invisible(NULL)
},
run_deployed_command=function(...)
{
lapply(private$get_vm(), function(obj) obj$run_deployed_command(...))
invisible(NULL)
},
run_script=function(...)
{
lapply(private$get_vm(), function(obj) obj$run_script(...))
invisible(NULL)
}, },
delete=function(confirm=TRUE, free_resources=TRUE) delete=function(confirm=TRUE, free_resources=TRUE)
{ {
# delete the resource group -- customised confirmation message # must reorder template output resources so that freeing resources will work
if(self$properties$mode == "Complete" && confirm && interactive()) private$reorder_for_delete()
{ super$delete(confirm=confirm, free_resources=free_resources)
vmtype <- if(self$clust_size == 1) "VM" else "VM cluster"
msg <- paste0("Do you really want to delete ", vmtype, " and resource group '", self$name, "'? (y/N) ")
yn <- readline(msg)
if(tolower(substr(yn, 1, 1)) != "y")
return(invisible(NULL))
super$delete(confirm=FALSE, free_resources=TRUE)
}
else
{
if(free_resources)
{
# delete individual resources
if(confirm && interactive())
{
vmtype <- if(self$clust_size == 1) "VM" else "VM cluster"
msg <- paste0("Do you really want to delete ", vmtype, " '", self$name, "'? (y/N) ")
yn <- readline(msg)
if(tolower(substr(yn, 1, 1)) != "y")
return(invisible(NULL))
}
lapply(private$vm, function(obj) obj$delete(confirm=FALSE, wait=TRUE))
super$delete(confirm=FALSE, free_resources=TRUE)
}
else super$delete(confirm=confirm, free_resources=FALSE)
}
}, },
print=function(...) print=function(...)
{ {
header <- "<Azure virtual machine " cat("<Azure virtual machine ", self$name, ">\n", sep="")
if(self$clust_size > 1)
header <- paste0(header, "cluster ")
cat(header, self$name, ">\n", sep="")
osProf <- names(private$vm[[1]]$properties$osProfile) osProf <- names(private$vm$properties$osProfile)
os <- if(any(grepl("linux", osProf))) "Linux" else if(any(grepl("windows", osProf))) "Windows" else "<unknown>" os <- if(any(grepl("linux", osProf))) "Linux" else if(any(grepl("windows", osProf))) "Windows" else "<unknown>"
exclusive <- self$properties$mode == "Complete" exclusive <- self$properties$mode == "Complete"
dns_label <- if(self$clust_size == 1) "Domain name:" else "Domain names:" status <- if(is_empty(private$vm$status))
dns_names <- if(is_empty(self$dns_name)) "<unknown>"
paste0(" ", dns_label, " <none>") else paste0(names(private$vm$status), "=", private$vm$status, collapse=", ")
else strwrap(paste(dns_label, paste0(self$dns_name, collapse=", ")),
width=0.8*getOption("width"), indent=2, exdent=4)
cat(" Operating system:", os, "\n") cat(" Operating system:", os, "\n")
cat(" Exclusive resource group:", exclusive, "\n") cat(" Exclusive resource group:", exclusive, "\n")
cat(paste0(dns_names, collapse="\n"), "\n", sep="") cat(" Domain name:", self$dns_name, "\n")
cat(" Status:") cat(" Status:", status, "\n")
if(is_empty(self$status) || is_empty(self$status[[1]]))
cat(" <unknown>\n")
else
{
prov_status <- as.data.frame(do.call(rbind, self$status))
row.names(prov_status) <- paste0(" ", row.names(prov_status))
cat("\n")
print(prov_status)
}
cat("---\n") cat("---\n")
exclude <- c("subscription", "resource_group", "name", "dns_name", "status") exclude <- c("subscription", "resource_group", "name", "dns_name")
if(self$clust_size == 1)
exclude <- c(exclude, "clust_size")
cat(AzureRMR::format_public_fields(self, exclude=exclude)) cat(AzureRMR::format_public_fields(self, exclude=exclude))
cat(AzureRMR::format_public_methods(self)) cat(AzureRMR::format_public_methods(self))
invisible(NULL) invisible(NULL)
} }
), ),
# propagate resource methods up to template
active=list(
sync_vm_status=function()
private$vm$sync_vm_status,
start=function()
private$vm$start,
stop=function()
private$vm$stop,
restart=function()
private$vm$restart,
add_extension=function()
private$vm$add_extension,
resize=function()
private$vm$resize,
run_deployed_command=function()
private$vm$run_deployed_command,
run_script=function()
private$vm$run_script,
get_public_ip_address=function()
private$vm$get_public_ip_address,
get_private_ip_address=function()
private$vm$get_private_ip_address,
do_vm_operation=function()
private$vm$do_operation
),
private=list( private=list(
vm=list(NULL), vm=NULL,
get_vm=function() reorder_for_delete=function()
{ {
if(is_empty(private$vm)) is_type <- function(id, type)
stop("VM deployment in progress", call.=FALSE)
private$vm
},
sync_vm_resources=function()
{
private$vm <- sapply(vmnames, function(name)
{ {
az_vm_resource$new(self$token, self$subscription, self$resource_group, grepl(type, id, fixed=TRUE)
type="Microsoft.Compute/virtualMachines", name=name) }
}, simplify=FALSE)
# get the hostname/IP address for the VM # insert managed disks into deletion queue
outputs <- unlist(self$properties$outputResources) stor <- private$vm$properties$storageProfile
ip_id <- grep("publicIPAddresses/.+$", outputs, ignore.case=TRUE, value=TRUE) managed_disks <- c(
ip <- lapply(ip_id, function(id) stor$osDisk$managedDisk$id,
az_resource$new(self$token, self$subscription, id=id)$properties) lapply(stor$dataDisks, function(x) x$managedDisk$id)
)
outs <- unique(c(unlist(self$properties$outputResources), unlist(managed_disks)))
self$ip_address <- sapply(ip, function(x) x$ipAddress) new_order <- sapply(outs, function(id)
self$dns_name <- sapply(ip, function(x) x$dnsSettings$fqdn) {
if(is_type(id, "Microsoft.Compute/virtualMachines")) 1
else if(is_type(id, "Microsoft.Compute/disks")) 2
else if(is_type(id, "Microsoft.Network/networkInterfaces")) 3
else if(is_type(id, "Microsoft.Network/virtualNetworks")) 4
else if(is_type(id, "Microsoft.Network/publicIPAddresses")) 5
else if(is_type(id, "Microsoft.Network/networkSecurityGroups")) 6
else 0 # delete all other resources first
})
lapply(private$vm, function(obj) obj$sync_vm_status()) outs <- outs[order(new_order)]
self$disks <- lapply(private$vm, "[[", "disks") self$properties$outputResources <- lapply(outs, function(x) list(id=x))
self$status <- lapply(private$vm, "[[", "status")
NULL
} }
)) ))
#' Is an object an Azure VM template
#'
#' @param object an R object.
#'
#' @details
#' This function returns TRUE only for an object representing a VM template deployment. In particular, it returns FALSE for a raw VM resource.
#'
#' @return
#' A boolean.
#' @export
is_vm_template <- function(object)
{
R6::is.R6(object) && inherits(object, "az_vm_template")
}
# arguments to this must be named
make_dsvm_param_list=function(...)
{
params <- list(...)
template <- tools::file_path_sans_ext(basename(params$template))
parm_map <- param_mappings[[template]]
# match supplied arguments to those expected by template
params <- params[names(params) %in% names(parm_map)]
names(params) <- parm_map[match(names(parm_map), names(params))]
lapply(params, function(x) list(value=as.character(x)))
}
get_dsvm_template=function(os, userauth_type, clust_size, ext_file_uris, inst_command)
{
if(os == "Ubuntu")
template <- "ubuntu_dsvm"
else if(os == "Windows")
template <- "win2016_dsvm"
else stop("Unknown OS: ", os, call.=FALSE)
if(clust_size > 1)
template <- paste0(template, "_cl")
if(userauth_type == "key")
template <- paste0(template, "_key")
if(!is_empty(ext_file_uris) || !is_empty(inst_command))
template <- paste0(template, "_ext")
template <- system.file("templates", paste0(template, ".json"), package="AzureVM")
if(template == "")
stop("Unsupported combination of parameters", call.=FALSE)
template
}

238
R/az_vmss_resource.R Normal file
Просмотреть файл

@ -0,0 +1,238 @@
#' Virtual machine scaleset resource class
#'
#' Class representing a virtual machine scaleset resource. In general, the methods in this class should not be called directly, nor should objects be directly instantiated from it. Use the `az_vmss_template` class for interacting with scalesets instead.
#'
#' @docType class
#' @section Methods:
#' The following methods are available, in addition to those provided by the [AzureRMR::az_template] class.
#' - `sync_vmss_status`: Check the status of the scaleset.
#' - `list_instances()`: Return a list of [az_vm_resource] objects, one for each VM instance in the scaleset. Note that if the scaleset has a load balancer attached, the number of instances will vary depending on the load.
#' - `get_instance(id)`: Return a specific VM instance in the scaleset.
#' - `start(id=NULL, wait=FALSE)`: Start the scaleset. In this and the other methods listed here, `id` can be an optional character vector of instance IDs; if supplied, only carry out the operation for those instances.
#' - `restart(id=NULL, wait=FALSE)`: Restart the scaleset.
#' - `stop(deallocate=TRUE, id=NULL, wait=FALSE)`: Stop the scaleset.
#' - `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 if the instances are 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.
#' - `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.
#' - `redeploy(id=NULL)`: Redeploy the instances in the scaleset.
#' - `mapped_vm_operation(..., id=NULL)`: Carry out an arbitrary operation on the instances in the scaleset. See the `do_operation` method of the [AzureRMR::az_resource] class for more details.
#' - `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).
#'
#' @seealso
#' [AzureRMR::az_resource], [get_vm_scaleset_resource], [az_vmss_template]
#'
#' [VM scaleset API reference](https://docs.microsoft.com/en-us/rest/api/compute/virtualmachinescalesets)
#' @format An R6 object of class `az_vmss_resource`, inheriting from `AzureRMR::az_resource`.
#' @export
az_vmss_resource <- R6::R6Class("az_vmss_resource", inherit=AzureRMR::az_resource,
public=list(
status=NULL,
sync_vmss_status=function(id=NULL)
{
instances <- self$list_instances()
if(!is.null(id))
instances <- instances[as.character(id)]
statuses <- private$vm_map(id, function(res)
{
status <- res$sync_vm_status()
if(length(status) < 2)
status <- c(status, NA)
status
})
self$status <- data.frame(id=names(statuses), do.call(rbind, statuses), stringsAsFactors=FALSE)
colnames(self$status) <- c("id", "ProvisioningState", "PowerState")
row.names(self$status) <- NULL
self$status
},
list_instances=function()
{
lst <- named_list(get_paged_list(self$do_operation("virtualMachines")), "instanceId")
lapply(lst, private$make_vm_resource)
},
get_instance=function(id)
{
obj <- self$do_operation(file.path("virtualMachines", id))
private$make_vm_resource(obj)
},
start=function(id=NULL, wait=FALSE)
{
body <- if(!is.null(id)) list(instanceIds=I(as.character(id))) else NULL
self$do_operation("start", body=body, http_verb="POST")
if(wait)
{
for(i in 1:100)
{
Sys.sleep(5)
status <- self$sync_vmss_status(id)
if(all(status$PowerState == "running"))
break
}
if(!all(status$PowerState == "running"))
stop("Unable to start VM scaleset", call.=FALSE)
}
},
restart=function(id=NULL, wait=FALSE)
{
body <- if(!is.null(id)) list(instanceIds=I(as.character(id))) else NULL
self$do_operation("restart", body=body, http_verb="POST")
if(wait)
{
for(i in 1:100)
{
Sys.sleep(5)
status <- self$sync_vmss_status(id)
if(all(status$PowerState == "running"))
break
}
if(!all(status$PowerState == "running"))
stop("Unable to restart VM scaleset", call.=FALSE)
}
},
stop=function(deallocate=TRUE, id=NULL, wait=FALSE)
{
body <- if(!is.null(id)) list(instanceIds=I(as.character(id))) else NULL
self$do_operation("powerOff", body=body, http_verb="POST")
if(deallocate)
self$do_operation("deallocate", body=body, http_verb="POST")
if(wait)
{
for(i in 1:100)
{
Sys.sleep(5)
status <- self$sync_vm_status(id)
if(all(status$PowerState %in% c("stopped", "deallocated")))
break
}
if(length(self$status) == 2 && !(self$status[2] %in% c("stopped", "deallocated")))
stop("Unable to shut down VM", call.=FALSE)
}
},
get_vm_public_ip_addresses=function(id=NULL, nic=1, config=1)
{
unlist(private$vm_map(id, function(vm) vm$get_public_ip_address(nic, config)))
},
get_vm_private_ip_addresses=function(id=NULL, nic=1, config=1)
{
unlist(private$vm_map(id, function(vm) vm$get_private_ip_address(nic, config)))
},
run_deployed_command=function(command, parameters=NULL, script=NULL, id=NULL)
{
private$vm_map(id, function(vm) vm$run_deployed_command(command, parameters, script))
},
run_script=function(script, parameters=NULL, id=NULL)
{
private$vm_map(id, function(vm) vm$run_script(script, parameters))
},
reimage=function(id=NULL, datadisks=FALSE)
{
op <- if(datadisks) "reimageall" else "reimage"
if(is.null(id))
self$do_operation(op, http_verb="POST")
else private$vm_map(id, function(vm) vm$do_operation(op, http_verb="POST"))
},
redeploy=function(id=NULL)
{
if(is.null(id))
self$do_operation("redeploy", http_verb="POST")
else private$vm_map(id, function(vm) vm$do_operation("redeploy", http_verb="POST"))
},
mapped_vm_operation=function(..., id=NULL)
{
private$vm_map(id, function(vm) vm$do_operation(...))
},
add_extension=function(publisher, type, version, settings=list(),
protected_settings=list(), key_vault_settings=list())
{
name <- gsub("[[:punct:]]", "", type)
op <- file.path("extensions", name)
props <- list(
publisher=publisher,
type=type,
typeHandlerVersion=version,
autoUpgradeMinorVersion=TRUE,
settings=settings
)
if(!is_empty(protected_settings))
props$protectedSettings <- protected_settings
if(!is_empty(key_vault_settings))
props$protectedSettingsFromKeyVault <- key_vault_settings
self$do_operation(op, body=list(properties=props), http_verb="PUT")
},
print=function(...)
{
cat("<Azure virtual machine scaleset resource ", self$name, ">\n", sep="")
osProf <- names(self$properties$virtualMachineProfile$osProfile)
os <- if(any(grepl("linux", osProf))) "Linux" else if(any(grepl("windows", osProf))) "Windows" else "<unknown>"
cat(" Operating system:", os, "\n")
cat(" Status:\n")
if(is_empty(self$status))
cat(" <unknown>\n")
else
{
status <- head(self$status)
row.names(status) <- paste0(" ", row.names(status))
print(status)
if(nrow(self$status) > nrow(status))
cat(" ...\n")
}
cat("---\n")
exclude <- c("subscription", "resource_group", "type", "name", "status")
cat(AzureRMR::format_public_fields(self, exclude=exclude))
cat(AzureRMR::format_public_methods(self))
invisible(NULL)
}
),
private=list(
make_vm_resource=function(params)
{
params$instanceId <- NULL
obj <- az_vm_resource$new(self$token, self$subscription, deployed_properties=params)
obj$nic_api_version <- "2018-10-01"
# make type and name useful
obj$type <- self$type
obj$name <- file.path(self$name, "virtualMachines", basename(params$id))
obj
},
vm_map=function(id, f)
{
vms <- self$list_instances()
if(!is.null(id))
vms <- vms[as.character(id)]
lapply(vms, f)
}
))

213
R/az_vmss_template.R Normal file
Просмотреть файл

@ -0,0 +1,213 @@
#' Virtual machine scaleset (cluster) template class
#'
#' Class representing a virtual machine scaleset deployment template. This class keeps track of all resources that are created as part of deploying a scaleset, and exposes methods for managing them.
#'
#' @docType class
#' @section Methods:
#' The following methods are available, in addition to those provided by the [AzureRMR::az_template] class.
#' - `sync_vmss_status`: Check the status of the scaleset.
#' - `list_instances()`: Return a list of [az_vm_resource] objects, one for each VM instance in the scaleset. Note that if the scaleset has an autoscaler attached, the number of instances will vary depending on the load.
#' - `get_instance(id)`: Return a specific VM instance in the scaleset.
#' - `start(id=NULL, wait=FALSE)`: Start the scaleset. In this and the other methods listed here, `id` can be an optional character vector of instance IDs; if supplied, only carry out the operation for those instances.
#' - `restart(id=NULL, wait=FALSE)`: Restart the scaleset.
#' - `stop(deallocate=TRUE, id=NULL, wait=FALSE)`: Stop the scaleset.
#' - `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 NULL.
#' - `get_vm_public_ip_addresses(id=NULL, nic=1, config=1)`: Get the public IP addresses for the instances in the scaleset. Returns NULL if the instances are 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.
#' - `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.
#' - `redeploy(id=NULL)`: Redeploy the instances in the scaleset.
#' - `mapped_vm_operation(..., id=NULL)`: Carry out an arbitrary operation on the instances in the scaleset. See the `do_operation` method of the [AzureRMR::az_resource] class for more details.
#' - `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).
#'
#' @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`)
#' - Virtual network (Azure resource type `Microsoft.Network/virtualNetworks`)
#' - Load balancer (Azure resource type `Microsoft.Network/loadBalancers`)
#' - Public IP address (Azure resource type `Microsoft.Network/publicIPAddresses`)
#' - Autoscaler (Azure resource type `Microsoft.Insights/autoscaleSettings`)
#' - The scaleset itself (Azure resource type `Microsoft.Compute/virtualMachineScaleSets`)
#'
#' By wrapping the deployment template used to create these resources, the `az_vmss_template` class allows managing them all as a single entity.
#'
#' @seealso
#' [AzureRMR::az_template], [create_vm_scaleset], [get_vm_scaleset], [delete_vm_scaleset]
#'
#' [VM scaleset API reference](https://docs.microsoft.com/en-us/rest/api/compute/virtualmachinescalesets)
#'
#' @examples
#' \dontrun{
#'
#' sub <- AzureRMR::get_azure_login()$
#' get_subscription("subscription_id")
#'
#' vmss <- sub$get_vm_scaleset("myscaleset")
#'
#' # start the VM
#' vmss$start()
#'
#' # run a shell command
#' vmss$run_script("ifconfig > /tmp/ifc.out")
#'
#' # get private IP addresses
#' vmss$get_vm_private_ip_addresses()
#'
#' # get the VM status
#' vmss$sync_vmss_status()
#'
#' }
#' @format An R6 object of class `az_vmss_template`, inheriting from `AzureRMR::az_template`.
#' @export
az_vmss_template <- R6::R6Class("az_vmss_template", inherit=az_template,
public=list(
dns_name=NULL,
initialize=function(token, subscription, resource_group, name, ..., wait=TRUE)
{
super$initialize(token, subscription, resource_group, name, ..., wait=wait)
if(wait)
{
private$vmss <- az_vmss_resource$new(self$token, self$subscription,
id=self$properties$outputs$vmResource$value)
# get the hostname/IP address for the VM
outputs <- unlist(self$properties$outputResources)
ip_id <- grep("publicIPAddresses/.+$", outputs, ignore.case=TRUE, value=TRUE)
if(!is_empty(ip_id))
{
ip <- az_resource$new(self$token, self$subscription, id=ip_id)
self$dns_name <- ip$properties$dnsSettings$fqdn
}
}
else message("Deployment started. Call the sync_vmss_status() method to track the status of the deployment.")
},
delete=function(confirm=TRUE, free_resources=TRUE)
{
# must reorder template output resources so that freeing resources will work
private$reorder_for_delete()
super$delete(confirm=confirm, free_resources=free_resources)
},
print=function(...)
{
cat("<Azure virtual machine scaleset ", self$name, ">\n", sep="")
osProf <- names(private$vmss$properties$virtualMachineProfile$osProfile)
os <- if(any(grepl("linux", osProf))) "Linux" else if(any(grepl("windows", osProf))) "Windows" else "<unknown>"
exclusive <- self$properties$mode == "Complete"
cat(" Operating system:", os, "\n")
cat(" Exclusive resource group:", exclusive, "\n")
cat(" Domain name:", self$dns_name, "\n")
cat(" Status:\n")
if(is_empty(private$vmss$status))
cat(" <unknown>\n")
else
{
status <- head(private$vmss$status)
row.names(status) <- paste0(" ", row.names(status))
print(status)
if(nrow(private$vmss$status) > nrow(status))
cat(" ...\n")
}
cat("---\n")
exclude <- c("subscription", "resource_group", "name", "dns_name")
cat(AzureRMR::format_public_fields(self, exclude=exclude))
cat(AzureRMR::format_public_methods(self))
invisible(NULL)
},
get_public_ip_address=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_
}
),
# propagate resource methods up to template
active=list(
sync_vmss_status=function()
private$vmss$sync_vmss_status,
list_instances=function()
private$vmss$list_instances,
get_instance=function()
private$vmss$get_instance,
start=function()
private$vmss$start,
stop=function()
private$vmss$stop,
restart=function()
private$vmss$restart,
get_vm_public_ip_addresses=function()
private$vmss$get_vm_public_ip_addresses,
get_vm_private_ip_addresses=function()
private$vmss$get_vm_private_ip_addresses,
run_deployed_command=function()
private$vmss$run_deployed_command,
run_script=function()
private$vmss$run_script,
reimage=function()
private$vmss$reimage,
redeploy=function()
private$vmss$redeploy,
mapped_vm_operation=function()
private$vmss$mapped_vm_operation,
add_extension=function()
private$vmss$add_extension,
do_vmss_operation=function()
private$vmss$do_operation
),
private=list(
vmss=NULL,
reorder_for_delete=function()
{
is_type <- function(id, type)
{
grepl(type, id, fixed=TRUE)
}
new_order <- sapply(self$properties$outputResources, function(x)
{
id <- x$id
if(is_type(id, "Microsoft.Compute/virtualMachineScaleSets")) 1
else if(is_type(id, "Microsoft.Compute/disks")) 2
else if(is_type(id, "Microsoft.Insights/autoscaleSettings")) 3
else if(is_type(id, "Microsoft.Network/loadBalancers")) 4
else if(is_type(id, "Microsoft.Network/publicIPAddresses")) 5
else if(is_type(id, "Microsoft.Network/virtualNetworks")) 6
else if(is_type(id, "Microsoft.Network/networkSecurityGroups")) 7
else 0
})
self$properties$outputResources <- self$properties$outputResources[order(new_order)]
}
))

218
R/build_json.R Normal file
Просмотреть файл

@ -0,0 +1,218 @@
#' Build template definition and parameters
#'
#' @param config An object of class `vm_config` or `vmss_config` representing a virtual machine or scaleset deployment.
#' @param name The VM or scaleset name. Will also be used for the domain name label, if a public IP address is included in the deployment.
#' @param login_user An object of class `user_config` representing the login details for the admin user account on the VM.
#' @param size The VM (instance) size.
#' @param ... Unused.
#'
#' @details
#' These are methods for the generics defined in the AzureRMR package.
#'
#' @seealso
#' [create_vm], [vm_config], [vmss_config]
#'
#' @examples
#'
#' vm <- ubuntu_18.04()
#' build_template_definition(vm)
#' build_template_parameters(vm, "myubuntuvm",
#' user_config("username", "~/.ssh/id_rsa.pub"), "Standard_DS3_v2")
#'
#' @rdname build_template
#' @export
build_template_definition.vm_config <- function(config, ...)
{
tpl <- list(
`$schema`="http://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
contentVersion="1.0.0.0",
parameters=add_template_parameters(config),
variables=add_template_variables(config),
resources=add_template_resources(config),
outputs=tpl_outputs_default
)
jsonlite::prettify(jsonlite::toJSON(tpl, auto_unbox=TRUE, null="null"))
}
#' @rdname build_template
#' @export
build_template_definition.vmss_config <- function(config, ...)
{
tpl <- list(
`$schema`="http://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
contentVersion="1.0.0.0",
parameters=add_template_parameters(config),
variables=add_template_variables(config),
resources=add_template_resources(config),
outputs=tpl_outputs_default
)
jsonlite::prettify(jsonlite::toJSON(tpl, auto_unbox=TRUE, null="null"))
}
#' @rdname build_template
#' @export
build_template_parameters.vm_config <- function(config, name, login_user, size, ...)
{
add_parameters <- function(...)
{
new_params <- lapply(list(...), function(obj) list(value=obj))
params <<- c(params, new_params)
}
stopifnot(inherits(login_user, "user_config"))
params <- list()
add_parameters(vmName=name, vmSize=size, adminUsername=login_user$user)
if(config$keylogin && !is_empty(login_user$key))
add_parameters(sshKeyData=login_user$key)
else add_parameters(adminPassword=login_user$pwd)
if(inherits(config$image, "image_marketplace"))
add_parameters(
imagePublisher=config$image$publisher,
imageOffer=config$image$offer,
imageSku=config$image$sku,
imageVersion=config$image$version
)
else add_parameters(imageId=config$image$id)
# add datadisks to params
if(!is_empty(config$datadisks))
{
# fixup datadisk LUNs and names
for(i in seq_along(config$datadisks))
{
config$datadisks[[i]]$vm_spec$lun <- i - 1
diskname <- config$datadisks[[i]]$vm_spec$name
if(!is.null(diskname))
{
newdiskname <- paste(name, diskname, i, sep="_")
config$datadisks[[i]]$res_spec$name <- newdiskname
config$datadisks[[i]]$vm_spec$name <- newdiskname
}
}
disk_res_spec <- lapply(config$datadisks, `[[`, "res_spec")
null <- sapply(disk_res_spec, is.null)
add_parameters(
dataDisks=lapply(config$datadisks, `[[`, "vm_spec"),
dataDiskResources=disk_res_spec[!null]
)
}
jsonlite::prettify(jsonlite::toJSON(params, auto_unbox=TRUE, null="null"))
}
#' @param instances For `vmss_config`, the number of (initial) instances in the VM scaleset.
#' @rdname build_template
#' @export
build_template_parameters.vmss_config <- function(config, name, login_user, size, instances, ...)
{
add_parameters <- function(...)
{
new_params <- lapply(list(...), function(obj) list(value=obj))
params <<- c(params, new_params)
}
stopifnot(inherits(login_user, "user_config"))
params <- list()
add_parameters(vmName=name, vmSize=size, instanceCount=instances, adminUsername=login_user$user)
if(config$options$keylogin && !is_empty(login_user$key))
add_parameters(sshKeyData=login_user$key)
else add_parameters(adminPassword=login_user$pwd)
if(inherits(config$image, "image_marketplace"))
add_parameters(
imagePublisher=config$image$publisher,
imageOffer=config$image$offer,
imageSku=config$image$sku,
imageVersion=config$image$version
)
else add_parameters(imageId=config$image$id)
do.call(add_parameters, config$options$params)
jsonlite::prettify(jsonlite::toJSON(params, auto_unbox=TRUE, null="null"))
}
add_template_parameters <- function(config, ...)
{
UseMethod("add_template_parameters")
}
add_template_variables <- function(config, ...)
{
UseMethod("add_template_variables")
}
add_template_variables.character <- function(config, type, ...)
{
# assume this is a resource ID
resname <- basename(config)
varnames <- paste0(type, c("Name", "Id"))
structure(list(resname, config), names=varnames)
}
add_template_variables.az_resource <- function(config, type, ...)
{
varnames <- paste0(type, c("Name", "Id"))
vars <- list(config$name, config$id)
# a bit hackish, should fully objectify
if(type == "vnet") # if we have a vnet, extract the 1st subnet name
{
subnet <- config$properties$subnets[[1]]$name
subnet_id <- "[concat(variables('vnetId'), '/subnets/', variables('subnet'))]"
varnames <- c(varnames, "subnet", "subnetId")
structure(c(vars, subnet, subnet_id), names=varnames)
}
else if(type == "lb") # if we have a load balancer, extract component names
{
frontend <- config$properties$frontendIPConfigurations[[1]]$name
backend <- config$properties$backendAddressPools[[1]]$name
frontend_id <- "[concat(variables('lbId'), '/frontendIPConfigurations/', variables('lbFrontendName'))]"
backend_id <- "[concat(variables('lbId'), '/backendAddressPools/', variables('lbBackendName'))]"
varnames <- c(varnames, "lbFrontendName", "lbBackendName", "lbFrontendId", "lbBackendId")
structure(c(vars, frontend, backend, frontend_id, backend_id), names=varnames)
}
else structure(vars, names=varnames)
}
add_template_variables.NULL <- function(config, ...)
{
NULL
}
add_template_resources <- function(config, ...)
{
UseMethod("add_template_resources")
}
build_resource_fields <- function(config)
{
UseMethod("build_resource_fields")
}
build_resource_fields.list <- function(config, ...)
{
unclass(config)
}

12
R/get_paged_list.R Normal file
Просмотреть файл

@ -0,0 +1,12 @@
# from AzureRMR
get_paged_list <- function(lst, token, next_link_name="nextLink", value_name="value")
{
res <- lst[[value_name]]
while(!is_empty(lst[[next_link_name]]))
{
lst <- call_azure_url(token, lst[[next_link_name]])
res <- c(res, lst[[value_name]])
}
res
}

50
R/ip_config.R Normal file
Просмотреть файл

@ -0,0 +1,50 @@
#' Public IP address configuration
#'
#' @param type The SKU of the IP address resource: "basic" or "standard". If NULL (the default), this will be determined based on the VM's configuration.
#' @param dynamic Whether the IP address should be dynamically or statically allocated. Note that the standard SKU only supports standard allocation. If NULL (the default) this will be determined based on the VM's configuration.
#' @param ipv6 Whether to create an IPv6 address. The default is IPv4.
#' @param domain_name The domain name label to associate with the address.
#' @param ... Other named arguments that will be treated as resource properties.
#'
#' @seealso
#' [create_vm], [vm_config], [vmss_config]
#' @export
ip_config <- function(type=NULL, dynamic=NULL, ipv6=FALSE, domain_name="[parameters('vmName')]", ...)
{
# structure(list(properties=props, sku=list(name=type)), class="ip_config")
props <- list(
type=type,
dynamic=dynamic,
ipv6=ipv6,
domain_name=domain_name,
other=list(...)
)
structure(props, class="ip_config")
}
build_resource_fields.ip_config <- function(config, ...)
{
alloc <- if(config$dynamic) "dynamic" else "static"
version <- if(config$ipv6) "IPv6" else "IPv4"
props <- c(
list(
publicIPAllocationMethod=alloc,
publicIPAddressVersion=version
),
config$other)
if(!is.null(config$domain_name))
props$dnsSettings$domainNameLabel <- config$domain_name
sku <- list(name=config$type)
utils::modifyList(ip_default, list(properties=props, sku=sku))
}
add_template_variables.ip_config <- function(config, ...)
{
name <- "[concat(parameters('vmName'), '-ip')]"
id <- "[resourceId('Microsoft.Network/publicIPAddresses', variables('ipName'))]"
ref <- "[concat('Microsoft.Network/publicIPAddresses/', variables('ipName'))]"
list(ipName=name, ipId=id, ipRef=ref)
}

49
R/is_vm.R Normal file
Просмотреть файл

@ -0,0 +1,49 @@
#' Is an object an Azure VM
#'
#' @param object an R object.
#'
#' @return
#' `is_vm` and `is_vm_template` return TRUE for an object representing a virtual machine deployment (which will include other resources besides the VM itself).
#'
#' `is_vm_resource` returns TRUE for an object representing the specific VM resource.
#'
#' `is_vm_scaleset` and `is_vm_scaleset_template` return TRUE for an object representing a VM scaleset deployment.
#'
#' `is_vm_scaleset_resource` returns TRUE for an object representing the specific VM scaleset resource.
#'
#' @seealso
#' [create_vm], [create_vm_scaleset], [az_vm_template], [az_vm_resource], [az_vmss_template], [az_vmss_resource]
#' @export
is_vm <- function(object)
{
R6::is.R6(object) && inherits(object, "az_vm_template")
}
#' @rdname is_vm
#' @export
is_vm_template <- is_vm
#' @rdname is_vm
#' @export
is_vm_resource <- function(object)
{
R6::is.R6(object) && inherits(object, "az_vm_resource")
}
#' @rdname is_vm
#' @export
is_vm_scaleset <- function(object)
{
R6::is.R6(object) && inherits(object, "az_vmss_template")
}
#' @rdname is_vm
#' @export
is_vm_scaleset_template <- is_vm_scaleset
#' @rdname is_vm
#' @export
is_vm_scaleset_resource <- function(object)
{
R6::is.R6(object) && inherits(object, "az_vmss_resource")
}

203
R/lb_config.R Normal file
Просмотреть файл

@ -0,0 +1,203 @@
#' Load balancer configuration
#'
#' @param type The SKU of the load balancer resource: "basic" or "standard". If NULL (the default), this will be determined based on the VM scaleset's configuration. Note that the load balancer SKU must be the same as that of its public IP address.
#' @param rules A list of load balancer rules, each obtained via a call to `lb_rule`.
#' @param probes A list of health checking probes, each obtained via a call to `lb_probe`. There must be a probe corresponding to each rule.
#' @param ... Other named arguments that will be treated as resource properties.
#' @param port For `lb_probe`, the port to probe.
#' @param interval For `lb_probe`, the time interval between probes in seconds.
#' @param fail_on For `lb_probe`, the probe health check will fail after this many non-responses.
#' @param protocol For `lb_probe` and `lb_rule`, the protocol: either "Tcp" or "Ip".
#' @param name For `lb_rule`, a name for the load balancing rule.
#' @param frontend_port,backend_port For `lb_rule`, the ports for this rule.
#' @param timeout The timeout interval for the rule. The default is 5 minutes.
#' @param floating_ip Whether to use floating IP addresses (direct server return). Only needed for specific scenarios, and when the frontend and backend ports don't match.
#' @param probe_name The name of the corresponding health check probe.
#'
#' @seealso
#' [create_vm_scaleset], [vmss_config], [lb_rules] for some predefined load balancing rules and probes
#' @export
lb_config <- function(type=NULL, rules=list(), probes=list(), ...)
{
rule_probe_names <- sapply(rules, function(x) x$properties$probe$id)
probe_names <- sapply(probes, `[[`, "name")
# basic checking
for(r in rule_probe_names)
{
found <- FALSE
for(p in probe_names)
{
found <- grepl(p, r, fixed=TRUE)
if(found) break
}
if(!found)
stop("Rule with no matching probe: ", r, call.=FALSE)
}
props <- list(
type=type,
rules=rules,
probes=probes,
other=list(...)
)
structure(props, class="lb_config")
}
build_resource_fields.lb_config <- function(config, ...)
{
props <- c(
list(
loadBalancingRules=lapply(config$rules, unclass),
probes=lapply(config$probes, unclass)
),
config$other
)
sku <- list(name=config$type)
utils::modifyList(lb_default, list(properties=props, sku=sku))
}
add_template_variables.lb_config <- function(config, ...)
{
name <- "[concat(parameters('vmName'), '-lb')]"
id <- "[resourceId('Microsoft.Network/loadBalancers', variables('lbName'))]"
ref <- "[concat('Microsoft.Network/loadBalancers/', variables('lbName'))]"
frontend <- "frontend"
backend <- "backend"
frontend_id <- "[concat(variables('lbId'), '/frontendIPConfigurations/', variables('lbFrontendName'))]"
backend_id <- "[concat(variables('lbId'), '/backendAddressPools/', variables('lbBackendName'))]"
list(
lbName=name,
lbId=id,
lbRef=ref,
lbFrontendName=frontend,
lbBackendName=backend,
lbFrontendId=frontend_id,
lbBackendId=backend_id
)
}
#' @rdname lb_config
#' @export
lb_probe <- function(name, port, interval=5, fail_on=2, protocol="Tcp")
{
props <- list(
port=port,
intervalInSeconds=interval,
numberOfProbes=fail_on,
protocol=protocol
)
structure(list(name=name, properties=props), class="lb_probe")
}
#' @rdname lb_config
#' @export
lb_rule <- function(name, frontend_port, backend_port=frontend_port, protocol="Tcp", timeout=5,
floating_ip=FALSE, probe_name)
{
frontend_id <- "[variables('lbFrontendId')]"
backend_id <- "[variables('lbBackendId')]"
probe_id <- sprintf("[concat(variables('lbId'), '/probes/%s')]", probe_name)
props <- list(
frontendIpConfiguration=list(id=frontend_id),
backendAddressPool=list(id=backend_id),
protocol=protocol,
frontendPort=frontend_port,
backendPort=backend_port,
enableFloatingIp=floating_ip,
idleTimeoutInMinutes=timeout,
probe=list(id=probe_id)
)
structure(list(name=name, properties=props), class="lb_rule")
}
#' Load balancing rules
#'
#' @format
#' Objects of class `lb_rule` and `lb_probe`.
#' @details
#' Some predefined load balancing objects, for commonly used ports. Each load balancing rule comes with its own health probe.
#' - HTTP: TCP port 80
#' - HTTPS: TCP port 443
#' - JupyterHub: TCP port 8000
#' - RDP: TCP port 3389
#' - RStudio Server: TCP port 8787
#' - SSH: TCP port 22
#' - SQL Server: TCP port 1433
#' - SQL Server browser service: TCP port 1434
#' @docType data
#' @seealso
#' [lb_config]
#' @rdname lb_rules
#' @aliases lb_rules
#' @export
lb_rule_ssh <- lb_rule("lb-ssh", 22, 22, probe_name="probe-ssh")
#' @rdname lb_rules
#' @export
lb_rule_http <- lb_rule("lb-http", 80, 80, probe_name="probe-http")
#' @rdname lb_rules
#' @export
lb_rule_https <- lb_rule("lb-https", 443, 443, probe_name="probe-https")
#' @rdname lb_rules
#' @export
lb_rule_rdp <- lb_rule("lb-rdp", 3389, 3389, probe_name="probe-rdp")
#' @rdname lb_rules
#' @export
lb_rule_jupyter <- lb_rule("lb-jupyter", 8000, 8000, probe_name="probe-jupyter")
#' @rdname lb_rules
#' @export
lb_rule_rstudio <- lb_rule("lb-rstudio", 8787, 8787, probe_name="probe-rstudio")
#' @rdname lb_rules
#' @export
lb_rule_mssql <- lb_rule("lb-mssql", 1433, 1433, probe_name="probe-mssql")
#' @rdname lb_rules
#' @export
lb_rule_mssql_browser <- lb_rule("lb-mssql-browser", 1434, 1434, probe_name="probe-mssql-browser")
#' @rdname lb_rules
#' @export
lb_probe_ssh <- lb_probe("probe-ssh", 22)
#' @rdname lb_rules
#' @export
lb_probe_http <- lb_probe("probe-http", 80)
#' @rdname lb_rules
#' @export
lb_probe_https <- lb_probe("probe-https", 443)
#' @rdname lb_rules
#' @export
lb_probe_rdp <- lb_probe("probe-rdp", 3389)
#' @rdname lb_rules
#' @export
lb_probe_jupyter <- lb_probe("probe-jupyter", 8000)
#' @rdname lb_rules
#' @export
lb_probe_rstudio <- lb_probe("probe-rstudio", 8787)
#' @rdname lb_rules
#' @export
lb_probe_mssql <- lb_probe("probe-mssql", 1433)
#' @rdname lb_rules
#' @export
lb_probe_mssql_browser <- lb_probe("probe-mssql-browser", 1434)

8
R/load_tpls.R Normal file
Просмотреть файл

@ -0,0 +1,8 @@
lapply(dir("inst/tpl", pattern="\\.json$"), function(f)
{
objname <- sub("\\.json$", "", f)
obj <- jsonlite::fromJSON(file.path("inst/tpl", f), simplifyVector=FALSE)
assign(objname, obj, parent.env(environment()))
})

59
R/nic_config.R Normal file
Просмотреть файл

@ -0,0 +1,59 @@
#' Network interface configuration
#'
#' @param nic_ip For `nic_config`, a list of IP configuration objects, each obtained via a call to `nic_ip_config`.
#' @param name For `nic_ip_config`, the name of the IP configuration.
#' @param private_alloc For `nic_ip_config`, the allocation method for a private IP address. Can be "dynamic" or "static".
#' @param subnet For `nic_ip_config`, the subnet to associate with this private IP address.
#' @param public_address For `nic_ip_config`, the public IP address. Defaults to the public IP address created or used as part of this VM deployment. Ignored if the deployment does not include a public address.
#' @param ... Other named arguments that will be treated as resource properties.
#'
#' @seealso
#' [create_vm], [vm_config]
#' @export
nic_config <- function(nic_ip=list(nic_ip_config()), ...)
{
# unique-ify ip config names
if(length(nic_ip) > 1)
{
ip_names <- make.unique(sapply(nic_ip, `[[`, "name"))
ip_names[1] <- paste0(ip_names[1], "0")
for(i in seq_along(nic_ip))
nic_ip[[i]]$name <- ip_names[i]
}
props <- list(ipConfigurations=nic_ip, ...)
structure(list(properties=props), class="nic_config")
}
build_resource_fields.nic_config <- function(config)
{
config$properties$ipConfigurations <- lapply(config$properties$ipConfigurations, unclass)
utils::modifyList(nic_default, config)
}
add_template_variables.nic_config <- function(config, ...)
{
name <- "[concat(parameters('vmName'), '-nic')]"
id <- "[resourceId('Microsoft.Network/networkInterfaces', variables('nicName'))]"
ref <- "[concat('Microsoft.Network/networkInterfaces/', variables('nicName'))]"
list(nicName=name, nicId=id, nicRef=ref)
}
#' @rdname nic_config
#' @export
nic_ip_config <- function(name="ipconfig", private_alloc="dynamic", subnet="[variables('subnetId')]",
public_address="[variables('ipId')]", ...)
{
props <- list(
privateIPAllocationMethod=private_alloc,
subnet=list(id=subnet),
publicIPAddress=list(id=public_address),
...
)
structure(list(name=name, properties=props), class="nic_ip_config")
}

127
R/nsg_config.R Normal file
Просмотреть файл

@ -0,0 +1,127 @@
#' Network security group configuration
#'
#' @param rules for `nsg_config`, a list of security rule objects, each obtained via a call to `nsg_rule`.
#' @param dest_port,dest_addr,dest_asgs For `nsg_rule`, the destination port, address range, and application security groups for a rule.
#' @param source_port,source_addr,source_asgs For `nsg_rule`, the source port, address range, and application security groups for a rule.
#' @param ... Other named arguments that will be treated as resource properties.
#' @param name For `nsg_rule`, a name for the rule.
#' @param access For `nsg_rule`, the action to take: "allow" or "deny".
#' @param direction For `nsg_rule`, the direction of traffic: "inbound" or "outbound".
#' @param protocol For `nsg_rule`, the network protocol: either "Tcp" or "Udp".
#' @param priority For `nsg_rule`, the rule priority. If NULL, this will be set automatically by AzureVM.
#'
#' @seealso
#' [create_vm], [vm_config], [vmss_config], [nsg_rules] for some predefined security rules
#' @export
nsg_config <- function(rules=list(), ...)
{
stopifnot(is.list(rules))
props <- list(securityRules=rules, ...)
structure(list(properties=props), class="nsg_config")
}
build_resource_fields.nsg_config <- function(config, ...)
{
for(i in seq_along(config$properties$securityRules))
{
# fixup nsg security rule priorities
if(is_empty(config$properties$securityRules[[i]]$properties$priority))
config$properties$securityRules[[i]]$properties$priority <- 1000 + 10 * i
config$properties$securityRules[[i]] <- unclass(config$properties$securityRules[[i]])
}
utils::modifyList(nsg_default, config)
}
add_template_variables.nsg_config <- function(config, ...)
{
name <- "[concat(parameters('vmName'), '-nsg')]"
id <- "[resourceId('Microsoft.Network/networkSecurityGroups', variables('nsgName'))]"
ref <- "[concat('Microsoft.Network/networkSecurityGroups/', variables('nsgName'))]"
list(nsgName=name, nsgId=id, nsgRef=ref)
}
#' @rdname nsg_config
#' @export
nsg_rule <- function(name, dest_port="*", dest_addr="*", dest_asgs=NULL,
source_port="*", source_addr="*", source_asgs=NULL,
access="allow", direction="inbound",
protocol="Tcp", priority=NULL)
{
if(is_empty(dest_asgs))
dest_asgs <- logical(0)
if(is_empty(source_asgs))
source_asgs <- logical(0)
properties <- list(
protocol=protocol,
access=access,
direction=direction,
sourceApplicationSecurityGroups=source_asgs,
destinationApplicationSecurityGroups=dest_asgs,
sourceAddressPrefix=source_addr,
sourcePortRange=as.character(source_port),
destinationAddressPrefix=dest_addr,
destinationPortRange=as.character(dest_port)
)
if(!is_empty(priority))
properties$priority <- priority
structure(list(name=name, properties=properties), class="nsg_rule")
}
#' Network security rules
#'
#' @format
#' Objects of class `nsg_rule`.
#' @details
#' Some predefined network security rule objects, to unblock commonly used ports.
#' - HTTP: TCP port 80
#' - HTTPS: TCP port 443
#' - JupyterHub: TCP port 8000
#' - RDP: TCP port 3389
#' - RStudio Server: TCP port 8787
#' - SSH: TCP port 22
#' - SQL Server: TCP port 1433
#' - SQL Server browser service: TCP port 1434
#' @docType data
#' @seealso
#' [nsg_config]
#' @rdname nsg_rules
#' @aliases nsg_rules
#' @export
nsg_rule_allow_ssh <- nsg_rule("Allow-ssh", 22)
#' @rdname nsg_rules
#' @export
nsg_rule_allow_http <- nsg_rule("Allow-http", 80)
#' @rdname nsg_rules
#' @export
nsg_rule_allow_https <- nsg_rule("Allow-https", 443)
#' @rdname nsg_rules
#' @export
nsg_rule_allow_rdp <- nsg_rule("Allow-rdp", 3389)
#' @rdname nsg_rules
#' @export
nsg_rule_allow_jupyter <- nsg_rule("Allow-jupyter", 8000)
#' @rdname nsg_rules
#' @export
nsg_rule_allow_rstudio <- nsg_rule("Allow-rstudio", 8787)
#' @rdname nsg_rules
#' @export
nsg_rule_allow_mssql <- nsg_rule("Allow-mssql", 1433)
#' @rdname nsg_rules
#' @export
nsg_rule_allow_mssql_browser <- nsg_rule("Allow-mssql-browser", 1434)

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

@ -1,68 +0,0 @@
param_mappings <- list()
param_mappings$win2016_dsvm <- c(
username="adminUsername",
passkey="adminPassword",
name="vmName",
size="vmSize"
)
param_mappings$win2016_dsvm_cl_ext <- c(
username="adminUsername",
passkey="adminPassword",
name="vmName",
size="vmSize",
clust_size="numberOfInstances",
ext_file_uris="fileUris",
inst_command="commandToExecute"
)
param_mappings$ubuntu_dsvm <- c(
username="adminUsername",
passkey="adminPassword",
name="vmName",
size="vmSize"
)
param_mappings$ubuntu_dsvm_key <- c(
username="adminUsername",
passkey="sshKeyData",
name="vmName",
size="vmSize"
)
param_mappings$ubuntu_dsvm_ext <- c(
username="adminUsername",
passkey="adminPassword",
name="vmName",
size="vmSize",
ext_file_uris="fileUris",
inst_command="commandToExecute",
command_parm="commandParameter"
)
param_mappings$ubuntu_dsvm_cl <- c(
username="adminUsername",
passkey="adminPassword",
name="vmName",
size="vmSize",
clust_size="numberOfInstances"
)
param_mappings$ubuntu_dsvm_cl_key <- c(
username="adminUsername",
passkey="sshKeyData",
name="vmName",
size="vmSize",
clust_size="numberOfInstances"
)
param_mappings$ubuntu_dsvm_cl_ext <- c(
username="adminUsername",
passkey="adminPassword",
name="vmName",
size="vmSize",
clust_size="numberOfInstances",
ext_file_uris="fileUris",
inst_command="commandToExecute"
)

253
R/vm_config.R Normal file
Просмотреть файл

@ -0,0 +1,253 @@
#' VM configuration functions
#'
#' @param image For `vm_config`, the VM image to deploy. This should be an object of class `image_config`, created by the function of the same name.
#' @param keylogin Boolean: whether to use an SSH public key to login (TRUE) or a password (FALSE). Note that Windows does not support SSH key logins.
#' @param managed Whether to provide a managed system identity for the VM.
#' @param datadisks The data disks to attach to the VM. Specify this as either a vector of numeric disk sizes in GB, or a list of `datadisk_config` objects for more control over the specification.
#' @param nsg The network security group for the VM. Can be a call to `nsg_config` to create a new NSG; an AzureRMR resource object or resource ID to reuse an existing NSG; or NULL to not use an NSG (not recommended).
#' @param ip The public IP address for the VM. Can be a call to `ip_config` to create a new IP address; an AzureRMR resource object or resource ID to reuse an existing address resource; or NULL if the VM should not be accessible from outside its subnet.
#' @param vnet The virtual network for the VM. Can be a call to `vnet_config` to create a new virtual network, or an AzureRMR resource object or resource ID to reuse an existing virtual network. Note that by default, AzureVM will associate the NSG with the virtual network/subnet, not with the VM's network interface.
#' @param nic The network interface for the VM. Can be a call to `nic_config` to create a new interface, or an AzureRMR resource object or resource ID to reuse an existing interface.
#' @param other_resources An optional list of other resources to include in the deployment.
#' @param variables An optional named list of variables to add to the template.
#' @param ... For the specific VM configurations, other customisation arguments to be passed to `vm_config`. For `vm_config`, named arguments that will be folded into the VM resource definition in the template.
#'
#' @details
#' These functions are for specifying the details of a new virtual machine deployment: the VM image and related options, along with the Azure resources that the VM may need. These include the datadisks, network security group, public IP address (if the VM is to be accessible from outside its subnet), virtual network, and network interface.
#'
#' Each resource can be specified in a number of ways:
#' - To _create_ a new resource as part of the deployment, call the corresponding `*_config` function.
#' - To use an _existing_ resource, supply either an `AzureRMR::az_resource` object (recommended) or a string containing the resource ID.
#' - If the resource is not needed, specify it as NULL.
#' - For the `other_resources` argument, supply a list of resources, each of which should be a list of resource fields (name, type, properties, sku, etc).
#'
#' The `vm_config` function is the base configuration function, and the others call it to create VMs with specific operating systems and other image details.
#' - `ubuntu_dsvm`: Data Science Virtual Machine, based on Ubuntu 16.04
#' - `windows_dsvm`: Data Science Virtual Machine, based on Windows Server 2016
#' - `ubuntu_16.04`, `ubuntu_18.04`: Ubuntu
#' - `windows_2016`, `windows_2019`: Windows Server Datacenter edition
#' - `rhel_7.6`, `rhel_8`: Red Hat Enterprise Linux
#' - `debian_9_backports`: Debian
#'
#' @return
#' An object of S3 class `vm_config`, that can be used by the `create_vm` method.
#'
#' @seealso
#' [image_config], [user_config], [datadisk_config] for options relating to the VM resource itself
#'
#' [nsg_config], [ip_config], [vnet_config], [nic_config] for other resource configs
#'
#' [vmss_config] for configuring a virtual machine scaleset
#'
#' [create_vm]
#'
#' @examples
#'
#' # basic Linux (Ubuntu) and Windows configs
#' ubuntu_18.04()
#' windows_2019()
#'
#' # Windows DSVM with 500GB data disk, no public IP address
#' windows_dsvm(datadisks=500, ip=NULL)
#'
#' # RHEL VM exposing ports 80 (HTTP) and 443 (HTTPS)
#' rhel_8(nsg=nsg_config(nsg_rule_allow_http, nsg_rule_allow_https))
#'
#' # exposing no ports externally
#' rhel_8(nsg=nsg_config(list()))
#'
#' # deploying an extra resource: storage account
#' ubuntu_18.04(
#' variables=list(storName="[concat(variables('vmName'), 'stor')]"),
#' other_resources=list(
#' list(
#' type="Microsoft.Storage/storageAccounts",
#' name="[variables('storName')]",
#' apiVersion="2018-07-01",
#' location="[variables('location')]",
#' properties=list(supportsHttpsTrafficOnly=TRUE),
#' sku=list(name="Standard_LRS"),
#' kind="Storage"
#' )
#' )
#' )
#'
#' ## custom VM configuration: Windows 10 Pro 1903 with data disks
#' ## this assumes you have a valid Win10 desktop license
#' user <- user_config("myname", password="Use-strong-passwords!")
#' image <- image_config(
#' publisher="MicrosoftWindowsDesktop",
#' offer="Windows-10",
#' sku="19h1-pro"
#' )
#' datadisks <- list(
#' datadisk_config(250, type="Premium_LRS"),
#' datadisk_config(1000, type="Standard_LRS")
#' )
#' nsg <- nsg_config(
#' list(nsg_rule_allow_rdp)
#' )
#' vm_config(
#' image=image,
#' keylogin=FALSE,
#' datadisks=datadisks,
#' nsg=nsg,
#' properties=list(licenseType="Windows_Client")
#' )
#'
#'
#' \dontrun{
#'
#' # reusing existing resources: placing multiple VMs in one vnet/subnet
#' rg <- AzureRMR::get_azure_login()$
#' get_subscription("sub_id")$
#' get_resource_group("rgname")
#'
#' vnet <- rg$get_resource(type="Microsoft.Network/virtualNetworks", name="myvnet")
#'
#' # by default, the NSG is associated with the subnet, so we don't need a new NSG either
#' vmconfig1 <- ubuntu_18.04(vnet=vnet, nsg=NULL)
#' vmconfig2 <- debian_9_backports(vnet=vnet, nsg=NULL)
#' vmconfig3 <- windows_2019(vnet=vnet, nsg=NULL)
#'
#' }
#' @export
vm_config <- function(image, keylogin, managed=TRUE,
datadisks=numeric(0),
nsg=nsg_config(),
ip=ip_config(),
vnet=vnet_config(),
nic=nic_config(),
other_resources=list(),
variables=list(),
...)
{
if(is.numeric(datadisks))
datadisks <- lapply(datadisks, datadisk_config)
stopifnot(inherits(image, "image_config"))
stopifnot(is.list(datadisks) && all(sapply(datadisks, inherits, "datadisk_config")))
ip <- vm_fixup_ip(ip)
obj <- list(
image=image,
keylogin=keylogin,
managed=managed,
datadisks=datadisks,
nsg=nsg,
ip=ip,
vnet=vnet,
nic=nic,
other=other_resources,
variables=variables,
vm_fields=list(...)
)
structure(obj, class="vm_config")
}
vm_fixup_ip <- function(ip)
{
# don't try to fix IP if not created here
if(is.null(ip) || !inherits(ip, "ip_config"))
return(ip)
# default for a regular VM: sku=basic, allocation=dynamic
if(is.null(ip$type))
ip$type <- "basic"
if(is.null(ip$dynamic))
ip$dynamic <- tolower(ip$type) == "basic"
# check consistency
if(tolower(ip$type) == "standard" && ip$dynamic)
stop("Standard IP address type does not support dynamic allocation", call.=FALSE)
ip
}
#' @rdname vm_config
#' @export
ubuntu_dsvm <- function(keylogin=TRUE, managed=TRUE, datadisks=numeric(0),
nsg=nsg_config(list(nsg_rule_allow_ssh, nsg_rule_allow_jupyter, nsg_rule_allow_rstudio)),
...)
{
if(is.numeric(datadisks))
datadisks <- lapply(datadisks, datadisk_config)
disk0 <- datadisk_config(NULL, NULL, "fromImage", "Premium_LRS")
vm_config(image_config("microsoft-dsvm", "linux-data-science-vm-ubuntu", "linuxdsvmubuntu"),
keylogin=keylogin, managed=managed, datadisks=c(list(disk0), datadisks), nsg=nsg, ...)
}
#' @rdname vm_config
#' @export
windows_dsvm <- function(keylogin=FALSE, managed=TRUE, datadisks=numeric(0),
nsg=nsg_config(list(nsg_rule_allow_rdp)), ...)
{
vm_config(image_config("microsoft-dsvm", "dsvm-windows", "server-2016"),
keylogin=FALSE, managed=managed, datadisks=datadisks, nsg=nsg, ...)
}
#' @rdname vm_config
#' @export
ubuntu_16.04 <- function(keylogin=TRUE, managed=TRUE, datadisks=numeric(0),
nsg=nsg_config(list(nsg_rule_allow_ssh)), ...)
{
vm_config(image_config("Canonical", "UbuntuServer", "16.04-LTS"),
keylogin=keylogin, managed=managed, datadisks=datadisks, nsg=nsg, ...)
}
#' @rdname vm_config
#' @export
ubuntu_18.04 <- function(keylogin=TRUE, managed=TRUE, datadisks=numeric(0),
nsg=nsg_config(list(nsg_rule_allow_ssh)), ...)
{
vm_config(image_config("Canonical", "UbuntuServer", "18.04-LTS"),
keylogin=keylogin, managed=managed, datadisks=datadisks, nsg=nsg, ...)
}
#' @rdname vm_config
#' @export
windows_2016 <- function(keylogin=FALSE, managed=TRUE, datadisks=numeric(0),
nsg=nsg_config(list(nsg_rule_allow_rdp)), ...)
{
vm_config(image_config("MicrosoftWindowsServer", "WindowsServer", "2016-Datacenter"),
keylogin=FALSE, managed=managed, datadisks=datadisks, nsg=nsg, ...)
}
#' @rdname vm_config
#' @export
windows_2019 <- function(keylogin=FALSE, managed=TRUE, datadisks=numeric(0),
nsg=nsg_config(list(nsg_rule_allow_rdp)), ...)
{
vm_config(image_config("MicrosoftWindowsServer", "WindowsServer", "2019-Datacenter"),
keylogin=FALSE, managed=managed, datadisks=datadisks, nsg=nsg, ...)
}
#' @rdname vm_config
#' @export
rhel_7.6 <- function(keylogin=TRUE, managed=TRUE, datadisks=numeric(0),
nsg=nsg_config(list(nsg_rule_allow_ssh)), ...)
{
vm_config(image_config("RedHat", "RHEL", "7-RAW"),
keylogin=keylogin, managed=managed, datadisks=datadisks, nsg=nsg, ...)
}
#' @rdname vm_config
#' @export
rhel_8 <- function(keylogin=TRUE, managed=TRUE, datadisks=numeric(0),
nsg=nsg_config(list(nsg_rule_allow_ssh)), ...)
{
vm_config(image_config("RedHat", "RHEL", "8"),
keylogin=keylogin, managed=managed, datadisks=datadisks, nsg=nsg, ...)
}
#' @rdname vm_config
#' @export
debian_9_backports <- function(keylogin=TRUE, managed=TRUE, datadisks=numeric(0),
nsg=nsg_config(list(nsg_rule_allow_ssh)), ...)
{
vm_config(image_config("Credativ", "Debian", "9-backports"),
keylogin=keylogin, managed=managed, datadisks=datadisks, nsg=nsg, ...)
}

79
R/vm_resource_config.R Normal file
Просмотреть файл

@ -0,0 +1,79 @@
#' Resource configuration functions for a virtual machine deployment
#'
#' @param username For `user_config`, the name for the admin user account.
#' @param sshkey For `user_config`, string containing an SSH public key. Can be the key itself, or the name of the public key file.
#' @param password For `user_config`, the admin password. Supply either `sshkey` or `password`, but not both; also, note that Windows does not support SSH logins.
#' @param size For `datadisk_config`, the size of the data disk in GB. St this to NULL for a disk that will be created from an image.
#' @param name For `datadisk_config`, the disk name. Duplicate names will automatically be disambiguated prior to VM deployment.
#' @param create For `datadisk_config`, the creation method. Can be "empty" (the default) to create a blank disk, or "fromImage" to use an image.
#' @param type For `datadisk_config`, the disk type (SKU). Can be "Standard_LRS", "StandardSSD_LRS" (the default), "Premium_LRS" or "UltraSSD_LRS". Of these, "Standard_LRS" uses hard disks and the others use SSDs as the underlying hardware.
#' @param write_accelerator For `datadisk_config`, whether the disk should have write acceleration enabled.
#' @param publisher,offer,sku,version For `image_config`, the details for a marketplace image.
#' @param id For `image_config`, the resource ID for a disk to use as a custom image.
#'
#' @rdname vm_resource_config
#' @export
user_config <- function(username, sshkey=NULL, password=NULL)
{
pwd <- is.character(password)
key <- is.character(sshkey)
if(!pwd && !key)
stop("Must supply either a login password or SSH key", call.=FALSE)
if(pwd && key)
stop("Supply either a login password or SSH key, but not both", call.=FALSE)
if(key && file.exists(sshkey))
sshkey <- readLines(sshkey)
structure(list(user=username, key=sshkey, pwd=password), class="user_config")
}
#' @rdname vm_resource_config
#' @export
datadisk_config <- function(size, name="datadisk", create="empty", type="StandardSSD_LRS", write_accelerator=FALSE)
{
vm_caching <- if(type == "Premium_LRS") "ReadOnly" else "None"
vm_create <- if(create == "empty") "attach" else "fromImage"
vm_storage <- if(create == "empty") NULL else type
vm_spec <- list(
createOption=vm_create,
caching=vm_caching,
writeAcceleratorEnabled=write_accelerator,
storageAccountType=vm_storage,
diskSizeGB=NULL,
id=NULL,
name=name
)
res_spec <- if(!is.null(size))
list(
diskSizeGB=size,
sku=type,
creationData=list(createOption=create),
name=name
)
else NULL
structure(list(res_spec=res_spec, vm_spec=vm_spec), class="datadisk_config")
}
#' @rdname vm_resource_config
#' @export
image_config <- function(publisher=NULL, offer=NULL, sku=NULL, version="latest", id=NULL)
{
if(!is.null(publisher) && !is.null(offer) && !is.null(sku))
{
structure(list(publisher=publisher, offer=offer, sku=sku, version=version),
class=c("image_marketplace", "image_config"))
}
else if(!is.null(id))
{
structure(list(id=id),
class=c("image_custom", "image_config"))
}
else stop("Invalid image configuration", call.=FALSE)
}

122
R/vm_template_builders.R Normal file
Просмотреть файл

@ -0,0 +1,122 @@
add_template_parameters.vm_config <- function(config, ...)
{
add_param <- function(...)
{
new_params <- lapply(list(...), function(obj) list(type=obj))
params <<- c(params, new_params)
}
params <- tpl_parameters_default
if(config$keylogin)
add_param(sshKeyData="string")
else add_param(adminPassword="securestring")
if(inherits(config$image, "image_marketplace"))
add_param(imagePublisher="string", imageOffer="string", imageSku="string", imageVersion="string")
else add_param(imageId="string")
if(length(config$datadisks) > 0)
add_param(dataDisks="array", dataDiskResources="array")
params
}
add_template_variables.vm_config <- function(config, ...)
{
vars <- list(
location="[resourceGroup().location]",
vmId="[resourceId('Microsoft.Compute/virtualMachines', parameters('vmName'))]",
vmRef="[concat('Microsoft.Compute/virtualMachines/', parameters('vmName'))]"
)
for(res in c("nsg", "ip", "vnet", "nic"))
vars <- c(vars, add_template_variables(config[[res]], res))
# add any extra variables provided by the user
utils::modifyList(vars, config$variables)
}
add_template_resources.vm_config <- function(config, ...)
{
vm <- vm_default
# fixup VM properties
n_disks <- length(config$datadisks)
n_disk_resources <- if(n_disks > 0)
sum(sapply(config$datadisks, function(x) !is.null(x$res_spec)))
else 0
if(n_disks > 0)
{
vm$properties$storageProfile$copy <- vm_datadisk
if(n_disk_resources > 0)
vm$dependsOn <- c(vm$dependsOn, "managedDiskResources")
}
if(config$managed)
vm$identity <- list(type="systemAssigned")
vm$properties$osProfile <- c(vm$properties$osProfile,
if(config$keylogin) vm_key_login else vm_pwd_login)
if(inherits(config$image, "image_custom"))
vm$properties$storageProfile$imageReference <- list(id="[parameters('imageId')]")
if(!is_empty(config$vm_fields))
vm <- utils::modifyList(vm, config$vm_fields)
resources <- config[c("nsg", "ip", "vnet", "nic")]
existing <- sapply(resources, existing_resource)
unused <- sapply(resources, is.null)
create <- !existing & !unused
# cannot use lapply(*, build_resource_fields) because of lapply wart
resources <- lapply(resources[create], function(x) build_resource_fields(x))
## fixup dependencies between resources
# vnet depends on nsg
# nic depends on ip, vnet (possibly nsg)
# vm depends on nic (but nic should always be created)
if(create["vnet"])
{
if(!create["nsg"])
resources$vnet$dependsOn <- NULL
if(unused["nsg"])
resources$vnet$properties$subnets[[1]]$properties$networkSecurityGroup <- NULL
}
if(create["nic"])
{
nic_created_depends <- create[c("ip", "vnet")]
resources$nic$dependsOn <- resources$nic$dependsOn[nic_created_depends]
if(unused["ip"])
resources$nic$properties$ipConfigurations[[1]]$properties$publicIPAddress <- NULL
}
else vm$dependsOn <- NULL
if(n_disk_resources > 0)
resources <- c(resources, list(disk_default))
resources <- c(resources, list(vm))
if(!is_empty(config$other))
resources <- c(resources, lapply(config$other, function(x) build_resource_fields(x)))
unname(resources)
}
# check if we are referring to an existing resource or creating a new one
existing_resource <- function(object)
{
# can be a resource ID string or AzureRMR::az_resource object
is.character(object) || is_resource(object)
}

316
R/vmss_config.R Normal file
Просмотреть файл

@ -0,0 +1,316 @@
#' Virtual machine scaleset configuration functions
#'
#' @param image For `vmss_config`, the VM image to deploy. This should be an object of class `image_config`, created by the function of the same name.
#' @param options Scaleset options, as obtained via a call to `scaleset_options`.
#' @param nsg The network security group for the scaleset. Can be a call to `nsg_config` to create a new NSG; an AzureRMR resource object or resource ID to reuse an existing NSG; or NULL to not use an NSG (not recommended).
#' @param vnet The virtual network for the scaleset. Can be a call to `vnet_config` to create a new virtual network, or an AzureRMR resource object or resource ID to reuse an existing virtual network. Note that by default, AzureVM will associate the NSG with the virtual network/subnet, not with the VM's network interface.
#' @param load_balancer The load balancer for the scaleset. Can be a call to `lb_config` to create a new load balancer; an AzureRMR resource object or resource ID to reuse an existing load balancer; or NULL if load balancing is not required.
#' @param load_balancer_address The public IP address for the load balancer. Can be a call to `ip_config` to create a new IP address, or an AzureRMR resource object or resource ID to reuse an existing address resource. Ignored if `load_balancer` is NULL.
#' @param autoscaler The autoscaler for the scaleset. Can be a call to `autoscaler_config` to create a new autoscaler; an AzureRMR resource object or resource ID to reuse an existing autoscaler; or NULL if autoscaling is not required.
#' @param other_resources An optional list of other resources to include in the deployment.
#' @param variables An optional named list of variables to add to the template.
#' @param ... For the specific VM configurations, other customisation arguments to be passed to `vm_config`. For `vmss_config`, named arguments that will be folded into the scaleset resource definition in the template.
#'
#' @details
#' These functions are for specifying the details of a new virtual machine scaleset deployment: the base VM image and related options, along with the Azure resources that the scaleset may need. These include the network security group, virtual network, load balancer and associated public IP address, and autoscaler.
#'
#' Each resource can be specified in a number of ways:
#' - To _create_ a new resource as part of the deployment, call the corresponding `*_config` function.
#' - To use an _existing_ resource, supply either an `AzureRMR::az_resource` object (recommended) or a string containing the resource ID.
#' - If the resource is not needed, specify it as NULL.
#' - For the `other_resources` argument, supply a list of resources, each of which should be a list of resource fields (name, type, properties, sku, etc).
#'
#' The `vmss_config` function is the base configuration function, and the others call it to create VM scalesets with specific operating systems and other image details.
#' - `ubuntu_dsvm_ss`: Data Science Virtual Machine, based on Ubuntu 16.04
#' - `windows_dsvm_ss`: Data Science Virtual Machine, based on Windows Server 2016
#' - `ubuntu_16.04_ss`, `ubuntu_18.04`: Ubuntu
#' - `windows_2016_ss`, `windows_2019`: Windows Server Datacenter edition
#' - `rhel_7.6_ss`, `rhel_8_ss`: Red Hat Enterprise Linux
#' - `debian_9_backports_ss`: Debian
#'
#' @return
#' An object of S3 class `vmss_config`, that can be used by the `create_vm_scaleset` method.
#'
#' @seealso
#' [scaleset_options] for options relating to the scaleset resource itself
#'
#' [nsg_config], [ip_config], [vnet_config], [lb_config], [autoscaler_config] for other resource configs
#'
#' [vm_config] for configuring an individual virtual machine
#'
#' [create_vm_scaleset]
#'
#' @examples
#'
#' # basic Linux (Ubuntu) and Windows configs
#' ubuntu_18.04_ss()
#' windows_2019_ss()
#'
#' # Windows DSVM scaleset, no load balancer and autoscaler
#' windows_dsvm_ss(load_balancer=NULL, autoscaler=NULL)
#'
#' # RHEL VM exposing ports 80 (HTTP) and 443 (HTTPS)
#' rhel_8_ss(nsg=nsg_config(nsg_rule_allow_http, nsg_rule_allow_https))
#'
#' # exposing no ports externally
#' rhel_8_ss(nsg=nsg_config(list()))
#'
#' # low-priority VMs, large scaleset (>100 instances allowed), no managed identity
#' rhel_8_ss(options=scaleset_options(low_priority=TRUE, large_scaleset=TRUE, managed=FALSE))
#'
#'
#' \dontrun{
#'
#' # reusing existing resources: placing a scaleset in an existing vnet/subnet
#' # we don't need a new network security group either
#' vnet <- AzureRMR::get_azure_login()$
#' get_subscription("sub_id")$
#' get_resource_group("rgname")$
#' get_resource(type="Microsoft.Network/virtualNetworks", name="myvnet")
#'
#' ubuntu_18.04_ss(vnet=vnet, nsg=NULL)
#'
#' }
#' @export
vmss_config <- function(image, options=scaleset_options(),
nsg=nsg_config(),
vnet=vnet_config(),
load_balancer=lb_config(),
load_balancer_address=ip_config(),
autoscaler=autoscaler_config(),
other_resources=list(),
variables=list(),
...)
{
stopifnot(inherits(image, "image_config"))
stopifnot(inherits(options, "scaleset_options"))
# make IP sku, balancer sku and scaleset size consistent with each other
load_balancer <- vmss_fixup_lb(options, load_balancer)
ip <- vmss_fixup_ip(options, load_balancer, load_balancer_address)
obj <- list(
image=image,
options=options,
nsg=nsg,
vnet=vnet,
lb=load_balancer,
ip=ip,
as=autoscaler,
other=other_resources,
variables=variables,
vmss_fields=list(...)
)
structure(obj, class="vmss_config")
}
vmss_fixup_lb <- function(options, lb)
{
# don't try to fix load balancer if not created here
if(is.null(lb) || !inherits(lb, "lb_config"))
return(lb)
# for a large scaleset, must set sku=standard
if(!options$params$singlePlacementGroup)
{
if(is.null(lb$type))
lb$type <- "standard"
else if(tolower(lb$type) != "standard")
stop("Load balancer type must be 'standard' for large scalesets", call.=FALSE)
}
else
{
if(is.null(lb$type))
lb$type <- "basic"
}
lb
}
vmss_fixup_ip <- function(options, lb, ip)
{
# IP address only required if load balancer is present
if(is.null(lb))
return(NULL)
# don't try to fix IP if load balancer was provided as a resource id
if(is.character(lb))
return(ip)
# don't try to fix IP if not created here
if(is.null(ip) || !inherits(ip, "ip_config"))
return(ip)
lb_type <- if(is_resource(lb))
lb$sku$name
else lb$type
# for a large scaleset, must set sku=standard, allocation=static
if(!options$params$singlePlacementGroup)
{
if(is.null(ip$type))
ip$type <- "standard"
else if(tolower(ip$type) != "standard")
stop("Load balancer IP address type must be 'standard' for large scalesets", call.=FALSE)
if(is.null(ip$dynamic))
ip$dynamic <- FALSE
else if(ip$dynamic)
stop("Load balancer dynamic IP address not supported for large scalesets", call.=FALSE)
}
else
{
# defaults for small scaleset: sku=load balancer sku, allocation=dynamic
if(is.null(ip$type))
ip$type <- lb_type
if(is.null(ip$dynamic))
ip$dynamic <- tolower(ip$type) == "basic"
}
# check consistency
if(tolower(ip$type) == "standard" && ip$dynamic)
stop("Standard IP address type does not support dynamic allocation", call.=FALSE)
ip
}
#' @rdname vmss_config
#' @export
ubuntu_dsvm_ss <- function(nsg=nsg_config(list(nsg_rule_allow_ssh, nsg_rule_allow_jupyter, nsg_rule_allow_rstudio)),
load_balancer=lb_config(rules=list(lb_rule_ssh, lb_rule_jupyter, lb_rule_rstudio),
probes=list(lb_probe_ssh, lb_probe_jupyter, lb_probe_rstudio)),
...)
{
vmss_config(image_config("microsoft-dsvm", "linux-data-science-vm-ubuntu", "linuxdsvmubuntu"),
nsg=nsg, load_balancer=load_balancer, ...)
}
#' @rdname vmss_config
#' @export
windows_dsvm_ss <- function(nsg=nsg_config(list(nsg_rule_allow_rdp)),
load_balancer=lb_config(rules=list(lb_rule_rdp),
probes=list(lb_probe_rdp)),
options=scaleset_options(keylogin=FALSE),
...)
{
options$keylogin <- FALSE
vmss_config(image_config("microsoft-dsvm", "dsvm-windows", "server-2016"),
options=options, nsg=nsg, load_balancer=load_balancer, ...)
}
#' @rdname vmss_config
#' @export
ubuntu_16.04_ss <- function(nsg=nsg_config(list(nsg_rule_allow_ssh)),
load_balancer=lb_config(rules=list(lb_rule_ssh),
probes=list(lb_probe_ssh)),
...)
{
vmss_config(image_config("Canonical", "UbuntuServer", "16.04-LTS"),
nsg=nsg, load_balancer=load_balancer, ...)
}
#' @rdname vmss_config
#' @export
ubuntu_18.04_ss <- function(nsg=nsg_config(list(nsg_rule_allow_ssh)),
load_balancer=lb_config(rules=list(lb_rule_ssh),
probes=list(lb_probe_ssh)),
...)
{
vmss_config(image_config("Canonical", "UbuntuServer", "18.04-LTS"),
nsg=nsg, load_balancer=load_balancer, ...)
}
#' @rdname vmss_config
#' @export
windows_2016_ss <- function(nsg=nsg_config(list(nsg_rule_allow_rdp)),
load_balancer=lb_config(rules=list(lb_rule_rdp),
probes=list(lb_probe_rdp)),
options=scaleset_options(keylogin=FALSE),
...)
{
options$keylogin <- FALSE
vmss_config(image_config("MicrosoftWindowsServer", "WindowsServer", "2016-Datacenter"),
options=options, nsg=nsg, load_balancer=load_balancer, ...)
}
#' @rdname vmss_config
#' @export
windows_2019_ss <- function(nsg=nsg_config(list(nsg_rule_allow_rdp)),
load_balancer=lb_config(rules=list(lb_rule_rdp),
probes=list(lb_probe_rdp)),
options=scaleset_options(keylogin=FALSE),
...)
{
options$keylogin <- FALSE
vmss_config(image_config("MicrosoftWindowsServer", "WindowsServer", "2019-Datacenter"),
options=options, nsg=nsg, load_balancer=load_balancer, ...)
}
#' @rdname vmss_config
#' @export
rhel_7.6_ss <- function(nsg=nsg_config(list(nsg_rule_allow_ssh)),
load_balancer=lb_config(rules=list(lb_rule_ssh),
probes=list(lb_probe_ssh)),
...)
{
vmss_config(image_config("RedHat", "RHEL", "7-RAW"),
nsg=nsg, load_balancer=load_balancer, ...)
}
#' @rdname vmss_config
#' @export
rhel_8_ss <- function(nsg=nsg_config(list(nsg_rule_allow_ssh)),
load_balancer=lb_config(rules=list(lb_rule_ssh),
probes=list(lb_probe_ssh)),
...)
{
vmss_config(image_config("RedHat", "RHEL", "8"),
nsg=nsg, load_balancer=load_balancer, ...)
}
#' @rdname vmss_config
#' @export
debian_9_backports_ss <- function(nsg=nsg_config(list(nsg_rule_allow_ssh)),
load_balancer=lb_config(rules=list(lb_rule_ssh),
probes=list(lb_probe_ssh)),
...)
{
vmss_config(image_config("Credativ", "Debian", "9-backports"),
nsg=nsg, load_balancer=load_balancer, ...)
}
#' Virtual machine scaleset options
#'
#' @param keylogin Boolean: whether to use an SSH public key to login (TRUE) or a password (FALSE). Note that Windows does not support SSH key logins.
#' @param managed Whether to provide a managed system identity for the VM.
#' @param public Whether the instances (nodes) of the scaleset should be visible from the public internet.
#' @param low_priority Whether to use low-priority VMs. Note that this option is only available for certain VM sizes.
#' @param delete_on_evict If low-priority VMs are being used, whether evicting (shutting down) a VM should delete it, as opposed to just deallocating it.
#' @param network_accel Whether to enable accelerated networking.
#' @param large_scaleset Whether to enable scaleset sizes > 100 instances.
#' @param overprovision Whether to overprovision the scaleset on creation.
#' @param upgrade_policy A list, giving the VM upgrade policy for the scaleset.
#'
#' @export
scaleset_options <- function(keylogin=TRUE, managed=TRUE, public=FALSE,
low_priority=FALSE, delete_on_evict=FALSE,
network_accel=FALSE, large_scaleset=FALSE,
overprovision=TRUE, upgrade_policy=list(mode="manual"))
{
params <- list(
priority=if(low_priority) "low" else "regular",
evictionPolicy=if(delete_on_evict) "delete" else "deallocate",
enableAcceleratedNetworking=network_accel,
singlePlacementGroup=!large_scaleset,
overprovision=overprovision,
upgradePolicy=upgrade_policy
)
out <- list(keylogin=keylogin, managed=managed, public=public, params=params)
structure(out, class="scaleset_options")
}

130
R/vmss_template_builders.R Normal file
Просмотреть файл

@ -0,0 +1,130 @@
add_template_parameters.vmss_config <- function(config, ...)
{
add_param <- function(...)
{
new_params <- lapply(list(...), function(obj) list(type=obj))
params <<- c(params, new_params)
}
params <- sstpl_parameters_default
if(config$options$keylogin)
add_param(sshKeyData="string")
else add_param(adminPassword="securestring")
if(inherits(config$image, "image_marketplace"))
add_param(imagePublisher="string", imageOffer="string", imageSku="string", imageVersion="string")
else add_param(imageId="string")
params
}
add_template_variables.vmss_config <- function(config, ...)
{
vars <- list(
location="[resourceGroup().location]",
vmId="[resourceId('Microsoft.Compute/virtualMachineScalesets', parameters('vmName'))]",
vmRef="[concat('Microsoft.Compute/virtualMachineScalesets/', parameters('vmName'))]",
vmPrefix="[concat(parameters('vmName'), '-instance')]"
)
for(res in c("nsg", "vnet", "lb", "ip", "as"))
vars <- c(vars, add_template_variables(config[[res]], res))
# add any extra variables provided by the user
utils::modifyList(vars, config$variables)
}
add_template_resources.vmss_config <- function(config, ...)
{
vmss <- vmss_default
# fixup VMSS properties
if(config$options$managed)
vmss$identity <- list(type="systemAssigned")
# fixup VM properties
vm <- vmss$properties$virtualMachineProfile
vm$osProfile <- c(vm$osProfile,
if(config$options$keylogin) vm_key_login else vm_pwd_login)
vm$storageProfile$imageReference <- if(inherits(config$image, "image_custom"))
list(id="[parameters('imageId')]")
else list(
publisher="[parameters('imagePublisher')]",
offer="[parameters('imageOffer')]",
sku="[parameters('imageSku')]",
version="[parameters('imageVersion')]"
)
if(config$options$params$priority == "low")
vm$evictionPolicy <- "[parameters('evictionPolicy')]"
if(!is_empty(config$lb))
{
vm$
networkProfile$
networkInterfaceConfigurations[[1]]$
properties$
ipConfigurations[[1]]$
properties$
loadBalancerBackendAddressPools <- list(list(id="[variables('lbBackendId')]")) # lol
}
if(config$options$public)
{
vm$
networkProfile$
networkInterfaceConfigurations[[1]]$
properties$
ipConfigurations[[1]]$
properties$
publicIpAddressConfiguration <- list(
name="pub1",
properties=list(idleTimeoutInMinutes=15)
)
}
vmss$properties$virtualMachineProfile <- vm
if(!is_empty(config$vmss_fields))
vmss <- utils::modifyList(vmss, config$vmss_fields)
resources <- config[c("nsg", "vnet", "lb", "ip", "as")]
existing <- sapply(resources, existing_resource)
unused <- sapply(resources, is.null)
create <- !existing & !unused
# cannot use lapply(*, build_resource_fields) because of lapply wart
resources <- lapply(resources[create], function(x) build_resource_fields(x))
## fixup dependencies between resources
# vnet depends on nsg
# vmss depends on vnet, lb
if(create["vnet"])
{
if(!create["nsg"])
resources$vnet$dependsOn <- NULL
if(unused["nsg"])
resources$vnet$properties$subnets[[1]]$properties$networkSecurityGroup <- NULL
}
vmss_depends <- character()
if(create["lb"])
vmss_depends <- c(vmss_depends, "[variables('lbRef')]")
if(create["vnet"])
vmss_depends <- c(vmss_depends, "[variables('vnetRef')]")
vmss$dependsOn <- I(vmss_depends)
resources <- c(resources, list(vmss))
if(!is_empty(config$other))
resources <- c(resources, lapply(config$other, function(x) build_resource_fields(x)))
unname(resources)
}

86
R/vnet_config.R Normal file
Просмотреть файл

@ -0,0 +1,86 @@
#' Virtual network configuration
#'
#' @param address_space For `vnet_config`, the address range accessible by the virtual network, expressed in CIDR block format.
#' @param subnets For `vnet_config`, a list of subnet objects, each obtained via a call to `subnet_config`.
#' @param name For `subnet_config`, the name of the subnet. Duplicate names will automatically be disambiguated prior to VM deployment.
#' @param addresses For `subnet_config`, the address ranges spanned by this subnet. Must be a subset of the address space available to the parent virtual network.
#' @param nsg The network security group associated with this subnet. Defaults to the NSG created as part of this VM deployment.
#' @param ... Other named arguments that will be treated as resource properties.
#'
#' @seealso
#' [create_vm], [vm_config], [vmss_config]
#' @export
vnet_config <- function(address_space="10.0.0.0/16", subnets=list(subnet_config()), ...)
{
# attempt to fixup address blocks so they are consistent (should use iptools when it's fixed)
ab_regex <- "^([0-9]+\\.[0-9]+).*$"
ab_block <- sub(ab_regex, "\\1", address_space)
fixaddr <- function(addr)
{
if(sub(ab_regex, "\\1", addr) == ab_block)
sub("^[0-9]+\\.[0-9]+", ab_block, addr)
else addr
}
subnets <- lapply(subnets, function(sn)
{
if(!is_empty(sn$properties$addressPrefix))
sn$properties$addressPrefix <- fixaddr(sn$properties$addressPrefix)
if(!is_empty(sn$properties$addressPrefixes))
sn$properties$addressPrefixes <- sapply(sn$properties$addressPrefixes, fixaddr)
sn
})
# unique-ify subnet names
sn_names <- make.unique(sapply(subnets, `[[`, "name"))
for(i in seq_along(subnets))
subnets[[i]]$name <- sn_names[i]
props <- list(
addressSpace=list(addressPrefixes=I(address_space)),
subnets=subnets,
...
)
structure(list(properties=props), class="vnet_config")
}
build_resource_fields.vnet_config <- function(config, ...)
{
config$properties$subnets <- lapply(config$properties$subnets, unclass)
utils::modifyList(vnet_default, config)
}
add_template_variables.vnet_config <- function(config, ...)
{
name <- "[concat(parameters('vmName'), '-vnet')]"
id <- "[resourceId('Microsoft.Network/virtualNetworks', variables('vnetName'))]"
ref <- "[concat('Microsoft.Network/virtualNetworks/', variables('vnetName'))]"
subnet <- config$properties$subnets[[1]]$name
subnet_id <- "[concat(variables('vnetId'), '/subnets/', variables('subnet'))]"
list(vnetName=name, vnetId=id, vnetRef=ref, subnet=subnet, subnetId=subnet_id)
}
#' @rdname vnet_config
#' @export
subnet_config <- function(name="subnet", addresses="10.0.0.0/16", nsg="[variables('nsgId')]", ...)
{
properties <- if(length(addresses) < 2)
list(addressPrefix=addresses, ...)
else list(addressPrefixes=addresses, ...)
# check if supplied a network security group resource ID or object
if(is.character(nsg))
properties$networkSecurityGroup$id <- nsg
else if(is_resource(nsg) && tolower(nsg$type) == "microsoft.network/networksecuritygroups")
properties$networkSecurityGroup$id <- nsg$id
else if(!is.null(nsg))
warning("Invalid network security group", call.=FALSE)
subnet <- list(name=name, properties=properties)
structure(subnet, class="subnet_config")
}

204
README.md
Просмотреть файл

@ -4,77 +4,165 @@
![Downloads](https://cranlogs.r-pkg.org/badges/AzureVM) ![Downloads](https://cranlogs.r-pkg.org/badges/AzureVM)
[![Travis Build Status](https://travis-ci.org/Azure/AzureVM.png?branch=master)](https://travis-ci.org/Azure/AzureVM) [![Travis Build Status](https://travis-ci.org/Azure/AzureVM.png?branch=master)](https://travis-ci.org/Azure/AzureVM)
This is a package for interacting with virtual machines in Azure. You can deploy, start up, shut down, run scripts, deallocate and delete VMs from the R command line. A number of VM templates are included based on the [Data Science Virtual Machine](https://azure.microsoft.com/en-us/services/virtual-machines/data-science-virtual-machines/), but you can also deploy other templates that you supply. AzureVM is a package for interacting with virtual machines and virtual machine scalesets in Azure. You can deploy, start up, shut down, run scripts, deallocate and delete VMs and scalesets from the R command line. It uses the tools provided by the [AzureRMR package](https://github.com/Azure/AzureRMR) to manage VM resources and templates.
AzureVM uses the tools provided by the [AzureRMR package](https://github.com/Azure/AzureRMR) to manage VM resources and templates. The main VM R6 class wraps the deployment template, allowing easy management of all resources as a unit. You can also create a VM in exclusive mode, meaning that it sits in its own resource group. ## Virtual machines
The package supports both single VMs as well as clusters. A single VM is treated as a cluster containing only one node. Here is a simple example. We create a VM using the default settings, run a shell command, and then delete the VM.
A sample workflow:
```r ```r
library(AzureRMR)
library(AzureVM) library(AzureVM)
# authenticate with Resource Manager sub <- AzureRMR::get_azure_login()$
az <- az_rm$new(tenant="xxx-xxx-xxx", app="yyy-yyy-yyy", secret="{secret goes here}") get_subscription("5710aa44-281f-49fe-bfa6-69e66bb55b11")
sub1 <- az$get_subscription("5710aa44-281f-49fe-bfa6-69e66bb55b11")
# list VM sizes -- a large data frame
sub1$list_vm_sizes(location="australiasoutheast")
# name numberOfCores osDiskSizeInMB resourceDiskSizeInMB memoryInMB maxDataDiskCount
# 1 Standard_A0 1 1047552 20480 768 1
# 2 Standard_A1 1 1047552 71680 1792 2
# 3 Standard_A2 2 1047552 138240 3584 4
# 4 Standard_A3 4 1047552 291840 7168 8
# 5 Standard_A5 2 1047552 138240 14336 4
# 6 Standard_A4 8 1047552 619520 14336 16
# ...
# create a new Ubuntu VM in an existing resource group
rg <- sub1$get_resource_group("rdev1")
key <- readLines("~/id_rsa.pub")
rdevtest <- rg$create_vm("rdevtest", username="user", passkey=key, userauth_type="key", os="Ubuntu",
location="australiasoutheast")
rdevtest
#<Azure virtual machine rdevtest>
# Operating system: Linux
# Exclusive resource group: FALSE
# Domain name: rdevtest.australiasoutheast.cloudapp.azure.com
# Status:
# ProvisioningState PowerState
# rdevtest succeeded running
#---
# disks: list(rdevtest)
# id: /subscriptions/5710aa44-281f-49fe-bfa6-69e66bb55b11/resourceGroups/rdev1/providers/Microsoft.Resou ...
# ip_address: xxx.xxx.xxx.xxx
# properties: list(templateHash, parameters, mode, debugSetting, provisioningState, timestamp, duration,
# correlationId, providers, dependencies, outputs, outputResources)
#---
# Methods:
# add_extension, cancel, check, delete, restart, run_deployed_command, run_script, start, stop,
# sync_vm_status
# shut down the VM
rdevtest$stop()
# ... and delete it (this will take some time)
rdevtest$delete()
# calling create_vm() from a subscription object will create the VM in its own resource group # calling create_vm() from a subscription object will create the VM in its own resource group
rdevtest2 <- sub1$create_vm("rdevtest2", username="user", passkey=key, userauth_type="key", os="Ubuntu", # default is an Ubuntu 18.04 VM, size Standard_DS3_v2, login via SSH key
location="australiasoutheast") # call sub$list_vm_sizes() to get the sizes available in your region
vm <- sub$create_vm("myubuntuvm", user_config("myname", "~/.ssh/id_rsa.pub"),
location="australiaeast")
# run a shell script or command remotely (will be PowerShell on a Windows VM) # run a shell script or command remotely (will be PowerShell on a Windows VM)
rdevtest2$run_script("ifconfig > /tmp/ifc.txt") vm$run_script("ifconfig > /tmp/ifc.txt")
# ... and stop it # ... and stop it
rdevtest2$stop() vm$stop()
# .. and delete it (this can be done asynchronously for a VM in its own group) # ... and resize it
rdevtest2$delete() vm$resize("Standard_DS4_v2")
# ... and delete it (this can be done asynchronously for a VM in its own group)
vm$delete()
```
AzureVM comes with a number of predefined configurations, for deploying commonly used VM images. For example, to create an Ubuntu DSVM accessible via SSH, JupyterHub and RStudio Server:
```r
sub$create_vm("mydsvm", user_config("myname", "~/.ssh/id_rsa.pub"), config="ubuntu_dsvm",
location="australiaeast")
```
And to create a Windows Server 2019 VM, accessible via RDP:
```r
sub$create_vm("mywinvm", user_config("myname", password="Use-strong-passwords!"), config="windows_2019",
location="australiaeast")
```
The available predefined configurations are `ubuntu_18.04` (the default), `ubuntu_16.04`, `ubuntu_dsvm`, `windows_2019`, `windows_2016`, `windows_dsvm`, `rhel_7.6`, `rhel_8` and `debian_9_backports`. You can combine these with several other arguments to customise the VM deployment to your needs:
- `size`: VM size. Use the `list_vm_sizes` method for the subscription and resource group classes to see the available sizes.
- `datadisks`: The data disk sizes/configurations to attach.
- `ip`: Public ip address. Set this to NULL if you don't want the VM to be accessible outside its subnet.
- `vnet`: Virtual network/subnet.
- `nsg`: Network security group. AzureVM will associate the NSG with the vnet/subnet, not with the VM's network interface.
- `nic`: Network interface.
- `other_resources`: Optionally, a list of other resources to deploy.
```r
# Windows Server 2016, with a 500GB datadisk attached, not publicly accessible
sub$create_vm("mywinvm2", user_config("myname", password="Use-strong-passwords!"),
size="Standard_DS4_v2", config="windows_2016", datadisks=500, ip=NULL,
location="australiaeast")
# Ubuntu DSVM, GPU-enabled
sub$create_vm("mydsvm", user_config("myname", "~/.ssh/id_rsa.pub"), size="Standard_NC12",
config="ubuntu_dsvm_ss",
location="australiaeast")
# Red Hat VM, serving HTTP/HTTPS
sub$create_vm("myrhvm", user_config("myname", "~/.ssh/id_rsa.pub"), config="rhel_8",
nsg=nsg_config(list(nsg_rule_allow_http, nsg_rule_allow_https)),
location="australiaeast")
```
Full customisation is provided by the `vm_config` function, which also lets you specify the image to deploy, either from the marketplace or a disk. (The predefined configurations actually call `vm_config`, with the appropriate arguments for each specific config.)
```r
## custom VM configuration: Windows 10 Pro 1903 with data disks
## this assumes you have a valid Win10 desktop license
user <- user_config("myname", password="Use-strong-passwords!")
image <- image_config(
publisher="MicrosoftWindowsDesktop",
offer="Windows-10",
sku="19h1-pro"
)
datadisks <- list(
datadisk_config(250, type="Premium_LRS"),
datadisk_config(1000, type="Standard_LRS")
)
nsg <- nsg_config(
list(nsg_rule_allow_rdp)
)
sub$create_vm("mywin10vm", user,
config=vm_config(
image=image,
keylogin=FALSE,
datadisks=datadisks,
nsg=nsg,
properties=list(licenseType="Windows_Client")
),
location="australiaeast"
)
```
## VM scalesets
The equivalent to `create_vm` for scalesets is the `create_vm_scaleset` method. By default, a new scaleset will come with a load balancer and autoscaler attached, but its instances will not be externally accessible.
```r
# default is Ubuntu 18.04 scaleset, size Standard_DS1_v2
sub$create_vm_scaleset("myubuntuss", user_config("myname", "~/.ssh/id_rsa.pub"), instances=5,
location="australiaeast")
```
Each predefined VM configuration has a corresponding scaleset configuration. To specify low-level scaleset settings, use the `scaleset_options` argument. Here are some sample scaleset deployments:
```r
# Windows Server 2019
sub$create_vm_scaleset("mywinss", user_config("myname", password="Use-strong-passwords!"), instances=5,
config="windows_2019",
location="australiaeast")
# RHEL scaleset, serving HTTP/HTTPS
sub$create_vm_scaleset("myrhelss", user_config("myname", "~/.ssh/id_rsa.pub"), instances=5,
config="rhel_8_ss",
nsg=nsg_config(list(nsg_rule_allow_http, nsg_rule_allow_https)),
location="australiaeast")
# Ubuntu DSVM, GPU-enabled, public instances, no load balancer or autoscaler
sub$create_vm_scaleset("mydsvmss", user_config("myname", "~/.ssh/id_rsa.pub"), instances=5,
size="Standard_NC6", config="ubuntu_dsvm_ss",
options=scaleset_options(public=TRUE),
load_balancer=NULL, autoscaler=NULL,
location="australiaeast")
# Large Debian scaleset (multiple placement groups), using low-priority VMs
# need to set the instance size to something that supports low-pri
sub$create_vm_scaleset("mydebss", user_config("myname", "~/.ssh/id_rsa.pub"), instances=10,
size="Standard_DS3_v2", config="debian_9_backports_ss",
options=scaleset_options(low_priority=TRUE, large_scaleset=TRUE),
location="australiaeast")
```
## Sharing resources
You can also include an existing Azure resource in a deployment, by supplying an AzureRMR `az_resource` object as an argument in the `create_vm` or `create_vm_scaleset` call. For example, here we create a VM and a scaleset that share a single virtual network/subnet.
```r
## VM and scaleset in the same resource group and virtual network
# first, create the resgroup
rg <- sub$create_resource_group("rgname", "australiaeast")
# create the master
rg$create_vm("mastervm", user_config("myname", "~/.ssh/id_rsa.pub"))
# get the vnet resource
vnet <- rg$get_resource(type="Microsoft.Network/virtualNetworks", name="mastervm-vnet")
# create the scaleset
# since the NSG is associated with the vnet, we don't need to create a new NSG either
rg$create_vm_scaleset("slavess", user_config("myname", "~/.ssh/id_rsa.pub"),
instances=5, vnet=vnet, nsg=NULL, load_balancer=NULL, autoscaler=NULL)
``` ```
--- ---

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

@ -1,210 +0,0 @@
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"adminUsername": {
"type": "string",
"metadata": {
"description": "Username for the Virtual Machine."
}
},
"adminPassword": {
"type": "securestring",
"metadata": {
"description": "Password for the Virtual Machine."
}
},
"vmName": {
"type": "string",
"metadata": {
"description": "Name Prefix for the Virtual Machine."
}
},
"vmSize": {
"type": "string",
"defaultValue": "Standard_DS3_v2",
"metadata": {
"description": "Size for the Virtual Machine."
}
}
},
"variables": {
"location": "[resourceGroup().location]",
"imagePublisher": "microsoft-dsvm",
"imageOffer": "linux-data-science-vm-ubuntu",
"OSDiskName": "[concat(parameters('vmName'),'-osdisk')]",
"DataDiskName": "[concat(parameters('vmName'),'-data-0')]",
"sku": "linuxdsvmubuntu",
"nicName": "[parameters('vmName')]",
"addressPrefix": "10.0.0.0/16",
"subnetName": "Subnet",
"subnetPrefix": "10.0.0.0/24",
"publicIPAddressType": "Dynamic",
"publicIPAddressName": "[parameters('vmName')]",
"vmName": "[parameters('vmName')]",
"vmSize": "[parameters('vmSize')]",
"virtualNetworkName": "[parameters('vmName')]",
"nsgName": "[concat(parameters('vmName'),'-nsg')]",
"nsgId": "[resourceId(resourceGroup().name, 'Microsoft.Network/networkSecurityGroups', variables('nsgName'))]",
"vnetID": "[resourceId('Microsoft.Network/virtualNetworks',variables('virtualNetworkName'))]",
"subnetRef": "[concat(variables('vnetID'),'/subnets/',variables('subnetName'))]"
},
"resources": [
{
"apiVersion": "2018-02-01",
"type": "Microsoft.Network/networkSecurityGroups",
"location": "[variables('location')]",
"name": "[variables('nsgName')]",
"properties": {
"securityRules": [
{
"name": "Allow-SSH-Jupyterhub",
"properties": {
"protocol": "Tcp",
"sourcePortRange": "*",
"sourceAddressPrefix": "*",
"destinationAddressPrefix": "*",
"access": "Allow",
"priority": 100,
"direction": "Inbound",
"sourcePortRanges": [],
"destinationPortRanges": [
"22",
"8000"
],
"destinationPortRange": ""
}
}
]
}
},
{
"apiVersion": "2015-05-01-preview",
"type": "Microsoft.Network/publicIPAddresses",
"name": "[variables('publicIPAddressName')]",
"location": "[variables('location')]",
"properties": {
"publicIPAllocationMethod": "[variables('publicIPAddressType')]",
"dnsSettings": {
"domainNameLabel": "[variables('publicIPAddressName')]"
}
}
},
{
"apiVersion": "2015-05-01-preview",
"type": "Microsoft.Network/virtualNetworks",
"name": "[variables('virtualNetworkName')]",
"location": "[variables('location')]",
"dependsOn": [
"[concat('Microsoft.Network/networkSecurityGroups/', variables('nsgName'))]"
],
"properties": {
"addressSpace": {
"addressPrefixes": [
"[variables('addressPrefix')]"
]
},
"subnets": [
{
"name": "[variables('subnetName')]",
"properties": {
"addressPrefix": "[variables('subnetPrefix')]"
}
}
]
}
},
{
"apiVersion": "2015-05-01-preview",
"type": "Microsoft.Network/networkInterfaces",
"name": "[variables('nicName')]",
"location": "[variables('location')]",
"dependsOn": [
"[concat('Microsoft.Network/publicIPAddresses/', variables('publicIPAddressName'))]",
"[concat('Microsoft.Network/virtualNetworks/', variables('virtualNetworkName'))]",
"[concat('Microsoft.Network/networkSecurityGroups/', variables('nsgName'))]"
],
"properties": {
"ipConfigurations": [
{
"name": "ipconfig1",
"properties": {
"privateIPAllocationMethod": "Dynamic",
"publicIPAddress": {
"id": "[resourceId('Microsoft.Network/publicIPAddresses',variables('publicIPAddressName'))]"
},
"subnet": {
"id": "[variables('subnetRef')]"
}
}
}
],
"networkSecurityGroup": {
"id": "[variables('nsgId')]"
}
}
},
{
"apiVersion": "2017-03-30",
"type": "Microsoft.Compute/virtualMachines",
"name": "[variables('vmName')]",
"location": "[variables('location')]",
"tags": {
"Application": "DataScience"
},
"dependsOn": [
"[concat('Microsoft.Network/networkInterfaces/', variables('nicName'))]"
],
"properties": {
"hardwareProfile": {
"vmSize": "[variables('vmSize')]"
},
"osProfile": {
"computerName": "[variables('vmName')]",
"adminUsername": "[parameters('adminUsername')]",
"adminPassword": "[parameters('adminPassword')]"
},
"storageProfile": {
"imageReference": {
"publisher": "[variables('imagePublisher')]",
"offer": "[variables('imageOffer')]",
"sku": "[variables('sku')]",
"version": "latest"
},
"osDisk": {
"name": "[variables('OSDiskName')]",
"managedDisk": {
"storageAccountType": "Standard_LRS"
},
"createOption": "FromImage"
},
"dataDisks": [
{
"name": "[variables('DataDiskName')]",
"managedDisk": {
"storageAccountType": "Standard_LRS"
},
"createOption": "FromImage",
"lun": 0
}
]
},
"networkProfile": {
"networkInterfaces": [
{
"id": "[resourceId('Microsoft.Network/networkInterfaces',variables('nicName'))]"
}
]
},
"diagnosticsProfile": {
"bootDiagnostics": {
"enabled": false
}
}
}
}
],
"outputs": {
"DataScienceVmUrl": { "type": "string", "value": "[concat('https://ms.portal.azure.com/#resource/subscriptions/', subscription().subscriptionId, '/resourceGroups/', resourceGroup().name, '/providers/Microsoft.Compute/virtualMachines/', variables('vmName'))]" }
}
}

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

@ -1,227 +0,0 @@
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"adminUsername": {
"type": "string",
"metadata": {
"description": "Username for the Virtual Machine."
}
},
"adminPassword": {
"type": "securestring",
"metadata": {
"description": "Password for the Virtual Machine."
}
},
"numberOfInstances": {
"type": "string",
"defaultValue": "1",
"metadata": {
"description": "Number of VMs to deploy."
}
},
"vmName": {
"type": "string",
"metadata": {
"description": "Name Prefix for the Virtual Machine."
}
},
"vmSize": {
"type": "string",
"defaultValue": "Standard_DS3_v2",
"metadata": {
"description": "Size for the Virtual Machine."
}
}
},
"variables": {
"location": "[resourceGroup().location]",
"numberOfInstances": "[int(parameters('numberOfInstances'))]",
"imagePublisher": "microsoft-dsvm",
"imageOffer": "linux-data-science-vm-ubuntu",
"sku": "linuxdsvmubuntu",
"nicName": "[parameters('vmName')]",
"addressPrefix": "10.0.0.0/16",
"subnetName": "Subnet",
"subnetPrefix": "10.0.0.0/24",
"publicIPAddressType": "Dynamic",
"publicIPAddressName": "[parameters('vmName')]",
"vmName": "[parameters('vmName')]",
"vmSize": "[parameters('vmSize')]",
"virtualNetworkName": "[parameters('vmName')]",
"nsgName": "[concat(parameters('vmName'),'-nsg')]",
"nsgId": "[resourceId(resourceGroup().name, 'Microsoft.Network/networkSecurityGroups', variables('nsgName'))]",
"vnetID": "[resourceId('Microsoft.Network/virtualNetworks',variables('virtualNetworkName'))]",
"subnetRef": "[concat(variables('vnetID'),'/subnets/',variables('subnetName'))]"
},
"resources": [
{
"apiVersion": "2018-02-01",
"type": "Microsoft.Network/networkSecurityGroups",
"location": "[variables('location')]",
"name": "[variables('nsgName')]",
"properties": {
"securityRules": [
{
"name": "Allow-SSH-Jupyterhub",
"properties": {
"protocol": "Tcp",
"sourcePortRange": "*",
"sourceAddressPrefix": "*",
"destinationAddressPrefix": "*",
"access": "Allow",
"priority": 100,
"direction": "Inbound",
"sourcePortRanges": [],
"destinationPortRanges": [
"22",
"8000"
],
"destinationPortRange": ""
}
}
]
}
},
{
"apiVersion": "2015-05-01-preview",
"type": "Microsoft.Network/publicIPAddresses",
"name": "[concat(variables('publicIPAddressName'), copyindex())]",
"location": "[variables('location')]",
"copy": {
"name": "publicIPLoop",
"count": "[variables('numberOfInstances')]"
},
"properties": {
"publicIPAllocationMethod": "[variables('publicIPAddressType')]",
"dnsSettings": {
"domainNameLabel": "[concat(variables('publicIPAddressName'), copyindex())]"
}
}
},
{
"apiVersion": "2015-05-01-preview",
"type": "Microsoft.Network/virtualNetworks",
"name": "[variables('virtualNetworkName')]",
"location": "[variables('location')]",
"dependsOn": [
"[concat('Microsoft.Network/networkSecurityGroups/', variables('nsgName'))]"
],
"properties": {
"addressSpace": {
"addressPrefixes": [
"[variables('addressPrefix')]"
]
},
"subnets": [
{
"name": "[variables('subnetName')]",
"properties": {
"addressPrefix": "[variables('subnetPrefix')]",
"networkSecurityGroup": {
"id": "[variables('nsgId')]"
}
}
}
]
}
},
{
"apiVersion": "2015-05-01-preview",
"type": "Microsoft.Network/networkInterfaces",
"name": "[concat(variables('nicName'), copyindex())]",
"location": "[variables('location')]",
"copy": {
"name": "nicLoop",
"count": "[variables('numberOfInstances')]"
},
"dependsOn": [
"[concat('Microsoft.Network/publicIPAddresses/', concat(variables('publicIPAddressName'),copyindex()))]",
"[concat('Microsoft.Network/networkSecurityGroups/', variables('nsgName'))]",
"[concat('Microsoft.Network/virtualNetworks/', variables('virtualNetworkName'))]"
],
"properties": {
"ipConfigurations": [
{
"name": "ipconfig1",
"properties": {
"privateIPAllocationMethod": "Dynamic",
"publicIPAddress": {
"id": "[resourceId('Microsoft.Network/publicIPAddresses',concat(variables('publicIPAddressName'),copyindex()))]"
},
"subnet": {
"id": "[variables('subnetRef')]"
}
}
}
]
}
},
{
"apiVersion": "2017-03-30",
"type": "Microsoft.Compute/virtualMachines",
"name": "[concat(variables('vmName'), copyIndex())]",
"location": "[variables('location')]",
"copy": {
"name": "virtualMachineLoop",
"count": "[variables('numberOfInstances')]"
},
"tags": {
"Application": "DataScience"
},
"dependsOn": [
"[concat('Microsoft.Network/networkInterfaces/', variables('nicName'), copyindex())]"
],
"properties": {
"hardwareProfile": {
"vmSize": "[variables('vmSize')]"
},
"osProfile": {
"computerName": "[concat(variables('vmName'), copyIndex())]",
"adminUsername": "[parameters('adminUsername')]",
"adminPassword": "[parameters('adminPassword')]"
},
"storageProfile": {
"imageReference": {
"publisher": "[variables('imagePublisher')]",
"offer": "[variables('imageOffer')]",
"sku": "[variables('sku')]",
"version": "latest"
},
"osDisk": {
"managedDisk": {
"storageAccountType": "Standard_LRS"
},
"createOption": "FromImage"
},
"dataDisks": [
{
"managedDisk": {
"storageAccountType": "Standard_LRS"
},
"createOption": "FromImage",
"lun": 0
}
]
},
"networkProfile": {
"networkInterfaces": [
{
"id": "[resourceId('Microsoft.Network/networkInterfaces',concat(variables('nicName'), copyindex()))]"
}
]
},
"diagnosticsProfile": {
"bootDiagnostics": {
"enabled": false
}
}
}
}
],
"outputs": {
"firstDataScienceVmUrl": { "type": "string", "value": "[concat('https://ms.portal.azure.com/#resource/subscriptions/', subscription().subscriptionId, '/resourceGroups/', resourceGroup().name, '/providers/Microsoft.Compute/virtualMachines/', variables('vmName'), '0')]" },
"numInstances": { "type": "string", "value": "[parameters('numberOfInstances')]" }
}
}

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

@ -1,263 +0,0 @@
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"adminUsername": {
"type": "string",
"metadata": {
"description": "Username for the Virtual Machine."
}
},
"adminPassword": {
"type": "securestring",
"metadata": {
"description": "Password for the Virtual Machine."
}
},
"numberOfInstances": {
"type": "string",
"defaultValue": "1",
"metadata": {
"description": "Number of VMs to deploy."
}
},
"vmName": {
"type": "string",
"metadata": {
"description": "Name Prefix for the Virtual Machine."
}
},
"vmSize": {
"type": "string",
"defaultValue": "Standard_DS3_v2",
"metadata": {
"description": "Size for the Virtual Machine."
}
},
"fileUris": {
"type": "string",
"metadata": {
"description": "URL of the extension package or file"
}
},
"commandToExecute": {
"type": "string",
"defaultValue": "install.sh",
"metadata": {
"description": "Extension bash script command to execute"
}
}
},
"variables": {
"location": "[resourceGroup().location]",
"numberOfInstances": "[int(parameters('numberOfInstances'))]",
"imagePublisher": "microsoft-dsvm",
"imageOffer": "linux-data-science-vm-ubuntu",
"sku": "linuxdsvmubuntu",
"nicName": "[parameters('vmName')]",
"addressPrefix": "10.0.0.0/16",
"subnetName": "Subnet",
"subnetPrefix": "10.0.0.0/24",
"publicIPAddressType": "Dynamic",
"publicIPAddressName": "[parameters('vmName')]",
"vmName": "[parameters('vmName')]",
"vmSize": "[parameters('vmSize')]",
"virtualNetworkName": "[parameters('vmName')]",
"nsgName": "[concat(parameters('vmName'),'-nsg')]",
"nsgId": "[resourceId(resourceGroup().name, 'Microsoft.Network/networkSecurityGroups', variables('nsgName'))]",
"vnetID": "[resourceId('Microsoft.Network/virtualNetworks',variables('virtualNetworkName'))]",
"subnetRef": "[concat(variables('vnetID'),'/subnets/',variables('subnetName'))]",
"fileUris": "[parameters('fileUris')]",
"commandToExecute": "[concat('bash ', parameters('commandToExecute'))]"
},
"resources": [
{
"apiVersion": "2018-02-01",
"type": "Microsoft.Network/networkSecurityGroups",
"location": "[variables('location')]",
"name": "[variables('nsgName')]",
"properties": {
"securityRules": [
{
"name": "Allow-SSH-Jupyterhub",
"properties": {
"protocol": "Tcp",
"sourcePortRange": "*",
"sourceAddressPrefix": "*",
"destinationAddressPrefix": "*",
"access": "Allow",
"priority": 100,
"direction": "Inbound",
"sourcePortRanges": [],
"destinationPortRanges": [
"22",
"8000"
],
"destinationPortRange": ""
}
}
]
}
},
{
"apiVersion": "2015-05-01-preview",
"type": "Microsoft.Network/publicIPAddresses",
"name": "[concat(variables('publicIPAddressName'), copyindex())]",
"location": "[variables('location')]",
"copy": {
"name": "publicIPLoop",
"count": "[variables('numberOfInstances')]"
},
"properties": {
"publicIPAllocationMethod": "[variables('publicIPAddressType')]",
"dnsSettings": {
"domainNameLabel": "[concat(variables('publicIPAddressName'), copyindex())]"
}
}
},
{
"apiVersion": "2015-05-01-preview",
"type": "Microsoft.Network/virtualNetworks",
"name": "[variables('virtualNetworkName')]",
"location": "[variables('location')]",
"dependsOn": [
"[concat('Microsoft.Network/networkSecurityGroups/', variables('nsgName'))]"
],
"properties": {
"addressSpace": {
"addressPrefixes": [
"[variables('addressPrefix')]"
]
},
"subnets": [
{
"name": "[variables('subnetName')]",
"properties": {
"addressPrefix": "[variables('subnetPrefix')]"
}
}
]
}
},
{
"apiVersion": "2015-05-01-preview",
"type": "Microsoft.Network/networkInterfaces",
"name": "[concat(variables('nicName'), copyindex())]",
"location": "[variables('location')]",
"copy": {
"name": "nicLoop",
"count": "[variables('numberOfInstances')]"
},
"dependsOn": [
"[concat('Microsoft.Network/publicIPAddresses/', concat(variables('publicIPAddressName'),copyindex()))]",
"[concat('Microsoft.Network/networkSecurityGroups/', variables('nsgName'))]",
"[concat('Microsoft.Network/virtualNetworks/', variables('virtualNetworkName'))]"
],
"properties": {
"ipConfigurations": [
{
"name": "ipconfig1",
"properties": {
"privateIPAllocationMethod": "Dynamic",
"publicIPAddress": {
"id": "[resourceId('Microsoft.Network/publicIPAddresses',concat(variables('publicIPAddressName'),copyindex()))]"
},
"subnet": {
"id": "[variables('subnetRef')]"
}
}
}
],
"networkSecurityGroup": {
"id": "[variables('nsgId')]"
}
}
},
{
"apiVersion": "2017-03-30",
"type": "Microsoft.Compute/virtualMachines",
"name": "[concat(variables('vmName'), copyIndex())]",
"location": "[variables('location')]",
"copy": {
"name": "virtualMachineLoop",
"count": "[variables('numberOfInstances')]"
},
"tags": {
"Application": "DataScience"
},
"dependsOn": [
"[concat('Microsoft.Network/networkInterfaces/', variables('nicName'), copyindex())]"
],
"properties": {
"hardwareProfile": {
"vmSize": "[variables('vmSize')]"
},
"osProfile": {
"computerName": "[concat(variables('vmName'), copyIndex())]",
"adminUsername": "[parameters('adminUsername')]",
"adminPassword": "[parameters('adminPassword')]"
},
"storageProfile": {
"imageReference": {
"publisher": "[variables('imagePublisher')]",
"offer": "[variables('imageOffer')]",
"sku": "[variables('sku')]",
"version": "latest"
},
"osDisk": {
"managedDisk": {
"storageAccountType": "Standard_LRS"
},
"createOption": "FromImage"
},
"dataDisks": [
{
"managedDisk": {
"storageAccountType": "Standard_LRS"
},
"createOption": "FromImage",
"lun": 0
}
]
},
"networkProfile": {
"networkInterfaces": [
{
"id": "[resourceId('Microsoft.Network/networkInterfaces',concat(variables('nicName'), copyindex()))]"
}
]
},
"diagnosticsProfile": {
"bootDiagnostics": {
"enabled": false
}
}
},
"resources": [
{
"type": "extensions",
"name": "[variables('vmName')]",
"apiVersion": "2017-03-30",
"location": "[variables('location')]",
"dependsOn": [
"[concat('Microsoft.Compute/virtualMachines/', variables('vmName'),copyindex())]"
],
"properties": {
"publisher": "Microsoft.OSTCExtensions",
"type": "CustomScriptForLinux",
"typeHandlerVersion": "1.4",
"autoUpgradeMinorVersion": true,
"settings": {
"fileUris": "[split(variables('fileUris'), ' ')]",
"commandToExecute": "[variables('commandToExecute')]"
}
}
}
]
}
],
"outputs": {
"firstDataScienceVmUrl": { "type": "string", "value": "[concat('https://ms.portal.azure.com/#resource/subscriptions/', subscription().subscriptionId, '/resourceGroups/', resourceGroup().name, '/providers/Microsoft.Compute/virtualMachines/', variables('vmName'), '0')]" },
"numInstances": { "type": "string", "value": "[parameters('numberOfInstances')]" }
}
}

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

@ -1,244 +0,0 @@
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"adminUsername": {
"type": "string",
"metadata": {
"description": "Username for the Virtual Machine."
}
},
"sshKeyData": {
"type": "string",
"metadata": {
"description": "SSH public key data as a string."
}
},
"numberOfInstances": {
"type": "string",
"defaultValue": "1",
"metadata": {
"description": "Number of VMs to deploy."
}
},
"vmName": {
"type": "string",
"metadata": {
"description": "Name Prefix for the Virtual Machine."
}
},
"vmSize": {
"type": "string",
"defaultValue": "Standard_DS3_v2",
"metadata": {
"description": "Size for the Virtual Machine."
}
}
},
"variables": {
"location": "[resourceGroup().location]",
"numberOfInstances": "[int(parameters('numberOfInstances'))]",
"imagePublisher": "microsoft-dsvm",
"imageOffer": "linux-data-science-vm-ubuntu",
"sku": "linuxdsvmubuntu",
"nicName": "[parameters('vmName')]",
"addressPrefix": "10.0.0.0/16",
"subnetName": "Subnet",
"subnetPrefix": "10.0.0.0/24",
"publicIPAddressType": "Dynamic",
"publicIPAddressName": "[parameters('vmName')]",
"vmName": "[parameters('vmName')]",
"vmSize": "[parameters('vmSize')]",
"virtualNetworkName": "[parameters('vmName')]",
"nsgName": "[concat(parameters('vmName'),'-nsg')]",
"nsgId": "[resourceId(resourceGroup().name, 'Microsoft.Network/networkSecurityGroups', variables('nsgName'))]",
"vnetID": "[resourceId('Microsoft.Network/virtualNetworks',variables('virtualNetworkName'))]",
"subnetRef": "[concat(variables('vnetID'),'/subnets/',variables('subnetName'))]",
"sshKeyPath": "[concat('/home/',parameters('adminUsername'),'/.ssh/authorized_keys')]"
},
"resources": [
{
"apiVersion": "2018-02-01",
"type": "Microsoft.Network/networkSecurityGroups",
"location": "[variables('location')]",
"name": "[variables('nsgName')]",
"properties": {
"securityRules": [
{
"name": "Allow-SSH-Jupyterhub",
"properties": {
"protocol": "Tcp",
"sourcePortRange": "*",
"sourceAddressPrefix": "*",
"destinationAddressPrefix": "*",
"access": "Allow",
"priority": 100,
"direction": "Inbound",
"sourcePortRanges": [],
"destinationPortRanges": [
"22",
"8000"
],
"destinationPortRange": ""
}
}
]
}
},
{
"apiVersion": "2015-05-01-preview",
"type": "Microsoft.Network/publicIPAddresses",
"name": "[concat(variables('publicIPAddressName'), copyindex())]",
"location": "[variables('location')]",
"copy": {
"name": "publicIPLoop",
"count": "[variables('numberOfInstances')]"
},
"properties": {
"publicIPAllocationMethod": "[variables('publicIPAddressType')]",
"dnsSettings": {
"domainNameLabel": "[concat(variables('publicIPAddressName'), copyindex())]"
}
}
},
{
"apiVersion": "2015-05-01-preview",
"type": "Microsoft.Network/virtualNetworks",
"name": "[variables('virtualNetworkName')]",
"location": "[variables('location')]",
"dependsOn": [
"[concat('Microsoft.Network/networkSecurityGroups/', variables('nsgName'))]"
],
"properties": {
"addressSpace": {
"addressPrefixes": [
"[variables('addressPrefix')]"
]
},
"subnets": [
{
"name": "[variables('subnetName')]",
"properties": {
"addressPrefix": "[variables('subnetPrefix')]"
}
}
]
}
},
{
"apiVersion": "2015-05-01-preview",
"type": "Microsoft.Network/networkInterfaces",
"name": "[concat(variables('nicName'), copyindex())]",
"location": "[variables('location')]",
"copy": {
"name": "nicLoop",
"count": "[variables('numberOfInstances')]"
},
"dependsOn": [
"[concat('Microsoft.Network/publicIPAddresses/', concat(variables('publicIPAddressName'),copyindex()))]",
"[concat('Microsoft.Network/networkSecurityGroups/', variables('nsgName'))]",
"[concat('Microsoft.Network/virtualNetworks/', variables('virtualNetworkName'))]"
],
"properties": {
"ipConfigurations": [
{
"name": "ipconfig1",
"properties": {
"privateIPAllocationMethod": "Dynamic",
"publicIPAddress": {
"id": "[resourceId('Microsoft.Network/publicIPAddresses',concat(variables('publicIPAddressName'),copyindex()))]"
},
"subnet": {
"id": "[variables('subnetRef')]"
}
}
}
],
"networkSecurityGroup": {
"id": "[variables('nsgId')]"
}
}
},
{
"apiVersion": "2017-03-30",
"type": "Microsoft.Compute/virtualMachines",
"name": "[concat(variables('vmName'), copyIndex())]",
"location": "[variables('location')]",
"copy": {
"name": "virtualMachineLoop",
"count": "[variables('numberOfInstances')]"
},
"tags": {
"Application": "DataScience"
},
"dependsOn": [
"[concat('Microsoft.Network/networkInterfaces/', variables('nicName'), copyindex())]"
],
"properties": {
"hardwareProfile": {
"vmSize": "[variables('vmSize')]"
},
"osProfile": {
"computerName": "[concat(variables('vmName'), copyIndex())]",
"adminUsername": "[parameters('adminUsername')]",
"linuxConfiguration": {
"disablePasswordAuthentication": true,
"ssh": {
"publicKeys": [
{
"path": "[variables('sshKeyPath')]",
"keyData": "[parameters('sshKeyData')]"
}
]
}
}
},
"storageProfile": {
"imageReference": {
"publisher": "[variables('imagePublisher')]",
"offer": "[variables('imageOffer')]",
"sku": "[variables('sku')]",
"version": "latest"
},
"osDisk": {
"managedDisk": {
"storageAccountType": "Standard_LRS"
},
"createOption": "FromImage"
},
"dataDisks": [
{
"managedDisk": {
"storageAccountType": "Standard_LRS"
},
"createOption": "FromImage",
"lun": 0
}
]
},
"networkProfile": {
"networkInterfaces": [
{
"id": "[resourceId('Microsoft.Network/networkInterfaces',concat(variables('nicName'), copyindex()))]"
}
]
},
"diagnosticsProfile": {
"bootDiagnostics": {
"enabled": false
}
}
}
}
],
"outputs": {
"firstDataScienceVmUrl": {
"type": "string",
"value": "[concat('https://ms.portal.azure.com/#resource/subscriptions/', subscription().subscriptionId, '/resourceGroups/', resourceGroup().name, '/providers/Microsoft.Compute/virtualMachines/', variables('vmName'), '0')]"
},
"numInstances": {
"type": "string",
"value": "[parameters('numberOfInstances')]"
}
}
}

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

@ -1,252 +0,0 @@
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"adminUsername": {
"type": "string",
"metadata": {
"description": "Username for the Virtual Machine."
}
},
"adminPassword": {
"type": "securestring",
"metadata": {
"description": "Password for the Virtual Machine."
}
},
"vmName": {
"type": "string",
"metadata": {
"description": "Name Prefix for the Virtual Machine."
}
},
"vmSize": {
"type": "string",
"defaultValue": "Standard_DS3_v2",
"metadata": {
"description": "Size for the Virtual Machine."
}
},
"fileUris": {
"type": "string",
"metadata": {
"description": "URL of the extension package or file"
}
},
"commandToExecute": {
"type": "string",
"defaultValue": "install.sh",
"metadata": {
"description": "Extension bash script command to execute"
}
},
"commandParameter": {
"type": "string",
"metadata": {
"description": "Extension bash script command parameter"
}
}
},
"variables": {
"location": "[resourceGroup().location]",
"imagePublisher": "microsoft-dsvm",
"imageOffer": "linux-data-science-vm-ubuntu",
"OSDiskName": "[concat(parameters('vmName'),'-osdisk')]",
"DataDiskName": "[concat(parameters('vmName'),'-data-0')]",
"sku": "linuxdsvmubuntu",
"nicName": "[parameters('vmName')]",
"addressPrefix": "10.0.0.0/16",
"subnetName": "Subnet",
"subnetPrefix": "10.0.0.0/24",
"publicIPAddressType": "Dynamic",
"publicIPAddressName": "[parameters('vmName')]",
"vmName": "[parameters('vmName')]",
"vmSize": "[parameters('vmSize')]",
"virtualNetworkName": "[parameters('vmName')]",
"nsgName": "[concat(parameters('vmName'),'-nsg')]",
"nsgId": "[resourceId(resourceGroup().name, 'Microsoft.Network/networkSecurityGroups', variables('nsgName'))]",
"vnetID": "[resourceId('Microsoft.Network/virtualNetworks',variables('virtualNetworkName'))]",
"subnetRef": "[concat(variables('vnetID'),'/subnets/',variables('subnetName'))]",
"fileUris": "[parameters('fileUris')]",
"commandToExecute": "[concat('bash ', parameters('commandToExecute'), ' ', parameters('commandParameter'))]"
},
"resources": [
{
"apiVersion": "2018-02-01",
"type": "Microsoft.Network/networkSecurityGroups",
"location": "[variables('location')]",
"name": "[variables('nsgName')]",
"properties": {
"securityRules": [
{
"name": "Allow-SSH-Jupyterhub",
"properties": {
"protocol": "Tcp",
"sourcePortRange": "*",
"sourceAddressPrefix": "*",
"destinationAddressPrefix": "*",
"access": "Allow",
"priority": 100,
"direction": "Inbound",
"sourcePortRanges": [],
"destinationPortRanges": [
"22",
"8000"
],
"destinationPortRange": ""
}
}
]
}
},
{
"apiVersion": "2015-05-01-preview",
"type": "Microsoft.Network/publicIPAddresses",
"name": "[variables('publicIPAddressName')]",
"location": "[variables('location')]",
"properties": {
"publicIPAllocationMethod": "[variables('publicIPAddressType')]",
"dnsSettings": {
"domainNameLabel": "[variables('publicIPAddressName')]"
}
}
},
{
"apiVersion": "2015-05-01-preview",
"type": "Microsoft.Network/virtualNetworks",
"name": "[variables('virtualNetworkName')]",
"location": "[variables('location')]",
"dependsOn": [
"[concat('Microsoft.Network/networkSecurityGroups/', variables('nsgName'))]"
],
"properties": {
"addressSpace": {
"addressPrefixes": [
"[variables('addressPrefix')]"
]
},
"subnets": [
{
"name": "[variables('subnetName')]",
"properties": {
"addressPrefix": "[variables('subnetPrefix')]"
}
}
]
}
},
{
"apiVersion": "2015-05-01-preview",
"type": "Microsoft.Network/networkInterfaces",
"name": "[variables('nicName')]",
"location": "[variables('location')]",
"dependsOn": [
"[concat('Microsoft.Network/publicIPAddresses/', variables('publicIPAddressName'))]",
"[concat('Microsoft.Network/networkSecurityGroups/', variables('nsgName'))]",
"[concat('Microsoft.Network/virtualNetworks/', variables('virtualNetworkName'))]"
],
"properties": {
"ipConfigurations": [
{
"name": "ipconfig1",
"properties": {
"privateIPAllocationMethod": "Dynamic",
"publicIPAddress": {
"id": "[resourceId('Microsoft.Network/publicIPAddresses',variables('publicIPAddressName'))]"
},
"subnet": {
"id": "[variables('subnetRef')]"
}
}
}
],
"networkSecurityGroup": {
"id": "[variables('nsgId')]"
}
}
},
{
"apiVersion": "2017-03-30",
"type": "Microsoft.Compute/virtualMachines",
"name": "[variables('vmName')]",
"location": "[variables('location')]",
"tags": {
"Application": "DataScience"
},
"dependsOn": [
"[concat('Microsoft.Network/networkInterfaces/', variables('nicName'))]"
],
"properties": {
"hardwareProfile": {
"vmSize": "[variables('vmSize')]"
},
"osProfile": {
"computerName": "[variables('vmName')]",
"adminUsername": "[parameters('adminUsername')]",
"adminPassword": "[parameters('adminPassword')]"
},
"storageProfile": {
"imageReference": {
"publisher": "[variables('imagePublisher')]",
"offer": "[variables('imageOffer')]",
"sku": "[variables('sku')]",
"version": "latest"
},
"osDisk": {
"name": "[variables('OSDiskName')]",
"managedDisk": {
"storageAccountType": "Standard_LRS"
},
"createOption": "FromImage"
},
"dataDisks": [
{
"name": "[variables('DataDiskName')]",
"managedDisk": {
"storageAccountType": "Standard_LRS"
},
"createOption": "FromImage",
"lun": 0
}
]
},
"networkProfile": {
"networkInterfaces": [
{
"id": "[resourceId('Microsoft.Network/networkInterfaces',variables('nicName'))]"
}
]
},
"diagnosticsProfile": {
"bootDiagnostics": {
"enabled": false
}
}
},
"resources": [
{
"type": "extensions",
"name": "[variables('vmName')]",
"apiVersion": "2017-03-30",
"location": "[variables('location')]",
"dependsOn": [
"[concat('Microsoft.Compute/virtualMachines/', variables('vmName')]"
],
"properties": {
"publisher": "Microsoft.OSTCExtensions",
"type": "CustomScriptForLinux",
"typeHandlerVersion": "1.4",
"autoUpgradeMinorVersion": true,
"settings": {
"fileUris": "[split(variables('fileUris'), ' ')]",
"commandToExecute": "[variables('commandToExecute')]"
}
}
}
]
}
],
"outputs": {
"DataScienceVmUrl": { "type": "string", "value": "[concat('https://ms.portal.azure.com/#resource/subscriptions/', subscription().subscriptionId, '/resourceGroups/', resourceGroup().name, '/providers/Microsoft.Compute/virtualMachines/', variables('vmName'))]" }
}
}

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

@ -1,221 +0,0 @@
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"adminUsername": {
"type": "string",
"metadata": {
"description": "Username for the Virtual Machine."
}
},
"sshKeyData": {
"type": "string",
"metadata": {
"description": "SSH public key data as a string."
}
},
"vmName": {
"type": "string",
"metadata": {
"description": "Name Prefix for the Virtual Machine."
}
},
"vmSize": {
"type": "string",
"defaultValue": "Standard_DS3_v2",
"metadata": {
"description": "Size for the Virtual Machine."
}
}
},
"variables": {
"location": "[resourceGroup().location]",
"imagePublisher": "microsoft-dsvm",
"imageOffer": "linux-data-science-vm-ubuntu",
"OSDiskName": "[concat(parameters('vmName'),'-osdisk')]",
"DataDiskName": "[concat(parameters('vmName'),'-data-0')]",
"sku": "linuxdsvmubuntu",
"nicName": "[parameters('vmName')]",
"addressPrefix": "10.0.0.0/16",
"subnetName": "Subnet",
"subnetPrefix": "10.0.0.0/24",
"publicIPAddressType": "Dynamic",
"publicIPAddressName": "[parameters('vmName')]",
"vmName": "[parameters('vmName')]",
"vmSize": "[parameters('vmSize')]",
"virtualNetworkName": "[parameters('vmName')]",
"nsgName": "[concat(parameters('vmName'),'-nsg')]",
"nsgId": "[resourceId(resourceGroup().name, 'Microsoft.Network/networkSecurityGroups', variables('nsgName'))]",
"vnetID": "[resourceId('Microsoft.Network/virtualNetworks',variables('virtualNetworkName'))]",
"subnetRef": "[concat(variables('vnetID'),'/subnets/',variables('subnetName'))]",
"sshKeyPath": "[concat('/home/',parameters('adminUsername'),'/.ssh/authorized_keys')]"
},
"resources": [
{
"apiVersion": "2018-02-01",
"type": "Microsoft.Network/networkSecurityGroups",
"location": "[variables('location')]",
"name": "[variables('nsgName')]",
"properties": {
"securityRules": [
{
"name": "Allow-SSH-Jupyterhub",
"properties": {
"protocol": "Tcp",
"sourcePortRange": "*",
"sourceAddressPrefix": "*",
"destinationAddressPrefix": "*",
"access": "Allow",
"priority": 100,
"direction": "Inbound",
"sourcePortRanges": [],
"destinationPortRanges": [
"22",
"8000"
],
"destinationPortRange": ""
}
}
]
}
},
{
"apiVersion": "2015-05-01-preview",
"type": "Microsoft.Network/publicIPAddresses",
"name": "[variables('publicIPAddressName')]",
"location": "[variables('location')]",
"properties": {
"publicIPAllocationMethod": "[variables('publicIPAddressType')]",
"dnsSettings": {
"domainNameLabel": "[variables('publicIPAddressName')]"
}
}
},
{
"apiVersion": "2015-05-01-preview",
"type": "Microsoft.Network/virtualNetworks",
"name": "[variables('virtualNetworkName')]",
"location": "[variables('location')]",
"dependsOn": [
"[concat('Microsoft.Network/networkSecurityGroups/', variables('nsgName'))]"
],
"properties": {
"addressSpace": {
"addressPrefixes": [
"[variables('addressPrefix')]"
]
},
"subnets": [
{
"name": "[variables('subnetName')]",
"properties": {
"addressPrefix": "[variables('subnetPrefix')]"
}
}
]
}
},
{
"apiVersion": "2015-05-01-preview",
"type": "Microsoft.Network/networkInterfaces",
"name": "[variables('nicName')]",
"location": "[variables('location')]",
"dependsOn": [
"[concat('Microsoft.Network/publicIPAddresses/', variables('publicIPAddressName'))]",
"[concat('Microsoft.Network/networkSecurityGroups/', variables('nsgName'))]",
"[concat('Microsoft.Network/virtualNetworks/', variables('virtualNetworkName'))]"
],
"properties": {
"ipConfigurations": [
{
"name": "ipconfig1",
"properties": {
"privateIPAllocationMethod": "Dynamic",
"publicIPAddress": {
"id": "[resourceId('Microsoft.Network/publicIPAddresses',variables('publicIPAddressName'))]"
},
"subnet": {
"id": "[variables('subnetRef')]"
}
}
}
],
"networkSecurityGroup": {
"id": "[variables('nsgId')]"
}
}
},
{
"apiVersion": "2017-03-30",
"type": "Microsoft.Compute/virtualMachines",
"name": "[variables('vmName')]",
"location": "[variables('location')]",
"tags": {
"Application": "DataScience"
},
"dependsOn": [
"[concat('Microsoft.Network/networkInterfaces/', variables('nicName'))]"
],
"properties": {
"hardwareProfile": {
"vmSize": "[variables('vmSize')]"
},
"osProfile": {
"computerName": "[variables('vmName')]",
"adminUsername": "[parameters('adminUsername')]",
"linuxConfiguration": {
"disablePasswordAuthentication": true,
"ssh": {
"publicKeys": [
{
"path": "[variables('sshKeyPath')]",
"keyData": "[parameters('sshKeyData')]"
}
]
}
}
},
"storageProfile": {
"imageReference": {
"publisher": "[variables('imagePublisher')]",
"offer": "[variables('imageOffer')]",
"sku": "[variables('sku')]",
"version": "latest"
},
"osDisk": {
"name": "[variables('OSDiskName')]",
"managedDisk": {
"storageAccountType": "Standard_LRS"
},
"createOption": "FromImage"
},
"dataDisks": [
{
"name": "[variables('DataDiskName')]",
"managedDisk": {
"storageAccountType": "Standard_LRS"
},
"createOption": "FromImage",
"lun": 0
}
]
},
"networkProfile": {
"networkInterfaces": [
{
"id": "[resourceId('Microsoft.Network/networkInterfaces',variables('nicName'))]"
}
]
},
"diagnosticsProfile": {
"bootDiagnostics": {
"enabled": false
}
}
}
}
],
"outputs": {
"DataScienceVmUrl": { "type": "string", "value": "[concat('https://ms.portal.azure.com/#resource/subscriptions/', subscription().subscriptionId, '/resourceGroups/', resourceGroup().name, '/providers/Microsoft.Compute/virtualMachines/', variables('vmName'))]" }
}
}

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

@ -1,198 +0,0 @@
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"adminUsername": {
"type": "string",
"metadata": {
"description": "Username for the Virtual Machine."
}
},
"adminPassword": {
"type": "securestring",
"metadata": {
"description": "Password for the Virtual Machine."
}
},
"vmName": {
"type": "string",
"metadata": {
"description": "Name for the Virtual Machine."
}
},
"vmSize": {
"type": "string",
"defaultValue": "Standard_DS3_v2",
"metadata": {
"description": "Size for the Virtual Machine."
}
}
},
"variables": {
"location": "[resourceGroup().location]",
"imagePublisher": "microsoft-dsvm",
"imageOffer": "dsvm-windows",
"sku": "server-2016",
"nicName": "[parameters('vmName')]",
"addressPrefix": "10.0.0.0/16",
"subnetName": "Subnet",
"subnetPrefix": "10.0.0.0/24",
"storageAccountType": "Standard_LRS",
"publicIPAddressType": "Dynamic",
"publicIPAddressName": "[parameters('vmName')]",
"vmStorageAccountContainerName": "vhds",
"vmName": "[parameters('vmName')]",
"vmSize": "[parameters('vmSize')]",
"virtualNetworkName": "[parameters('vmName')]",
"nsgName": "[concat(parameters('vmName'),'-nsg')]",
"nsgId": "[resourceId(resourceGroup().name, 'Microsoft.Network/networkSecurityGroups', variables('nsgName'))]",
"vnetID": "[resourceId('Microsoft.Network/virtualNetworks',variables('virtualNetworkName'))]",
"subnetRef": "[concat(variables('vnetID'),'/subnets/',variables('subnetName'))]"
},
"resources": [
{
"apiVersion": "2018-02-01",
"type": "Microsoft.Network/networkSecurityGroups",
"location": "[variables('location')]",
"name": "[variables('nsgName')]",
"properties": {
"securityRules": [
{
"name": "Allow-RDP",
"properties": {
"protocol": "Tcp",
"sourcePortRange": "*",
"sourceAddressPrefix": "*",
"destinationAddressPrefix": "*",
"access": "Allow",
"priority": 100,
"direction": "Inbound",
"sourcePortRanges": [],
"destinationPortRanges": [
"3389"
],
"destinationPortRange": ""
}
}
]
}
},
{
"apiVersion": "2015-05-01-preview",
"type": "Microsoft.Network/publicIPAddresses",
"name": "[variables('publicIPAddressName')]",
"location": "[variables('location')]",
"properties": {
"publicIPAllocationMethod": "[variables('publicIPAddressType')]",
"dnsSettings": {
"domainNameLabel": "[variables('publicIPAddressName')]"
}
}
},
{
"apiVersion": "2015-05-01-preview",
"type": "Microsoft.Network/virtualNetworks",
"name": "[variables('virtualNetworkName')]",
"location": "[variables('location')]",
"dependsOn": [
"[concat('Microsoft.Network/networkSecurityGroups/', variables('nsgName'))]"
],
"properties": {
"addressSpace": {
"addressPrefixes": [
"[variables('addressPrefix')]"
]
},
"subnets": [
{
"name": "[variables('subnetName')]",
"properties": {
"addressPrefix": "[variables('subnetPrefix')]"
}
}
]
}
},
{
"apiVersion": "2015-05-01-preview",
"type": "Microsoft.Network/networkInterfaces",
"name": "[variables('nicName')]",
"location": "[variables('location')]",
"dependsOn": [
"[concat('Microsoft.Network/publicIPAddresses/', variables('publicIPAddressName'))]",
"[concat('Microsoft.Network/networkSecurityGroups/', variables('nsgName'))]",
"[concat('Microsoft.Network/virtualNetworks/', variables('virtualNetworkName'))]"
],
"properties": {
"ipConfigurations": [
{
"name": "ipconfig1",
"properties": {
"privateIPAllocationMethod": "Dynamic",
"publicIPAddress": {
"id": "[resourceId('Microsoft.Network/publicIPAddresses',variables('publicIPAddressName'))]"
},
"subnet": {
"id": "[variables('subnetRef')]"
}
}
}
],
"networkSecurityGroup": {
"id": "[variables('nsgId')]"
}
}
},
{
"apiVersion": "2017-03-30",
"type": "Microsoft.Compute/virtualMachines",
"name": "[variables('vmName')]",
"location": "[variables('location')]",
"tags": {
"Application": "DataScience"
},
"dependsOn": [
"[concat('Microsoft.Network/networkInterfaces/', variables('nicName'))]"
],
"properties": {
"hardwareProfile": {
"vmSize": "[variables('vmSize')]"
},
"osProfile": {
"computerName": "[variables('vmName')]",
"adminUsername": "[parameters('adminUsername')]",
"adminPassword": "[parameters('adminPassword')]"
},
"storageProfile": {
"imageReference": {
"publisher": "[variables('imagePublisher')]",
"offer": "[variables('imageOffer')]",
"sku": "[variables('sku')]",
"version": "latest"
},
"osDisk": {
"managedDisk": {
"storageAccountType": "[variables('storageAccountType')]"
},
"createOption": "FromImage"
}
},
"networkProfile": {
"networkInterfaces": [
{
"id": "[resourceId('Microsoft.Network/networkInterfaces',variables('nicName'))]"
}
]
},
"diagnosticsProfile": {
"bootDiagnostics": {
"enabled": false
}
}
}
}
],
"outputs": {
"DataScienceVmUrl": { "type": "string", "value": "[concat('https://ms.portal.azure.com/#resource/subscriptions/', subscription().subscriptionId, '/resourceGroups/', resourceGroup().name, '/providers/Microsoft.Compute/virtualMachines/', variables('vmName'))]" }
}
}

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

@ -1,254 +0,0 @@
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"adminUsername": {
"type": "string",
"metadata": {
"description": "Username for the Virtual Machine."
}
},
"adminPassword": {
"type": "securestring",
"metadata": {
"description": "Password for the Virtual Machine."
}
},
"numberOfInstances": {
"type": "string",
"defaultValue": "1",
"metadata": {
"description": "Number of VMs to deploy."
}
},
"vmName": {
"type": "string",
"metadata": {
"description": "Name Prefix for the Virtual Machine."
}
},
"vmSize": {
"type": "string",
"defaultValue": "Standard_DS3_v2",
"metadata": {
"description": "Size for the Virtual Machine."
}
},
"fileUris": {
"type": "string",
"metadata": {
"description": "URL of the extension package or file"
}
},
"commandToExecute": {
"type": "string",
"defaultValue": "install.ps1",
"metadata": {
"description": "Extension powershell script command to execute"
}
}
},
"variables": {
"location": "[resourceGroup().location]",
"numberOfInstances": "[int(parameters('numberOfInstances'))]",
"imagePublisher": "microsoft-dsvm",
"imageOffer": "dsvm-windows",
"sku": "server-2016",
"nicName": "[parameters('vmName')]",
"addressPrefix": "10.0.0.0/16",
"subnetName": "Subnet",
"subnetPrefix": "10.0.0.0/24",
"storageAccountType": "Standard_LRS",
"publicIPAddressType": "Dynamic",
"publicIPAddressName": "[parameters('vmName')]",
"vmName": "[parameters('vmName')]",
"vmSize": "[parameters('vmSize')]",
"virtualNetworkName": "[parameters('vmName')]",
"nsgName": "[concat(parameters('vmName'),'-nsg')]",
"nsgId": "[resourceId(resourceGroup().name, 'Microsoft.Network/networkSecurityGroups', variables('nsgName'))]",
"vnetID": "[resourceId('Microsoft.Network/virtualNetworks',variables('virtualNetworkName'))]",
"subnetRef": "[concat(variables('vnetID'),'/subnets/',variables('subnetName'))]",
"fileUris": "[parameters('fileUris')]",
"commandToExecute": "[concat('powershell.exe -ExecutionPolicy Unrestricted -File ', parameters('commandToExecute'))]"
},
"resources": [
{
"apiVersion": "2018-02-01",
"type": "Microsoft.Network/networkSecurityGroups",
"location": "[variables('location')]",
"name": "[variables('nsgName')]",
"properties": {
"securityRules": [
{
"name": "Allow-RDP",
"properties": {
"protocol": "Tcp",
"sourcePortRange": "*",
"sourceAddressPrefix": "*",
"destinationAddressPrefix": "*",
"access": "Allow",
"priority": 100,
"direction": "Inbound",
"sourcePortRanges": [],
"destinationPortRanges": [
"3389"
],
"destinationPortRange": ""
}
}
]
}
},
{
"apiVersion": "2015-05-01-preview",
"type": "Microsoft.Network/publicIPAddresses",
"name": "[concat(variables('publicIPAddressName'), copyindex())]",
"location": "[variables('location')]",
"copy": {
"name": "publicIPLoop",
"count": "[variables('numberOfInstances')]"
},
"properties": {
"publicIPAllocationMethod": "[variables('publicIPAddressType')]",
"dnsSettings": {
"domainNameLabel": "[concat(variables('publicIPAddressName'), copyindex())]"
}
}
},
{
"apiVersion": "2015-05-01-preview",
"type": "Microsoft.Network/virtualNetworks",
"name": "[variables('virtualNetworkName')]",
"location": "[variables('location')]",
"dependsOn": [
"[concat('Microsoft.Network/networkSecurityGroups/', variables('nsgName'))]"
],
"properties": {
"addressSpace": {
"addressPrefixes": [
"[variables('addressPrefix')]"
]
},
"subnets": [
{
"name": "[variables('subnetName')]",
"properties": {
"addressPrefix": "[variables('subnetPrefix')]"
}
}
]
}
},
{
"apiVersion": "2015-05-01-preview",
"type": "Microsoft.Network/networkInterfaces",
"name": "[concat(variables('nicName'), copyindex())]",
"location": "[variables('location')]",
"copy": {
"name": "nicLoop",
"count": "[variables('numberOfInstances')]"
},
"dependsOn": [
"[concat('Microsoft.Network/publicIPAddresses/', concat(variables('publicIPAddressName'),copyindex()))]",
"[concat('Microsoft.Network/networkSecurityGroups/', variables('nsgName'))]",
"[concat('Microsoft.Network/virtualNetworks/', variables('virtualNetworkName'))]"
],
"properties": {
"ipConfigurations": [
{
"name": "ipconfig1",
"properties": {
"privateIPAllocationMethod": "Dynamic",
"publicIPAddress": {
"id": "[resourceId('Microsoft.Network/publicIPAddresses',concat(variables('publicIPAddressName'),copyindex()))]"
},
"subnet": {
"id": "[variables('subnetRef')]"
}
}
}
],
"networkSecurityGroup": {
"id": "[variables('nsgId')]"
}
}
},
{
"apiVersion": "2017-03-30",
"type": "Microsoft.Compute/virtualMachines",
"name": "[concat(variables('vmName'), copyIndex())]",
"location": "[variables('location')]",
"copy": {
"name": "virtualMachineLoop",
"count": "[variables('numberOfInstances')]"
},
"tags": {
"Application": "DataScience"
},
"dependsOn": [
"[concat('Microsoft.Network/networkInterfaces/', variables('nicName'), copyindex())]"
],
"properties": {
"hardwareProfile": {
"vmSize": "[variables('vmSize')]"
},
"osProfile": {
"computerName": "[concat(variables('vmName'), copyIndex())]",
"adminUsername": "[parameters('adminUsername')]",
"adminPassword": "[parameters('adminPassword')]"
},
"storageProfile": {
"imageReference": {
"publisher": "[variables('imagePublisher')]",
"offer": "[variables('imageOffer')]",
"sku": "[variables('sku')]",
"version": "latest"
},
"osDisk": {
"managedDisk": {
"storageAccountType": "[variables('storageAccountType')]"
},
"createOption": "FromImage"
}
},
"networkProfile": {
"networkInterfaces": [
{
"id": "[resourceId('Microsoft.Network/networkInterfaces',concat(variables('nicName'), copyindex()))]"
}
]
},
"diagnosticsProfile": {
"bootDiagnostics": {
"enabled": false
}
}
},
"resources": [
{
"type": "extensions",
"name": "[variables('vmName')]",
"apiVersion": "2017-03-30",
"location": "[variables('location')]",
"dependsOn": [
"[concat('Microsoft.Compute/virtualMachines/', variables('vmName'),copyindex())]"
],
"properties": {
"publisher": "Microsoft.Compute",
"type": "CustomScriptExtension",
"typeHandlerVersion": "1.8",
"autoUpgradeMinorVersion": true,
"settings": {
"fileUris": "[split(variables('fileUris'), ' ')]",
"commandToExecute": "[variables('commandToExecute')]"
}
}
}
]
}
],
"outputs": {
"firstDataScienceVmUrl": { "type": "string", "value": "[concat('https://ms.portal.azure.com/#resource/subscriptions/', subscription().subscriptionId, '/resourceGroups/', resourceGroup().name, '/providers/Microsoft.Compute/virtualMachines/', variables('vmName'), '0')]" },
"numInstances": { "type": "string", "value": "[parameters('numberOfInstances')]" }
}
}

14
inst/tpl/as_default.json Normal file
Просмотреть файл

@ -0,0 +1,14 @@
{
"apiVersion": "2015-04-01",
"type": "Microsoft.Insights/autoscaleSettings",
"name": "[variables('asName')]",
"location": "[variables('location')]",
"dependsOn": [
"[variables('vmRef')]"
],
"properties": {
"name": "[variables('asName')]",
"targetResourceUri": "[variables('vmId')]",
"enabled": true
}
}

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

@ -0,0 +1,17 @@
{
"apiVersion": "2018-09-30",
"name": "[parameters('dataDiskResources')[copyIndex()].name]",
"type": "Microsoft.Compute/disks",
"location": "[variables('location')]",
"properties": {
"diskSizeGB": "[parameters('dataDiskResources')[copyIndex()].diskSizeGB]",
"creationData": "[parameters('dataDiskResources')[copyIndex()].creationData]"
},
"sku": {
"name": "[parameters('dataDiskResources')[copyIndex()].sku]"
},
"copy": {
"name": "managedDiskResources",
"count": "[length(parameters('dataDiskResources'))]"
}
}

10
inst/tpl/ip_default.json Normal file
Просмотреть файл

@ -0,0 +1,10 @@
{
"apiVersion": "2018-11-01",
"type": "Microsoft.Network/publicIPAddresses",
"name": "[variables('ipName')]",
"location": "[variables('location')]",
"properties": {},
"sku": {
"name": "Basic"
}
}

29
inst/tpl/lb_default.json Normal file
Просмотреть файл

@ -0,0 +1,29 @@
{
"apiVersion": "2018-11-01",
"type": "Microsoft.Network/loadBalancers",
"name": "[variables('lbName')]",
"location": "[variables('location')]",
"dependsOn": [
"[variables('ipRef')]"
],
"sku": {
"name": "basic"
},
"properties": {
"frontendIPConfigurations": [
{
"name": "[variables('lbFrontendName')]",
"properties": {
"publicIPAddress": {
"id": "[variables('ipId')]"
}
}
}
],
"backendAddressPools": [
{
"name": "[variables('lbBackendName')]"
}
]
}
}

11
inst/tpl/nic_default.json Normal file
Просмотреть файл

@ -0,0 +1,11 @@
{
"apiVersion": "2018-11-01",
"type": "Microsoft.Network/networkInterfaces",
"name": "[variables('nicName')]",
"location": "[variables('location')]",
"dependsOn": [
"[variables('ipRef')]",
"[variables('vnetRef')]"
],
"properties": {}
}

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

@ -0,0 +1,9 @@
{
"apiVersion": "2018-11-01",
"type": "Microsoft.Network/networkSecurityGroups",
"name": "[variables('nsgName')]",
"location": "[variables('location')]",
"properties": {
"securityRules": []
}
}

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

@ -0,0 +1,32 @@
{
"vmName": {
"type": "string"
},
"vmSize": {
"type": "string"
},
"adminUsername": {
"type": "string"
},
"instanceCount": {
"type": "int"
},
"priority": {
"type": "string"
},
"evictionPolicy": {
"type": "string"
},
"enableAcceleratedNetworking": {
"type": "bool"
},
"singlePlacementGroup": {
"type": "bool"
},
"overprovision":{
"type": "bool"
},
"upgradePolicy":{
"type": "object"
}
}

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

@ -0,0 +1,10 @@
{
"vmResource": {
"type": "string",
"value": "[variables('vmId')]"
},
"adminUsername": {
"type": "string",
"value": "[parameters('adminUsername')]"
}
}

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

@ -0,0 +1,11 @@
{
"vmName": {
"type": "string"
},
"vmSize": {
"type": "string"
},
"adminUsername": {
"type": "string"
}
}

18
inst/tpl/vm_datadisk.json Normal file
Просмотреть файл

@ -0,0 +1,18 @@
[
{
"name": "dataDisks",
"count": "[length(parameters('dataDisks'))]",
"input": {
"lun": "[parameters('dataDisks')[copyIndex('dataDisks')].lun]",
"createOption": "[parameters('dataDisks')[copyIndex('dataDisks')].createOption]",
"caching": "[parameters('dataDisks')[copyIndex('dataDisks')].caching]",
"writeAcceleratorEnabled": "[parameters('dataDisks')[copyIndex('dataDisks')].writeAcceleratorEnabled]",
"diskSizeGB": "[parameters('dataDisks')[copyIndex('dataDisks')].diskSizeGB]",
"managedDisk": {
"id": "[coalesce(parameters('dataDisks')[copyIndex('dataDisks')].id, if(equals(parameters('dataDisks')[copyIndex('dataDisks')].name, json('null')), json('null'), resourceId('Microsoft.Compute/disks', parameters('dataDisks')[copyIndex('dataDisks')].name)))]",
"storageAccountType": "[parameters('dataDisks')[copyIndex('dataDisks')].storageAccountType]"
}
}
}
]

42
inst/tpl/vm_default.json Normal file
Просмотреть файл

@ -0,0 +1,42 @@
{
"apiVersion": "2019-03-01",
"type": "Microsoft.Compute/virtualMachines",
"name": "[parameters('vmName')]",
"location": "[variables('location')]",
"tags": {
"CreatedBy": "AzureR/AzureVM"
},
"dependsOn": [
"[variables('nicRef')]"
],
"properties": {
"hardwareProfile": {
"vmSize": "[parameters('vmSize')]"
},
"osProfile": {
"computerName": "[parameters('vmName')]",
"adminUsername": "[parameters('adminUsername')]"
},
"storageProfile": {
"imageReference": {
"publisher": "[parameters('imagePublisher')]",
"offer": "[parameters('imageOffer')]",
"sku": "[parameters('imageSku')]",
"version": "[parameters('imageVersion')]"
},
"osDisk": {
"managedDisk": {
"storageAccountType": "Premium_LRS"
},
"createOption": "FromImage"
}
},
"networkProfile": {
"networkInterfaces": [
{
"id": "[variables('nicId')]"
}
]
}
}
}

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

@ -0,0 +1,13 @@
{
"linuxConfiguration": {
"disablePasswordAuthentication": true,
"ssh": {
"publicKeys": [
{
"path": "[concat('/home/', parameters('adminUsername'), '/.ssh/authorized_keys')]",
"keyData": "[parameters('sshKeyData')]"
}
]
}
}
}

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

@ -0,0 +1,3 @@
{
"adminPassword": "[parameters('adminPassword')]"
}

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

@ -0,0 +1,54 @@
{
"apiVersion": "2019-03-01",
"type": "Microsoft.Compute/virtualMachineScaleSets",
"name": "[parameters('vmName')]",
"location": "[variables('location')]",
"tags": {
"CreatedBy": "AzureR/AzureVM"
},
"dependsOn": [],
"sku": {
"name": "[parameters('vmSize')]",
"tier": "Standard",
"capacity": "[parameters('instanceCount')]"
},
"properties": {
"overprovision": "[parameters('overprovision')]",
"upgradePolicy": "[parameters('upgradePolicy')]",
"singlePlacementGroup": "[parameters('singlePlacementGroup')]",
"virtualMachineProfile": {
"priority": "[parameters('priority')]",
"storageProfile": {
"osDisk": {
"createOption": "FromImage",
"caching": "ReadWrite"
}
},
"osProfile": {
"computerNamePrefix": "[variables('vmPrefix')]",
"adminUsername": "[parameters('adminUsername')]"
},
"networkProfile": {
"networkInterfaceConfigurations": [
{
"name": "[concat(parameters('vmName'), '-nic')]",
"properties": {
"primary": "true",
"enableAcceleratedNetworking": "[parameters('enableAcceleratedNetworking')]",
"ipConfigurations": [
{
"name": "[concat(parameters('vmName'), '-nic-ip')]",
"properties": {
"subnet": {
"id": "[variables('subnetId')]"
}
}
}
]
}
}
]
}
}
}
}

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

@ -0,0 +1,10 @@
{
"apiVersion": "2018-11-01",
"type": "Microsoft.Network/virtualNetworks",
"name": "[variables('vnetName')]",
"location": "[variables('location')]",
"dependsOn": [
"[variables('nsgRef')]"
],
"properties": {}
}

34
man/autoscaler_config.Rd Normal file
Просмотреть файл

@ -0,0 +1,34 @@
% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/autoscaler_config.R
\name{autoscaler_config}
\alias{autoscaler_config}
\alias{autoscaler_profile}
\title{Autoscaler configuration}
\usage{
autoscaler_config(profiles = list(autoscaler_profile()), ...)
autoscaler_profile(name = "Profile", minsize = 1, maxsize = NA,
default = NA, scale_out = 0.75, scale_in = 0.25,
interval = "PT1M", window = "PT5M")
}
\arguments{
\item{profiles}{A list of autoscaling profiles, each obtained via a call to \code{autoscaler_profile}.}
\item{...}{Other named arguments that will be treated as resource properties.}
\item{name}{For \code{autoscaler_profile}, a name for the profile.}
\item{minsize, maxsize, default}{For \code{autoscaler_profile}, the minimum, maximum and default number of instances.}
\item{scale_out, scale_in}{For \code{autoscaler_profile}, the percentage CPU at which to scale out and in, respectively.}
\item{interval}{For \code{autoscaler_profile}, The interval between samples, in ISO 8601 format. The default is 1 minute.}
\item{window}{For \code{autoscaler_profile}, the window width over which to compute the percentage CPU. The default is 5 minutes.}
}
\description{
Autoscaler configuration
}
\seealso{
\link{create_vm_scaleset}, \link{vmss_config}
}

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

@ -15,19 +15,23 @@ Class representing a virtual machine resource. In general, the methods in this c
The following methods are available, in addition to those provided by the \link[AzureRMR:az_resource]{AzureRMR::az_resource} class: The following methods are available, in addition to those provided by the \link[AzureRMR:az_resource]{AzureRMR::az_resource} class:
\itemize{ \itemize{
\item \code{new(...)}: Initialize a new VM object.
\item \code{start(wait=TRUE)}: Start the VM. By default, wait until the startup process is complete. \item \code{start(wait=TRUE)}: Start the VM. By default, wait until the startup process is complete.
\item \code{stop(deallocate=TRUE, wait=FALSE)}: Stop the VM. By default, deallocate it as well. \item \code{stop(deallocate=TRUE, wait=FALSE)}: Stop the VM. By default, deallocate it as well.
\item \code{restart(wait=TRUE)}: Restart the VM. \item \code{restart(wait=TRUE)}: Restart the VM.
\item \code{run_deployed_command(command, parameters, script)}: Run a PowerShell command on the VM. \item \code{run_deployed_command(command, parameters, script)}: Run a PowerShell command on the VM.
\item \code{run_script(script, parameters)}: 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{run_script(script, parameters)}: 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{sync_vm_status()}: Update the VM status fields in this object with information from the host. \item \code{sync_vm_status()}: Check the status of the VM.
\item \code{resize(size, deallocate=FALSE, wait=FALSE)}: Resize the VM. Optionally deallocate it first (may sometimes be necessary). \item \code{resize(size, deallocate=FALSE, wait=FALSE)}: Resize the VM. Optionally stop and deallocate it first (may sometimes be necessary).
\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{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.
} }
} }
\seealso{ \seealso{
\link[AzureRMR:az_resource]{AzureRMR::az_resource}, \link[AzureRMR:az_resource]{AzureRMR::az_resource}, \link{get_vm_resource}, \link{az_vm_template}
\href{https://docs.microsoft.com/en-us/rest/api/compute/virtualmachines}{VM API reference} \href{https://docs.microsoft.com/en-us/rest/api/compute/virtualmachines}{VM API reference}
} }
\keyword{datasets} \keyword{datasets}

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

@ -3,66 +3,50 @@
\docType{class} \docType{class}
\name{az_vm_template} \name{az_vm_template}
\alias{az_vm_template} \alias{az_vm_template}
\title{Virtual machine cluster template class} \title{Virtual machine template class}
\format{An R6 object of class \code{az_vm_template}, inheriting from \code{AzureRMR::az_template}.} \format{An R6 object of class \code{az_vm_template}, inheriting from \code{AzureRMR::az_template}.}
\usage{ \usage{
az_vm_template az_vm_template
} }
\description{ \description{
Class representing a virtual machine template. This class keeps track of all resources that are created as part of deploying a VM or cluster of VMs, and exposes methods for managing them. In this page, "VM" refers to both a cluster of virtual machines, as well as a single virtual machine (which is treated as the special case of a cluster containing a single node). 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{ \details{
A single virtual machine in Azure is actually a collection of resources, including any and all of the following. A cluster can share a storage account and virtual network, but each individual node will still have its own IP address and network interface. 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{ \itemize{
\item Storage account \item Network interface (Azure resource type \code{Microsoft.Network/networkInterfaces})
\item Network interface \item Network security group (Azure resource type \code{Microsoft.Network/networkSecurityGroups})
\item Network security group \item Virtual network (Azure resource type \code{Microsoft.Network/virtualNetworks})
\item Virtual network \item Public IP address (Azure resource type \code{Microsoft.Network/publicIPAddresses})
\item IP address \item The VM itself (Azure resource type \code{Microsoft.Compute/virtualMachines})
\item The VM itself
} }
By wrapping the deployment template used to create these resources, the \code{az_vm_template} class allows managing them all as a single entity. By wrapping the deployment template used to create these resources, the \code{az_vm_template} class allows managing them all as a single entity.
} }
\section{Methods}{ \section{Methods}{
The following methods are available, in addition to those provided by the \link[AzureRMR:az_template]{AzureRMR::az_template} class: The following methods are available, in addition to those provided by the \link[AzureRMR:az_template]{AzureRMR::az_template} class.
\itemize{ \itemize{
\item \code{new(...)}: Initialize a new VM object. See 'Initialization' for more details.
\item \code{start(wait=TRUE)}: Start the VM. By default, wait until the startup process is complete. \item \code{start(wait=TRUE)}: Start the VM. By default, wait until the startup process is complete.
\item \code{stop(deallocate=TRUE, wait=FALSE)}: Stop the VM. By default, deallocate it as well. \item \code{stop(deallocate=TRUE, wait=FALSE)}: Stop the VM. By default, deallocate it as well.
\item \code{restart(wait=TRUE)}: Restart the VM. \item \code{restart(wait=TRUE)}: Restart the VM.
\item \code{run_deployed_command(command, parameters, script)}: Run a PowerShell command on the VM. \item \code{run_deployed_command(command, parameters, script)}: Run a PowerShell command on the VM.
\item \code{run_script(script, parameters)}: 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{run_script(script, parameters)}: 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{sync_vm_status()}: Update the VM status fields in this object with information from the host. \item \code{sync_vm_status()}: Check the status of the VM.
\item \code{resize(size, deallocate=FALSE, wait=FALSE)}: Resize the VM. Optionally deallocate it first (may sometimes be necessary). \item \code{resize(size, deallocate=FALSE, wait=FALSE)}: Resize the VM. Optionally stop and deallocate it first (may sometimes be necessary).
\item \code{get_public_ip_address(nic=1, config=1)}: Get the public IP address of the VM. Returns NULL 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{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.
} }
} }
\section{Fields}{
The following fields are available, in addition to those provided by the \code{AzureRMR::az_template} class. Each is a list with one element per node in the cluster.
\itemize{
\item \code{disks}: The status of any attached disks.
\item \code{ip_address}: The IP address. NULL if the node is currently deallocated.
\item \code{dns_name}: The fully qualified domain name.
\item \code{status}: The status of the node, giving the provisioning state and power state.
}
}
\section{Initialization}{
Initializing a new object of this class can either retrieve an existing VM template, or deploy a new VM template on the host. Generally, the best way to initialize an object is via the VM-related methods of the \link{az_subscription} and \link{az_resource_group} class, which handle the details automatically.
A new VM can be created in \emph{exclusive} mode, meaning a new resource group is created solely to hold the VM. This simplifies deleting a VM considerably, as deleting the resource group will also automatically delete all the VM's resources. This can be done asynchronously, meaning that the \code{delete()} method returns immediately while the process continues on the host. Otherwise, deleting a VM will explicitly delete each of its resources, a task that must be done synchronously to allow for dependencies.
}
\examples{ \examples{
\dontrun{ \dontrun{
# recommended way to retrieve a VM: via a resource group or subscription object sub <- AzureRMR::get_azure_login()$
sub <- AzureRMR::az_rm$
new(tenant="myaadtenant.onmicrosoft.com", app="app_id", password="password")$
get_subscription("subscription_id") get_subscription("subscription_id")
vm <- sub$get_vm("myLinuxDSVM") vm <- sub$get_vm("myLinuxDSVM")
@ -85,8 +69,8 @@ vm$sync_vm_status()
} }
} }
\seealso{ \seealso{
\link[AzureRMR:az_resource]{AzureRMR::az_resource}, \link{create_vm}, \link{create_vm_cluster}, \link{get_vm}, \link{get_vm_cluster}, \link{list_vms}, \link[AzureRMR:az_template]{AzureRMR::az_template}, \link{create_vm}, \link{get_vm}, \link{delete_vm}
\link{delete_vm}, \link{delete_vm_cluster},
\href{https://docs.microsoft.com/en-us/rest/api/compute/virtualmachines}{VM API reference} \href{https://docs.microsoft.com/en-us/rest/api/compute/virtualmachines}{VM API reference}
} }
\keyword{datasets} \keyword{datasets}

42
man/az_vmss_resource.Rd Normal file
Просмотреть файл

@ -0,0 +1,42 @@
% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/az_vmss_resource.R
\docType{class}
\name{az_vmss_resource}
\alias{az_vmss_resource}
\title{Virtual machine scaleset resource class}
\format{An R6 object of class \code{az_vmss_resource}, inheriting from \code{AzureRMR::az_resource}.}
\usage{
az_vmss_resource
}
\description{
Class representing a virtual machine scaleset resource. In general, the methods in this class should not be called directly, nor should objects be directly instantiated from it. Use the \code{az_vmss_template} class for interacting with scalesets instead.
}
\section{Methods}{
The following methods are available, in addition to those provided by the \link[AzureRMR:az_template]{AzureRMR::az_template} class.
\itemize{
\item \code{sync_vmss_status}: Check the status of the scaleset.
\item \code{list_instances()}: Return a list of \link{az_vm_resource} objects, one for each VM instance in the scaleset. Note that if the scaleset has a load balancer attached, the number of instances will vary depending on the load.
\item \code{get_instance(id)}: Return a specific VM instance in the scaleset.
\item \code{start(id=NULL, wait=FALSE)}: Start the scaleset. In this and the other methods listed here, \code{id} can be an optional character vector of instance IDs; if supplied, only carry out the operation for those instances.
\item \code{restart(id=NULL, wait=FALSE)}: Restart the scaleset.
\item \code{stop(deallocate=TRUE, id=NULL, wait=FALSE)}: Stop the scaleset.
\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 if the instances are 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{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.
\item \code{redeploy(id=NULL)}: Redeploy the instances in the scaleset.
\item \code{mapped_vm_operation(..., id=NULL)}: Carry out an arbitrary operation on the instances in the scaleset. See the \code{do_operation} method of the \link[AzureRMR:az_resource]{AzureRMR::az_resource} class for more details.
\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).
}
}
\seealso{
\link[AzureRMR:az_resource]{AzureRMR::az_resource}, \link{get_vm_scaleset_resource}, \link{az_vmss_template}
\href{https://docs.microsoft.com/en-us/rest/api/compute/virtualmachinescalesets}{VM scaleset API reference}
}
\keyword{datasets}

77
man/az_vmss_template.Rd Normal file
Просмотреть файл

@ -0,0 +1,77 @@
% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/az_vmss_template.R
\docType{class}
\name{az_vmss_template}
\alias{az_vmss_template}
\title{Virtual machine scaleset (cluster) template class}
\format{An R6 object of class \code{az_vmss_template}, inheriting from \code{AzureRMR::az_template}.}
\usage{
az_vmss_template
}
\description{
Class representing a virtual machine scaleset deployment template. This class keeps track of all resources that are created as part of deploying a scaleset, and exposes methods for managing them.
}
\details{
A virtual machine scaleset in Azure is actually a collection of resources, including any and all of the following.
\itemize{
\item Network security group (Azure resource type \code{Microsoft.Network/networkSecurityGroups})
\item Virtual network (Azure resource type \code{Microsoft.Network/virtualNetworks})
\item Load balancer (Azure resource type \code{Microsoft.Network/loadBalancers})
\item Public IP address (Azure resource type \code{Microsoft.Network/publicIPAddresses})
\item Autoscaler (Azure resource type \code{Microsoft.Insights/autoscaleSettings})
\item The scaleset itself (Azure resource type \code{Microsoft.Compute/virtualMachineScaleSets})
}
By wrapping the deployment template used to create these resources, the \code{az_vmss_template} class allows managing them all as a single entity.
}
\section{Methods}{
The following methods are available, in addition to those provided by the \link[AzureRMR:az_template]{AzureRMR::az_template} class.
\itemize{
\item \code{sync_vmss_status}: Check the status of the scaleset.
\item \code{list_instances()}: Return a list of \link{az_vm_resource} objects, one for each VM instance in the scaleset. Note that if the scaleset has an autoscaler attached, the number of instances will vary depending on the load.
\item \code{get_instance(id)}: Return a specific VM instance in the scaleset.
\item \code{start(id=NULL, wait=FALSE)}: Start the scaleset. In this and the other methods listed here, \code{id} can be an optional character vector of instance IDs; if supplied, only carry out the operation for those instances.
\item \code{restart(id=NULL, wait=FALSE)}: Restart the scaleset.
\item \code{stop(deallocate=TRUE, id=NULL, wait=FALSE)}: Stop the scaleset.
\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 NULL.
\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 NULL if the instances are 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{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.
\item \code{redeploy(id=NULL)}: Redeploy the instances in the scaleset.
\item \code{mapped_vm_operation(..., id=NULL)}: Carry out an arbitrary operation on the instances in the scaleset. See the \code{do_operation} method of the \link[AzureRMR:az_resource]{AzureRMR::az_resource} class for more details.
\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).
}
}
\examples{
\dontrun{
sub <- AzureRMR::get_azure_login()$
get_subscription("subscription_id")
vmss <- sub$get_vm_scaleset("myscaleset")
# start the VM
vmss$start()
# run a shell command
vmss$run_script("ifconfig > /tmp/ifc.out")
# get private IP addresses
vmss$get_vm_private_ip_addresses()
# get the VM status
vmss$sync_vmss_status()
}
}
\seealso{
\link[AzureRMR:az_template]{AzureRMR::az_template}, \link{create_vm_scaleset}, \link{get_vm_scaleset}, \link{delete_vm_scaleset}
\href{https://docs.microsoft.com/en-us/rest/api/compute/virtualmachinescalesets}{VM scaleset API reference}
}
\keyword{datasets}

49
man/build_template.Rd Normal file
Просмотреть файл

@ -0,0 +1,49 @@
% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/build_json.R
\name{build_template_definition.vm_config}
\alias{build_template_definition.vm_config}
\alias{build_template_definition.vmss_config}
\alias{build_template_parameters.vm_config}
\alias{build_template_parameters.vmss_config}
\title{Build template definition and parameters}
\usage{
\method{build_template_definition}{vm_config}(config, ...)
\method{build_template_definition}{vmss_config}(config, ...)
\method{build_template_parameters}{vm_config}(config, name, login_user,
size, ...)
\method{build_template_parameters}{vmss_config}(config, name, login_user,
size, instances, ...)
}
\arguments{
\item{config}{An object of class \code{vm_config} or \code{vmss_config} representing a virtual machine or scaleset deployment.}
\item{...}{Unused.}
\item{name}{The VM or scaleset name. Will also be used for the domain name label, if a public IP address is included in the deployment.}
\item{login_user}{An object of class \code{user_config} representing the login details for the admin user account on the VM.}
\item{size}{The VM (instance) size.}
\item{instances}{For \code{vmss_config}, the number of (initial) instances in the VM scaleset.}
}
\description{
Build template definition and parameters
}
\details{
These are methods for the generics defined in the AzureRMR package.
}
\examples{
vm <- ubuntu_18.04()
build_template_definition(vm)
build_template_parameters(vm, "myubuntuvm",
user_config("username", "~/.ssh/id_rsa.pub"), "Standard_DS3_v2")
}
\seealso{
\link{create_vm}, \link{vm_config}, \link{vmss_config}
}

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

@ -2,115 +2,167 @@
% Please edit documentation in R/add_methods.R % Please edit documentation in R/add_methods.R
\name{create_vm} \name{create_vm}
\alias{create_vm} \alias{create_vm}
\alias{create_vm_cluster} \alias{create_vm_scaleset}
\title{Create a new virtual machine or cluster of virtual machines} \title{Create a new virtual machine or scaleset of virtual machines}
\description{ \description{
Method for the \link[AzureRMR:az_subscription]{AzureRMR::az_subscription} and \link[AzureRMR:az_resource_group]{AzureRMR::az_resource_group} classes. Method for the \link[AzureRMR:az_subscription]{AzureRMR::az_subscription} and \link[AzureRMR:az_resource_group]{AzureRMR::az_resource_group} classes.
} }
\section{Usage}{ \section{Usage}{
\preformatted{## R6 method for class 'az_resource_group' \preformatted{## R6 method for class 'az_resource_group'
create_vm(name, os = c("Windows", "Ubuntu"), size = "Standard_DS3_v2", create_vm(name, login_user, size = "Standard_DS3_v2", config = "ubuntu_dsvm",
username, passkey, userauth_type = c("password", "key"), managed = TRUE, datadisks = numeric(0), ...,
ext_file_uris = NULL, inst_command = NULL, template, parameters, mode = "Incremental", wait = TRUE)
template, parameters, ..., wait = TRUE)
## R6 method for class 'az_subscription' ## R6 method for class 'az_subscription'
create_vm(name, location, os = c("Windows", "Ubuntu"), size = "Standard_DS3_v2", create_vm(name, ..., resource_group = name, location)
username, passkey, userauth_type = c("password", "key"),
ext_file_uris = NULL, inst_command = NULL,
template, parameters, ..., wait = TRUE)
## R6 method for class 'az_resource_group' ## R6 method for class 'az_resource_group'
create_vm_cluster(name, os = c("Windows", "Ubuntu"), size = "Standard_DS3_v2", create_vm_scaleset(name, login_user, instances, size = "Standard_DS1_v2",
username, passkey, userauth_type = c("password", "key"), config = "ubuntu_dsvm_ss", ...,
ext_file_uris = NULL, inst_command = NULL, clust_size, template, parameters, mode = "Incremental", wait = TRUE)
template, parameters, ..., wait = TRUE)
## R6 method for class 'az_subscription' ## R6 method for class 'az_subscription'
create_vm_cluster(name, location, os = c("Windows", "Ubuntu"), size = "Standard_DS3_v2", create_vm_scaleset(name, ..., resource_group = name, location)
username, passkey, userauth_type = c("password", "key"),
ext_file_uris = NULL, inst_command = NULL, clust_size,
template, parameters, ..., wait = TRUE)
} }
} }
\section{Arguments}{ \section{Arguments}{
\itemize{ \itemize{
\item \code{name}: The name of the VM or cluster. \item \code{name}: The name of the VM or scaleset.
\item \code{location}: For the subscription class methods, the location for the VM. Use the \code{list_locations()} method of the \code{AzureRMR::az_subscription} class to see what locations are available. \item \code{location}: For the subscription methods, the location for the VM or scaleset. Use the \code{list_locations()} method of the \code{AzureRMR::az_subscription} class to see what locations are available.
\item \code{os}: The operating system for the VM. \item \code{resource_group}: For the subscription methods, the resource group in which to place the VM or scaleset. Defaults to a new resource group with the same name as the VM.
\item \code{size}: The VM size. Use the \code{list_vm_sizes()} method of the \code{AzureRMR::az_subscription} class to see what sizes are available. \item \code{login_user}: The details for the admin login account. An object of class \code{user_config}, obtained by a call to the \code{user_config} function.
\item \code{username}: The login username for the VM. \item \code{size}: The VM (instance) size. Use the \link{list_vm_sizes} method to see what sizes are available.
\item \code{passkey}: The login password or public key. \item \code{config}: The VM or scaleset configuration. See 'Details' below for how to specify this. The default is to use an Ubuntu Data Science Virtual Machine.
\item \code{userauth_type}: The type of login authentication to use. Only has an effect for Linux-based VMs; Windows VMs will always use \code{"password"}. \item \code{managed}: For \code{create_vm}, whether the VM should have a managed identity attached.
\item \code{ext_file_uris}: Optional link to download extension packages. \item \code{datadisks}: For \code{create_vm}, any data disks to attach to the VM. See 'Details' below.
\item \code{inst_command}: If \code{ext_file_uris} is supplied, the install script to run. Defaults to \code{install.sh} for an Ubuntu VM, or \code{install.ps1} for a Windows VM. \item \code{instances}: For \code{create_vm_scaleset}, the initial number of instances in the scaleset.
\item \code{clust_size}: For a cluster, the number of nodes to create. \item \code{...} For the subscription methods, any of the other arguments listed here, which will be passed to the resource group method. For the resource group method, additional arguments to pass to the VM/scaleset configuration functions \link{vm_config} and \link{vmss_config}. See the examples below.
\item \code{template}: Optional: the VM template to deploy. By default, this is determined by the values of the other arguments; see 'Details' below. \item \code{template,parameters}: The template definition and parameters to deploy. By default, these are constructed from the values of the other arguments, but you can supply your own template and/or parameters as well.
\item \code{parameters}: Optional: other parameters to pass to the deployment.
\item \code{wait}: Whether to wait until the deployment is complete. \item \code{wait}: Whether to wait until the deployment is complete.
\item \code{...}: Other arguments to lower-level methods. \item \code{mode}: The template deployment mode. If "Complete", any existing resources in the resource group will be deleted.
} }
} }
\section{Details}{ \section{Details}{
This method deploys a template to create a new virtual machine or cluster of VMs. Currently, seven templates are supplied with this package, based on the Azure Data Science Virtual Machine: These methods deploy a template to create a new virtual machine or scaleset.
The \code{config} argument can be specified in the following ways:
\itemize{ \itemize{
\item Ubuntu DSVM \item As the name of a supplied VM or scaleset configuration, like "ubuntu_dsvm" or "ubuntu_dsvm_ss". AzureVM comes with a number of supplied configurations to deploy commonly used images, which can be seen at \link{vm_config} and \link{vmss_config}. Any arguments in \code{...} will be passed to the configuration, allowing you to customise the deployment.
\item Ubuntu DSVM using public key authentication \item As a call to the \code{vm_config} or \code{vmss_config} functions, to deploy a custom VM image.
\item Ubuntu DSVM with extensions \item As an object of class \code{vm_config} or \code{vmss_config}.
\item Ubuntu DSVM cluster
\item Ubuntu DSVM cluster with extensions
\item Windows Server 2016 DSVM
\item Windows Server 2016 DSVM cluster with extensions
} }
An individual virtual machine is treated as a cluster containing only a single node. The data disks for the VM can be specified as either a vector of numeric disk sizes in GB, or as a list of \code{datadisk_config} objects, created via calls to the \code{datadisk_config} function. Currently, AzureVM only supports creating data disks at deployment time for single VMs, not scalesets.
You can also supply your own VM template for deployment, via the \code{template} argument. See \link[AzureRMR:az_template]{AzureRMR::az_template} for information how to supply templates. Note that if you do this, you may also have to supply a \code{parameters} argument, as the standard parameters for this method are customised for the DSVM. You can also supply your own template definition and parameters for deployment, via the \code{template} and \code{parameters} arguments. See \link[AzureRMR:az_template]{AzureRMR::az_template} for information how to create templates.
For the \code{AzureRMR::az_subscription} method, this will by default create the VM in \emph{exclusive} mode, meaning a new resource group is created solely to hold the VM. This simplifies managing the VM considerably, in particular deleting the resource group will also automatically delete all the VM's resources. The \code{AzureRMR::az_subscription} methods will by default create the VM in \emph{exclusive} mode, meaning a new resource group is created solely to hold the VM or scaleset. This simplifies managing the VM considerably; in particular deleting the resource group will also automatically delete all the deployed resources.
} }
\section{Value}{ \section{Value}{
An object of class \code{az_vm_template} representing the created VM. For \code{create_vm}, an object of class \code{az_vm_template} representing the created VM. For \code{create_vm_scaleset}, an object of class \code{az_vmss_template} representing the scaleset.
} }
\examples{ \examples{
\dontrun{ \dontrun{
sub <- AzureRMR::az_rm$ sub <- AzureRMR::get_azure_login()$
new(tenant="myaadtenant.onmicrosoft.com", app="app_id", password="password")$
get_subscription("subscription_id") get_subscription("subscription_id")
# default Windows Server DSVM: make sure to use a strong password! # default Ubuntu 18.04 VM:
sub$create_vm("myWindowsDSVM", # SSH key login, Standard_DS3_v2, publicly accessible via SSH
location="australiaeast", sub$create_vm("myubuntuvm", user_config("myname", "~/.ssh/id_rsa.pub"),
username="ds", location="australiaeast")
passkey="Password123!")
# upsized Linux (Ubuntu) DSVM # Windows Server 2019, with a 500GB datadisk attached, not publicly accessible
sub$create_vm("myLinuxDSVM", sub$create_vm("mywinvm", user_config("myname", password="Use-strong-passwords!"),
location="australiaeast", size="Standard_DS4_v2", config="windows_2019", datadisks=500, ip=NULL,
os="Linux", location="australiaeast")
username="ds",
passkey=readLines("~/id_rsa.pub"),
size="Standard_DS13_v2")
sub$create_vm_cluster("myLinuxCluster", # Ubuntu DSVM, GPU-enabled
location="australiaeast", sub$create_vm("mydsvm", user_config("myname", "~/.ssh/id_rsa.pub"), size="Standard_NC12",
os="Linux", config="ubuntu_dsvm_ss",
username="ds", location="australiaeast")
passkey=readLines("~/id_rsa.pub"),
clust_size=5) ## custom VM configuration: Windows 10 Pro 1903 with data disks
## this assumes you have a valid Win10 desktop license
user <- user_config("myname", password="Use-strong-passwords!")
image <- image_config(
publisher="MicrosoftWindowsDesktop",
offer="Windows-10",
sku="19h1-pro"
)
datadisks <- list(
datadisk_config(250, type="Premium_LRS"),
datadisk_config(1000, type="Standard_LRS")
)
nsg <- nsg_config(
list(nsg_rule_allow_rdp)
)
config <- vm_config(
image=image,
keylogin=FALSE,
datadisks=datadisks,
nsg=nsg,
properties=list(licenseType="Windows_Client")
)
sub$create_vm("mywin10vm", user, size="Standard_DS2_v2", config=config,
location="australiaeast")
# default Ubuntu scaleset:
# load balancer and autoscaler enabled, Standard_DS1_v2
sub$create_vm_scaleset("mydsvmss", user_config("myname", "~/.ssh/id_rsa.pub"),
instances=5,
location="australiaeast"))
# Ubuntu DSVM scaleset with public GPU-enabled instances, no load balancer or autoscaler
sub$create_vm_scaleset("mydsvmss", user_config("myname", "~/.ssh/id_rsa.pub"),
instances=5, size="Standard_NC12", config="ubuntu_dsvm_ss",
options=scaleset_options(public=TRUE),
load_balancer=NULL, autoscaler=NULL,
location="australiaeast")
# RHEL scaleset, allow http/https access
sub$create_vm_scaleset("myrhelss", user_config("myname", "~/.ssh/id_rsa.pub"),
instances=5, config="rhel_8_ss",
nsg=nsg_config(list(nsg_rule_allow_http, nsg_rule_allow_https)),
location="australiaeast")
# Large Debian scaleset, using low-priority VMs
# need to set the instance size to something that supports low-pri
sub$create_vm_scaleset("mydebss", user_config("myname", "~/.ssh/id_rsa.pub"),
instances=50, size="Standard_DS3_v2", config="debian_9_backports_ss",
options=scaleset_options(low_priority=TRUE, large_scaleset=TRUE),
location="australiaeast")
## VM and scaleset in the same resource group and virtual network
# first, create the resgroup
rg <- sub$create_resource_group("rgname", "australiaeast")
# create the master
rg$create_vm("mastervm", user_config("myname", "~/.ssh/id_rsa.pub"))
# get the vnet resource
vnet <- rg$get_resource(type="Microsoft.Network/virtualNetworks", name="mastervm-vnet")
# create the scaleset
rg$create_vm_scaleset("slavess", user_config("myname", "~/.ssh/id_rsa.pub"),
instances=5, vnet=vnet, nsg=NULL, load_balancer=NULL, autoscaler=NULL)
} }
} }
\seealso{ \seealso{
\link{az_vm_template}, \link{az_vm_template}, \link{az_vmss_template}
\link{vm_config}, \link{vmss_config}, \link{user_config}, \link{datadisk_config}
\link[AzureRMR:az_subscription]{AzureRMR::az_subscription}, \link[AzureRMR:az_resource_group]{AzureRMR::az_resource_group}, \link[AzureRMR:az_subscription]{AzureRMR::az_subscription}, \link[AzureRMR:az_resource_group]{AzureRMR::az_resource_group},
\href{https://azure.microsoft.com/en-us/services/virtual-machines/data-science-virtual-machines/}{Data Science Virtual Machine} \href{https://azure.microsoft.com/en-us/services/virtual-machines/data-science-virtual-machines/}{Data Science Virtual Machine}
} }

20
man/defunct.Rd Normal file
Просмотреть файл

@ -0,0 +1,20 @@
% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/add_methods.R
\name{defunct}
\alias{defunct}
\alias{get_vm_cluster}
\alias{create_vm_cluster}
\alias{delete_vm_cluster}
\title{Defunct methods}
\description{
Defunct methods
}
\section{Usage}{
\preformatted{get_vm_cluster(...)
create_vm_cluster(...)
delete_vm_cluster(...)
}
These methods for the \code{az_subscription} and \code{az_resource_group} classes are defunct in AzureVM 2.0. To work with virtual machine clusters, call the \link{get_vm_scaleset}, \link{create_vm_scaleset} and \link{delete_vm_scaleset} methods instead.
}

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

@ -3,7 +3,7 @@
\docType{class} \docType{class}
\name{delete_vm} \name{delete_vm}
\alias{delete_vm} \alias{delete_vm}
\alias{delete_vm_cluster} \alias{delete_vm_scaleset}
\title{Delete virtual machine} \title{Delete virtual machine}
\description{ \description{
Method for the \link[AzureRMR:az_subscription]{AzureRMR::az_subscription} and \link[AzureRMR:az_resource_group]{AzureRMR::az_resource_group} classes. Method for the \link[AzureRMR:az_subscription]{AzureRMR::az_subscription} and \link[AzureRMR:az_resource_group]{AzureRMR::az_resource_group} classes.
@ -17,10 +17,10 @@ delete_vm(name, confirm = TRUE, free_resources = TRUE,
resource_group = name) resource_group = name)
## R6 method for class 'az_resource_group' ## R6 method for class 'az_resource_group'
delete_vm_cluster(name, confirm = TRUE, free_resources = TRUE) delete_vm_scaleset(name, confirm = TRUE, free_resources = TRUE)
## R6 method for class 'az_subscription' ## R6 method for class 'az_subscription'
delete_vm_cluster(name, confirm = TRUE, free_resources = TRUE, delete_vm_scaleset(name, confirm = TRUE, free_resources = TRUE,
resource_group = name) resource_group = name)
} }
} }
@ -28,29 +28,21 @@ delete_vm_cluster(name, confirm = TRUE, free_resources = TRUE,
\section{Arguments}{ \section{Arguments}{
\itemize{ \itemize{
\item \code{name}: The name of the VM or cluster. \item \code{name}: The name of the VM or scaleset.
\item \code{confirm}: Whether to confirm the delete. \item \code{confirm}: Whether to confirm the delete.
\item \code{free_resources}: If this was a deployed template, whether to free all resources created during the deployment process. \item \code{free_resources}: If this was a deployed template, whether to free all resources created during the deployment process.
\item \code{resource_group}: For the \code{AzureRMR::az_subscription} method, the resource group containing the VM or cluster. \item \code{resource_group}: For the \code{AzureRMR::az_subscription} method, the resource group containing the VM or scaleset.
} }
} }
\section{Details}{
If the VM or cluster is of class \link{az_vm_template} and was created in exclusive mode, this method deletes the entire resource group that it occupies. This automatically frees all resources that were created during the deployment process. Otherwise, if \code{free_resources=TRUE}, it manually deletes each individual resource in turn. This is done synchronously (the method does not return until the deletion is complete) to allow for dependencies.
If the VM is of class \link{az_vm_resource}, this method only deletes the VM resource itself, not any other resources it may depend on.
}
\examples{ \examples{
\dontrun{ \dontrun{
sub <- AzureRMR::az_rm$ sub <- AzureRMR::get_azure_login()$
new(tenant="myaadtenant.onmicrosoft.com", app="app_id", password="password")$
get_subscription("subscription_id") get_subscription("subscription_id")
sub$delete_vm("myWindowsDSVM") sub$delete_vm("myvm")
sub$delete_vm("myLinuxDSVM") sub$delete_vm_scaleset("myscaleset")
} }
} }

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

@ -2,8 +2,9 @@
% Please edit documentation in R/add_methods.R % Please edit documentation in R/add_methods.R
\name{get_vm} \name{get_vm}
\alias{get_vm} \alias{get_vm}
\alias{get_vm_cluster} \alias{get_vm_scaleset}
\alias{list_vms} \alias{get_vm_resource}
\alias{get_vm_scaleset_resource}
\title{Get existing virtual machine(s)} \title{Get existing virtual machine(s)}
\description{ \description{
Method for the \link[AzureRMR:az_subscription]{AzureRMR::az_subscription} and \link[AzureRMR:az_resource_group]{AzureRMR::az_resource_group} classes. Method for the \link[AzureRMR:az_subscription]{AzureRMR::az_subscription} and \link[AzureRMR:az_resource_group]{AzureRMR::az_resource_group} classes.
@ -16,55 +17,51 @@ get_vm(name, resource_group = name)
get_vm(name) get_vm(name)
## R6 method for class 'az_subscription' ## R6 method for class 'az_subscription'
get_vm_cluster(name, resource_group = name) get_vm_scaleset(name, resource_group = name)
## R6 method for class 'az_resource_group' ## R6 method for class 'az_resource_group'
get_vm_cluster(name) get_vm_scaleset(name)
## R6 method for class 'az_resource_group' ## R6 method for class 'az_resource_group')
## R6 method for class 'az_subscription' get_vm_resource(name)
list_vms() get_vm_scaleset_resource(name)
} }
} }
\section{Arguments}{ \section{Arguments}{
\itemize{ \itemize{
\item \code{name}: The name of the VM or cluster. \item \code{name}: The name of the VM or scaleset.
\item \code{resource_group}: For the \code{az_subscription} method, the resource group in which \code{get_vm()} will look for the VM. Defaults to the VM name. \item \code{resource_group}: For the \code{az_subscription} methods, the resource group in which \code{get_vm()} and \code{get_vm_scaleset()} will look for the VM or scaleset. Defaults to the VM name.
} }
} }
\section{Details}{
Despite the names, \code{get_vm} and \code{get_vm_cluster} can both be used to retrieve individual VMs and clusters. The main difference is in their behaviour if a deployment template is not found. In the case of \code{get_vm}, it also searches for a raw VM resource of the given name, whereas \code{get_vm_cluster} will throw an error immediately.
}
\section{Value}{ \section{Value}{
For \code{get_vm()}, an object representing the VM, either of class \code{az_vm_template} or \code{az_vm_resource}. For \code{get_vm()}, an object representing the VM deployment. This will include other resources besides the VM itself, such as the network interface, virtual network, etc.
For \code{list_vms()}, a list of such objects. For \code{get_vm_scaleset()}, an object representing the scaleset deployment. Similarly to \code{get_vm()}, this includes other resources besides the scaleset.
For \code{get_vm_cluster()}, an object representing the cluster. For \code{get_vm_resource()} and \code{get_vm_scaleset_resource()}, the VM or scaleset resource itself.
} }
\examples{ \examples{
\dontrun{ \dontrun{
sub <- AzureRMR::az_rm$ sub <- AzureRMR::get_azure_login()$
new(tenant="myaadtenant.onmicrosoft.com", app="app_id", password="password")$
get_subscription("subscription_id") get_subscription("subscription_id")
sub$list_vms() sub$get_vm("myvirtualmachine")
sub$get_vm("myVirtualMachine") sub$get_vm_scaleset("myscaleset")
rg <- sub$get_resource_group("rgname") rg <- sub$get_resource_group("rgname")
rg$get_vm("myOtherVirtualMachine") rg$get_vm("myothervirtualmachine")
rg$get_vm_scaleset("myotherscaleset")
} }
} }
\seealso{ \seealso{
\link{az_vm_template}, \link{az_vm_resource}, \link{az_vm_template}, \link{az_vm_resource}, \link{az_vmss_template}, \link{az_vmss_resource} for the methods available for working with VMs and VM scalesets.
\link[AzureRMR:az_subscription]{AzureRMR::az_subscription}, \link[AzureRMR:az_resource_group]{AzureRMR::az_resource_group} \link[AzureRMR:az_subscription]{AzureRMR::az_subscription}, \link[AzureRMR:az_resource_group]{AzureRMR::az_resource_group}
} }

26
man/ip_config.Rd Normal file
Просмотреть файл

@ -0,0 +1,26 @@
% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/ip_config.R
\name{ip_config}
\alias{ip_config}
\title{Public IP address configuration}
\usage{
ip_config(type = NULL, dynamic = NULL, ipv6 = FALSE,
domain_name = "[parameters('vmName')]", ...)
}
\arguments{
\item{type}{The SKU of the IP address resource: "basic" or "standard". If NULL (the default), this will be determined based on the VM's configuration.}
\item{dynamic}{Whether the IP address should be dynamically or statically allocated. Note that the standard SKU only supports standard allocation. If NULL (the default) this will be determined based on the VM's configuration.}
\item{ipv6}{Whether to create an IPv6 address. The default is IPv4.}
\item{domain_name}{The domain name label to associate with the address.}
\item{...}{Other named arguments that will be treated as resource properties.}
}
\description{
Public IP address configuration
}
\seealso{
\link{create_vm}, \link{vm_config}, \link{vmss_config}
}

41
man/is_vm.Rd Normal file
Просмотреть файл

@ -0,0 +1,41 @@
% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/is_vm.R
\name{is_vm}
\alias{is_vm}
\alias{is_vm_template}
\alias{is_vm_resource}
\alias{is_vm_scaleset}
\alias{is_vm_scaleset_template}
\alias{is_vm_scaleset_resource}
\title{Is an object an Azure VM}
\usage{
is_vm(object)
is_vm_template(object)
is_vm_resource(object)
is_vm_scaleset(object)
is_vm_scaleset_template(object)
is_vm_scaleset_resource(object)
}
\arguments{
\item{object}{an R object.}
}
\value{
\code{is_vm} and \code{is_vm_template} return TRUE for an object representing a virtual machine deployment (which will include other resources besides the VM itself).
\code{is_vm_resource} returns TRUE for an object representing the specific VM resource.
\code{is_vm_scaleset} and \code{is_vm_scaleset_template} return TRUE for an object representing a VM scaleset deployment.
\code{is_vm_scaleset_resource} returns TRUE for an object representing the specific VM scaleset resource.
}
\description{
Is an object an Azure VM
}
\seealso{
\link{create_vm}, \link{create_vm_scaleset}, \link{az_vm_template}, \link{az_vm_resource}, \link{az_vmss_template}, \link{az_vmss_resource}
}

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

@ -1,20 +0,0 @@
% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/az_vm_template.R
\name{is_vm_template}
\alias{is_vm_template}
\title{Is an object an Azure VM template}
\usage{
is_vm_template(object)
}
\arguments{
\item{object}{an R object.}
}
\value{
A boolean.
}
\description{
Is an object an Azure VM template
}
\details{
This function returns TRUE only for an object representing a VM template deployment. In particular, it returns FALSE for a raw VM resource.
}

48
man/lb_config.Rd Normal file
Просмотреть файл

@ -0,0 +1,48 @@
% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/lb_config.R
\name{lb_config}
\alias{lb_config}
\alias{lb_probe}
\alias{lb_rule}
\title{Load balancer configuration}
\usage{
lb_config(type = NULL, rules = list(), probes = list(), ...)
lb_probe(name, port, interval = 5, fail_on = 2, protocol = "Tcp")
lb_rule(name, frontend_port, backend_port = frontend_port,
protocol = "Tcp", timeout = 5, floating_ip = FALSE, probe_name)
}
\arguments{
\item{type}{The SKU of the load balancer resource: "basic" or "standard". If NULL (the default), this will be determined based on the VM scaleset's configuration. Note that the load balancer SKU must be the same as that of its public IP address.}
\item{rules}{A list of load balancer rules, each obtained via a call to \code{lb_rule}.}
\item{probes}{A list of health checking probes, each obtained via a call to \code{lb_probe}. There must be a probe corresponding to each rule.}
\item{...}{Other named arguments that will be treated as resource properties.}
\item{name}{For \code{lb_rule}, a name for the load balancing rule.}
\item{port}{For \code{lb_probe}, the port to probe.}
\item{interval}{For \code{lb_probe}, the time interval between probes in seconds.}
\item{fail_on}{For \code{lb_probe}, the probe health check will fail after this many non-responses.}
\item{protocol}{For \code{lb_probe} and \code{lb_rule}, the protocol: either "Tcp" or "Ip".}
\item{frontend_port, backend_port}{For \code{lb_rule}, the ports for this rule.}
\item{timeout}{The timeout interval for the rule. The default is 5 minutes.}
\item{floating_ip}{Whether to use floating IP addresses (direct server return). Only needed for specific scenarios, and when the frontend and backend ports don't match.}
\item{probe_name}{The name of the corresponding health check probe.}
}
\description{
Load balancer configuration
}
\seealso{
\link{create_vm_scaleset}, \link{vmss_config}, \link{lb_rules} for some predefined load balancing rules and probes
}

76
man/lb_rules.Rd Normal file
Просмотреть файл

@ -0,0 +1,76 @@
% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/lb_config.R
\docType{data}
\name{lb_rule_ssh}
\alias{lb_rule_ssh}
\alias{lb_rules}
\alias{lb_rule_http}
\alias{lb_rule_https}
\alias{lb_rule_rdp}
\alias{lb_rule_jupyter}
\alias{lb_rule_rstudio}
\alias{lb_rule_mssql}
\alias{lb_rule_mssql_browser}
\alias{lb_probe_ssh}
\alias{lb_probe_http}
\alias{lb_probe_https}
\alias{lb_probe_rdp}
\alias{lb_probe_jupyter}
\alias{lb_probe_rstudio}
\alias{lb_probe_mssql}
\alias{lb_probe_mssql_browser}
\title{Load balancing rules}
\format{Objects of class \code{lb_rule} and \code{lb_probe}.}
\usage{
lb_rule_ssh
lb_rule_http
lb_rule_https
lb_rule_rdp
lb_rule_jupyter
lb_rule_rstudio
lb_rule_mssql
lb_rule_mssql_browser
lb_probe_ssh
lb_probe_http
lb_probe_https
lb_probe_rdp
lb_probe_jupyter
lb_probe_rstudio
lb_probe_mssql
lb_probe_mssql_browser
}
\description{
Load balancing rules
}
\details{
Some predefined load balancing objects, for commonly used ports. Each load balancing rule comes with its own health probe.
\itemize{
\item HTTP: TCP port 80
\item HTTPS: TCP port 443
\item JupyterHub: TCP port 8000
\item RDP: TCP port 3389
\item RStudio Server: TCP port 8787
\item SSH: TCP port 22
\item SQL Server: TCP port 1433
\item SQL Server browser service: TCP port 1434
}
}
\seealso{
\link{lb_config}
}
\keyword{datasets}

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

@ -31,8 +31,7 @@ If \code{name_only} is TRUE, a character vector of names, suitable for passing t
\examples{ \examples{
\dontrun{ \dontrun{
sub <- AzureRMR::az_rm$ sub <- AzureRMR::get_azure_login$
new(tenant="myaadtenant.onmicrosoft.com", app="app_id", password="password")$
get_subscription("subscription_id") get_subscription("subscription_id")
sub$list_vm_sizes("australiaeast") sub$list_vm_sizes("australiaeast")

32
man/nic_config.Rd Normal file
Просмотреть файл

@ -0,0 +1,32 @@
% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/nic_config.R
\name{nic_config}
\alias{nic_config}
\alias{nic_ip_config}
\title{Network interface configuration}
\usage{
nic_config(nic_ip = list(nic_ip_config()), ...)
nic_ip_config(name = "ipconfig", private_alloc = "dynamic",
subnet = "[variables('subnetId')]",
public_address = "[variables('ipId')]", ...)
}
\arguments{
\item{nic_ip}{For \code{nic_config}, a list of IP configuration objects, each obtained via a call to \code{nic_ip_config}.}
\item{...}{Other named arguments that will be treated as resource properties.}
\item{name}{For \code{nic_ip_config}, the name of the IP configuration.}
\item{private_alloc}{For \code{nic_ip_config}, the allocation method for a private IP address. Can be "dynamic" or "static".}
\item{subnet}{For \code{nic_ip_config}, the subnet to associate with this private IP address.}
\item{public_address}{For \code{nic_ip_config}, the public IP address. Defaults to the public IP address created or used as part of this VM deployment. Ignored if the deployment does not include a public address.}
}
\description{
Network interface configuration
}
\seealso{
\link{create_vm}, \link{vm_config}
}

39
man/nsg_config.Rd Normal file
Просмотреть файл

@ -0,0 +1,39 @@
% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/nsg_config.R
\name{nsg_config}
\alias{nsg_config}
\alias{nsg_rule}
\title{Network security group configuration}
\usage{
nsg_config(rules = list(), ...)
nsg_rule(name, dest_port = "*", dest_addr = "*", dest_asgs = NULL,
source_port = "*", source_addr = "*", source_asgs = NULL,
access = "allow", direction = "inbound", protocol = "Tcp",
priority = NULL)
}
\arguments{
\item{rules}{for \code{nsg_config}, a list of security rule objects, each obtained via a call to \code{nsg_rule}.}
\item{...}{Other named arguments that will be treated as resource properties.}
\item{name}{For \code{nsg_rule}, a name for the rule.}
\item{dest_port, dest_addr, dest_asgs}{For \code{nsg_rule}, the destination port, address range, and application security groups for a rule.}
\item{source_port, source_addr, source_asgs}{For \code{nsg_rule}, the source port, address range, and application security groups for a rule.}
\item{access}{For \code{nsg_rule}, the action to take: "allow" or "deny".}
\item{direction}{For \code{nsg_rule}, the direction of traffic: "inbound" or "outbound".}
\item{protocol}{For \code{nsg_rule}, the network protocol: either "Tcp" or "Udp".}
\item{priority}{For \code{nsg_rule}, the rule priority. If NULL, this will be set automatically by AzureVM.}
}
\description{
Network security group configuration
}
\seealso{
\link{create_vm}, \link{vm_config}, \link{vmss_config}, \link{nsg_rules} for some predefined security rules
}

52
man/nsg_rules.Rd Normal file
Просмотреть файл

@ -0,0 +1,52 @@
% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/nsg_config.R
\docType{data}
\name{nsg_rule_allow_ssh}
\alias{nsg_rule_allow_ssh}
\alias{nsg_rules}
\alias{nsg_rule_allow_http}
\alias{nsg_rule_allow_https}
\alias{nsg_rule_allow_rdp}
\alias{nsg_rule_allow_jupyter}
\alias{nsg_rule_allow_rstudio}
\alias{nsg_rule_allow_mssql}
\alias{nsg_rule_allow_mssql_browser}
\title{Network security rules}
\format{Objects of class \code{nsg_rule}.}
\usage{
nsg_rule_allow_ssh
nsg_rule_allow_http
nsg_rule_allow_https
nsg_rule_allow_rdp
nsg_rule_allow_jupyter
nsg_rule_allow_rstudio
nsg_rule_allow_mssql
nsg_rule_allow_mssql_browser
}
\description{
Network security rules
}
\details{
Some predefined network security rule objects, to unblock commonly used ports.
\itemize{
\item HTTP: TCP port 80
\item HTTPS: TCP port 443
\item JupyterHub: TCP port 8000
\item RDP: TCP port 3389
\item RStudio Server: TCP port 8787
\item SSH: TCP port 22
\item SQL Server: TCP port 1433
\item SQL Server browser service: TCP port 1434
}
}
\seealso{
\link{nsg_config}
}
\keyword{datasets}

17
man/reexports.Rd Normal file
Просмотреть файл

@ -0,0 +1,17 @@
% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/AzureVM.R
\docType{import}
\name{reexports}
\alias{reexports}
\alias{build_template_definition}
\alias{build_template_parameters}
\title{Objects exported from other packages}
\keyword{internal}
\description{
These objects are imported from other packages. Follow the links
below to see their documentation.
\describe{
\item{AzureRMR}{\code{\link[AzureRMR]{build_template_definition}}, \code{\link[AzureRMR]{build_template_parameters}}}
}}

33
man/scaleset_options.Rd Normal file
Просмотреть файл

@ -0,0 +1,33 @@
% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/vmss_config.R
\name{scaleset_options}
\alias{scaleset_options}
\title{Virtual machine scaleset options}
\usage{
scaleset_options(keylogin = TRUE, managed = TRUE, public = FALSE,
low_priority = FALSE, delete_on_evict = FALSE,
network_accel = FALSE, large_scaleset = FALSE,
overprovision = TRUE, upgrade_policy = list(mode = "manual"))
}
\arguments{
\item{keylogin}{Boolean: whether to use an SSH public key to login (TRUE) or a password (FALSE). Note that Windows does not support SSH key logins.}
\item{managed}{Whether to provide a managed system identity for the VM.}
\item{public}{Whether the instances (nodes) of the scaleset should be visible from the public internet.}
\item{low_priority}{Whether to use low-priority VMs. Note that this option is only available for certain VM sizes.}
\item{delete_on_evict}{If low-priority VMs are being used, whether evicting (shutting down) a VM should delete it, as opposed to just deallocating it.}
\item{network_accel}{Whether to enable accelerated networking.}
\item{large_scaleset}{Whether to enable scaleset sizes > 100 instances.}
\item{overprovision}{Whether to overprovision the scaleset on creation.}
\item{upgrade_policy}{A list, giving the VM upgrade policy for the scaleset.}
}
\description{
Virtual machine scaleset options
}

182
man/vm_config.Rd Normal file
Просмотреть файл

@ -0,0 +1,182 @@
% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/vm_config.R
\name{vm_config}
\alias{vm_config}
\alias{ubuntu_dsvm}
\alias{windows_dsvm}
\alias{ubuntu_16.04}
\alias{ubuntu_18.04}
\alias{windows_2016}
\alias{windows_2019}
\alias{rhel_7.6}
\alias{rhel_8}
\alias{debian_9_backports}
\title{VM configuration functions}
\usage{
vm_config(image, keylogin, managed = TRUE, datadisks = numeric(0),
nsg = nsg_config(), ip = ip_config(), vnet = vnet_config(),
nic = nic_config(), other_resources = list(), variables = list(),
...)
ubuntu_dsvm(keylogin = TRUE, managed = TRUE, datadisks = numeric(0),
nsg = nsg_config(list(nsg_rule_allow_ssh, nsg_rule_allow_jupyter,
nsg_rule_allow_rstudio)), ...)
windows_dsvm(keylogin = FALSE, managed = TRUE,
datadisks = numeric(0), nsg = nsg_config(list(nsg_rule_allow_rdp)),
...)
ubuntu_16.04(keylogin = TRUE, managed = TRUE, datadisks = numeric(0),
nsg = nsg_config(list(nsg_rule_allow_ssh)), ...)
ubuntu_18.04(keylogin = TRUE, managed = TRUE, datadisks = numeric(0),
nsg = nsg_config(list(nsg_rule_allow_ssh)), ...)
windows_2016(keylogin = FALSE, managed = TRUE,
datadisks = numeric(0), nsg = nsg_config(list(nsg_rule_allow_rdp)),
...)
windows_2019(keylogin = FALSE, managed = TRUE,
datadisks = numeric(0), nsg = nsg_config(list(nsg_rule_allow_rdp)),
...)
rhel_7.6(keylogin = TRUE, managed = TRUE, datadisks = numeric(0),
nsg = nsg_config(list(nsg_rule_allow_ssh)), ...)
rhel_8(keylogin = TRUE, managed = TRUE, datadisks = numeric(0),
nsg = nsg_config(list(nsg_rule_allow_ssh)), ...)
debian_9_backports(keylogin = TRUE, managed = TRUE,
datadisks = numeric(0), nsg = nsg_config(list(nsg_rule_allow_ssh)),
...)
}
\arguments{
\item{image}{For \code{vm_config}, the VM image to deploy. This should be an object of class \code{image_config}, created by the function of the same name.}
\item{keylogin}{Boolean: whether to use an SSH public key to login (TRUE) or a password (FALSE). Note that Windows does not support SSH key logins.}
\item{managed}{Whether to provide a managed system identity for the VM.}
\item{datadisks}{The data disks to attach to the VM. Specify this as either a vector of numeric disk sizes in GB, or a list of \code{datadisk_config} objects for more control over the specification.}
\item{nsg}{The network security group for the VM. Can be a call to \code{nsg_config} to create a new NSG; an AzureRMR resource object or resource ID to reuse an existing NSG; or NULL to not use an NSG (not recommended).}
\item{ip}{The public IP address for the VM. Can be a call to \code{ip_config} to create a new IP address; an AzureRMR resource object or resource ID to reuse an existing address resource; or NULL if the VM should not be accessible from outside its subnet.}
\item{vnet}{The virtual network for the VM. Can be a call to \code{vnet_config} to create a new virtual network, or an AzureRMR resource object or resource ID to reuse an existing virtual network. Note that by default, AzureVM will associate the NSG with the virtual network/subnet, not with the VM's network interface.}
\item{nic}{The network interface for the VM. Can be a call to \code{nic_config} to create a new interface, or an AzureRMR resource object or resource ID to reuse an existing interface.}
\item{other_resources}{An optional list of other resources to include in the deployment.}
\item{variables}{An optional named list of variables to add to the template.}
\item{...}{For the specific VM configurations, other customisation arguments to be passed to \code{vm_config}. For \code{vm_config}, named arguments that will be folded into the VM resource definition in the template.}
}
\value{
An object of S3 class \code{vm_config}, that can be used by the \code{create_vm} method.
}
\description{
VM configuration functions
}
\details{
These functions are for specifying the details of a new virtual machine deployment: the VM image and related options, along with the Azure resources that the VM may need. These include the datadisks, network security group, public IP address (if the VM is to be accessible from outside its subnet), virtual network, and network interface.
Each resource can be specified in a number of ways:
\itemize{
\item To \emph{create} a new resource as part of the deployment, call the corresponding \code{*_config} function.
\item To use an \emph{existing} resource, supply either an \code{AzureRMR::az_resource} object (recommended) or a string containing the resource ID.
\item If the resource is not needed, specify it as NULL.
\item For the \code{other_resources} argument, supply a list of resources, each of which should be a list of resource fields (name, type, properties, sku, etc).
}
The \code{vm_config} function is the base configuration function, and the others call it to create VMs with specific operating systems and other image details.
\itemize{
\item \code{ubuntu_dsvm}: Data Science Virtual Machine, based on Ubuntu 16.04
\item \code{windows_dsvm}: Data Science Virtual Machine, based on Windows Server 2016
\item \code{ubuntu_16.04}, \code{ubuntu_18.04}: Ubuntu
\item \code{windows_2016}, \code{windows_2019}: Windows Server Datacenter edition
\item \code{rhel_7.6}, \code{rhel_8}: Red Hat Enterprise Linux
\item \code{debian_9_backports}: Debian
}
}
\examples{
# basic Linux (Ubuntu) and Windows configs
ubuntu_18.04()
windows_2019()
# Windows DSVM with 500GB data disk, no public IP address
windows_dsvm(datadisks=500, ip=NULL)
# RHEL VM exposing ports 80 (HTTP) and 443 (HTTPS)
rhel_8(nsg=nsg_config(nsg_rule_allow_http, nsg_rule_allow_https))
# exposing no ports externally
rhel_8(nsg=nsg_config(list()))
# deploying an extra resource: storage account
ubuntu_18.04(
variables=list(storName="[concat(variables('vmName'), 'stor')]"),
other_resources=list(
list(
type="Microsoft.Storage/storageAccounts",
name="[variables('storName')]",
apiVersion="2018-07-01",
location="[variables('location')]",
properties=list(supportsHttpsTrafficOnly=TRUE),
sku=list(name="Standard_LRS"),
kind="Storage"
)
)
)
## custom VM configuration: Windows 10 Pro 1903 with data disks
## this assumes you have a valid Win10 desktop license
user <- user_config("myname", password="Use-strong-passwords!")
image <- image_config(
publisher="MicrosoftWindowsDesktop",
offer="Windows-10",
sku="19h1-pro"
)
datadisks <- list(
datadisk_config(250, type="Premium_LRS"),
datadisk_config(1000, type="Standard_LRS")
)
nsg <- nsg_config(
list(nsg_rule_allow_rdp)
)
vm_config(
image=image,
keylogin=FALSE,
datadisks=datadisks,
nsg=nsg,
properties=list(licenseType="Windows_Client")
)
\dontrun{
# reusing existing resources: placing multiple VMs in one vnet/subnet
rg <- AzureRMR::get_azure_login()$
get_subscription("sub_id")$
get_resource_group("rgname")
vnet <- rg$get_resource(type="Microsoft.Network/virtualNetworks", name="myvnet")
# by default, the NSG is associated with the subnet, so we don't need a new NSG either
vmconfig1 <- ubuntu_18.04(vnet=vnet, nsg=NULL)
vmconfig2 <- debian_9_backports(vnet=vnet, nsg=NULL)
vmconfig3 <- windows_2019(vnet=vnet, nsg=NULL)
}
}
\seealso{
\link{image_config}, \link{user_config}, \link{datadisk_config} for options relating to the VM resource itself
\link{nsg_config}, \link{ip_config}, \link{vnet_config}, \link{nic_config} for other resource configs
\link{vmss_config} for configuring a virtual machine scaleset
\link{create_vm}
}

40
man/vm_resource_config.Rd Normal file
Просмотреть файл

@ -0,0 +1,40 @@
% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/vm_resource_config.R
\name{user_config}
\alias{user_config}
\alias{datadisk_config}
\alias{image_config}
\title{Resource configuration functions for a virtual machine deployment}
\usage{
user_config(username, sshkey = NULL, password = NULL)
datadisk_config(size, name = "datadisk", create = "empty",
type = "StandardSSD_LRS", write_accelerator = FALSE)
image_config(publisher = NULL, offer = NULL, sku = NULL,
version = "latest", id = NULL)
}
\arguments{
\item{username}{For \code{user_config}, the name for the admin user account.}
\item{sshkey}{For \code{user_config}, string containing an SSH public key. Can be the key itself, or the name of the public key file.}
\item{password}{For \code{user_config}, the admin password. Supply either \code{sshkey} or \code{password}, but not both; also, note that Windows does not support SSH logins.}
\item{size}{For \code{datadisk_config}, the size of the data disk in GB. St this to NULL for a disk that will be created from an image.}
\item{name}{For \code{datadisk_config}, the disk name. Duplicate names will automatically be disambiguated prior to VM deployment.}
\item{create}{For \code{datadisk_config}, the creation method. Can be "empty" (the default) to create a blank disk, or "fromImage" to use an image.}
\item{type}{For \code{datadisk_config}, the disk type (SKU). Can be "Standard_LRS", "StandardSSD_LRS" (the default), "Premium_LRS" or "UltraSSD_LRS". Of these, "Standard_LRS" uses hard disks and the others use SSDs as the underlying hardware.}
\item{write_accelerator}{For \code{datadisk_config}, whether the disk should have write acceleration enabled.}
\item{publisher, offer, sku, version}{For \code{image_config}, the details for a marketplace image.}
\item{id}{For \code{image_config}, the resource ID for a disk to use as a custom image.}
}
\description{
Resource configuration functions for a virtual machine deployment
}

148
man/vmss_config.Rd Normal file
Просмотреть файл

@ -0,0 +1,148 @@
% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/vmss_config.R
\name{vmss_config}
\alias{vmss_config}
\alias{ubuntu_dsvm_ss}
\alias{windows_dsvm_ss}
\alias{ubuntu_16.04_ss}
\alias{ubuntu_18.04_ss}
\alias{windows_2016_ss}
\alias{windows_2019_ss}
\alias{rhel_7.6_ss}
\alias{rhel_8_ss}
\alias{debian_9_backports_ss}
\title{Virtual machine scaleset configuration functions}
\usage{
vmss_config(image, options = scaleset_options(), nsg = nsg_config(),
vnet = vnet_config(), load_balancer = lb_config(),
load_balancer_address = ip_config(),
autoscaler = autoscaler_config(), other_resources = list(),
variables = list(), ...)
ubuntu_dsvm_ss(nsg = nsg_config(list(nsg_rule_allow_ssh,
nsg_rule_allow_jupyter, nsg_rule_allow_rstudio)),
load_balancer = lb_config(rules = list(lb_rule_ssh, lb_rule_jupyter,
lb_rule_rstudio), probes = list(lb_probe_ssh, lb_probe_jupyter,
lb_probe_rstudio)), ...)
windows_dsvm_ss(nsg = nsg_config(list(nsg_rule_allow_rdp)),
load_balancer = lb_config(rules = list(lb_rule_rdp), probes =
list(lb_probe_rdp)), options = scaleset_options(keylogin = FALSE), ...)
ubuntu_16.04_ss(nsg = nsg_config(list(nsg_rule_allow_ssh)),
load_balancer = lb_config(rules = list(lb_rule_ssh), probes =
list(lb_probe_ssh)), ...)
ubuntu_18.04_ss(nsg = nsg_config(list(nsg_rule_allow_ssh)),
load_balancer = lb_config(rules = list(lb_rule_ssh), probes =
list(lb_probe_ssh)), ...)
windows_2016_ss(nsg = nsg_config(list(nsg_rule_allow_rdp)),
load_balancer = lb_config(rules = list(lb_rule_rdp), probes =
list(lb_probe_rdp)), options = scaleset_options(keylogin = FALSE), ...)
windows_2019_ss(nsg = nsg_config(list(nsg_rule_allow_rdp)),
load_balancer = lb_config(rules = list(lb_rule_rdp), probes =
list(lb_probe_rdp)), options = scaleset_options(keylogin = FALSE), ...)
rhel_7.6_ss(nsg = nsg_config(list(nsg_rule_allow_ssh)),
load_balancer = lb_config(rules = list(lb_rule_ssh), probes =
list(lb_probe_ssh)), ...)
rhel_8_ss(nsg = nsg_config(list(nsg_rule_allow_ssh)),
load_balancer = lb_config(rules = list(lb_rule_ssh), probes =
list(lb_probe_ssh)), ...)
debian_9_backports_ss(nsg = nsg_config(list(nsg_rule_allow_ssh)),
load_balancer = lb_config(rules = list(lb_rule_ssh), probes =
list(lb_probe_ssh)), ...)
}
\arguments{
\item{image}{For \code{vmss_config}, the VM image to deploy. This should be an object of class \code{image_config}, created by the function of the same name.}
\item{options}{Scaleset options, as obtained via a call to \code{scaleset_options}.}
\item{nsg}{The network security group for the scaleset. Can be a call to \code{nsg_config} to create a new NSG; an AzureRMR resource object or resource ID to reuse an existing NSG; or NULL to not use an NSG (not recommended).}
\item{vnet}{The virtual network for the scaleset. Can be a call to \code{vnet_config} to create a new virtual network, or an AzureRMR resource object or resource ID to reuse an existing virtual network. Note that by default, AzureVM will associate the NSG with the virtual network/subnet, not with the VM's network interface.}
\item{load_balancer}{The load balancer for the scaleset. Can be a call to \code{lb_config} to create a new load balancer; an AzureRMR resource object or resource ID to reuse an existing load balancer; or NULL if load balancing is not required.}
\item{load_balancer_address}{The public IP address for the load balancer. Can be a call to \code{ip_config} to create a new IP address, or an AzureRMR resource object or resource ID to reuse an existing address resource. Ignored if \code{load_balancer} is NULL.}
\item{autoscaler}{The autoscaler for the scaleset. Can be a call to \code{autoscaler_config} to create a new autoscaler; an AzureRMR resource object or resource ID to reuse an existing autoscaler; or NULL if autoscaling is not required.}
\item{other_resources}{An optional list of other resources to include in the deployment.}
\item{variables}{An optional named list of variables to add to the template.}
\item{...}{For the specific VM configurations, other customisation arguments to be passed to \code{vm_config}. For \code{vmss_config}, named arguments that will be folded into the scaleset resource definition in the template.}
}
\value{
An object of S3 class \code{vmss_config}, that can be used by the \code{create_vm_scaleset} method.
}
\description{
Virtual machine scaleset configuration functions
}
\details{
These functions are for specifying the details of a new virtual machine scaleset deployment: the base VM image and related options, along with the Azure resources that the scaleset may need. These include the network security group, virtual network, load balancer and associated public IP address, and autoscaler.
Each resource can be specified in a number of ways:
\itemize{
\item To \emph{create} a new resource as part of the deployment, call the corresponding \code{*_config} function.
\item To use an \emph{existing} resource, supply either an \code{AzureRMR::az_resource} object (recommended) or a string containing the resource ID.
\item If the resource is not needed, specify it as NULL.
\item For the \code{other_resources} argument, supply a list of resources, each of which should be a list of resource fields (name, type, properties, sku, etc).
}
The \code{vmss_config} function is the base configuration function, and the others call it to create VM scalesets with specific operating systems and other image details.
\itemize{
\item \code{ubuntu_dsvm_ss}: Data Science Virtual Machine, based on Ubuntu 16.04
\item \code{windows_dsvm_ss}: Data Science Virtual Machine, based on Windows Server 2016
\item \code{ubuntu_16.04_ss}, \code{ubuntu_18.04}: Ubuntu
\item \code{windows_2016_ss}, \code{windows_2019}: Windows Server Datacenter edition
\item \code{rhel_7.6_ss}, \code{rhel_8_ss}: Red Hat Enterprise Linux
\item \code{debian_9_backports_ss}: Debian
}
}
\examples{
# basic Linux (Ubuntu) and Windows configs
ubuntu_18.04_ss()
windows_2019_ss()
# Windows DSVM scaleset, no load balancer and autoscaler
windows_dsvm_ss(load_balancer=NULL, autoscaler=NULL)
# RHEL VM exposing ports 80 (HTTP) and 443 (HTTPS)
rhel_8_ss(nsg=nsg_config(nsg_rule_allow_http, nsg_rule_allow_https))
# exposing no ports externally
rhel_8_ss(nsg=nsg_config(list()))
# low-priority VMs, large scaleset (>100 instances allowed), no managed identity
rhel_8_ss(options=scaleset_options(low_priority=TRUE, large_scaleset=TRUE, managed=FALSE))
\dontrun{
# reusing existing resources: placing a scaleset in an existing vnet/subnet
# we don't need a new network security group either
vnet <- AzureRMR::get_azure_login()$
get_subscription("sub_id")$
get_resource_group("rgname")$
get_resource(type="Microsoft.Network/virtualNetworks", name="myvnet")
ubuntu_18.04_ss(vnet=vnet, nsg=NULL)
}
}
\seealso{
\link{scaleset_options} for options relating to the scaleset resource itself
\link{nsg_config}, \link{ip_config}, \link{vnet_config}, \link{lb_config}, \link{autoscaler_config} for other resource configs
\link{vm_config} for configuring an individual virtual machine
\link{create_vm_scaleset}
}

32
man/vnet_config.Rd Normal file
Просмотреть файл

@ -0,0 +1,32 @@
% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/vnet_config.R
\name{vnet_config}
\alias{vnet_config}
\alias{subnet_config}
\title{Virtual network configuration}
\usage{
vnet_config(address_space = "10.0.0.0/16",
subnets = list(subnet_config()), ...)
subnet_config(name = "subnet", addresses = "10.0.0.0/16",
nsg = "[variables('nsgId')]", ...)
}
\arguments{
\item{address_space}{For \code{vnet_config}, the address range accessible by the virtual network, expressed in CIDR block format.}
\item{subnets}{For \code{vnet_config}, a list of subnet objects, each obtained via a call to \code{subnet_config}.}
\item{...}{Other named arguments that will be treated as resource properties.}
\item{name}{For \code{subnet_config}, the name of the subnet. Duplicate names will automatically be disambiguated prior to VM deployment.}
\item{addresses}{For \code{subnet_config}, the address ranges spanned by this subnet. Must be a subset of the address space available to the parent virtual network.}
\item{nsg}{The network security group associated with this subnet. Defaults to the NSG created as part of this VM deployment.}
}
\description{
Virtual network configuration
}
\seealso{
\link{create_vm}, \link{vm_config}, \link{vmss_config}
}

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

@ -0,0 +1 @@
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDSMJcL3SJ1knfBegs0r2UmHoHhux3rfxQLa1uv4PJUWqxhAOoGY3kbBt5qx9Hn8vNrUtGn06Brcsr/MQg3Iv7GYeh+EofJOX1ZewU7+vDR4UkGHBbl1xQDkeZdqNZ9RqbiB6V7mDaGjIlc+j5op2HxOMBU4DSKNbTu4CJCEGYZKf2ln+PIAv5FyHINTIOYRHCBvFERMOyxkTHclfkbcoedkRZILoOKVB3kbPwTREJpYG0co+nz6tkw45VTFXjBx75DSN2097NsReCNgdYM8R6eEqChsmDSmjsE43F0/pyM1F8tVDTSYbpVQn56Qaq9Ymbd6WOkhOSmPVIvmnKrymTV hongo@LAPTOP-P18OIHUP

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

@ -0,0 +1,175 @@
context("Resource configs")
test_that("User config works",
{
user <- user_config("username", sshkey="random key")
expect_is(user, "user_config")
expect_identical(user$key, "random key")
user <- user_config("username", password="random password")
expect_is(user, "user_config")
expect_identical(user$pwd, "random password")
user <- user_config("username", sshkey="../testthat.R")
expect_is(user, "user_config")
expect_identical(user$key, readLines("../testthat.R"))
})
test_that("Datadisk config works",
{
disk <- datadisk_config(100)
expect_is(disk, "datadisk_config")
expect_identical(disk$res_spec$diskSizeGB, 100)
expect_identical(disk$vm_spec$createOption, "attach")
expect_identical(disk$vm_spec$caching, "None")
expect_null(disk$vm_spec$storageAccountType)
})
test_that("Image config works",
{
expect_error(image_config())
img <- image_config(publisher="pubname", offer="offname", sku="skuname")
expect_is(img, "image_marketplace")
img <- image_config(id="resource_id")
expect_is(img, "image_custom")
})
test_that("Network security group config works",
{
nsg <- nsg_config()
expect_is(nsg, "nsg_config")
expect_identical(build_resource_fields(nsg), nsg_default)
nsg <- nsg_config(list(nsg_rule_allow_ssh))
expect_is(nsg, "nsg_config")
expect_is(nsg$properties$securityRules[[1]], "nsg_rule")
expect_identical(nsg$properties$securityRules[[1]]$name, "Allow-ssh")
})
test_that("Public IP address config works",
{
ip <- ip_config()
expect_is(ip, "ip_config")
expect_null(ip$type)
expect_null(ip$dynamic)
ip <- ip_config("static", FALSE)
expect_is(ip, "ip_config")
res <- build_resource_fields(ip)
expect_identical(res$properties,
list(
publicIPAllocationMethod="static",
publicIPAddressVersion="IPv4",
dnsSettings=list(domainNameLabel="[parameters('vmName')]")
)
)
expect_identical(res$sku,
list(name="static")
)
})
test_that("Virtual network config works",
{
vnet <- vnet_config()
expect_is(vnet, "vnet_config")
expect_is(vnet$properties$subnets[[1]], "subnet_config")
res <- build_resource_fields(vnet)
expect_identical(res$properties,
list(
addressSpace=list(addressPrefixes=I("10.0.0.0/16")),
subnets=list(
list(
name="subnet",
properties=list(
addressPrefix="10.0.0.0/16",
networkSecurityGroup=list(id="[variables('nsgId')]")
)
)
)
)
)
})
test_that("Network interface config works",
{
nic <- nic_config()
expect_is(nic, "nic_config")
res <- build_resource_fields(nic)
expect_identical(res$properties,
list(
ipConfigurations=list(
list(
name="ipconfig",
properties=list(
privateIPAllocationMethod="dynamic",
subnet=list(id="[variables('subnetId')]"),
publicIPAddress=list(id="[variables('ipId')]")
)
)
)
)
)
})
test_that("Load balancer config works",
{
lb <- lb_config()
expect_is(lb, "lb_config")
expect_null(lb$type)
lb <- lb_config(type="basic")
res <- build_resource_fields(lb)
expect_identical(res$properties,
list(
frontendIPConfigurations=list(
list(
name="[variables('lbFrontendName')]",
properties=list(
publicIPAddress=list(id="[variables('ipId')]")
)
)
),
backendAddressPools=list(
list(
name="[variables('lbBackendName')]"
)
),
loadBalancingRules=list(),
probes=list()
)
)
expect_identical(res$sku,
list(name="basic")
)
lb <- lb_config(type="basic", rules=list(lb_rule_ssh), probes=list(lb_probe_ssh))
expect_is(lb$rules[[1]], "lb_rule")
expect_is(lb$probes[[1]], "lb_probe")
res <- build_resource_fields(lb)
expect_identical(res$properties$loadBalancingRules[[1]], unclass(lb_rule_ssh))
expect_identical(res$properties$probes[[1]], unclass(lb_probe_ssh))
})
test_that("Autoscaler config works",
{
as <- autoscaler_config()
expect_is(as, "as_config")
expect_is(as$properties$profiles[[1]], "as_profile_config")
res <- build_resource_fields(as)
expect_identical(res$properties,
list(
name="[variables('asName')]",
targetResourceUri="[variables('vmId')]",
enabled=TRUE,
profiles=list(
unclass(autoscaler_profile())
)
)
)
})

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

@ -1,115 +0,0 @@
context("VM interface")
tenant <- Sys.getenv("AZ_TEST_TENANT_ID")
app <- Sys.getenv("AZ_TEST_APP_ID")
password <- Sys.getenv("AZ_TEST_PASSWORD")
subscription <- Sys.getenv("AZ_TEST_SUBSCRIPTION")
if(tenant == "" || app == "" || password == "" || subscription == "")
skip("Tests skipped: ARM credentials not set")
sub <- AzureRMR::az_rm$new(tenant=tenant, app=app, password=password)$get_subscription(subscription)
rgname <- paste(sample(letters, 20, replace=TRUE), collapse="")
winvm_name <- paste0("win", paste0(sample(letters, 10, TRUE), collapse=""))
luxvm_name <- paste0("lux", paste0(sample(letters, 10, TRUE), collapse=""))
winvmrg_name <- paste0("winrg", paste0(sample(letters, 10, TRUE), collapse=""))
luxvmrg_name <- paste0("luxrg", paste0(sample(letters, 10, TRUE), collapse=""))
winvmclus_name <- paste0("wincl", paste0(sample(letters, 10, TRUE), collapse=""))
luxvmclus_name <- paste0("luxcl", paste0(sample(letters, 10, TRUE), collapse=""))
test_that("VM creation works",
{
expect_is(sub$create_vm(winvm_name, location="australiaeast",
username="ds", pass="PassWord343!"),
"az_vm_template")
expect_true(sub$resource_group_exists(winvm_name))
expect_is(sub$create_vm(luxvm_name, location="australiaeast",
os="Ubuntu", username="ds", pass=readLines("~/.ssh/id_rsa.pub"), userauth_type="key"),
"az_vm_template")
expect_true(sub$resource_group_exists(luxvm_name))
rg <- sub$create_resource_group(rgname, location="australiaeast")
expect_is(rg$create_vm(winvmrg_name,
username="ds", pass="PassWord343!"),
"az_vm_template")
expect_is(rg$create_vm(luxvmrg_name,
os="Ubuntu", username="ds", pass=readLines("~/.ssh/id_rsa.pub"), userauth_type="key"),
"az_vm_template")
})
test_that("VM interaction works",
{
winvm <- sub$get_vm(winvm_name)
expect_is(winvm, "az_vm_template")
expect_silent(winvm$run_script("dir \\"))
winvm$stop(deallocate=FALSE, wait=TRUE)
expect_true(winvm$status[[1]]["PowerState"] == "stopped")
winvm$resize("Standard_DS2_v2", wait=TRUE)
expect_true(winvm$.__enclos_env__$private$vm[[1]]$properties$hardwareProfile == "Standard_DS2_v2")
winvm$start(wait=TRUE)
expect_true(winvm$status[[1]]["PowerState"] == "running")
luxvm <- sub$get_vm(luxvm_name)
expect_is(luxvm, "az_vm_template")
expect_silent(luxvm$run_script("ls -al /"))
luxvm$stop(deallocate=FALSE, wait=TRUE)
expect_true(luxvm$status[[1]]["PowerState"] == "stopped")
luxvm$resize("Standard_DS2_v2", wait=TRUE)
expect_true(luxvm$.__enclos_env__$private$vm[[1]]$properties$hardwareProfile == "Standard_DS2_v2")
luxvm$start(wait=TRUE)
expect_true(luxvm$status[[1]]["PowerState"] == "running")
})
test_that("VM deletion works",
{
verify_rg_deleted <- function(rgname)
{
for(i in 1:100)
{
Sys.sleep(5)
if(!sub$resource_group_exists(rgname))
break
}
expect_false(sub$resource_group_exists(rgname))
}
winvm <- sub$get_vm(winvm_name)
expect_is(winvm, "az_vm_template")
winvm$delete(confirm=FALSE)
verify_rg_deleted(winvm_name)
luxvm <- sub$get_vm(luxvm_name)
expect_is(luxvm, "az_vm_template")
luxvm$delete(confirm=FALSE)
verify_rg_deleted(luxvm_name)
rg <- sub$get_resource_group(rgname)
winvmrg <- rg$get_vm(winvmrg_name)
expect_is(winvmrg, "az_vm_template")
winvmrg$delete(confirm=FALSE)
luxvmrg <- rg$get_vm(luxvmrg_name)
expect_is(luxvmrg, "az_vm_template")
luxvmrg$delete(confirm=FALSE)
Sys.sleep(10)
expect_true(is_empty(rg$list_resources()))
})
sub$delete_resource_group(rgname, confirm=FALSE)

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

@ -0,0 +1,170 @@
context("VM+scaleset config")
test_that("VM config works",
{
key_user <- user_config("username", ssh="random key")
pwd_user <- user_config("username", password="random password")
img <- image_config(publisher="pubname", offer="offname", sku="skuname")
vm <- vm_config(img, keylogin=TRUE)
expect_is(vm, "vm_config")
expect_silent(build_template_definition(vm))
expect_silent(build_template_parameters(vm, "vmname", key_user, "size"))
vm <- ubuntu_18.04()
expect_is(vm, "vm_config")
expect_true(vm$image$publisher == "Canonical" &&
vm$image$offer == "UbuntuServer" &&
vm$image$sku == "18.04-LTS")
expect_silent(build_template_definition(vm))
expect_silent(build_template_parameters(vm, "vmname", key_user, "size"))
vm <- ubuntu_16.04()
expect_is(vm, "vm_config")
expect_true(vm$image$publisher == "Canonical" &&
vm$image$offer == "UbuntuServer" &&
vm$image$sku == "16.04-LTS")
expect_silent(build_template_definition(vm))
expect_silent(build_template_parameters(vm, "vmname", key_user, "size"))
vm <- windows_2019()
expect_is(vm, "vm_config")
expect_true(vm$image$publisher == "MicrosoftWindowsServer" &&
vm$image$offer == "WindowsServer" &&
vm$image$sku == "2019-Datacenter")
expect_silent(build_template_definition(vm))
expect_silent(build_template_parameters(vm, "vmname", pwd_user, "size"))
vm <- windows_2016()
expect_is(vm, "vm_config")
expect_true(vm$image$publisher == "MicrosoftWindowsServer" &&
vm$image$offer == "WindowsServer" &&
vm$image$sku == "2016-Datacenter")
expect_silent(build_template_definition(vm))
expect_silent(build_template_parameters(vm, "vmname", pwd_user, "size"))
vm <- rhel_8()
expect_is(vm, "vm_config")
expect_true(vm$image$publisher == "RedHat" &&
vm$image$offer == "RHEL" &&
vm$image$sku == "8")
expect_silent(build_template_definition(vm))
expect_silent(build_template_parameters(vm, "vmname", key_user, "size"))
vm <- rhel_7.6()
expect_is(vm, "vm_config")
expect_true(vm$image$publisher == "RedHat" &&
vm$image$offer == "RHEL" &&
vm$image$sku == "7-RAW")
expect_silent(build_template_definition(vm))
expect_silent(build_template_parameters(vm, "vmname", key_user, "size"))
vm <- debian_9_backports()
expect_is(vm, "vm_config")
expect_true(vm$image$publisher == "Credativ" &&
vm$image$offer == "Debian" &&
vm$image$sku == "9-backports")
expect_silent(build_template_definition(vm))
expect_silent(build_template_parameters(vm, "vmname", key_user, "size"))
vm <- ubuntu_dsvm()
expect_is(vm, "vm_config")
expect_true(vm$image$publisher == "microsoft-dsvm" &&
vm$image$offer == "linux-data-science-vm-ubuntu" &&
vm$image$sku == "linuxdsvmubuntu")
expect_silent(build_template_definition(vm))
expect_silent(build_template_parameters(vm, "vmname", key_user, "size"))
vm <- windows_dsvm()
expect_is(vm, "vm_config")
expect_true(vm$image$publisher == "microsoft-dsvm" &&
vm$image$offer == "dsvm-windows" &&
vm$image$sku == "server-2016")
expect_silent(build_template_definition(vm))
expect_silent(build_template_parameters(vm, "vmname", pwd_user, "size"))
})
test_that("VM scaleset config works",
{
key_user <- user_config("username", ssh="random key")
pwd_user <- user_config("username", password="random password")
img <- image_config(publisher="pubname", offer="offname", sku="skuname")
vm <- vmss_config(img, keylogin=TRUE)
expect_is(vm, "vmss_config")
expect_silent(build_template_definition(vm))
expect_silent(build_template_parameters(vm, "vmname", key_user, "size", 5))
vm <- ubuntu_18.04_ss()
expect_is(vm, "vmss_config")
expect_true(vm$image$publisher == "Canonical" &&
vm$image$offer == "UbuntuServer" &&
vm$image$sku == "18.04-LTS")
expect_silent(build_template_definition(vm))
expect_silent(build_template_parameters(vm, "vmname", key_user, "size", 5))
vm <- ubuntu_16.04_ss()
expect_is(vm, "vmss_config")
expect_true(vm$image$publisher == "Canonical" &&
vm$image$offer == "UbuntuServer" &&
vm$image$sku == "16.04-LTS")
expect_silent(build_template_definition(vm))
expect_silent(build_template_parameters(vm, "vmname", key_user, "size", 5))
vm <- windows_2019_ss()
expect_is(vm, "vmss_config")
expect_true(vm$image$publisher == "MicrosoftWindowsServer" &&
vm$image$offer == "WindowsServer" &&
vm$image$sku == "2019-Datacenter")
expect_silent(build_template_definition(vm))
expect_silent(build_template_parameters(vm, "vmname", pwd_user, "size", 5))
vm <- windows_2016_ss()
expect_is(vm, "vmss_config")
expect_true(vm$image$publisher == "MicrosoftWindowsServer" &&
vm$image$offer == "WindowsServer" &&
vm$image$sku == "2016-Datacenter")
expect_silent(build_template_definition(vm))
expect_silent(build_template_parameters(vm, "vmname", pwd_user, "size", 5))
vm <- rhel_8_ss()
expect_is(vm, "vmss_config")
expect_true(vm$image$publisher == "RedHat" &&
vm$image$offer == "RHEL" &&
vm$image$sku == "8")
expect_silent(build_template_definition(vm))
expect_silent(build_template_parameters(vm, "vmname", key_user, "size", 5))
vm <- rhel_7.6_ss()
expect_is(vm, "vmss_config")
expect_true(vm$image$publisher == "RedHat" &&
vm$image$offer == "RHEL" &&
vm$image$sku == "7-RAW")
expect_silent(build_template_definition(vm))
expect_silent(build_template_parameters(vm, "vmname", key_user, "size", 5))
vm <- debian_9_backports_ss()
expect_is(vm, "vmss_config")
expect_true(vm$image$publisher == "Credativ" &&
vm$image$offer == "Debian" &&
vm$image$sku == "9-backports")
expect_silent(build_template_definition(vm))
expect_silent(build_template_parameters(vm, "vmname", key_user, "size", 5))
vm <- ubuntu_dsvm_ss()
expect_is(vm, "vmss_config")
expect_true(vm$image$publisher == "microsoft-dsvm" &&
vm$image$offer == "linux-data-science-vm-ubuntu" &&
vm$image$sku == "linuxdsvmubuntu")
expect_silent(build_template_definition(vm))
expect_silent(build_template_parameters(vm, "vmname", key_user, "size", 5))
vm <- windows_dsvm_ss()
expect_is(vm, "vmss_config")
expect_true(vm$image$publisher == "microsoft-dsvm" &&
vm$image$offer == "dsvm-windows" &&
vm$image$sku == "server-2016")
expect_silent(build_template_definition(vm))
expect_silent(build_template_parameters(vm, "vmname", pwd_user, "size", 5))
})

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

@ -0,0 +1,57 @@
context("VM interface")
tenant <- Sys.getenv("AZ_TEST_TENANT_ID")
app <- Sys.getenv("AZ_TEST_APP_ID")
password <- Sys.getenv("AZ_TEST_PASSWORD")
subscription <- Sys.getenv("AZ_TEST_SUBSCRIPTION")
if(tenant == "" || app == "" || password == "" || subscription == "")
skip("Tests skipped: ARM credentials not set")
vm_name <- paste0("vm", paste0(sample(letters, 10, TRUE), collapse=""))
location <- "australiaeast"
rg <- AzureRMR::az_rm$
new(tenant=tenant, app=app, password=password)$
get_subscription(subscription)$
create_resource_group(vm_name, location)
test_that("VM creation works",
{
vm <- rg$create_vm(vm_name, user_config("username", "../resources/testkey.pub"), "Standard_DS1_v2")
expect_is(vm, "az_vm_template")
})
test_that("VM interaction works",
{
vm <- rg$get_vm(vm_name)
expect_is(vm, "az_vm_template")
expect_silent(vm$run_script("ls /tmp"))
vm$stop(deallocate=FALSE, wait=TRUE)
status <- vm$sync_vm_status()
expect_true(status["PowerState"] == "stopped")
vm$resize("Standard_DS2_v2", wait=TRUE)
expect_true(vm$.__enclos_env__$private$vm$properties$hardwareProfile == "Standard_DS2_v2")
vm$start(wait=TRUE)
status <- vm$sync_vm_status()
expect_true(status["PowerState"] == "running")
expect_is(vm$get_public_ip_address(), "character")
expect_is(vm$get_private_ip_address(), "character")
})
test_that("VM deletion works",
{
vm <- rg$get_vm(vm_name)
vm$delete(confirm=FALSE)
Sys.sleep(10)
expect_true(is_empty(rg$list_resources()))
})
rg$delete(confirm=FALSE)

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

@ -0,0 +1,46 @@
context("VM scaleset interface")
tenant <- Sys.getenv("AZ_TEST_TENANT_ID")
app <- Sys.getenv("AZ_TEST_APP_ID")
password <- Sys.getenv("AZ_TEST_PASSWORD")
subscription <- Sys.getenv("AZ_TEST_SUBSCRIPTION")
if(tenant == "" || app == "" || password == "" || subscription == "")
skip("Tests skipped: ARM credentials not set")
vmss_name <- paste0("vmss", paste0(sample(letters, 10, TRUE), collapse=""))
location <- "australiaeast"
rg <- AzureRMR::az_rm$
new(tenant=tenant, app=app, password=password)$
get_subscription(subscription)$
create_resource_group(vmss_name, location)
test_that("Scaleset creation works",
{
vm <- rg$create_vm_scaleset(vmss_name, user_config("username", "../resources/testkey.pub"), instances=2)
expect_is(vm, "az_vmss_template")
})
test_that("Scaleset interaction works",
{
vm <- rg$get_vm_scaleset(vmss_name)
expect_is(vm, "az_vmss_template")
expect_silent(vm$run_script("ls /tmp"))
expect_is(vm$get_vm_private_ip_addresses(), "character")
expect_is(vm$get_vm_public_ip_addresses(), "character")
expect_is(vm$get_public_ip_address(), "character")
})
test_that("Scaleset deletion works",
{
vm <- rg$get_vm_scaleset(vmss_name)
vm$delete(confirm=FALSE)
Sys.sleep(10)
expect_true(is_empty(rg$list_resources()))
})
rg$delete(confirm=FALSE)

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

@ -8,157 +8,164 @@ vignette: >
%\VignetteEncoding{utf8} %\VignetteEncoding{utf8}
--- ---
This is a short introduction on how to use AzureVM. AzureVM is a package for interacting with virtual machines and virtual machine scalesets in Azure. You can deploy, start up, shut down, run scripts, deallocate and delete VMs and scalesets from the R command line. It uses the tools provided by the [AzureRMR package](https://github.com/Azure/AzureRMR) to manage VM resources and templates.
## Virtual machines
## Creating a VM Here is a simple example. We create a VM using the default settings, run a shell command, and then delete the VM.
Creating a VM is as simple as using the `create_vm` method, which is available as part of the `az_subscription` and `az_resource_group` classes. ```r
library(AzureVM)
```{r, eval=FALSE} sub <- AzureRMR::get_azure_login()$
## using the subscription method get_subscription("5710aa44-281f-49fe-bfa6-69e66bb55b11")
sub <- az_rm$
new(tenant="{tenant_id}", app="{app_id}", password="{password}")$
get_subscription("{subscription_id}")
myNewVM <- sub$create_vm("myNewVM", # calling create_vm() from a subscription object will create the VM in its own resource group
location="australiaeast", # default is an Ubuntu 18.04 VM, size Standard_DS3_v2, login via SSH key
username="datascience", # call sub$list_vm_sizes() to get the sizes available in your region
passkey="fAs30q-2a5vF!Z") # be sure to choose a strong password! vm <- sub$create_vm("myubuntuvm", user_config("myname", "~/.ssh/id_rsa.pub"),
location="australiaeast")
# run a shell script or command remotely (will be PowerShell on a Windows VM)
vm$run_script("ifconfig > /tmp/ifc.txt")
## using the resource group method # ... and stop it
rg <- sub$create_resource_group("myresourcegroup", vm$stop()
location="australiaeast")
myOtherVM <- rg$create_vm("myOtherVM", # ... and resize it
username="datascience", vm$resize("Standard_DS4_v2")
passkey="l3Kgrf21%?0DFm")
```
Without any other options, this will create a Windows Server 2016 [Data Science Virtual Machine](https://docs.microsoft.com/en-us/azure/machine-learning/data-science-virtual-machine/overview#whats-included-in-the-data-science-vm), which is pre-installed with several tools useful for analytics: Python, R (and RStudio), Tensorflow, XGBoost, SQL Server, and so on. The size will be a Standard DS3 V2 VM, which has 4 cores, 14GB of memory, 1TB primary disk, and up to 16x28GB data disks. # ... and delete it (this can be done asynchronously for a VM in its own group)
A feature of using the `az_subscription` method is that it creates a new resource group specifically to hold the VM. This simplifies the task of managing and (eventually) deleting the VM considerably. See "Deleting a VM" below.
You can change the specifications for the VM by providing any of the following arguments:
- `os`: either "Windows" or "Ubuntu" (for Ubuntu LTS 16.04).
- `size`: the VM size. Use the `az_subscription$list_vm_sizes()` method to see what sizes are available in your region. Note that in Azure, a VM's size is really a broad-ranging label that encapsulates the number of cores, memory, and disk available.
- `passkey`: if creating an Ubuntu VM, you can supply a public key as the `passkey` argument.
- `userauth_type`: set this to "key" if you supply a public key.
Setting these will determine whether you get a Windows or Ubuntu DSVM, the login details, and how powerful the VM is in terms of cores and memory/disk capacity.
```{r, eval=FALSE}
# examine VM sizes available in australiaeast region
sub$list_vm_sizes("australiaeast")
# create a Linux (Ubuntu) NC-series DSVM using public key authentication
myLinuxVM <- sub$create_vm("myLinuxVM",
location="australiaeast",
size="Standard_NC6s_v3",
os="Ubuntu",
username="datascience",
passkey=readLines("~/id_rsa.pub"),
userauth_type="key")
```
## Retrieving an existing VM
If you have an existing VM, you can retrieve it with the `get_vm()` method. As with `create_vm()`, this is available as part of the `az_subscription` and `az_resource_group` classes. The only argument you need to supply is the name of the VM.
```{r, eval=FALSE}
## using the subscription method
sub <- az_rm$
new(tenant="{tenant_id}", app="{app_id}", password="{password}")$
get_subscription("{subscription_id}")
# retrieve the VM we created above
myNewVM <- sub$get_vm("myNewVM")
## and with the resource group method
rg <- sub$get_resource_group("myresourcegroup")
myOtherVM <- rg$get_vm("myOtherVM")
```
## Working with a VM
There are various things you can do with a VM object.
To stop (shutdown) a VM, call its `stop()` method. The `deallocate` argument sets whether to deallocate its resources as well, with the default being TRUE; you may want to set this to FALSE if you know you will be restarting the VM soon. To restart it, call either the `start()` or `restart()` method. The main difference between the two is that `restart()` will shutdown the VM first if it is currently running.
To sync the object with the resource in Azure, call the `sync_vm_status()` method. The most common situation where you might want to do this is if you create a VM with the argument `wait=FALSE`. In this case, rather than waiting for provisioning to complete, the `create_vm` method will return an incomplete VM object; you then call its `sync_vm_status()` method to update it with how the provisioning is going in Azure.
To run a script in the VM (without manually logging in first), call the `run_script()` method. This will be a PowerShell script if it is a Windows VM, or a bash script if it is Linux. The script is just a character vector:
```{r, eval=FALSE}
# simple bash script for executing on a Linux VM
script <-
'#!/bin/bash
var=Hello world!
# redirect output to a file so we know whether it ran successfully
echo "$var" > /tmp/helloworld.txt
'
vm$run_script(script)
```
If you login to the VM after running this script, you should find the file `helloworld.txt` in the `/tmp` directory.
## Deleting a VM
Simply deleting a virtual machine object in R, eg with `rm()`, will not do anything to the VM itself in Azure. To delete the VM and its resources, call the object's `delete()` method:
```{r, eval=FALSE}
vm$delete() vm$delete()
``` ```
AzureVM will prompt you for confirmation that you really want to delete the VM. By default, this will also free up all the individual Azure resources used by the VM, such as its storage, network interface, security group, and so on. AzureVM comes with a number of predefined configurations, for deploying commonly used VM images. For example, to create an Ubuntu DSVM accessible via SSH, JupyterHub and RStudio Server:
If you created the VM using the `create_vm()` method of the `az_subscription` class, the deletion process is very simple: it simply removes the resource group containing the VM. This is possible because the resource group was created as part of deploying the VM. Be aware that any other resources you may have created in this resource group will also be deleted. ```r
sub$create_vm("mydsvm", user_config("myname", "~/.ssh/id_rsa.pub"), config="ubuntu_dsvm",
location="australiaeast")
```
And to create a Windows Server 2019 VM, accessible via RDP:
Alternatively, you can use the `delete_vm()` method of the `az_subscription` and `az_resource_group` classes. These will retrieve the VM of the given name and then call its `delete()` method. ```r
sub$create_vm("mywinvm", user_config("myname", password="Use-strong-passwords!"), config="windows_2019",
location="australiaeast")
## Other topics
### GPU enabled VMs
If you are running deep learning workloads, you'll want to ensure that your VM is GPU-enabled. In Azure, the various [NC- and ND-series VMs](https://docs.microsoft.com/en-us/azure/virtual-machines/windows/sizes-gpu) are designed for these workloads. You can create a GPU-enabled VM by setting the `size` argument appropriately, for example
```{r, eval=FALSE}
myGpuVM <- sub$create_vm(size="Standard_NC12s_v3", ...)
``` ```
However, the following caveats apply to GPU-enabled VMs: The available predefined configurations are `ubuntu_18.04` (the default), `ubuntu_16.04`, `ubuntu_dsvm`, `windows_2019`, `windows_2016`, `windows_dsvm`, `rhel_7.6`, `rhel_8` and `debian_9_backports`. You can combine these with several other arguments to customise the VM deployment to your needs:
- Not all regions have GPUs available. To check on availability, use the `az_subscription$list_vm_sizes()` method and provide your region.
- Currently, the supply of GPUs is limited. You must [apply for a quota increase](https://docs.microsoft.com/en-us/azure/azure-supportability/resource-manager-core-quotas-request) if you want to deploy a GPU-enabled VM.
### VM clusters - `size`: VM size. Use the `list_vm_sizes` method for the subscription and resource group classes to see the available sizes.
- `datadisks`: The data disk sizes/configurations to attach.
- `ip`: Public ip address. Set this to NULL if you don't want the VM to be accessible outside its subnet.
- `vnet`: Virtual network/subnet.
- `nsg`: Network security group. AzureVM will associate the NSG with the vnet/subnet, not with the VM's network interface.
- `nic`: Network interface.
- `other_resources`: Optionally, a list of other resources to deploy.
You can work with VM clusters (a collection of VMs sharing the same configuration) by using the `get_vm_cluster`, `create_vm_cluster` and `delete_vm_cluster` methods. These work almost identically to `get_vm`, `create_vm` and `delete_vm` with the addition of a `clust_size` argument that sets the size of the cluster. ```r
# Windows Server 2016, with a 500GB datadisk attached, not publicly accessible
sub$create_vm("mywinvm2", user_config("myname", password="Use-strong-passwords!"),
size="Standard_DS4_v2", config="windows_2016", datadisks=500, ip=NULL,
location="australiaeast")
```{r, eval=FALSE} # Ubuntu DSVM, GPU-enabled
sub <- az_rm$ sub$create_vm("mydsvm", user_config("myname", "~/.ssh/id_rsa.pub"), size="Standard_NC12",
new(tenant="{tenant_id}", app="{app_id}", password="{password}")$ config="ubuntu_dsvm_ss",
get_subscription("{subscription_id}") location="australiaeast")
# create a cluster of 5 Ubuntu VMs # Red Hat VM, serving HTTP/HTTPS
vmCluster <- sub$create_vm_cluster("vmCluster", sub$create_vm("myrhvm", user_config("myname", "~/.ssh/id_rsa.pub"), config="rhel_8",
location="australiaeast", nsg=nsg_config(list(nsg_rule_allow_http, nsg_rule_allow_https)),
os="Ubuntu", location="australiaeast")
username="datascience",
passkey=readLines("~/id_rsa.pub"),
userauth_type="key",
clust_size=5)
``` ```
Most things that you can do with a single VM, you can also do with a VM cluster. For example, running a script with the `run_script()` method will run the script on all the VMs in the cluster. Starting, stopping and restarting a cluster similarly carries out the given action on all the VMs. Full customisation is provided by the `vm_config` function, which also lets you specify the image to deploy, either from the marketplace or a disk. (The predefined configurations actually call `vm_config`, with the appropriate arguments for each specific config.)
```r
## custom VM configuration: Windows 10 Pro 1903 with data disks
## this assumes you have a valid Win10 desktop license
user <- user_config("myname", password="Use-strong-passwords!")
image <- image_config(
publisher="MicrosoftWindowsDesktop",
offer="Windows-10",
sku="19h1-pro"
)
datadisks <- list(
datadisk_config(250, type="Premium_LRS"),
datadisk_config(1000, type="Standard_LRS")
)
nsg <- nsg_config(
list(nsg_rule_allow_rdp)
)
sub$create_vm("mywin10vm", user,
config=vm_config(
image=image,
keylogin=FALSE,
datadisks=datadisks,
nsg=nsg,
properties=list(licenseType="Windows_Client")
),
location="australiaeast"
)
```
## VM scalesets
The equivalent to `create_vm` for scalesets is the `create_vm_scaleset` method. By default, a new scaleset will come with a load balancer and autoscaler attached, but its instances will not be externally accessible.
```r
# default is Ubuntu 18.04 scaleset, size Standard_DS1_v2
sub$create_vm_scaleset("myubuntuss", user_config("myname", "~/.ssh/id_rsa.pub"), instances=5,
location="australiaeast")
```
Each predefined VM configuration has a corresponding scaleset configuration. To specify low-level scaleset settings, use the `scaleset_options` argument. Here are some sample scaleset deployments:
```r
# Windows Server 2019
sub$create_vm_scaleset("mywinss", user_config("myname", password="Use-strong-passwords!"), instances=5,
config="windows_2019",
location="australiaeast")
# RHEL scaleset, serving HTTP/HTTPS
sub$create_vm_scaleset("myrhelss", user_config("myname", "~/.ssh/id_rsa.pub"), instances=5,
config="rhel_8_ss",
nsg=nsg_config(list(nsg_rule_allow_http, nsg_rule_allow_https)),
location="australiaeast")
# Ubuntu DSVM, GPU-enabled, public instances, no load balancer or autoscaler
sub$create_vm_scaleset("mydsvmss", user_config("myname", "~/.ssh/id_rsa.pub"), instances=5,
size="Standard_NC6", config="ubuntu_dsvm_ss",
options=scaleset_options(public=TRUE),
load_balancer=NULL, autoscaler=NULL,
location="australiaeast")
# Large Debian scaleset (multiple placement groups), using low-priority VMs
# need to set the instance size to something that supports low-pri
sub$create_vm_scaleset("mydebss", user_config("myname", "~/.ssh/id_rsa.pub"), instances=10,
size="Standard_DS3_v2", config="debian_9_backports_ss",
options=scaleset_options(low_priority=TRUE, large_scaleset=TRUE),
location="australiaeast")
```
## Sharing resources
You can also include an existing Azure resource in a deployment, by supplying an AzureRMR `az_resource` object as an argument in the `create_vm` or `create_vm_scaleset` call. For example, here we create a VM and a scaleset that share a single virtual network/subnet.
```r
## VM and scaleset in the same resource group and virtual network
# first, create the resgroup
rg <- sub$create_resource_group("rgname", "australiaeast")
# create the master
rg$create_vm("mastervm", user_config("myname", "~/.ssh/id_rsa.pub"))
# get the vnet resource
vnet <- rg$get_resource(type="Microsoft.Network/virtualNetworks", name="mastervm-vnet")
# create the scaleset
# since the NSG is associated with the vnet, we don't need to create a new NSG either
rg$create_vm_scaleset("slavess", user_config("myname", "~/.ssh/id_rsa.pub"),
instances=5, vnet=vnet, nsg=NULL, load_balancer=NULL, autoscaler=NULL)
```