diff --git a/DESCRIPTION b/DESCRIPTION index 036bafc..05fbf56 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -23,7 +23,11 @@ Imports: jsonlite, XML, base64enc, - digest + digest, + shiny (>= 0.13), + miniUI (>= 0.1.1), + rstudioapi (>= 0.5), + DT Depends: R(>= 3.0.0) Suggests: diff --git a/NAMESPACE b/NAMESPACE index b5c4d85..c553922 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -24,6 +24,7 @@ export(azureDeleteVM) export(azureDeletestorageAccount) export(azureDeployStatus) export(azureDeployTemplate) +export(azureGetAllVMstatus) export(azureGetBlob) export(azureHDIConf) export(azureHiveSQL) @@ -57,7 +58,10 @@ export(azureVMStatus) export(createAzureContext) export(dumpAzureContext) export(is.azureActiveContext) +export(read.AzureSMR.config) export(setAzureContext) +importFrom(DT,dataTableOutput) +importFrom(DT,renderDataTable) importFrom(XML,htmlParse) importFrom(XML,xmlValue) importFrom(XML,xpathApply) @@ -78,6 +82,12 @@ importFrom(httr,headers) importFrom(httr,http_status) importFrom(httr,status_code) importFrom(jsonlite,fromJSON) +importFrom(miniUI,gadgetTitleBar) +importFrom(miniUI,miniContentPanel) +importFrom(miniUI,miniPage) +importFrom(shiny,observeEvent) +importFrom(shiny,paneViewer) +importFrom(shiny,runGadget) importFrom(utils,URLencode) importFrom(utils,browseURL) importFrom(utils,ls.str) diff --git a/R/AzureContextObject.R b/R/AzureContextObject.R index 781e5a7..7ebb732 100644 --- a/R/AzureContextObject.R +++ b/R/AzureContextObject.R @@ -7,19 +7,30 @@ #' @inheritParams setAzureContext #' @family azureActiveContext functions #' -#' @seealso [setAzureContext()], [azureAuthenticate()] +#' @seealso [setAzureContext()], [azureAuthenticate()], [read.AzureSMR.config)] #' @return An `azureActiveContext` object #' @export -createAzureContext <- function(tenantID, clientID, authKey){ +createAzureContext <- function(tenantID, clientID, authKey, configFile){ azEnv <- new.env(parent = emptyenv()) azEnv <- as.azureActiveContext(azEnv) - if (!missing(tenantID)) azEnv$tenantID <- tenantID else azEnv$tenantID <- "?" - if (!missing(clientID)) azEnv$clientID <- clientID else azEnv$tenantID <- "?" - if (!missing(authKey)) azEnv$authKey <- authKey else azEnv$tenantID <- "?" + list2env( + list(tenantID = "", clientID = "", authKey = ""), + envir = azEnv + ) + if (!missing(configFile)) { + config <- read.AzureSMR.config(configFile) + list2env(config, envir = azEnv) + azureAuthenticate(azEnv) + } else { + if (!missing(tenantID)) azEnv$tenantID <- tenantID + if (!missing(clientID)) azEnv$clientID <- clientID + if (!missing(authKey)) azEnv$authKey <- authKey + if (!missing(tenantID) && !missing(clientID) && !missing(authKey)) { + azureAuthenticate(azEnv) + } + } - if (!missing(tenantID) && !missing(clientID) && !missing(authKey) ) - azureAuthenticate(azEnv,tenantID, clientID, authKey) return(azEnv) } diff --git a/R/AzureHDI.R b/R/AzureHDI.R index 135a610..0d81d41 100644 --- a/R/AzureHDI.R +++ b/R/AzureHDI.R @@ -457,8 +457,11 @@ azureRunScriptAction <- function(azureActiveContext, scriptname, scriptURL, stopWithAzureError(r) azureActiveContext$clustername <- clustername + azureActiveContext$resourceGroup <- resourceGroup + + message("Accepted") - if (wait) pollStatusScriptAction(azureActiveContext, scriptname = scriptname) + if (wait) pollStatusScriptAction(azureActiveContext, scriptname = scriptname, resourceGroup = resourceGroup) return(TRUE) } @@ -497,7 +500,7 @@ azureScriptActionHistory <- function(azureActiveContext, resourceGroup, r <- GET(URL, azureApiHeaders(azToken), verbosity) stopWithAzureError(r) - rc <- content(r)$value + rc <- content(r, bigint_as_char = TRUE)$value if (length(rc) == 0) { message("No script action history found") } diff --git a/R/AzureStorageAccount.R b/R/AzureStorageAccount.R index 350aa80..2f5a1d4 100644 --- a/R/AzureStorageAccount.R +++ b/R/AzureStorageAccount.R @@ -64,7 +64,6 @@ azureSAGetKey <- function(azureActiveContext, storageAccount, rl <- content(r, "text", encoding = "UTF-8") df <- fromJSON(rl) azureActiveContext$storageAccount <- storageAccount - azureActiveContext$storageAccountK <- storageAccount azureActiveContext$resourceGroup <- resourceGroup azureActiveContext$storageKey <- df$keys$value[1] diff --git a/R/AzureVM.R b/R/AzureVM.R index 679b303..db23527 100644 --- a/R/AzureVM.R +++ b/R/AzureVM.R @@ -50,6 +50,41 @@ azureListVM <- function(azureActiveContext, resourceGroup, location, subscriptio return(dfn) } +#' List the status of every virtual machine in the azure active context. +#' +#' First queries the azure active context for all visible resources, then sequentially queries the status of all virtuam machines. +#' +#' @inheritParams setAzureContext +#' @inheritParams azureListAllResources +#' +#' @family Virtual machine functions +#' @export +azureGetAllVMstatus <- function(azureActiveContext) { + res <- azureListAllResources(azureActiveContext) + vms <- res[res$type == "Microsoft.Compute/virtualMachines",] + n <- nrow(vms) + pb <- txtProgressBar(min = 0, max = n, style = 3) + on.exit(close(pb)) + z <- lapply(seq_len(n), function(i) { + setTxtProgressBar(pb, i) + z <- tryCatch(azureVMStatus(azureActiveContext, + resourceGroup = vms$resourceGroup[i], + vmName = vms$name[i], + subscriptionID = vms$subscriptionID[i] + ), error = function(e) e) + z <- if (inherits(z, "error")) NA_character_ else z + data.frame( + name = vms$name[i], + resourceGroup = vms$resourceGroup[i], + subscriptionID = vms$subscriptionID[i], + provisioning = gsub("Provisioning (.*?), .*$", "\\1", z), + status = gsub(".*?, VM (.*)$", "\\1", z) + ) + }) + do.call(rbind, z) +} + + #' Start a Virtual Machine. #' diff --git a/R/addins.R b/R/addins.R new file mode 100644 index 0000000..0cc7467 --- /dev/null +++ b/R/addins.R @@ -0,0 +1,45 @@ +# this is a template to view a DT object +# @param data.frame +# @param title Text to display in pane title + +#' @importFrom miniUI miniPage gadgetTitleBar miniContentPanel +#' @importFrom DT dataTableOutput renderDataTable +#' @importFrom shiny observeEvent paneViewer runGadget +dataTableViewer <- function(x, title = "") { + + ui <- miniPage( + gadgetTitleBar(title), + miniContentPanel( + DT::dataTableOutput("dt", height = "100%") + ) + ) + + server <- function(input, output, session) { + output$dt <- DT::renderDataTable(x) + + observeEvent(input$done, stopApp()) + } + + viewer <- paneViewer() + runGadget(ui, server, viewer = viewer) + +} + + +addinListAllResources <- function() { + settingsfile <- getOption("AzureSMR.config") + assert_that(file.exists(settingsfile)) + az <- createAzureContext(configFile = settingsfile) + z <- azureListAllResources(az) + z$id <- NULL + dataTableViewer(z, title = "All resources") +} + +addinGetAllVMstatus <- function() { + settingsfile <- getOption("AzureSMR.config") + assert_that(file.exists(settingsfile)) + az <- createAzureContext(configFile = settingsfile) + z <- azureGetAllVMstatus(az) + z$id <- NULL + dataTableViewer(z, title = "All virtual machines") +} \ No newline at end of file diff --git a/R/config.R b/R/config.R index 84393db..c7ef918 100644 --- a/R/config.R +++ b/R/config.R @@ -1,14 +1,17 @@ -# Reads settings from configuration file in JSON format. +#' Reads settings from configuration file in JSON format. +#' +#' @param config location of file that contains configuration in JSON format +#' @export # -# @param config location of file that contains configuration in JSON format -# -read.AzureSMR.config <- function(config = getOption("AzureSMR.config")){ - z <- tryCatch(fromJSON(file(config)), +read.AzureSMR.config <- function(configFile = getOption("AzureSMR.config")) { + assert_that(is.character(configFile)) + assert_that(file.exists(configFile)) + z <- tryCatch(fromJSON(file(configFile)), error = function(e)e ) # Error check the settings file for invalid JSON if(inherits(z, "error")) { - msg <- sprintf("Your config file contains invalid json", config) + msg <- sprintf("Your config file contains invalid json", configFile) msg <- paste(msg, z$message, sep = "\n\n") stop(msg, call. = FALSE) } diff --git a/R/internal.R b/R/internal.R index 737f679..aacc788 100644 --- a/R/internal.R +++ b/R/internal.R @@ -161,9 +161,8 @@ extractStorageAccount <- function(x) gsub(".*?/storageAccounts/(.*?)(/.*)*$", refreshStorageKey <- function(azureActiveContext, storageAccount, resourceGroup){ - if (length(azureActiveContext$storageAccountK) < 1 || - storageAccount != azureActiveContext$storageAccountK || - length(azureActiveContext$storageKey) <1 + if (storageAccount != azureActiveContext$storageAccount || + length(azureActiveContext$storageKey) == 0 ) { message("Fetching Storage Key..") azureSAGetKey(azureActiveContext, resourceGroup = resourceGroup, storageAccount = storageAccount) diff --git a/R/pollStatus.R b/R/pollStatus.R index b83390c..94691a8 100644 --- a/R/pollStatus.R +++ b/R/pollStatus.R @@ -126,7 +126,7 @@ pollStatusHDI <- function(azureActiveContext, clustername) { } -pollStatusScriptAction <- function(azureActiveContext, scriptname) { +pollStatusScriptAction <- function(azureActiveContext, scriptname, resourceGroup) { message("Script action request submitted: ", Sys.time()) message("Key: A - accepted, (.) - in progress, S - succeeded, E - error, F - failed") @@ -134,7 +134,8 @@ pollStatusScriptAction <- function(azureActiveContext, scriptname) { waiting <- TRUE while (iteration < 500 && waiting) { - status <- azureScriptActionHistory(azureActiveContext) + status <- azureScriptActionHistory(azureActiveContext, + resourceGroup = resourceGroup) idx <- which(sapply(status, "[[", "name") == scriptname)[1] summary <- status[[idx]]$status rc <- switch(tolower(summary), diff --git a/R/zzz.R b/R/zzz.R index eb637cd..6c8ef31 100644 --- a/R/zzz.R +++ b/R/zzz.R @@ -1,5 +1,6 @@ -AzureSMR.config.default <- "~/.azureml/settings.json" +AzureSMR.config.default <- "~/.azuresmr/config.json" -.onAttach <- function(libname, pkgname){ +.onAttach <- function(libname, pkgname) { + if (is.null(getOption("AzureSMR.config"))) options(AzureSMR.config = AzureSMR.config.default) } diff --git a/inst/examples/example_azureCreateHDI.R b/inst/examples/example_azureCreateHDI.R index 12fd4fe..b198932 100644 --- a/inst/examples/example_azureCreateHDI.R +++ b/inst/examples/example_azureCreateHDI.R @@ -1,16 +1,12 @@ \dontrun{ -library(AzureSMR) - - azureCreateHDI(context, - resourceGroup = RG, +azureCreateHDI(context, + resourceGroup = RG, clustername = "smrhdi", # only low case letters, digit, and dash. storageAccount = "smrhdisa", - adminUser = "hdiadmin", + adminUser = "hdiadmin", adminPassword = "AzureSMR_password123", - sshUser = "hdisshuser", + sshUser = "hdisshuser", sshPassword = "AzureSMR_password123", # need at least digits. - kind = "rserver", - debug = FALSE + kind = "rserver" ) - -} +} \ No newline at end of file diff --git a/inst/rstudio/addins.dcf b/inst/rstudio/addins.dcf new file mode 100644 index 0000000..442dce5 --- /dev/null +++ b/inst/rstudio/addins.dcf @@ -0,0 +1,9 @@ +Name: Azure-resources +Description: List all Azure resources. +Binding: addinListAllResources +Interactive: true + +Name: Azure-VM status +Description: List the status of all virtual machines. +Binding: addinGetAllVMstatus +Interactive: true diff --git a/man/azureDeleteVM.Rd b/man/azureDeleteVM.Rd index 5dc45fa..58985a8 100644 --- a/man/azureDeleteVM.Rd +++ b/man/azureDeleteVM.Rd @@ -24,7 +24,8 @@ azureDeleteVM(azureActiveContext, resourceGroup, vmName, subscriptionID, Delete a Virtual Machine. } \seealso{ -Other Virtual machine functions: \code{\link{azureListScaleSetNetwork}}, +Other Virtual machine functions: \code{\link{azureGetAllVMstatus}}, + \code{\link{azureListScaleSetNetwork}}, \code{\link{azureListScaleSetVM}}, \code{\link{azureListScaleSets}}, \code{\link{azureListVM}}, \code{\link{azureStartVM}}, diff --git a/man/azureGetAllVMstatus.Rd b/man/azureGetAllVMstatus.Rd new file mode 100644 index 0000000..6527fb6 --- /dev/null +++ b/man/azureGetAllVMstatus.Rd @@ -0,0 +1,22 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/AzureVM.R +\name{azureGetAllVMstatus} +\alias{azureGetAllVMstatus} +\title{List the status of every virtual machine in the azure active context.} +\usage{ +azureGetAllVMstatus(azureActiveContext) +} +\arguments{ +\item{azureActiveContext}{A container used for caching variables used by \code{AzureSMR}} +} +\description{ +First queries the azure active context for all visible resources, then sequentially queries the status of all virtuam machines. +} +\seealso{ +Other Virtual machine functions: \code{\link{azureDeleteVM}}, + \code{\link{azureListScaleSetNetwork}}, + \code{\link{azureListScaleSetVM}}, + \code{\link{azureListScaleSets}}, + \code{\link{azureListVM}}, \code{\link{azureStartVM}}, + \code{\link{azureStopVM}}, \code{\link{azureVMStatus}} +} diff --git a/man/azureListScaleSetNetwork.Rd b/man/azureListScaleSetNetwork.Rd index eceb7c5..8791fde 100644 --- a/man/azureListScaleSetNetwork.Rd +++ b/man/azureListScaleSetNetwork.Rd @@ -26,6 +26,7 @@ https://docs.microsoft.com/en-us/rest/api/network/loadbalancer/list-load-balance } \seealso{ Other Virtual machine functions: \code{\link{azureDeleteVM}}, + \code{\link{azureGetAllVMstatus}}, \code{\link{azureListScaleSetVM}}, \code{\link{azureListScaleSets}}, \code{\link{azureListVM}}, \code{\link{azureStartVM}}, diff --git a/man/azureListScaleSetVM.Rd b/man/azureListScaleSetVM.Rd index f4547cd..6f4f757 100644 --- a/man/azureListScaleSetVM.Rd +++ b/man/azureListScaleSetVM.Rd @@ -25,6 +25,7 @@ List VMs within a scale set } \seealso{ Other Virtual machine functions: \code{\link{azureDeleteVM}}, + \code{\link{azureGetAllVMstatus}}, \code{\link{azureListScaleSetNetwork}}, \code{\link{azureListScaleSets}}, \code{\link{azureListVM}}, \code{\link{azureStartVM}}, diff --git a/man/azureListScaleSets.Rd b/man/azureListScaleSets.Rd index 5439ad2..08021e0 100644 --- a/man/azureListScaleSets.Rd +++ b/man/azureListScaleSets.Rd @@ -23,6 +23,7 @@ List scale sets within a resource group. } \seealso{ Other Virtual machine functions: \code{\link{azureDeleteVM}}, + \code{\link{azureGetAllVMstatus}}, \code{\link{azureListScaleSetNetwork}}, \code{\link{azureListScaleSetVM}}, \code{\link{azureListVM}}, \code{\link{azureStartVM}}, diff --git a/man/azureListVM.Rd b/man/azureListVM.Rd index f83f423..692534a 100644 --- a/man/azureListVM.Rd +++ b/man/azureListVM.Rd @@ -23,6 +23,7 @@ List VMs in a Subscription. } \seealso{ Other Virtual machine functions: \code{\link{azureDeleteVM}}, + \code{\link{azureGetAllVMstatus}}, \code{\link{azureListScaleSetNetwork}}, \code{\link{azureListScaleSetVM}}, \code{\link{azureListScaleSets}}, diff --git a/man/azureStartVM.Rd b/man/azureStartVM.Rd index b727fcd..19a72b8 100644 --- a/man/azureStartVM.Rd +++ b/man/azureStartVM.Rd @@ -25,6 +25,7 @@ Start a Virtual Machine. } \seealso{ Other Virtual machine functions: \code{\link{azureDeleteVM}}, + \code{\link{azureGetAllVMstatus}}, \code{\link{azureListScaleSetNetwork}}, \code{\link{azureListScaleSetVM}}, \code{\link{azureListScaleSets}}, diff --git a/man/azureStopVM.Rd b/man/azureStopVM.Rd index 0a82112..78885ce 100644 --- a/man/azureStopVM.Rd +++ b/man/azureStopVM.Rd @@ -25,6 +25,7 @@ Stop a Virtual Machine. } \seealso{ Other Virtual machine functions: \code{\link{azureDeleteVM}}, + \code{\link{azureGetAllVMstatus}}, \code{\link{azureListScaleSetNetwork}}, \code{\link{azureListScaleSetVM}}, \code{\link{azureListScaleSets}}, diff --git a/man/azureVMStatus.Rd b/man/azureVMStatus.Rd index b2da4f4..aa55c7a 100644 --- a/man/azureVMStatus.Rd +++ b/man/azureVMStatus.Rd @@ -25,6 +25,7 @@ Get Status of a Virtual Machine. } \seealso{ Other Virtual machine functions: \code{\link{azureDeleteVM}}, + \code{\link{azureGetAllVMstatus}}, \code{\link{azureListScaleSetNetwork}}, \code{\link{azureListScaleSetVM}}, \code{\link{azureListScaleSets}}, diff --git a/man/createAzureContext.Rd b/man/createAzureContext.Rd index 7d90d4f..c124465 100644 --- a/man/createAzureContext.Rd +++ b/man/createAzureContext.Rd @@ -4,7 +4,7 @@ \alias{createAzureContext} \title{Create an Azure Context.} \usage{ -createAzureContext(tenantID, clientID, authKey) +createAzureContext(tenantID, clientID, authKey, configFile) } \arguments{ \item{tenantID}{The Tenant ID provided during creation of the Active Directory application / service principal} @@ -23,7 +23,9 @@ Create a container (\code{azureActiveContext}) for holding variables used by the See the Azure documentation (\url{https://azure.microsoft.com/en-us/documentation/articles/resource-group-create-service-principal-portal/}) for information to configure an Active Directory application. } \seealso{ -\code{\link[=setAzureContext]{setAzureContext()}}, \code{\link[=azureAuthenticate]{azureAuthenticate()}} +\code{\link[=setAzureContext]{setAzureContext()}}, \code{\link[=azureAuthenticate]{azureAuthenticate()}}, [read.AzureSMR.config)] + +[read.AzureSMR.config)]: R:read.AzureSMR.config) Other azureActiveContext functions: \code{\link{setAzureContext}} } diff --git a/man/read.AzureSMR.config.Rd b/man/read.AzureSMR.config.Rd new file mode 100644 index 0000000..e2e07f9 --- /dev/null +++ b/man/read.AzureSMR.config.Rd @@ -0,0 +1,14 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/config.R +\name{read.AzureSMR.config} +\alias{read.AzureSMR.config} +\title{Reads settings from configuration file in JSON format.} +\usage{ +read.AzureSMR.config(configFile = getOption("AzureSMR.config")) +} +\arguments{ +\item{config}{location of file that contains configuration in JSON format} +} +\description{ +Reads settings from configuration file in JSON format. +} diff --git a/tests/testthat/test-1-authentication.R b/tests/testthat/test-1-authentication.R index ffa59a7..db729b5 100644 --- a/tests/testthat/test-1-authentication.R +++ b/tests/testthat/test-1-authentication.R @@ -1,8 +1,6 @@ if(interactive()) library("testthat") - settingsfile <- system.file("tests/testthat/config.json", package = "AzureSMR") -config <- read.AzureSMR.config(settingsfile) # ------------------------------------------------------------------------ @@ -12,24 +10,28 @@ context("Authenticate") test_that("Can authenticate to Azure Service Manager API", { skip_if_missing_config(settingsfile) + config <- read.AzureSMR.config(settingsfile) asc <- createAzureContext() expect_is(asc, "azureActiveContext") with(config, - setAzureContext(asc, tenantID = tenantID, clientID = clientID, authKey = authKey) + setAzureContext(asc, + tenantID = tenantID, + clientID = clientID, + authKey = authKey) ) expect_true(azureAuthenticate(asc)) -}) + asc <- createAzureContext(configFile = settingsfile) + expect_is(asc, "azureActiveContext") -asc <- createAzureContext() -with(config, - setAzureContext(asc, tenantID = tenantID, clientID = clientID, authKey = authKey) -) -azureAuthenticate(asc, verbose = FALSE) +}) + +asc <- createAzureContext(configFile = settingsfile) + test_that("Can connect to workspace with config file", { skip_if_missing_config(settingsfile) diff --git a/tests/testthat/test-5-HDI.R b/tests/testthat/test-5-HDI.R index 9bd9271..425fb81 100644 --- a/tests/testthat/test-5-HDI.R +++ b/tests/testthat/test-5-HDI.R @@ -1,19 +1,12 @@ if (interactive()) library("testthat") settingsfile <- system.file("tests/testthat/config.json", package = "AzureSMR") -config <- read.AzureSMR.config(settingsfile) # ------------------------------------------------------------------------ context("HDI") -asc <- createAzureContext() -with(config, - setAzureContext(asc, tenantID = tenantID, clientID = clientID, authKey = authKey) -) - - -azureAuthenticate(asc, verbose = FALSE) +asc <- createAzureContext(configFile = settingsfile) timestamp <- format(Sys.time(), format = "%y%m%d%H%M") resourceGroup_name <- paste0("_AzureSMtest_", timestamp) @@ -139,7 +132,8 @@ test_that("can run action scripts", { scriptname = "installPackages", scriptURL = "http://mrsactionscripts.blob.core.windows.net/rpackages-v01/InstallRPackages.sh", workerNode = TRUE, edgeNode = TRUE, - parameters = "useCRAN stringr") + parameters = "useCRAN stringr" + ) ) # retrieve action script history diff --git a/tests/testthat/test-6-ARM.R b/tests/testthat/test-6-ARM.R index 88a760d..97ab4d7 100644 --- a/tests/testthat/test-6-ARM.R +++ b/tests/testthat/test-6-ARM.R @@ -65,12 +65,13 @@ templateJSON1 <- ' } ' -paramJSON2 <- ' -"parameters" : { - "vmssName": {"value": "azuresmrvmss"}, - "instanceCount": {"value": 2}, - "adminUsername": {"value": "ubuntu"}, - "adminPassword": {"value": "Password123"} +paramJSON2 <- '"parameters": { + "vnetName": {"value": "VNet1"}, + "vnetAddressPrefix": {"value": "10.0.0.0/16"}, + "subnet1Name": {"value": "Subnet1"}, + "subnet1Prefix": {"value": "10.0.0.0/24"}, + "subnet2Name": {"value": "Subnet2"}, + "subnet2Prefix": {"value": "10.0.1.0/24"} }' context(" - deploy 1") @@ -86,8 +87,9 @@ test_that("Can create resource from json", { context(" - deploy 2") test_that("Can create resource from URL", { - tempURL = "https://raw.githubusercontent.com/Azure/azure-quickstart-templates/master/201-vmss-linux-jumpbox/azuredeploy.json" - res <- azureDeployTemplate(asc, deplname = "Deploy2", + #tempURL = "https://raw.githubusercontent.com/Azure/azure-quickstart-templates/master/201-vmss-linux-jumpbox/azuredeploy.json" + tempURL <- "https://raw.githubusercontent.com/Azure/azure-quickstart-templates/master/101-vnet-two-subnets/azuredeploy.json" + res <- azureDeployTemplate(asc, deplname = "Deploy2", templateURL = tempURL, paramJSON = paramJSON2, resourceGroup = resourceGroup_name,