-
-
Notifications
You must be signed in to change notification settings - Fork 24
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add support for basic digital ocean spaces API #138
Changes from 8 commits
7be15c2
6fedc20
8e1661d
991bff6
aee4cb0
7233bb7
9c37877
d356f71
18f99fa
5e5ffb5
110c188
644da88
af08b76
44e5e5c
35ff528
cea751a
ea83011
f08b373
ceed414
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,137 @@ | ||
spaces_base <- "nyc3.digitaloceanspaces.com" | ||
|
||
check_space_access <- function(spaces_key) { | ||
tmp <- if (is.null(spaces_key)) Sys.getenv("DO_SPACES_ACCESS_KEY") else spaces_key | ||
if (tmp == "") stop("Need a digital ocean spaces access key defined in your session", call. = FALSE) else tmp | ||
} | ||
|
||
check_space_secret <- function(spaces_secret) { | ||
tmp <- if (is.null(spaces_secret)) Sys.getenv("DO_SPACES_SECRET_KEY") else spaces_secret | ||
if (tmp == "") stop("Need a digital ocean spaces access key defined in your session", call. = FALSE) else tmp | ||
} | ||
|
||
#' @param x Object to coerce to a space | ||
#' @export | ||
#' @rdname spaces | ||
as.space <- function(x) UseMethod("as.space") | ||
#' @export | ||
as.space.space <- function(x) x | ||
|
||
#' @export | ||
print.space <- function(x, ...) { | ||
cat("<space>", x$Name, "\n", sep = "") | ||
cat(" Created at: ", x$CreationDate, "\n") | ||
} | ||
|
||
#' @export | ||
summary.space <- function(object, ...) { | ||
space_info <- space_info(name = object$Name, ...) | ||
|
||
# obtain total size used by space | ||
size <- space_size(space_info) | ||
|
||
# obtain number of files in space | ||
n_files <- space_files(space_info) | ||
|
||
cat("<space_detail>", object$Name, "\n", sep = "") | ||
cat(" Size (GB): ", size, "\n") | ||
cat(" Files: ", n_files, "\n", sep = "") | ||
cat(" Created at: ", object$CreationDate, "\n") | ||
} | ||
|
||
#' Spaces storage operations | ||
#' | ||
#' \describe{ | ||
#' \item{space}{List space contents} | ||
#' \item{spaces}{List spaces in your digital ocean account} | ||
#' \item{space_create}{Create a new space} | ||
#' } | ||
#' | ||
#' @param name (character) Space name. | ||
#' @param spaces_key (character) String containing a spaces access key. If | ||
#' missing, defaults to value stored in an environment variable \code{DO_SPACES_ACCESS_KEY}. | ||
#' @param spaces_secret (character) String containing the secret associated | ||
#' with the spaces key. If missing, defaults to value stored in an environment | ||
#' variable \code{DO_SPACES_SECRET_KEY}. | ||
#' @param ... Additional arguments passed down to \code{\link[aws.s3]{bucketlist}}, | ||
#' \code{\link[aws.s3]{get_bucket}}, \code{\link[aws.s3]{put_bucket}} functions. | ||
|
||
#' @importFrom aws.s3 bucketlist | ||
#' @export | ||
#' @rdname spaces | ||
spaces_GET <- function(spaces_key = NULL, spaces_secret = NULL, ...) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. did you mean to export There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This was also supposed to be an internal function, since the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ok, thx |
||
|
||
spaces_key <- check_space_access(spaces_key) | ||
spaces_secret <- check_space_secret(spaces_secret) | ||
|
||
res <- aws.s3::s3HTTP(verb = "GET", | ||
region = NULL, | ||
key = spaces_key, | ||
secret = spaces_secret, | ||
base_url = spaces_base, | ||
...) | ||
|
||
return(res) | ||
} | ||
|
||
#' @export | ||
#' @rdname spaces | ||
spaces <- function(spaces_key = NULL, spaces_secret = NULL, ...) { | ||
|
||
res <- spaces_GET(spaces_key = spaces_key, spaces_secret = spaces_secret, ...) | ||
spaces <- lapply(res$Buckets, structure, class = "space") | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. try doing There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This was rather nefarious, but when only one space is present the structure of the result changed such that only the |
||
setNames(spaces, vapply(res$Buckets, function(x) x$Name, character(1))) | ||
} | ||
|
||
#' @importFrom aws.s3 get_bucket | ||
#' @export | ||
#' @rdname spaces | ||
space_info <- function(name, spaces_key = NULL, spaces_secret = NULL, ...) { | ||
if (is.null(name)) stop("Please specify the space name") | ||
spaces_key <- check_space_access(spaces_key) | ||
spaces_secret <- check_space_secret(spaces_secret) | ||
|
||
space_info <- get_bucket(name, | ||
region = NULL, | ||
check_region = FALSE, | ||
key = spaces_key, | ||
secret = spaces_secret, | ||
base_url = spaces_base, | ||
max = Inf, | ||
...) | ||
|
||
return(space_info) | ||
} | ||
|
||
space_size <- function(space_info) { | ||
# grab the sizes from each file (unit is bytes) | ||
sizes <- vapply(space_info, function(x) x$Size, numeric(1)) | ||
|
||
# compute total size (convert to gb) | ||
sum(sizes) * 1e-09 | ||
} | ||
|
||
space_files <- function(space_info) { | ||
# remove entries with size 0 (those are nested directories) | ||
length(lapply(space_info, function(x) x[x$Size > 0])) | ||
} | ||
|
||
#' Create a new space | ||
#' @importFrom aws.s3 put_bucket | ||
#' @export | ||
#' @rdname spaces | ||
space_create <- function(name, spaces_key = NULL, spaces_secret = NULL, ...) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. instead of name with no default, you could do https://github.com/sckott/analogsea/blob/master/R/droplet-actions.R#L84 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. don't know if that makes sense for spaces, def. feel free to not change it There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm inclined to not give There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ok |
||
if (is.null(name)) stop("Please specify the space name") | ||
spaces_key <- check_space_access(spaces_key) | ||
spaces_secret <- check_space_secret(spaces_secret) | ||
|
||
res <- put_bucket(name, | ||
region = NULL, | ||
acl = acl, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That is one of the parameters used by There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. sounds good, thx |
||
key = spaces_key, | ||
secret = spaces_secret, | ||
base_url = spaces_base, | ||
...) | ||
|
||
if (res) message(sprintf("New space %s created successfully")) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. doesn't There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Good catch, I will fix that. It was supposed to be passing There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Will this error well if the space isn't created? curious what that looks like. i assume that error handling is in aws pkg There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. So far I haven't had any errors occur when creating a new space. But I am going to add a simple check to ensure the user does not have an existing space with the same name. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. okay, something to explore later, though may be handled well already in aws.s3 pkg |
||
} |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
# tests for spaces | ||
context("space") | ||
|
||
test_that("fails well with no input", { | ||
expect_error(space_info(), "argument \"name\" is missing") | ||
}) | ||
|
||
test_that("key checks fail when not defined in environment", { | ||
skip_on_cran() | ||
|
||
Sys.unsetenv("DO_SPACES_ACCESS_KEY") | ||
expect_error(check_space_access(spaces_key = NULL), "Need a digital ocean spaces access key defined in your session") | ||
|
||
Sys.unsetenv("DO_SPACES_SECRET_KEY") | ||
expect_error(check_space_secret(spaces_secret = NULL), "Need a digital ocean spaces access key defined in your session") | ||
}) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i don't see a
space
function, though maybe it's something to be addedThere was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ah, maybe
space
==space_info
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I went back and forth with this, but now I'm going to omit a
space()
function sincespaces()
will grab everything and it is straight forward for the user to grab whichever space they want to work with. They all have a specialspace
class so we'll be able to add many more methods and operations as time goes on I'll delete references to aspace
function in my next PR.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also I've made
space_info()
an internal functionThere was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
sounds good