Skip to content
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

Verify location before addition #188

Merged
merged 11 commits into from
Oct 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion DESCRIPTION
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Package: orderly2
Title: Orderly Next Generation
Version: 1.99.48
Version: 1.99.49
Authors@R: c(person("Rich", "FitzJohn", role = c("aut", "cre"),
email = "[email protected]"),
person("Robert", "Ashton", role = "aut"),
Expand Down
68 changes: 37 additions & 31 deletions R/location.R
Original file line number Diff line number Diff line change
Expand Up @@ -75,26 +75,27 @@
##' @param args Arguments to the location driver. The arguments here
##' will vary depending on the type used, see Details.
##'
##' @param verify Logical, indicating if we should verify that the
##' location can be used before adding.
##'
##' @inheritParams orderly_metadata
##'
##' @return Nothing
##' @export
orderly_location_add <- function(name, type, args, root = NULL) {
orderly_location_add <- function(name, type, args, verify = TRUE, root = NULL) {
root <- root_open(root, require_orderly = FALSE)
assert_scalar_character(name, call = environment())
assert_scalar_character(name)
assert_scalar_logical(verify)

if (name %in% location_reserved_name) {
cli::cli_abort("Cannot add a location with reserved name '{name}'")
}

location_check_new_name(root, name, environment())
match_value(type, setdiff(location_types, location_reserved_name),
call = environment())
match_value(type, setdiff(location_types, location_reserved_name))

loc <- new_location_entry(name, type, args, call = environment())
if (type == "path") {
assert_scalar_character(args$path, name = "path")
root_open(args$path, require_orderly = FALSE)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As far as I can tell this means there's no more validation of path locations, since the location_path class does not have an authorize method.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

there was, but it was not at all obvious. I've added a verify method which makes this much less weird, though we'll need to add that to the other location types (e.g., ssh) soon too.

} else if (type == "http") {
assert_scalar_character(args$url, name = "url")
} else if (type == "packit") {
Expand All @@ -105,12 +106,23 @@ orderly_location_add <- function(name, type, args, root = NULL) {
if (!is.null(args$token) && !is.null(args$save_token)) {
cli::cli_abort("Cannot specify both 'token' and 'save_token'")
}
if (is.null(args$save_token)) {
args$save_token <- is.null(args$token)
}
}
loc <- new_location_entry(name, type, args, call = environment())

if (verify) {
cli_alert_info("Testing location")
location_driver_create(type, args)$verify()
cli_alert_success("Location configured successfully")
}

config <- root$config
config$location <- rbind(config$location, loc)
rownames(config$location) <- NULL
config_update(config, root)
cli_alert_success("Added location '{name}' ({type})")
invisible()
}

Expand All @@ -122,9 +134,9 @@ orderly_location_add <- function(name, type, args, root = NULL) {
##' be unreliable.
##'
##' @export
orderly_location_add_path <- function(name, path, root = NULL) {
orderly_location_add_path <- function(name, path, verify = TRUE, root = NULL) {
args <- list(path = path)
orderly_location_add(name, "path", args, root = root)
orderly_location_add(name, "path", args, verify = verify, root = root)
}


Expand All @@ -134,9 +146,9 @@ orderly_location_add_path <- function(name, path, root = NULL) {
##' example `http://example.com:8080`
##'
##' @export
orderly_location_add_http <- function(name, url, root = NULL) {
orderly_location_add_http <- function(name, url, verify = TRUE, root = NULL) {
args <- list(url = url)
orderly_location_add(name, "http", args, root = root)
orderly_location_add(name, "http", args, verify = verify, root = root)
}


Expand All @@ -153,9 +165,10 @@ orderly_location_add_http <- function(name, url, root = NULL) {
##'
##' @export
orderly_location_add_packit <- function(name, url, token = NULL,
save_token = NULL, root = NULL) {
save_token = NULL,
verify = TRUE, root = NULL) {
args <- list(url = url, token = token, save_token = save_token)
orderly_location_add(name, "packit", args, root = root)
orderly_location_add(name, "packit", args, verify = verify, root = root)
}


Expand Down Expand Up @@ -483,6 +496,11 @@ location_driver <- function(location_name, root) {
i <- match(location_name, root$config$location$name)
type <- root$config$location$type[[i]]
args <- root$config$location$args[[i]]
location_driver_create(type, args)
}


location_driver_create <- function(type, args) {
location <- switch(type,
path = orderly_location_path$new,
http = orderly_location_http$new,
Expand Down Expand Up @@ -794,28 +812,16 @@ location_build_push_plan <- function(packet_id, location_name, root) {
## This validation probably will need generalising in future as we add
## new types. The trick is going to be making sure that we can support
## different location types in different target languages effectively.
new_location_entry <- function(name, type, args, call = NULL) {
match_value(type, location_types, call = call)
required <- NULL
if (type == "path") {
required <- "path"
} else if (type == "http") {
required <- "url"
} else if (type == "packit") {
required <- "url"
} else if (type == "custom") {
required <- "driver"
}
new_location_entry <- function(name, type, args, call = parent.frame()) {
match_value(type, location_types)
if (length(args) > 0) {
assert_is(args, "list", call = call)
assert_named(args, call = call)
}
msg <- setdiff(required, names(args))
if (length(msg) > 0) {
cli::cli_abort("Field{?s} missing from args: {squote(msg)}")
assert_is(args, "list")
assert_named(args)
}

if (type == "custom") {
if (is.null(args$driver)) {
cli::cli_abort("Field missing from args: 'driver'")
}
check_symbol_from_str(args$driver, "args$driver")
}

Expand Down
16 changes: 16 additions & 0 deletions R/location_http.R
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,22 @@ orderly_location_http <- R6::R6Class(
self$client <- outpack_http_client$new(url, authorise)
},

verify = function() {
## This should never end up triggering the assertion here as
## http_client_handle_error() in the client will convert
## unsuccessful requests into an error already, but this should
## serve as a reasonable backstop.
##
## The act of making the request will force validation, which is
## the most likely source of errors (along with getting the URL
## wrong).
stopifnot(identical(self$client$request("/")$status, "success"))
},

authorise = function() {
self$client$authorise()
},

list = function() {
dat <- self$client$request("/metadata/list")$data
data_frame(
Expand Down
4 changes: 2 additions & 2 deletions R/location_packit.R
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ packit_authorisation <- function(base_url, token, save_token) {
key <- rlang::hash(list(base_url = base_url, token = token))

if (is.null(auth_cache[[key]])) {
cli::cli_alert_info("Logging in to {base_url}")
cli_alert_info("Logging in to {base_url}")
if (is.null(token)) {
token <- do_oauth_device_flow(base_url, cache_disk = save_token)
}
Expand All @@ -62,7 +62,7 @@ packit_authorisation <- function(base_url, token, save_token) {
login_url,
function(r) http_body_json(r, list(token = scalar(token))))

cli::cli_alert_success("Logged in successfully")
cli_alert_success("Logged in successfully")

auth_cache[[key]] <- list("Authorization" = paste("Bearer", res$token))
}
Expand Down
4 changes: 4 additions & 0 deletions R/location_path.R
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@ orderly_location_path <- R6::R6Class(
private$root <- root_open(path, require_orderly = FALSE)
},

verify = function() {
## No implementation needed as we verify the root in initialize()
},

list = function() {
private$root$index$location(local)[c("packet", "time", "hash")]
},
Expand Down
10 changes: 7 additions & 3 deletions man/orderly_location_add.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions tests/testthat/test-location-packit.R
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
test_that("can authenticate with existing GitHub token", {
withr::local_options(orderly.quiet = FALSE)
clear_auth_cache()
withr::defer(clear_auth_cache())

Expand Down Expand Up @@ -43,6 +44,7 @@ test_that("can authenticate with existing Packit token", {


test_that("can authenticate using device flow", {
withr::local_options(orderly.quiet = FALSE)
clear_auth_cache()
withr::defer(clear_auth_cache())

Expand Down Expand Up @@ -70,7 +72,9 @@ test_that("can authenticate using device flow", {
expect_equal(args[[1]]$body$type, "json")
})


test_that("location_packit uses authentication", {
withr::local_options(orderly.quiet = FALSE)
clear_auth_cache()
withr::defer(clear_auth_cache())

Expand Down
Loading
Loading