This commit is contained in:
Hong Ooi 2019-06-19 02:11:40 +10:00
Родитель 0a3c038ca1
Коммит c829497f5b
22 изменённых файлов: 205 добавлений и 62 удалений

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

@ -3,7 +3,7 @@
* 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 scalesets, rather than simplistic arrays of individual VMs. The methods to work with scalesets are named `get_vm_scaleset`, `create_vm_scaleset` and `delete_vm_scaleset`; `get/create/delete_vm_cluster` are now defunct.
* New UI for VM/scaleset creation, with many more ways 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, DSVM).
* Several predefined configurations supplied to allow quick deployment of commonly used images (Ubuntu, Windows Server, RHEL, Debian, Centos, DSVM).
* Allow referring to existing resources in a deployment (eg placing VMs into an existing vnet), by supplying `AzureRMR::az_resource` objects as arguments.
* Clear distinction between a VM deployment template and a resource. `get_vm` and `get_vm_scaleset` will always attempt to retrieve the template; to get the resource, use `get_vm_resource` and `get_vm_scaleset_resource`.
* New VM resource methods: `get_public_ip_address`, `get_private_ip_address`.

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

@ -4,12 +4,17 @@
#' @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 scale_out,scale_in For `autoscaler_profile`, the CPU usage (a fraction between 0 and 1) 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]
#' @examples
#' autoscaler_config()
#' autoscaler_config(list(
#' autoscaler_profile(minsize=2, maxsize=50, scale_out=0.9, scale_in=0.1)
#' ))
#' @export
autoscaler_config <- function(profiles=list(autoscaler_profile()), ...)
{

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

@ -44,21 +44,21 @@
#' sub <- AzureRMR::get_azure_login()$
#' get_subscription("subscription_id")
#'
#' vm <- sub$get_vm("myLinuxDSVM")
#' vm <- sub$get_vm("myvm")
#'
#' vm$identity
#'
#' # start the VM
#' vm$start()
#' vm$get_private_ip_address()
#' vm$get_public_ip_address()
#'
#' # run a shell command
#' vm$run_script("ifconfig > /tmp/ifc.out")
#' vm$run_script("echo hello world! > /tmp/hello.txt")
#'
#' # stop (and deallocate) the VM
#' vm$stop()
#' vm$get_private_ip_address()
#' vm$get_public_ip_address() # NA, assuming VM has a dynamic IP address
#'
#' # resize the VM
#' vm$resize("Standard_DS13_v2")
#'
#' # get the VM status
#' vm$sync_vm_status()
#'
#' }

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

@ -57,16 +57,20 @@
#'
#' vmss <- sub$get_vm_scaleset("myscaleset")
#'
#' # start the VM
#' vmss$identity
#'
#' vmss$get_public_ip_address() # NA if the scaleset doesn't have a load balancer
#'
#' vmss$start()
#'
#' # run a shell command
#' vmss$run_script("ifconfig > /tmp/ifc.out")
#'
#' # get private IP addresses
#' vmss$get_vm_private_ip_addresses()
#' vmss$get_vm_public_ip_addresses() # NA if scaleset nodes are not publicly visible
#'
#' instances <- vmss$list_instances()
#' first <- instances[1]
#' vmss$run_script("echo hello world! > /tmp/hello.txt", id=first)
#' vmss$stop(id=first)
#' vmss$reimage(id=first)
#'
#' # get the VM status
#' vmss$sync_vmss_status()
#'
#' }

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

@ -8,6 +8,12 @@
#'
#' @seealso
#' [create_vm], [vm_config], [vmss_config]
#' @examples
#' ip_config()
#' ip_config(type="basic", dynamic=TRUE)
#'
#' # if you don't want a domain name associated with the IP address
#' ip_config(domain_name=NULL)
#' @export
ip_config <- function(type=NULL, dynamic=NULL, ipv6=FALSE, domain_name="[parameters('vmName')]", ...)
{

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

@ -16,6 +16,13 @@
#'
#' @seealso
#' [create_vm_scaleset], [vmss_config], [lb_rules] for some predefined load balancing rules and probes
#' @examples
#' lb_config()
#' lb_config(type="basic")
#' lb_config(
#' rules=list(lb_rule_ssh, lb_rule_rdp),
#' probes=list(lb_probe_ssh, lb_probe_rdp)
#' )
#' @export
lb_config <- function(type=NULL, rules=list(), probes=list(), ...)
{

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

@ -9,6 +9,8 @@
#'
#' @seealso
#' [create_vm], [vm_config]
#' @examples
#' nic_config()
#' @export
nic_config <- function(nic_ip=list(nic_ip_config()), ...)
{

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

@ -12,6 +12,21 @@
#'
#' @seealso
#' [create_vm], [vm_config], [vmss_config], [nsg_rules] for some predefined security rules
#' @examples
#' nsg_config()
#' nsg_config(list(nsg_rule_allow_ssh)) # for Linux
#' nsg_config(list(nsg_rule_allow_rdp)) # for Windows
#' nsg_config(list(nsg_rule_allow_http, nsg_rule_allow_https))
#'
#' # a custom rule
#' nsg_config(list(
#' nsg_rule(
#' name="whitelist",
#' source_addr="114.198.100.0/24",
#' access="allow",
#' protocol="*"
#' )
#' ))
#' @export
nsg_config <- function(rules=list(), ...)
{

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

@ -9,6 +9,12 @@
#'
#' @seealso
#' [create_vm], [vm_config], [vmss_config]
#' @examples
#' vnet_config()
#' vnet_config(address_space="10.1.0.0/16")
#' vnet_config(subnets=list(
#' subnet_config("subnet", "10.0.0.0/24")
#' ))
#' @export
vnet_config <- function(address_space="10.0.0.0/16", subnets=list(subnet_config()), ...)
{
@ -17,7 +23,7 @@ vnet_config <- function(address_space="10.0.0.0/16", subnets=list(subnet_config(
ab_block <- sub(ab_regex, "\\1", address_space)
fixaddr <- function(addr)
{
if(sub(ab_regex, "\\1", addr) == ab_block)
if(sub(ab_regex, "\\1", addr) != ab_block)
sub("^[0-9]+\\.[0-9]+", ab_block, addr)
else addr
}

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

@ -4,7 +4,10 @@
![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)
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 is a package for interacting with [virtual machines](https://azure.microsoft.com/services/virtual-machines/) and [virtual machine scalesets](https://azure.microsoft.com/services/virtual-machine-scale-sets/) 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.
Version 2.0 of AzureVM is a complete rewrite of the package, aiming to make it a truly generic and flexible interface to VMs.
## Virtual machines
@ -35,7 +38,7 @@ vm$resize("Standard_DS4_v2")
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:
AzureVM comes with a number of predefined configurations, for deploying commonly used VM images. For example, to create an Ubuntu [Data Science Virtual Machine](https://azure.microsoft.com/services/virtual-machines/data-science-virtual-machines/) accessible via SSH, JupyterHub and RStudio Server:
```r
sub$create_vm("mydsvm", user_config("myname", "~/.ssh/id_rsa.pub"), config="ubuntu_dsvm",

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

@ -20,7 +20,7 @@ autoscaler_profile(name = "Profile", minsize = 1, maxsize = NA,
\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{scale_out, scale_in}{For \code{autoscaler_profile}, the CPU usage (a fraction between 0 and 1) 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.}
@ -29,6 +29,12 @@ autoscaler_profile(name = "Profile", minsize = 1, maxsize = NA,
\description{
Autoscaler configuration
}
\examples{
autoscaler_config()
autoscaler_config(list(
autoscaler_profile(minsize=2, maxsize=50, scale_out=0.9, scale_in=0.1)
))
}
\seealso{
\link{create_vm_scaleset}, \link{vmss_config}
}

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

@ -58,21 +58,21 @@ The following methods are available, in addition to those provided by the \link[
sub <- AzureRMR::get_azure_login()$
get_subscription("subscription_id")
vm <- sub$get_vm("myLinuxDSVM")
vm <- sub$get_vm("myvm")
vm$identity
# start the VM
vm$start()
vm$get_private_ip_address()
vm$get_public_ip_address()
# run a shell command
vm$run_script("ifconfig > /tmp/ifc.out")
vm$run_script("echo hello world! > /tmp/hello.txt")
# stop (and deallocate) the VM
vm$stop()
vm$get_private_ip_address()
vm$get_public_ip_address() # NA, assuming VM has a dynamic IP address
# resize the VM
vm$resize("Standard_DS13_v2")
# get the VM status
vm$sync_vm_status()
}

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

@ -73,16 +73,20 @@ sub <- AzureRMR::get_azure_login()$
vmss <- sub$get_vm_scaleset("myscaleset")
# start the VM
vmss$identity
vmss$get_public_ip_address() # NA if the scaleset doesn't have a load balancer
vmss$start()
# run a shell command
vmss$run_script("ifconfig > /tmp/ifc.out")
# get private IP addresses
vmss$get_vm_private_ip_addresses()
vmss$get_vm_public_ip_addresses() # NA if scaleset nodes are not publicly visible
instances <- vmss$list_instances()
first <- instances[1]
vmss$run_script("echo hello world! > /tmp/hello.txt", id=first)
vmss$stop(id=first)
vmss$reimage(id=first)
# get the VM status
vmss$sync_vmss_status()
}

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

@ -21,6 +21,13 @@ ip_config(type = NULL, dynamic = NULL, ipv6 = FALSE,
\description{
Public IP address configuration
}
\examples{
ip_config()
ip_config(type="basic", dynamic=TRUE)
# if you don't want a domain name associated with the IP address
ip_config(domain_name=NULL)
}
\seealso{
\link{create_vm}, \link{vm_config}, \link{vmss_config}
}

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

@ -43,6 +43,14 @@ lb_rule(name, frontend_port, backend_port = frontend_port,
\description{
Load balancer configuration
}
\examples{
lb_config()
lb_config(type="basic")
lb_config(
rules=list(lb_rule_ssh, lb_rule_rdp),
probes=list(lb_probe_ssh, lb_probe_rdp)
)
}
\seealso{
\link{create_vm_scaleset}, \link{vmss_config}, \link{lb_rules} for some predefined load balancing rules and probes
}

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

@ -27,6 +27,9 @@ nic_ip_config(name = "ipconfig", private_alloc = "dynamic",
\description{
Network interface configuration
}
\examples{
nic_config()
}
\seealso{
\link{create_vm}, \link{vm_config}
}

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

@ -34,6 +34,22 @@ nsg_rule(name, dest_port = "*", dest_addr = "*", dest_asgs = NULL,
\description{
Network security group configuration
}
\examples{
nsg_config()
nsg_config(list(nsg_rule_allow_ssh)) # for Linux
nsg_config(list(nsg_rule_allow_rdp)) # for Windows
nsg_config(list(nsg_rule_allow_http, nsg_rule_allow_https))
# a custom rule
nsg_config(list(
nsg_rule(
name="whitelist",
source_addr="114.198.100.0/24",
access="allow",
protocol="*"
)
))
}
\seealso{
\link{create_vm}, \link{vm_config}, \link{vmss_config}, \link{nsg_rules} for some predefined security rules
}

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

@ -27,6 +27,13 @@ subnet_config(name = "subnet", addresses = "10.0.0.0/16",
\description{
Virtual network configuration
}
\examples{
vnet_config()
vnet_config(address_space="10.1.0.0/16")
vnet_config(subnets=list(
subnet_config("subnet", "10.0.0.0/24")
))
}
\seealso{
\link{create_vm}, \link{vm_config}, \link{vmss_config}
}

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

@ -103,6 +103,16 @@ test_that("Virtual network config works",
)
)
)
vnet <- vnet_config("10.1.0.0/16")
expect_identical(vnet$properties$subnets[[1]]$properties$addressPrefix, "10.1.0.0/16")
vnet <- vnet_config(
address_space="10.1.0.0/16",
subnets=list(subnet_config("mysubnet", addresses="10.0.0.0/24"))
)
expect_identical(vnet$properties$subnets[[1]]$properties$addressPrefix, "10.1.0.0/24")
})
test_that("Network interface config works",

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

@ -1,4 +1,4 @@
context("Custom deployments")
context("Manual deletion")
tenant <- Sys.getenv("AZ_TEST_TENANT_ID")
app <- Sys.getenv("AZ_TEST_APP_ID")
@ -67,28 +67,3 @@ test_that("Custom resource works",
expect_true(is_empty(rg$list_resources()))
})
test_that("Scaleset options work",
{
ssname <- paste0(sample(letters, 10, TRUE), collapse="")
size <- "Standard_DS3_v2"
opts <- scaleset_options(
managed=FALSE,
public=TRUE,
low_priority=TRUE,
delete_on_evict=TRUE,
network_accel=TRUE,
large_scaleset=TRUE,
overprovision=FALSE
)
vmss <- rg$create_vm_scaleset(ssname, user, instances=3, size=size, options=opts)
expect_is(vmss, "az_vmss_template")
expect_is(vmss$get_public_ip_address(), "character")
expect_is(vmss$get_vm_public_ip_addresses(), "character")
expect_is(vmss$get_vm_private_ip_addresses(), "character")
expect_true(is.null(vmss$identity))
})
rg$delete(confirm=FALSE)

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

@ -0,0 +1,55 @@
context("Custom deployments")
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")
rgname <- paste0("vm", paste0(sample(letters, 10, TRUE), collapse=""))
location <- "australiaeast"
user <- user_config("username", "../resources/testkey.pub")
size <- "Standard_DS1_v2"
rg <- AzureRMR::az_rm$
new(tenant=tenant, app=app, password=password)$
get_subscription(subscription)$
create_resource_group(rgname, location)
test_that("Custom vnet works",
{
vmname <- paste0(sample(letters, 10, TRUE), collapse="")
# should detect and fix subnet mismatch
vnet <- vnet_config(address_space="10.1.0.0/16")
vm <- rg$create_vm(vmname, user, size, vnet=vnet)
expect_is(vm, "az_vm_template")
})
test_that("Scaleset options work",
{
ssname <- paste0(sample(letters, 10, TRUE), collapse="")
size <- "Standard_DS3_v2"
opts <- scaleset_options(
managed=FALSE,
public=TRUE,
low_priority=TRUE,
delete_on_evict=TRUE,
network_accel=TRUE,
large_scaleset=TRUE,
overprovision=FALSE
)
vmss <- rg$create_vm_scaleset(ssname, user, instances=3, size=size, options=opts)
expect_is(vmss, "az_vmss_template")
expect_is(vmss$get_public_ip_address(), "character")
expect_is(vmss$get_vm_public_ip_addresses(), "character")
expect_is(vmss$get_vm_private_ip_addresses(), "character")
expect_true(is.null(vmss$identity))
})
rg$delete(confirm=FALSE)

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

@ -24,8 +24,12 @@ test_that("Scaleset connection pool works",
autoscaler=NULL, load_balancer=NULL)
expect_is(vm, "az_vmss_template")
# sometimes deployment will return prematurely
Sys.sleep(5)
inst <- vm$list_instances()
expect_is(inst, "list")
expect_length(inst, 5)
expect_message(vm$run_script("ls /tmp", id=names(inst)[1:2]), "Creating background pool")
expect_true(exists("pool", AzureVM:::.AzureVM) && length(AzureVM:::.AzureVM$pool) == 2)