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

Strategus keyring cli #6

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
174 changes: 174 additions & 0 deletions Tutorials/StrategusSetup.Qmd
@@ -0,0 +1,174 @@
---
title: "Strategus Setup Guide"
subtitle : "Lost in config land"
date: "2023-10-21"
format:
revealjs:
theme: default
logo: https://www.ohdsi.org/web/wiki/lib/exe/fetch.php?w=100&tok=44f68f&media=t-ohdsi-logo-only.png
css: logo.css
footer: "Strategus Setup Guide"
---

## `keyringSetup.R`/`keyringSetupCli.R`

Running this file is for setting up secret credentials that are used for your CDM.

```{r eval = FALSE, echo=TRUE}
source('keyringSetup.R')
```

:::{.incremental}
- Set `STRATEGUS_KEYRING_PASSWORD` environmental variable
- Set `INSTANTIATED_MODULES_FOLDER` environmental variable
- Create and securely save database connection details for your CDM
:::



## `StrategusCodeToRun.R`
Edit the top of this file before you begin:

```{r eval = FALSE, echo=TRUE}
#| code-line-numbers: 7-18
# install the network package
# install.packages('remotes')
# remotes::install_github("OHDSI/Strategus", ref="develop")
library(Strategus)

##=========== START OF INPUTS ==========
keyringName <- "HowOften"
connectionDetailsReference <- "optum_dod"
workDatabaseSchema <- 'scratch_cknoll1'
cdmDatabaseSchema <- 'cdm_optum_extended_dod_v2434'
outputLocation <- 'D:/projects/HowOften/Strategus'
resultsLocation <- 'D:/projects/HowOften/Results'
minCellCount <- 5
cohortTableName <- "howoften_cohort"

....
```

## `StrategusCodeToRun.R`
The keyring name will be used for this project.

Make sure its set to the value in the previous script

```{r eval = FALSE, echo=TRUE}
#| code-line-numbers: 7
# install the network package
# install.packages('remotes')
# remotes::install_github("OHDSI/Strategus", ref="develop")
library(Strategus)

##=========== START OF INPUTS ==========
keyringName <- "HowOften"
connectionDetailsReference <- "optum_dod"
workDatabaseSchema <- 'scratch_cknoll1'
cdmDatabaseSchema <- 'cdm_optum_extended_dod_v2434'
outputLocation <- 'D:/projects/HowOften/Strategus'
resultsLocation <- 'D:/projects/HowOften/Results'
minCellCount <- 5
cohortTableName <- "howoften_cohort"

....
```

## `StrategusCodeToRun.R`
These cdm schema settings are where the data will live.
The `workDatabaseSchema` must be writable

```{r eval = FALSE, echo=TRUE}
#| code-line-numbers: 9-10
# install the network package
# install.packages('remotes')
# remotes::install_github("OHDSI/Strategus", ref="develop")
library(Strategus)

##=========== START OF INPUTS ==========
keyringName <- "HowOften"
connectionDetailsReference <- "optum_dod"
workDatabaseSchema <- 'scratch_cknoll1'
cdmDatabaseSchema <- 'cdm_optum_extended_dod_v2434'
outputLocation <- 'D:/projects/HowOften/Strategus'
resultsLocation <- 'D:/projects/HowOften/Results'
minCellCount <- 5
cohortTableName <- "howoften_cohort"

....
```

## `StrategusCodeToRun.R`

These output and results locations should be different, writable directories.
Make sure you have enough disk space

```{r eval = FALSE, echo=TRUE}
#| code-line-numbers: 11-12
# install the network package
# install.packages('remotes')
# remotes::install_github("OHDSI/Strategus", ref="develop")
library(Strategus)

##=========== START OF INPUTS ==========
keyringName <- "HowOften"
connectionDetailsReference <- "optum_dod"
workDatabaseSchema <- 'scratch_cknoll1'
cdmDatabaseSchema <- 'cdm_optum_extended_dod_v2434'
outputLocation <- 'D:/projects/HowOften/Strategus'
resultsLocation <- 'D:/projects/HowOften/Results'
minCellCount <- 5
cohortTableName <- "howoften_cohort"

....
```



## `StrategusCodeToRun.R`

Make sure that your `minCellCount` complies with your governance on the minimum number for identify patients.

```{r eval = FALSE, echo=TRUE}
#| code-line-numbers: 13
# install the network package
# install.packages('remotes')
# remotes::install_github("OHDSI/Strategus", ref="develop")
library(Strategus)

##=========== START OF INPUTS ==========
keyringName <- "HowOften"
connectionDetailsReference <- "optum_dod"
workDatabaseSchema <- 'scratch_cknoll1'
cdmDatabaseSchema <- 'cdm_optum_extended_dod_v2434'
outputLocation <- 'D:/projects/HowOften/Strategus'
resultsLocation <- 'D:/projects/HowOften/Results'
minCellCount <- 5
cohortTableName <- "howoften_cohort"

....
```

## `StrategusCodeToRun.R`

Your cohort table should be unique - this will be overwritten

```{r eval = FALSE, echo=TRUE}
#| code-line-numbers: 14
# install the network package
# install.packages('remotes')
# remotes::install_github("OHDSI/Strategus", ref="develop")
library(Strategus)

##=========== START OF INPUTS ==========
keyringName <- "HowOften"
connectionDetailsReference <- "optum_dod"
workDatabaseSchema <- 'scratch_cknoll1'
cdmDatabaseSchema <- 'cdm_optum_extended_dod_v2434'
outputLocation <- 'D:/projects/HowOften/Strategus'
resultsLocation <- 'D:/projects/HowOften/Results'
minCellCount <- 5
cohortTableName <- "howoften_cohort"

....
```
152 changes: 152 additions & 0 deletions keyringSetupCli.R
@@ -0,0 +1,152 @@
# Install keyring - one time operation ---------
appendToRenviron <- function(varName, value, environFile = "~/.Renviron") {
if (file.exists(environFile))
lines <- readLines(environFile)
else
lines <- c()

if (any(grepl(varName, lines))) {
cli::cli_alert_info("Found existing environment variable {varName}, last value set will be taken by system")
}

renviron <- c(lines, glue::glue("{varName}='{value}'"))
writeLines(renviron, environFile)
}

#' Create Strategus Keyring
#' @description
#' CLI utility for creating a strategus keyring.
#'
#' This will perform the required setup for secure credentials inside a study.
#'
#' Creates a system wide keyring password if not already present.
#' @export
#' @param keyringName string name for keyring on system to store credentials inside of
#' @param connectionDetailsReference string reference name for connection details e.g. "myCdmName". This will be used
#' in strategus executions to reference your database.
createStrategusKeyring <- function(keyringName = "HowOften",
connectionDetailsReference = 'myDatasourceKey') {
if (!interactive()) {
stop("Requires interactive session")
}

requiredPackages <- c("keyring", "cli", "getPass")
requiredPackages <- requiredPackages[!requiredPackages %in% as.data.frame(installed.packages())$Package]

if (length(requiredPackages)) {
resp <- utils::menu(c("yes", "no"), title = paste("Package", requiredPackages, "not installed. install now?"))
if (resp != 1) {
stop("Required system packages missing for this configuration utility")
}
}

cli::cli_text("Creating keyring {keyringName}")
cli::cli_text("This script is designed to set up your variables for your strategus keyring.")
cli::cli_text("You will be prompted for a number of inputs that will be validated.")

if (Sys.getenv("STRATEGUS_KEYRING_PASSWORD") == "") {
cli::cli_par("Please enter a password for your keyring")
passVar <- getPass::getPass("Keyring password", noblank = TRUE)

if (passVar == "" || is.null(passVar)) {
cli::cli_abort("Must enter a password")
}
Sys.setenv("STRATEGUS_KEYRING_PASSWORD" = passVar)
appendToRenviron("STRATEGUS_KEYRING_PASSWORD", passVar)
}

cli::cli_alert_success("STRATEGUS_KEYRING_PASSWORD environment var set")

strategusModuleFolder <- Sys.getenv("INSTANTIATED_MODULES_FOLDER")
if (strategusModuleFolder == "") {
while (!checkmate::test_directory(strategusModuleFolder, "w")) {
cli::cli_alert_info("INSTANTIATED_MODULES_FOLDER environment variable not set please enter a directory:")
strategusModuleFolder <- readLines(n=1)
dir.create(strategusModuleFolder, showWarnings = FALSE)
}
Sys.setenv("INSTANTIATED_MODULES_FOLDER" = strategusModuleFolder)
appendToRenviron("INSTANTIATED_MODULES_FOLDER", strategusModuleFolder)
}

cli::cli_alert_success("INSTANTIATED_MODULES_FOLDER environment var set")

tempconnectionFile <- tempfile(fileext = ".R")

cli::cli_alert_info("Creating file {tempconnectionFile} for Database credentials - this file will be automaticaly removed when completed and the settings saved securly")
on.exit(unlink(tempconnectionFile, force = TRUE))

rscript <- "# Enter your database connection values here and press save
# the connection will be tested
connectionDetails <-
DatabaseConnector::createConnectionDetails(
dbms = '',
server = '',
password = '',
user = '',
port = 0,
extraSettings = NULL,
connectionString = NULL,
pathToDriver = Sys.getenv('DATABASECONNECTOR_JAR_FOLDER')
)

# short abbreviation that describes these connection details

"

writeLines(rscript, con = tempconnectionFile)
connectionValid <- FALSE
while (!connectionValid) {
resp <- utils::menu(c("yes", "no"), title = "Secure creation of connection details required, continue?")
if (resp != 1) {
cli::cli_abort("Secure database credentials cannot be aquired")
}
utils::file.edit(tempconnectionFile)
# test the connection
tryCatch(
{
source(tempconnectionFile)
conn <- DatabaseConnector::connect(connectionDetails)
DatabaseConnector::disconnect(conn)
connectionValid <- TRUE
cli::cli_alert_success("Database Connection Works")
},
error = function(message) {
cli::cli_alert_warning("Database Connection Failed, retrying...")
cli::cli_alert(message)
}
)
}
unlink(tempconnectionFile, force = TRUE)
cli::cli_alert_info("Removed temporary credentials file {tempconnectionFile}")

keyringPassword <- Sys.getenv("STRATEGUS_KEYRING_PASSWORD") # This password is simply to avoid a prompt when creating the keyring
# Create the keyring if it does not exist.
# If it exists, clear it out so we can re-load the keys
allKeyrings <- keyring::keyring_list()
if (keyringName %in% allKeyrings$keyring) {
if (keyring::keyring_is_locked(keyring = keyringName)) {
keyring::keyring_unlock(keyring = keyringName, password = keyringPassword)
}
# Delete all keys from the keyring so we can delete it
message(paste0("Delete existing keyring: ", keyringName))
keys <- keyring::key_list(keyring = keyringName)
if (nrow(keys) > 0) {
for (i in 1:nrow(keys)) {
keyring::key_delete(keys$service[i], keyring = keyringName)
}
}
keyring::keyring_delete(keyring = keyringName)
}

keyring::keyring_create(keyring = keyringName, password = keyringPassword)

# excecute this for each connectionDetails/ConnectionDetailsReference you are going to use
Strategus::storeConnectionDetails(
connectionDetails = connectionDetails,
connectionDetailsReference = connectionDetailsReference,
keyringName = keyringName
)
cli::cli_alert_success("Secure strategus keyring reference {keyringName} created")
}

createStrategusKeyring()