diff --git a/NAMESPACE b/NAMESPACE index ca6f6d7..291c38c 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -9,6 +9,7 @@ export(crew_launcher_aws_batch) export(crew_launcher_aws_batch_launch) export(crew_launcher_aws_batch_terminate) export(crew_monitor_aws_batch) +export(crew_options_aws_batch) importFrom(R6,R6Class) importFrom(cli,cli_progress_bar) importFrom(cli,cli_progress_done) diff --git a/R/crew_definition_aws_batch.R b/R/crew_definition_aws_batch.R index 767cf85..3edeab7 100644 --- a/R/crew_definition_aws_batch.R +++ b/R/crew_definition_aws_batch.R @@ -653,10 +653,10 @@ crew_class_definition_aws_batch <- R6::R6Class( submit = function( command = c("sleep", "300"), name = paste0("crew-aws-batch-job-", crew::crew_random_name()), - memory_units = "gigabytes", - memory = NULL, cpus = NULL, gpus = NULL, + memory_units = "gigabytes", + memory = NULL, seconds_timeout = NULL, share_identifier = NULL, scheduling_priority_override = NULL, diff --git a/R/crew_options_aws_batch.R b/R/crew_options_aws_batch.R new file mode 100644 index 0000000..41cf008 --- /dev/null +++ b/R/crew_options_aws_batch.R @@ -0,0 +1,204 @@ +#' @title AWS Batch options +#' @export +#' @keywords plugin_aws_batch +#' @description Options for the AWS Batch controller. +#' @return A classed list of options for the controller. +#' @param job_definition Character of length 1, name of the AWS +#' Batch job definition to use. There is no default for this argument, +#' and a job definition must be created prior to running the controller. +#' Please see for details. +#' +#' To create a job definition, you will need to create a Docker-compatible +#' image which can run R and `crew`. You may which to inherit +#' from the images at . +#' @param job_queue Character of length 1, name of the AWS +#' Batch job queue to use. There is no default for this argument, +#' and a job queue must be created prior to running the controller. +#' Please see for details. +#' @param cpus Number of virtual CPUs to request per job. Can be `NULL` +#' to go with the defaults in the job definition. Ignored if +#' `container_overrides` is not `NULL`. +#' @param gpus Number of GPUs to request per job. Can be `NULL` +#' to go with the defaults in the job definition. Ignored if +#' `container_overrides` is not `NULL`. +#' @param memory Positive number, amount of memory to request per job. +#' Choose the units of memory with the `memory_units` argument. +#' Fargate instances can only be certain discrete values of mebibytes, +#' so please choose `memory_units = "mebibytes"` in that case. +#' The `memory` argument can be `NULL` +#' to go with the defaults in the job definition. Ignored if +#' `container_overrides` is not `NULL`. +#' @param units_memory Character string, units of memory of the `memory` +#' argument. Can be `"gigabytes"` or `"mebibytes"`. +#' Fargate instances can only be certain discrete values of mebibytes, +#' so please choose `memory_units = "mebibytes"` in that case. +#' @param share_identifier `NULL` or character of length 1. +#' For details, visit +#' and the +#' "AWS arguments" sections of this help file. +#' @param scheduling_priority_override `NULL` or integer of length 1. +#' For details, visit +#' and the +#' "AWS arguments" sections of this help file. +#' @param parameters `NULL` or a nonempty list. +#' For details, visit +#' and the +#' "AWS arguments" sections of this help file. +#' @param container_overrides `NULL` or a nonempty named list of +#' fields to override +#' in the container specified in the job definition. Any overrides for the +#' `command` field are ignored because `crew.aws.batch` needs to override +#' the command to run the `crew` worker. +#' For more details, visit +#' and the +#' "AWS arguments" sections of this help file. +#' @param node_overrides `NULL` or a nonempty named list. +#' For more details, visit +#' and the +#' "AWS arguments" sections of this help file. +#' @param retry_strategy `NULL` or a nonempty named list. +#' For more details, visit +#' and the +#' "AWS arguments" sections of this help file. +#' @param propagate_tags `NULL` or a logical of length 1. +#' For more details, visit +#' and the +#' "AWS arguments" sections of this help file. +#' @param timeout `NULL` or a nonempty named list. +#' For more details, visit +#' and the +#' "AWS arguments" sections of this help file. +#' @param tags `NULL` or a nonempty named list. +#' For more details, visit +#' and the +#' "AWS arguments" sections of this help file. +#' @param eks_properties_override `NULL` or a nonempty named list. +#' For more details, visit +#' and the +#' "AWS arguments" sections of this help file. +crew_options_aws_batch <- function( + job_definition, + job_queue, + cpus = NULL, + gpus = NULL, + memory = NULL, + memory_units = "gigabytes", + config = list(), + credentials = list(), + endpoint = NULL, + region = NULL, + share_identifier = NULL, + scheduling_priority_override = NULL, + parameters = NULL, + container_overrides = NULL, + node_overrides = NULL, + retry_strategy = NULL, + propagate_tags = NULL, + timeout = NULL, + tags = NULL, + eks_properties_override = NULL +) { + crew::crew_assert( + job_definition, + is.character(.), + length(.) == 1L, + !anyNA(.), + nzchar(.), + message = "job_definition must be a valid nonempty character string" + ) + crew::crew_assert( + job_queue, + is.character(.), + length(.) == 1L, + !anyNA(.), + nzchar(.), + message = "job_queue must be a valid nonempty character string" + ) + crew::crew_assert( + memory_units, + is.character(.), + length(.) == 1L, + !anyNA(.), + nzchar(.), + . %in% c("gigabytes", "mebibytes"), + message = "memory_units must be \"gigabytes\" or \"mebibytes\"" + ) + crew::crew_assert( + cpus %|||% 1, + is.numeric(.), + length(.) == 1L, + is.finite(.), + . > 0, + message = "cpus must be NULL or a single positive number" + ) + crew::crew_assert( + gpus %|||% 0, + is.numeric(.), + length(.) == 1L, + is.finite(.), + . >= 0, + message = "gpus must be NULL or a single non-negative number" + ) + crew::crew_assert( + memory %|||% 0, + is.numeric(.), + length(.) == 1L, + is.finite(.), + . >= 0, + message = "memory must be NULL or a single positive number" + ) + container_overrides <- container_overrides %|||% make_container_overrides( + cpus = cpus, + gpus = gpus, + memory = memory, + memory_units = memory_units + ) + structure( + list( + job_definition = job_definition, + job_queue = job_queue, + config = config, + credentials = credentials, + endpoint = endpoint, + region = region, + share_identifier = share_identifier, + scheduling_priority_override = scheduling_priority_override, + parameters = parameters, + container_overrides = container_overrides, + node_overrides = node_overrides, + retry_strategy = retry_strategy, + propagate_tags = propagate_tags, + timeout = timeout, + tags = tags, + eks_properties_override = eks_properties_override + ), + class = c("crew_options_aws_batch", "crew_options") + ) +} + +make_container_overrides <- function( + cpus = cpus, + gpus = gpus, + memory = memory, + memory_units = memory_units +) { + if (!is.null(memory) && identical(memory_units, "gigabytes")) { + memory <- memory * ((5L ^ 9L) / (2L ^ 11L)) + } + resources <- list() + if (!is.null(memory)) { + memory <- as.character(round(memory)) + resources$memory <- list(value = memory, type = "MEMORY") + } + if (!is.null(cpus)) { + resources$cpus <- list(value = as.character(cpus), type = "VCPU") + } + if (!is.null(gpus)) { + resources$gpus <- list(value = as.character(gpus), type = "GPU") + } + out <- list() + if (length(resources)) { + out$resourceRequirements <- resources + } + out +} diff --git a/_pkgdown.yml b/_pkgdown.yml index 2f7b8a6..37c3503 100644 --- a/_pkgdown.yml +++ b/_pkgdown.yml @@ -8,6 +8,7 @@ reference: - title: AWS Batch launcher plugin contents: - 'crew_controller_aws_batch' + - 'crew_options_aws_batch' - 'crew_launcher_aws_batch' - 'crew_class_launcher_aws_batch' - title: AWS Batch monitor diff --git a/man/crew_class_definition_aws_batch.Rd b/man/crew_class_definition_aws_batch.Rd index c309d2c..fa77254 100644 --- a/man/crew_class_definition_aws_batch.Rd +++ b/man/crew_class_definition_aws_batch.Rd @@ -262,10 +262,10 @@ Submit an AWS Batch job with the given job definition. \if{html}{\out{
}}\preformatted{crew_class_definition_aws_batch$submit( command = c("sleep", "300"), name = paste0("crew-aws-batch-job-", crew::crew_random_name()), - memory_units = "gigabytes", - memory = NULL, cpus = NULL, gpus = NULL, + memory_units = "gigabytes", + memory = NULL, seconds_timeout = NULL, share_identifier = NULL, scheduling_priority_override = NULL, @@ -284,6 +284,12 @@ with each term in its own character string.} \item{\code{name}}{Character of length 1 with the job name.} +\item{\code{cpus}}{Positive numeric of length 1, number of virtual +CPUs to request for each job.} + +\item{\code{gpus}}{Positive numeric of length 1, number of GPUs to +request for each job.} + \item{\code{memory_units}}{Character of length 1, either \code{"gigabytes"} or \code{"mebibytes"} to set the units of the \code{memory} argument. \code{"gigabytes"} is simpler for EC2 jobs, but @@ -294,12 +300,6 @@ mebibytes (MiB). for details, read \item{\code{memory}}{Positive numeric of length 1, amount of memory to request for each job.} -\item{\code{cpus}}{Positive numeric of length 1, number of virtual -CPUs to request for each job.} - -\item{\code{gpus}}{Positive numeric of length 1, number of GPUs to -request for each job.} - \item{\code{seconds_timeout}}{Optional positive numeric of length 1, number of seconds until a job times out.} diff --git a/man/crew_options_aws_batch.Rd b/man/crew_options_aws_batch.Rd new file mode 100644 index 0000000..d2761eb --- /dev/null +++ b/man/crew_options_aws_batch.Rd @@ -0,0 +1,126 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/crew_options_aws_batch.R +\name{crew_options_aws_batch} +\alias{crew_options_aws_batch} +\title{AWS Batch options} +\usage{ +crew_options_aws_batch( + job_definition, + job_queue, + cpus = NULL, + gpus = NULL, + memory = NULL, + memory_units = "gigabytes", + config = list(), + credentials = list(), + endpoint = NULL, + region = NULL, + share_identifier = NULL, + scheduling_priority_override = NULL, + parameters = NULL, + container_overrides = NULL, + node_overrides = NULL, + retry_strategy = NULL, + propagate_tags = NULL, + timeout = NULL, + tags = NULL, + eks_properties_override = NULL +) +} +\arguments{ +\item{job_definition}{Character of length 1, name of the AWS +Batch job definition to use. There is no default for this argument, +and a job definition must be created prior to running the controller. +Please see \url{https://docs.aws.amazon.com/batch/} for details. + +To create a job definition, you will need to create a Docker-compatible +image which can run R and \code{crew}. You may which to inherit +from the images at \url{https://github.com/rocker-org/rocker-versioned2}.} + +\item{job_queue}{Character of length 1, name of the AWS +Batch job queue to use. There is no default for this argument, +and a job queue must be created prior to running the controller. +Please see \url{https://docs.aws.amazon.com/batch/} for details.} + +\item{cpus}{Number of virtual CPUs to request per job. Can be \code{NULL} +to go with the defaults in the job definition. Ignored if +\code{container_overrides} is not \code{NULL}.} + +\item{gpus}{Number of GPUs to request per job. Can be \code{NULL} +to go with the defaults in the job definition. Ignored if +\code{container_overrides} is not \code{NULL}.} + +\item{memory}{Positive number, amount of memory to request per job. +Choose the units of memory with the \code{memory_units} argument. +Fargate instances can only be certain discrete values of mebibytes, +so please choose \code{memory_units = "mebibytes"} in that case. +The \code{memory} argument can be \code{NULL} +to go with the defaults in the job definition. Ignored if +\code{container_overrides} is not \code{NULL}.} + +\item{share_identifier}{\code{NULL} or character of length 1. +For details, visit +\url{https://www.paws-r-sdk.com/docs/batch_submit_job/} and the +"AWS arguments" sections of this help file.} + +\item{scheduling_priority_override}{\code{NULL} or integer of length 1. +For details, visit +\url{https://www.paws-r-sdk.com/docs/batch_submit_job/} and the +"AWS arguments" sections of this help file.} + +\item{parameters}{\code{NULL} or a nonempty list. +For details, visit +\url{https://www.paws-r-sdk.com/docs/batch_submit_job/} and the +"AWS arguments" sections of this help file.} + +\item{container_overrides}{\code{NULL} or a nonempty named list of +fields to override +in the container specified in the job definition. Any overrides for the +\code{command} field are ignored because \code{crew.aws.batch} needs to override +the command to run the \code{crew} worker. +For more details, visit +\url{https://www.paws-r-sdk.com/docs/batch_submit_job/} and the +"AWS arguments" sections of this help file.} + +\item{node_overrides}{\code{NULL} or a nonempty named list. +For more details, visit +\url{https://www.paws-r-sdk.com/docs/batch_submit_job/} and the +"AWS arguments" sections of this help file.} + +\item{retry_strategy}{\code{NULL} or a nonempty named list. +For more details, visit +\url{https://www.paws-r-sdk.com/docs/batch_submit_job/} and the +"AWS arguments" sections of this help file.} + +\item{propagate_tags}{\code{NULL} or a logical of length 1. +For more details, visit +\url{https://www.paws-r-sdk.com/docs/batch_submit_job/} and the +"AWS arguments" sections of this help file.} + +\item{timeout}{\code{NULL} or a nonempty named list. +For more details, visit +\url{https://www.paws-r-sdk.com/docs/batch_submit_job/} and the +"AWS arguments" sections of this help file.} + +\item{tags}{\code{NULL} or a nonempty named list. +For more details, visit +\url{https://www.paws-r-sdk.com/docs/batch_submit_job/} and the +"AWS arguments" sections of this help file.} + +\item{eks_properties_override}{\code{NULL} or a nonempty named list. +For more details, visit +\url{https://www.paws-r-sdk.com/docs/batch_submit_job/} and the +"AWS arguments" sections of this help file.} + +\item{units_memory}{Character string, units of memory of the \code{memory} +argument. Can be \code{"gigabytes"} or \code{"mebibytes"}. +Fargate instances can only be certain discrete values of mebibytes, +so please choose \code{memory_units = "mebibytes"} in that case.} +} +\value{ +A classed list of options for the controller. +} +\description{ +Options for the AWS Batch controller. +} +\keyword{plugin_aws_batch} diff --git a/tests/definition/test-definition.R b/tests/definition/test-definition.R index 3f74e65..0b92967 100644 --- a/tests/definition/test-definition.R +++ b/tests/definition/test-definition.R @@ -59,7 +59,7 @@ test_that("submit a job", { job <- x$submit( command = c("sleep", "1"), memory_units = "mebibytes", - memory = 128, + memory = 500, cpus = 1, seconds_timeout = 60, tags = c("crew_aws_batch_1", "crew_aws_batch_2"), diff --git a/tests/testthat/test-crew_options_aws_batch.R b/tests/testthat/test-crew_options_aws_batch.R new file mode 100644 index 0000000..572e02b --- /dev/null +++ b/tests/testthat/test-crew_options_aws_batch.R @@ -0,0 +1,50 @@ +test_that("basic options", { + out <- crew_options_aws_batch( + job_definition = "x", + job_queue = "y" + ) + expect_s3_class(out, c("crew_options_aws_batch", "crew_options")) + expect_equal(out$job_definition, "x") + expect_equal(out$job_queue, "y") +}) + +test_that("cpu and memory", { + out <- crew_options_aws_batch( + job_definition = "x", + job_queue = "y", + cpus = 0.5, + memory = 2, + memory_units = "gigabytes" + ) + expect_s3_class(out, c("crew_options_aws_batch", "crew_options")) + expect_equal(out$job_definition, "x") + expect_equal(out$job_queue, "y") + expect_equal( + out$container_overrides, + list( + resourceRequirements = list( + memory = list(value = "1907", type = "MEMORY"), + cpus = list(value = "0.5", type = "VCPU") + ) + ) + ) +}) + +test_that("gpus", { + out <- crew_options_aws_batch( + job_definition = "x", + job_queue = "y", + gpus = 2 + ) + expect_s3_class(out, c("crew_options_aws_batch", "crew_options")) + expect_equal(out$job_definition, "x") + expect_equal(out$job_queue, "y") + expect_equal( + out$container_overrides, + list( + resourceRequirements = list( + gpus = list(value = "2", type = "GPU") + ) + ) + ) +})