* vignette tweak

* bump ver no

* tool tests

* pass cmd args as processx::run expects

* update news
This commit is contained in:
Hong Ooi 2020-05-06 03:24:27 +10:00 коммит произвёл GitHub
Родитель c69fd4f087
Коммит b9cbbdd262
9 изменённых файлов: 99 добавлений и 52 удалений

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

@ -1,6 +1,6 @@
Package: AzureContainers
Title: Interface to 'Container Instances', 'Docker Registry' and 'Kubernetes' in 'Azure'
Version: 1.2.1.9000
Version: 1.3.0
Authors@R: c(
person("Hong", "Ooi", , "hongooi@microsoft.com", role = c("aut", "cre")),
person("Bill", "Liang", role = "ctb", comment = "Assistance debugging MMLS on Kubernetes"),

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

@ -1,4 +1,4 @@
# AzureContainers 1.2.1.9000
# AzureContainers 1.3.0
- Significant enhancements for AKS:
- Fully support creating clusters with managed identities. This is recommended and the new default, compared to the older method of using service principals to control cluster resources.
@ -11,6 +11,7 @@
- The functions to call external tools (`call_docker`, `call_docker_compose`, `call_kubernetes` and `call_helm`) now use the value of the system option `azure_containers_tool_echo` to determine whether to echo output to the screen. If this is unset, the fallback is `TRUE` (as in previous versions).
- Remove MMLS vignette; version 9.3.0 is now very old.
- New vignettes on securing an ACI deployment with RestRserve, and deploying a secured service on AKS with Traefik/Let's Encrypt.
- The utility functions `call_docker`, `call_docker_compose`, `call_kubectl` and `call_helm` now accept a vector of individual commandline options as the first argument, which is the format expected by `processx::run`. You can still provide the full commandline as a single string but this is discouraged, as it will likely fail for things like paths containing spaces.
# AzureContainers 1.2.1

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

@ -1,12 +1,14 @@
#' Call the docker commandline tool
#'
#' @param cmd The docker command line to execute.
#' @param cmd The docker command. This should be a _vector_ of individual docker arguments, but can also be a single commandline string. See below.
#' @param echo Whether to echo the output of the command to the console.
#' @param ... Other arguments to pass to [processx::run].
#'
#' @details
#' This function calls the `docker` binary, which must be located in your search path. AzureContainers will search for the binary at package startup, and print a warning if it is not found.
#'
#' The docker command should be specified as a vector of the individual arguments, which is what `processx::run` expects. If a single string is passed, for convenience and back-compatibility reasons `call_docker` will split it into arguments for you. This is prone to error, for example if you are working with pathnames that contain spaces, so it's strongly recommended to pass a vector of arguments as a general practice.
#'
#' @return
#' A list with the following components:
#' - `status`: The exit status of the docker tool. If this is `NA`, then the process was killed and had no exit status.
@ -30,15 +32,18 @@
#' # without any args, prints the docker help screen
#' call_docker()
#'
#' # build an image
#' # build an image: recommended usage
#' call_docker(c("build", "-t", "myimage", ""."))
#'
#' # alternative usage, will be split into individual arguments
#' call_docker("build -t myimage .")
#'
#' # list running containers
#' call_docker("container ls")
#' call_docker(c("container", "ls"))
#'
#' # prune unused containers and images
#' call_docker("container prune -f")
#' call_docker("image prune -f")
#' call_docker(c("container", "prune", "-f"))
#' call_docker(c("image", "prune", "-f"))
#'
#' }
#' @export
@ -46,13 +51,15 @@ call_docker <- function(cmd="", ..., echo=getOption("azure_containers_tool_echo"
{
if(.AzureContainers$docker == "")
stop("docker binary not found", call.=FALSE)
message("Docker operation: ", cmd)
if(length(cmd) == 1 && grepl(" ", cmd, fixed=TRUE))
cmd <- strsplit(cmd, "\\s+")[[1]]
win <- .Platform$OS.type == "windows"
if(!win)
{
dockercmd <- "sudo"
realcmd <- paste(.AzureContainers$docker, cmd)
realcmd <- c(.AzureContainers$docker, cmd)
}
else
{
@ -61,21 +68,23 @@ call_docker <- function(cmd="", ..., echo=getOption("azure_containers_tool_echo"
}
echo <- as.logical(echo)
val <- processx::run(dockercmd, strsplit(realcmd, " ", fixed=TRUE)[[1]], ..., echo=echo)
val$cmdline <- paste("docker", cmd)
val <- processx::run(dockercmd, realcmd, ..., echo=echo)
val$cmdline <- paste("docker", paste(realcmd, collapse=" "))
invisible(val)
}
#' Call the docker-compose commandline tool
#'
#' @param cmd The docker-compose command line to execute.
#' @param cmd The docker-compose command line to execute. This should be a _vector_ of individual docker-compose arguments, but can also be a single commandline string. See below.
#' @param echo Whether to echo the output of the command to the console.
#' @param ... Other arguments to pass to [processx::run].
#'
#' @details
#' This function calls the `docker-compose` binary, which must be located in your search path. AzureContainers will search for the binary at package startup, and print a warning if it is not found.
#'
#' The docker-compose command should be specified as a vector of the individual arguments, which is what `processx::run` expects. If a single string is passed, for convenience and back-compatibility reasons `call_docker_compose` will split it into arguments for you. This is prone to error, for example if you are working with pathnames that contain spaces, so it's strongly recommended to pass a vector of arguments as a general practice.
#'
#' @return
#' A list with the following components:
#' - `status`: The exit status of the docker-compose tool. If this is `NA`, then the process was killed and had no exit status.
@ -97,13 +106,15 @@ call_docker_compose <- function(cmd="", ..., echo=getOption("azure_containers_to
{
if(.AzureContainers$dockercompose == "")
stop("docker-compose binary not found", call.=FALSE)
message("Docker-compose operation: ", cmd)
if(length(cmd) == 1 && grepl(" ", cmd, fixed=TRUE))
cmd <- strsplit(cmd, "\\s+")[[1]]
win <- .Platform$OS.type == "windows"
if(!win)
{
dcmpcmd <- "sudo"
realcmd <- paste(.AzureContainers$dockercompose, cmd)
realcmd <- c(.AzureContainers$dockercompose, cmd)
}
else
{
@ -112,22 +123,24 @@ call_docker_compose <- function(cmd="", ..., echo=getOption("azure_containers_to
}
echo <- as.logical(echo)
val <- processx::run(dcmpcmd, strsplit(realcmd, " ", fixed=TRUE)[[1]], ..., echo=echo)
val$cmdline <- paste("docker-compose", cmd)
val <- processx::run(dcmpcmd, realcmd, ..., echo=echo)
val$cmdline <- paste("docker-compose", paste(realcmd, collapse=" "))
invisible(val)
}
#' Call the Kubernetes commandline tool, kubectl
#'
#' @param cmd The kubectl command line to execute.
#' @param cmd The kubectl command line to execute. This should be a _vector_ of individual kubectl arguments, but can also be a single commandline string. See below.
#' @param echo Whether to echo the output of the command to the console.
#' @param config The pathname of the cluster config file, if required.
#' @param ... Other arguments to pass to [processx::run].
#'
#' @details
#' This function calls the `kubectl` binary, which must be located in your search path. AzureContainers will search for the binary at package startup, and print a warning if it is not found.
#'
#' The kubectl command should be specified as a vector of the individual arguments, which is what `processx::run` expects. If a single string is passed, for convenience and back-compatibility reasons `call_docker_compose` will split it into arguments for you. This is prone to error, for example if you are working with pathnames that contain spaces, so it's strongly recommended to pass a vector of arguments as a general practice.
#'
#' @return
#' A list with the following components:
#' - `status`: The exit status of the kubectl tool. If this is `NA`, then the process was killed and had no exit status.
@ -170,25 +183,29 @@ call_kubectl <- function(cmd="", config=NULL, ..., echo=getOption("azure_contain
if(!is.null(config))
config <- paste0("--kubeconfig=", config)
message("Kubernetes operation: ", cmd, " ", config)
if(length(cmd) == 1 && grepl(" ", cmd, fixed=TRUE))
cmd <- strsplit(cmd, "\\s+")[[1]]
echo <- as.logical(echo)
val <- processx::run(.AzureContainers$kubectl, c(strsplit(cmd, " ", fixed=TRUE)[[1]], config), ..., echo=echo)
val$cmdline <- paste("kubectl", cmd, config)
val <- processx::run(.AzureContainers$kubectl, c(cmd, config), ..., echo=echo)
val$cmdline <- paste("kubectl", paste(cmd, collapse=" "), config)
invisible(val)
}
#' Call the Helm commandline tool
#'
#' @param cmd The Helm command line to execute.
#' @param cmd The Helm command line to execute. This should be a _vector_ of individual helm arguments, but can also be a single commandline string. See below.
#' @param echo Whether to echo the output of the command to the console.
#' @param config The pathname of the cluster config file, if required.
#' @param ... Other arguments to pass to [processx::run].
#'
#' @details
#' This function calls the `helm` binary, which must be located in your search path. AzureContainers will search for the binary at package startup, and print a warning if it is not found.
#'
#' The helm command should be specified as a vector of the individual arguments, which is what `processx::run` expects. If a single string is passed, for convenience and back-compatibility reasons `call_docker_compose` will split it into arguments for you. This is prone to error, for example if you are working with pathnames that contain spaces, so it's strongly recommended to pass a vector of arguments as a general practice.
#'
#' @return
#' A list with the following components:
#' - `status`: The exit status of the helm tool. If this is `NA`, then the process was killed and had no exit status.
@ -214,11 +231,13 @@ call_helm <- function(cmd="", config=NULL, ..., echo=getOption("azure_containers
if(!is.null(config))
config <- paste0("--kubeconfig=", config)
message("Helm operation: ", cmd, " ", config)
if(length(cmd) == 1 && grepl(" ", cmd, fixed=TRUE))
cmd <- strsplit(cmd, "\\s+")[[1]]
echo <- as.logical(echo)
val <- processx::run(.AzureContainers$helm, c(strsplit(cmd, " ", fixed=TRUE)[[1]], config), ..., echo=echo)
val$cmdline <- paste("helm", cmd, config)
val <- processx::run(.AzureContainers$helm, c(cmd, config), ..., echo=echo)
val$cmdline <- paste("helm", paste(cmd, collapse=" "), config)
invisible(val)
}

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

@ -8,7 +8,7 @@ call_docker(cmd = "", ..., echo = getOption("azure_containers_tool_echo",
TRUE))
}
\arguments{
\item{cmd}{The docker command line to execute.}
\item{cmd}{The docker command. This should be a \emph{vector} of individual docker arguments, but can also be a single commandline string. See below.}
\item{...}{Other arguments to pass to \link[processx:run]{processx::run}.}
@ -31,24 +31,8 @@ Call the docker commandline tool
}
\details{
This function calls the \code{docker} binary, which must be located in your search path. AzureContainers will search for the binary at package startup, and print a warning if it is not found.
}
\examples{
\dontrun{
# without any args, prints the docker help screen
call_docker()
# build an image
call_docker("build -t myimage .")
# list running containers
call_docker("container ls")
# prune unused containers and images
call_docker("container prune -f")
call_docker("image prune -f")
}
The docker command should be specified as a vector of the individual arguments, which is what \code{processx::run} expects. If a single string is passed, for convenience and back-compatibility reasons \code{call_docker} will split it into arguments for you. This is prone to error, for example if you are working with pathnames that contain spaces, so it's strongly recommended to pass a vector of arguments as a general practice.
}
\seealso{
\link[processx:run]{processx::run}, \link{call_docker_compose}, \link{call_kubectl} for the equivalent interface to the \code{kubectl} Kubernetes tool

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

@ -8,7 +8,7 @@ call_docker_compose(cmd = "", ...,
echo = getOption("azure_containers_tool_echo", TRUE))
}
\arguments{
\item{cmd}{The docker-compose command line to execute.}
\item{cmd}{The docker-compose command line to execute. This should be a \emph{vector} of individual docker-compose arguments, but can also be a single commandline string. See below.}
\item{...}{Other arguments to pass to \link[processx:run]{processx::run}.}
@ -31,6 +31,8 @@ Call the docker-compose commandline tool
}
\details{
This function calls the \code{docker-compose} binary, which must be located in your search path. AzureContainers will search for the binary at package startup, and print a warning if it is not found.
The docker-compose command should be specified as a vector of the individual arguments, which is what \code{processx::run} expects. If a single string is passed, for convenience and back-compatibility reasons \code{call_docker_compose} will split it into arguments for you. This is prone to error, for example if you are working with pathnames that contain spaces, so it's strongly recommended to pass a vector of arguments as a general practice.
}
\seealso{
\link[processx:run]{processx::run}, \link{call_docker}, \link{call_kubectl} for the equivalent interface to the \code{kubectl} Kubernetes tool

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

@ -8,7 +8,7 @@ call_helm(cmd = "", config = NULL, ...,
echo = getOption("azure_containers_tool_echo", TRUE))
}
\arguments{
\item{cmd}{The Helm command line to execute.}
\item{cmd}{The Helm command line to execute. This should be a \emph{vector} of individual helm arguments, but can also be a single commandline string. See below.}
\item{config}{The pathname of the cluster config file, if required.}
@ -33,6 +33,8 @@ Call the Helm commandline tool
}
\details{
This function calls the \code{helm} binary, which must be located in your search path. AzureContainers will search for the binary at package startup, and print a warning if it is not found.
The helm command should be specified as a vector of the individual arguments, which is what \code{processx::run} expects. If a single string is passed, for convenience and back-compatibility reasons \code{call_docker_compose} will split it into arguments for you. This is prone to error, for example if you are working with pathnames that contain spaces, so it's strongly recommended to pass a vector of arguments as a general practice.
}
\seealso{
\link[processx:run]{processx::run}, \link{call_docker}, \link{call_kubectl}

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

@ -8,7 +8,7 @@ call_kubectl(cmd = "", config = NULL, ...,
echo = getOption("azure_containers_tool_echo", TRUE))
}
\arguments{
\item{cmd}{The kubectl command line to execute.}
\item{cmd}{The kubectl command line to execute. This should be a \emph{vector} of individual kubectl arguments, but can also be a single commandline string. See below.}
\item{config}{The pathname of the cluster config file, if required.}
@ -33,6 +33,8 @@ Call the Kubernetes commandline tool, kubectl
}
\details{
This function calls the \code{kubectl} binary, which must be located in your search path. AzureContainers will search for the binary at package startup, and print a warning if it is not found.
The kubectl command should be specified as a vector of the individual arguments, which is what \code{processx::run} expects. If a single string is passed, for convenience and back-compatibility reasons \code{call_docker_compose} will split it into arguments for you. This is prone to error, for example if you are working with pathnames that contain spaces, so it's strongly recommended to pass a vector of arguments as a general practice.
}
\examples{
\dontrun{

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

@ -0,0 +1,39 @@
context("Tools interface")
if(.AzureContainers$docker == "" ||
.AzureContainers$dockercompose == "" ||
.AzureContainers$kubectl == "" ||
.AzureContainers$helm == "")
skip("Tests skipped: external tools not found")
test_that("Docker works",
{
cmd <- "--help"
obj <- call_docker(cmd)
expect_is(obj, "list")
expect_identical(obj$cmdline, "docker --help")
})
test_that("Docker compose works",
{
cmd <- "--help"
obj <- call_docker_compose(cmd)
expect_is(obj, "list")
expect_identical(obj$cmdline, "docker-compose --help")
})
test_that("Kubectl works",
{
cmd <- "--help"
obj <- call_kubectl(cmd)
expect_is(obj, "list")
expect_identical(trimws(obj$cmdline), "kubectl --help")
})
test_that("Helm works",
{
cmd <- "--help"
obj <- call_helm(cmd)
expect_is(obj, "list")
expect_identical(trimws(obj$cmdline), "helm --help")
})

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

@ -321,7 +321,5 @@ httr::content(response, simplifyVector=TRUE)
## Further comments
In this vignette, we've used Let's Encrypt to obtain a TLS certificate, as it is a convenient and free source of certificates. In a production setting you would generally use a certificate issued to your organisation.
Similarly, we've secured the predictive service with a single username and password. While we could add more users to the authentication file, a more flexible and scalable solution is to use a frontend service, such as [Azure API Management](https://azure.microsoft.com/services/api-management/), or a directory service like [Azure Active Directory](https://azure.microsoft.com/services/active-directory/). The specifics will typically be determined by your organisation's IT infrastructure, and are beyond the scope of this vignette.
In this vignette, we've secured the predictive service with a single username and password. While we could add more users to the authentication file, a more flexible and scalable solution is to use a frontend service, such as [Azure API Management](https://azure.microsoft.com/services/api-management/), or a directory service like [Azure Active Directory](https://azure.microsoft.com/services/active-directory/). The specifics will typically be determined by your organisation's IT infrastructure, and are beyond the scope of this vignette.