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

Add custom java truststore support and improved exception handling #49

Merged
merged 12 commits into from
Jul 1, 2024
Merged
16 changes: 16 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,22 @@
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [[0.3.0](https://github.com/seqeralabs/nf-aggregate/releases/tag/0.3.0)] - 2024-07-01

### Credits

Special thanks to the following for their contributions to the release:

- [Adam Talbot](https://github.com/adamrtalbot)
- [Esha Joshi](https://github.com/ejseqera)
- [Rob Syme](https://github.com/robsyme)

Thank you to everyone else that has contributed by reporting bugs, enhancements or in any other way, shape or form.

### Enhancements & fixes

[PR #49](https://github.com/seqeralabs/nf-aggregate/pull/49) - Add custom java truststore support and improved exception handling

## [[0.2.0](https://github.com/seqeralabs/nf-aggregate/releases/tag/0.2.0)] - 2024-05-29

### Credits
Expand Down
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@ nextflow run seqeralabs/nf-aggregate \
-profile docker
```

If you are using a Seqera Platform Enterprise instance that is secured with a private CA SSL certificate not recognized by default Java certificate authorities, you can specify a custom `cacerts` store path through the `--java_truststore_path` parameter and optionally, a password with the `--java_truststore_password`. This certificate will be used to achieve connectivity with your Seqera Platform instance through API and CLI.

## Output

The results from the pipeline will be published in the path specified by the `--outdir` and will consist of the following contents:
Expand Down
4 changes: 3 additions & 1 deletion main.nf
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,9 @@ workflow {
ch_multiqc_logo,
params.seqera_api_endpoint,
params.skip_run_gantt,
params.skip_multiqc
params.skip_multiqc,
params.java_truststore_path,
params.java_truststore_password
)
}

Expand Down
2 changes: 2 additions & 0 deletions modules/local/plot_run_gantt/tests/main.nf.test
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ nextflow_process {
"""
input[0] = ['id': '4Bi5xBK6E2Nbhj', 'workspace': 'community/showcase']
input[1] = "https://api.tower.nf"
input[2] = ""
input[3] = ""
"""
}
}
Expand Down
30 changes: 26 additions & 4 deletions modules/local/seqera_runs_dump/functions.nf
Original file line number Diff line number Diff line change
@@ -1,6 +1,14 @@

@Grab('com.github.groovy-wslite:groovy-wslite:1.1.2;transitive=false')
import wslite.rest.RESTClient
import groovy.json.JsonSlurper

// Set system properties for custom Java trustStore
def setTrustStore(trustStorePath, trustStorePassword) {
System.setProperty("javax.net.ssl.trustStore", trustStorePath)
if (trustStorePassword) {
System.setProperty("javax.net.ssl.trustStorePassword", trustStorePassword)
}
}

drpatelh marked this conversation as resolved.
Show resolved Hide resolved
Long getWorkspaceId(orgName, workspaceName, client, authHeader) {
def orgResponse = client.get(path: '/orgs', headers: authHeader)
Expand All @@ -14,15 +22,22 @@ Long getWorkspaceId(orgName, workspaceName, client, authHeader) {
if (workspaceReponse.statusCode == 200) {
def workspaceMap = workspaceReponse.json?.workspaces.collectEntries { ws -> [ws.name, ws.id]}
return workspaceMap?.get(workspaceName)
} else {
log.error "Failed to fetch workspaces for orgId: ${orgId}, statusCode: ${workspaceResponse.statusCode}"
}
}
return null
}

Map getRunMetadata(meta, log, api_endpoint) {
Map getRunMetadata(meta, log, api_endpoint, trustStorePath, trustStorePassword) {
def runId = meta.id
def (orgName, workspaceName) = meta.workspace.tokenize("/")

if (trustStorePath) {
log.info "Setting custom truststore: ${trustStorePath}"
setTrustStore(trustStorePath, trustStorePassword)
}

def client = new RESTClient(api_endpoint)
def token = System.getenv("TOWER_ACCESS_TOKEN")
def authHeader = ["Authorization": "Bearer ${token}"]
Expand All @@ -39,11 +54,18 @@ Map getRunMetadata(meta, log, api_endpoint) {
return metaMap ?: [:]
}
}
} catch(Exception ex) {
} catch (wslite.rest.RESTClientException ex) {
log.warn """
ejseqera marked this conversation as resolved.
Show resolved Hide resolved
Could not get workflow details for workflow ${runId} in workspace ${meta.workspace}:
↳ Status code ${ex.response.statusCode} returned from request to ${ex.request.url} (authentication headers excluded)
↳ Status code ${ex.response?.statusCode} returned from request to ${ex.request?.url} (authentication headers excluded)
""".stripIndent()
log.error "Exception: ${ex.message}", ex
} catch (Exception ex) {
log.warn """
An error occurred while getting workflow details for workflow ${runId} in workspace ${meta.workspace}:
↳ ${ex.message}
""".stripIndent()
log.error "Exception: ${ex.message}", ex
}
return [:]
}
8 changes: 7 additions & 1 deletion modules/local/seqera_runs_dump/main.nf
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ process SEQERA_RUNS_DUMP {
input:
val meta
val api_endpoint
val java_truststore_path
val java_truststore_password

output:
tuple val(metaOut), path("${prefix}"), emit: run_dump
Expand All @@ -17,11 +19,15 @@ process SEQERA_RUNS_DUMP {
def args = task.ext.args ?: ''
def args2 = task.ext.args2 ?: ''
prefix = task.ext.prefix ?: "${meta.id}"
metaOut = meta + getRunMetadata(meta, log, api_endpoint)
metaOut = meta + getRunMetadata(meta, log, api_endpoint, java_truststore_path, java_truststore_password)
fusion = metaOut.fusion ? '--add-fusion-logs' : ''
javaTrustStore = java_truststore_path ? "-Djavax.net.ssl.trustStore=${java_truststore_path}" : ''
javaTrustStorePassword = java_truststore_password ? "-Djavax.net.ssl.trustStorePassword=${java_truststore_password}" : ''
"""
tw \\
$args \\
$javaTrustStore \\
$javaTrustStorePassword \\
--url=${api_endpoint} \\
--access-token=$TOWER_ACCESS_TOKEN \\
runs \\
Expand Down
1 change: 1 addition & 0 deletions modules/local/seqera_runs_dump/nextflow.config
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ process {
withName: 'SEQERA_RUNS_DUMP' {
ext.args = { params.seqera_cli_extra_args ? params.seqera_cli_extra_args.split("\\s(?=--)") : '' }
ext.args2 = { params.skip_run_gantt ? '' : '--add-task-logs' }
containerOptions = { params.java_truststore_path ? "--volume ${params.java_truststore_path}:${params.java_truststore_path}" : '' }
publishDir = [
path: { "${params.outdir}/${metaOut?.projectName?.replace("/", "_") ?: ""}/runs_dump" },
mode: params.publish_dir_mode,
Expand Down
2 changes: 2 additions & 0 deletions modules/local/seqera_runs_dump/tests/main.nf.test
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ nextflow_process {
"""
input[0] = ['id': '4Bi5xBK6E2Nbhj', 'workspace': 'community/showcase']
input[1] = "https://api.tower.nf"
input[2] = ""
input[3] = ""
"""
}
}
Expand Down
5 changes: 4 additions & 1 deletion nextflow.config
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ params {
// Seqera CLI options
seqera_api_endpoint = "https://api.cloud.seqera.io"
seqera_cli_extra_args = null
java_truststore_path = null
java_truststore_password = null

// MultiQC options
multiqc_config = null
multiqc_title = null
Expand Down Expand Up @@ -219,6 +222,6 @@ manifest {
mainScript = 'main.nf'
nextflowVersion = '!>=23.10.0'
defaultBranch = 'main'
version = '0.2.0'
version = '0.3.0'
doi = ''
}
10 changes: 10 additions & 0 deletions nextflow_schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,16 @@
"description": "Extra arguments to pass to the Seqera Platform CLI command in addition to defaults defined by the pipeline.",
"fa_icon": "fas fa-plus"
},
"java_truststore_path": {
"type": "string",
"description": "Path to custom cacerts Java truststore used by Seqera Platform.",
"fa_icon": "fas fa-key"
},
"java_truststore_password": {
"type": "string",
"description": "Password for custom cacerts Java truststore used by Seqera Platform.",
"fa_icon": "fas fa-key"
},
"skip_run_gantt": {
"type": "boolean",
"description": "Skip GANTT chart creation for each run.",
Expand Down
24 changes: 14 additions & 10 deletions workflows/nf_aggregate/main.nf
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,15 @@ include { paramsSummaryMap } from 'plugin/nf-validation'
workflow NF_AGGREGATE {

take:
ids // channel: run ids read in from --input
multiqc_custom_config // channel: user specified custom config file used by MultiQC
multiqc_logo // channel: logo rendered in MultiQC report
seqera_api_endpoint // val: Seqera Platform API endpoint URL
skip_run_gantt // val: Skip GANTT chart creation for each run
skip_multiqc // val: Skip MultiQC

ids // channel: run ids read in from --input
multiqc_custom_config // channel: user specified custom config file used by MultiQC
multiqc_logo // channel: logo rendered in MultiQC report
seqera_api_endpoint // val: Seqera Platform API endpoint URL
skip_run_gantt // val: Skip GANTT chart creation for each run
skip_multiqc // val: Skip MultiQC
java_truststore_path // val: Path to java truststore if using private certs
java_truststore_password // val: Password for java truststore if using private certs

main:

ch_versions = Channel.empty()
Expand All @@ -30,7 +32,9 @@ workflow NF_AGGREGATE {
//
SEQERA_RUNS_DUMP (
ids,
seqera_api_endpoint
seqera_api_endpoint,
java_truststore_path ?: '',
java_truststore_password ?: ''
)
ch_versions = ch_versions.mix(SEQERA_RUNS_DUMP.out.versions.first())

Expand All @@ -40,9 +44,9 @@ workflow NF_AGGREGATE {
SEQERA_RUNS_DUMP
.out
.run_dump
.filter {
.filter {
meta, run_dir ->
meta.fusion && !params.skip_run_gantt
meta.fusion && !params.skip_run_gantt
}
.set { ch_runs_for_gantt }

Expand Down
2 changes: 2 additions & 0 deletions workflows/nf_aggregate/tests/main.nf.test
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ nextflow_workflow {
input[3] = 'https://api.tower.nf'
input[4] = false
input[5] = false
input[6] = ""
input[7] = ""
"""
}
}
Expand Down
Loading