added versions 3.136,3.13.8 and 3.15.0

This commit is contained in:
Marco Lettere 2023-12-11 09:54:14 +01:00
parent e4585299d4
commit 112395d292
146 changed files with 7579 additions and 17 deletions

View File

@ -0,0 +1,21 @@
FROM nginx:alpine
LABEL maintainer="Nubisware <info@nubisware.com>"
# Bake common configurations for Conductor PEP
COPY config/nginx/nginx.conf /etc/nginx/nginx.conf
COPY config/nginx/pep.js /etc/nginx/pep.js
COPY config/nginx/config.js /etc/nginx/config.js
# Ensure that cache is invalidated
ADD "https://www.random.org/cgi-bin/randbyte?nbytes=10&format=h" skipcache
# Copy compiled UI assets to nginx www directory
WORKDIR /usr/share/nginx/html
RUN rm -rf ./*
COPY build/ .
# Copy NGINX default configuration
COPY default.conf /etc/nginx/conf.d/default.conf

View File

@ -0,0 +1,15 @@
FROM nubisware/conductor-frontend:common
LABEL maintainer="Nubisware <info@nubisware.com>"
# Ensure that cache is invalidated
ADD "https://www.random.org/cgi-bin/randbyte?nbytes=10&format=h" skipcache
# Copy compiled UI assets to nginx www directory
WORKDIR /usr/share/nginx/html
RUN rm -rf ./*
COPY build/ .
# Copy NGINX default configuration
COPY ./config.dev/nginx/conf.d/default.conf /etc/nginx/conf.d/default.conf

View File

@ -0,0 +1,15 @@
FROM nubisware/conductor-frontend:common
LABEL maintainer="Nubisware <info@nubisware.com>"
# Ensure that cache is invalidated
ADD "https://www.random.org/cgi-bin/randbyte?nbytes=10&format=h" skipcache
# Copy compiled UI assets to nginx www directory
WORKDIR /usr/share/nginx/html
RUN rm -rf ./*
COPY build/ .
# Copy NGINX default configuration
COPY ./config.pre/nginx/conf.d/default.conf /etc/nginx/conf.d/default.conf

View File

@ -0,0 +1,15 @@
FROM nubisware/conductor-frontend:common
LABEL maintainer="Nubisware <info@nubisware.com>"
# Ensure that cache is invalidated
ADD "https://www.random.org/cgi-bin/randbyte?nbytes=10&format=h" skipcache
# Copy compiled UI assets to nginx www directory
WORKDIR /usr/share/nginx/html
RUN rm -rf ./*
COPY build/ .
# Copy NGINX default configuration
COPY ./config.prod/nginx/conf.d/default.conf /etc/nginx/conf.d/default.conf

38
v3.13.6/Dockerfile-server Normal file
View File

@ -0,0 +1,38 @@
#
# ===========================================================================================================
# 0. Builder stage
# ===========================================================================================================
FROM eclipse-temurin:11-jdk-focal AS builder
LABEL maintainer="Nubisware SRL"
# Copy the project directly onto the image
COPY ./conductor-community /conductor
COPY build.gradle /conductor/community-server/
WORKDIR /conductor
# Build the server on run
RUN ./gradlew generateLock updateLock saveLock
RUN ./gradlew build -x test --stacktrace
# ===========================================================================================================
# 1. Bin stage
# ===========================================================================================================
FROM eclipse-temurin:11-jre-focal
LABEL maintainer="Nubisware SRL"
# Make app folders
RUN mkdir -p /app/config /app/logs /app/libs
# Copy the compiled output to new image
COPY --from=builder /conductor/community-server/build/libs/conductor-community-server-*-SNAPSHOT-boot.jar /app/libs/conductor-server.jar
COPY ./config.properties /app/config.properties
COPY startup.sh /app/
RUN chmod +x /app/startup.sh
HEALTHCHECK --interval=60s --timeout=30s --retries=10 CMD curl -I -XGET http://localhost:8080/health || exit 1
CMD [ "/app/startup.sh" ]
ENTRYPOINT [ "/bin/sh"]

24
v3.13.6/build-dev-images.sh Executable file
View File

@ -0,0 +1,24 @@
ln -s config.dev/config-pg-es7.properties config.properties
docker build -t nubisware/conductor-server:3.13.6-dev -f Dockerfile-server .
docker push nubisware/conductor-server:3.13.6-dev
unlink config.properties
# Override fetch plugin with one that uses d4s-boot secure fetch
#cp config/fetch.js conductor/ui/src/plugins/fetch.js
# Override root App with one instantiating d4s-boot configured for dev
#cp config.dev/App.jsx conductor/ui/src/App.jsx
# jump to ui code and build
#cd conductor/ui/
#yarn install && yarn build
#cd -
# copy the built app to local folder and build Docker image. The clean up.
#cp -r conductor/ui/build .
#ln -s config.dev/nginx/conf.d/default.conf default.conf
#docker build -t nubisware/conductor-frontend:3.13.6-dev -f Dockerfile-frontend .
#rm -rf build
#unlink default.conf
#docker push nubisware/conductor-frontend:dev

12
v3.13.6/build-pre-images.sh Executable file
View File

@ -0,0 +1,12 @@
docker build -t nubisware/conductor-server3:pre -f Dockerfile-server-pre .
docker push nubisware/conductor-server3:pre
#docker build -t nubisware/conductor-frontend:common -f Dockerfile-frontend .
#cd /home/lettere/git/conductor/ui/
#./build-pre-code.sh
#cd -
#cp -r /home/lettere/git/conductor/ui/build .
#docker build -t nubisware/conductor-frontend:pre -f Dockerfile-frontend-pre .
#rm -rf build
#docker push nubisware/conductor-frontend:pre

4
v3.13.6/build-prepare.sh Executable file
View File

@ -0,0 +1,4 @@
git clone https://github.com/Netflix/conductor
git clone https://github.com/Netflix/conductor-community
find conductor-community/ -name dependencies.lock -exec rm -v {} \;

12
v3.13.6/build-prod-images.sh Executable file
View File

@ -0,0 +1,12 @@
docker build -t nubisware/conductor-server3:prod -f Dockerfile-server-prod .
docker push nubisware/conductor-server3:prod
#docker build -t nubisware/conductor-frontend:common -f Dockerfile-frontend .
#cd /home/lettere/git/conductor/ui/
#./build-prod-code.sh
#cd -
#cp -r /home/lettere/git/conductor/ui/build .
#docker build -t nubisware/conductor-frontend:prod -f Dockerfile-frontend-prod .
#rm -rf build
#docker push nubisware/conductor-frontend:prod

72
v3.13.6/build.gradle Normal file
View File

@ -0,0 +1,72 @@
plugins {
id 'org.springframework.boot'
}
dependencies {
implementation "com.netflix.conductor:conductor-rest:${revConductor}"
implementation "com.netflix.conductor:conductor-core:${revConductor}"
implementation "com.netflix.conductor:conductor-redis-persistence:${revConductor}"
implementation "com.netflix.conductor:conductor-cassandra-persistence:${revConductor}"
implementation "com.netflix.conductor:conductor-grpc-server:${revConductor}"
implementation "com.netflix.conductor:conductor-redis-lock:${revConductor}"
implementation "com.netflix.conductor:conductor-redis-concurrency-limit:${revConductor}"
implementation "com.netflix.conductor:conductor-http-task:${revConductor}"
implementation "com.netflix.conductor:conductor-json-jq-task:${revConductor}"
implementation "com.netflix.conductor:conductor-awss3-storage:${revConductor}"
implementation "com.netflix.conductor:conductor-awssqs-event-queue:${revConductor}"
implementation project(':event-queue:conductor-amqp')
implementation project(':event-queue:conductor-nats')
implementation project(':index:conductor-es7-persistence')
implementation project(':external-payload-storage:conductor-azureblob-storage')
implementation project(':external-payload-storage:conductor-postgres-external-storage')
implementation project(':lock:conductor-zookeeper-lock')
implementation project(':conductor-metrics')
implementation project(':persistence:conductor-common-persistence')
implementation project(':persistence:conductor-postgres-persistence')
implementation project(':persistence:conductor-mysql-persistence')
implementation project(':task:conductor-kafka')
implementation project(':conductor-workflow-event-listener')
implementation 'org.springframework.boot:spring-boot-starter'
implementation 'org.springframework.boot:spring-boot-starter-validation'
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.retry:spring-retry'
implementation 'org.springframework.boot:spring-boot-starter-log4j2'
implementation 'org.apache.logging.log4j:log4j-web'
implementation 'org.springframework.boot:spring-boot-starter-actuator'
implementation "org.springdoc:springdoc-openapi-ui:${revOpenapi}"
runtimeOnly "org.glassfish.jaxb:jaxb-runtime:${revJAXB}"
testImplementation "com.netflix.conductor:conductor-rest:${revConductor}"
testImplementation "com.netflix.conductor:conductor-common:${revConductor}"
testImplementation "io.grpc:grpc-testing:${revGrpc}"
testImplementation "com.google.protobuf:protobuf-java:${revProtoBuf}"
testImplementation "io.grpc:grpc-protobuf:${revGrpc}"
testImplementation "io.grpc:grpc-stub:${revGrpc}"
}
jar {
enabled = true
}
bootJar {
mainClass = 'com.netflix.conductor.Conductor'
classifier = 'boot'
}
springBoot {
buildInfo()
}

View File

@ -0,0 +1,13 @@
{
"files": {
"main.css": "/static/css/main.98e59355.css",
"main.js": "/static/js/main.18fa60f5.js",
"index.html": "/index.html",
"main.98e59355.css.map": "/static/css/main.98e59355.css.map",
"main.18fa60f5.js.map": "/static/js/main.18fa60f5.js.map"
},
"entrypoints": [
"static/css/main.98e59355.css",
"static/js/main.18fa60f5.js"
]
}

52
v3.13.6/build/favicon.svg Normal file
View File

@ -0,0 +1,52 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
viewBox="0 0 419.77176 434.76002"
version="1.1"
id="svg134"
sodipodi:docname="favicon.svg"
width="419.77176"
height="434.76001"
inkscape:version="1.1.2 (b8e25be8, 2022-02-05)"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<sodipodi:namedview
id="namedview136"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
showgrid="false"
inkscape:zoom="1.2341567"
inkscape:cx="208.64449"
inkscape:cy="217.15233"
inkscape:window-width="1296"
inkscape:window-height="932"
inkscape:window-x="2544"
inkscape:window-y="454"
inkscape:window-maximized="0"
inkscape:current-layer="svg134" />
<defs
id="defs124">
<style
id="style122">.cls-1{fill:none;}.cls-2{fill:#1976d2;}</style>
</defs>
<rect
class="cls-1"
width="565"
height="570.42999"
id="rect126"
x="-73.398232"
y="-67.82" />
<path
class="cls-2"
d="m 384.31177,242.99 -59.55,103.19 a 13.52,13.52 0 0 1 -11.67,6.73 h -19.95 l 63.46,-109.92 h -35.47 l -63.45,109.88 h -85.46 a 13.49,13.49 0 0 1 -11.62,-6.69 l -70.490004,-122 a 13.54,13.54 0 0 1 0,-13.48 l 70.450004,-122 a 13.51,13.51 0 0 1 11.67,-6.73 h 67.67 l -13.3,-23.16 a 54.43,54.43 0 0 0 -5.55,-7.6 h -48.83 a 44.3,44.3 0 0 0 -38.26,22.09 l -70.440004,122 a 44.29,44.29 0 0 0 0,44.18 l 70.430004,122 a 44.31,44.31 0 0 0 38.27,22.1 h 140.87 a 44.3,44.3 0 0 0 38.26,-22.09 l 68.42,-118.5 z"
id="path128" />
<path
class="cls-2"
d="m 218.88177,398.93 a 55.89,55.89 0 0 1 -23.16,5.12 h -33.54 a 56.31,56.31 0 0 1 -48.58,-28.07 L 38.211766,245.47 a 56.3,56.3 0 0 1 0,-56.14 L 113.60177,58.81 a 56.29,56.29 0 0 1 48.62,-28.07 h 33.54 a 56.28,56.28 0 0 1 48.62,28.07 l 76.79,133 h 35.43 l -63.46,-109.89 h 19.95 a 13.52,13.52 0 0 1 11.67,6.73 l 59.55,103.16 h 35.46 l -68.41,-118.5 a 44.31,44.31 0 0 0 -38.27,-22.13 h -37.68 l -4.47,-7.76 A 87.11,87.11 0 0 0 195.72177,0 h -33.54 A 87.1,87.1 0 0 0 86.971766,43.42 l -75.37,130.55 a 87.07,87.07 0 0 0 0,86.85 l 75.35,130.52 a 87.1,87.1 0 0 0 75.210004,43.42 h 33.54 a 87,87 0 0 0 70.12,-35.83 z"
id="path130" />
</svg>

After

Width:  |  Height:  |  Size: 2.4 KiB

1
v3.13.6/build/index.html Normal file
View File

@ -0,0 +1 @@
<!doctype html><html lang="en"><head><meta charset="utf-8"/><meta name="viewport" content="width=device-width,initial-scale=1"/><meta name="theme-color" content="#000000"/><title>Conductor UI</title><script defer="defer" src="/static/js/main.18fa60f5.js"></script><link href="/static/css/main.98e59355.css" rel="stylesheet"></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div></body></html>

1
v3.13.6/build/logo.svg Normal file
View File

@ -0,0 +1 @@
<svg version="1.1" id="svg39" width="874.922" height="185.4" xmlns="http://www.w3.org/2000/svg"><defs id="defs11"><style id="style9">.cls-2{fill:#242a36}.cls-3{fill:#1976d2}</style></defs><g id="Layer_2" data-name="Layer 2" transform="translate(-73.828 -68)"><path id="rect13" style="fill:none" d="M0 0h1022.01v320.7H0z"/><path class="cls-2" d="M433.91 140.05q-14.78 0-25 9.56t-10.22 24.58q0 15 10.22 24.65 10.22 9.65 25 9.62a34.71 34.71 0 0 0 24.78-9.62q10.14-9.63 10.15-24.65.01-15.02-10.09-24.58-10.08-9.55-24.84-9.56zm15.15 50.29a21.72 21.72 0 0 1-30.51 0q-6.39-6.27-6.39-16.15 0-9.88 6.39-16.19a21.72 21.72 0 0 1 30.51 0q6.46 6.27 6.46 16.15 0 9.88-6.46 16.19z" id="path15"/><path class="cls-2" d="M515.55 139.66q-14.37 0-22.67 9.88v-8h-13.71v65.38h13.71v-30.23q0-12 5.21-18.18t14.3-6.2a14.28 14.28 0 0 1 11.27 4.88q4.29 4.88 4.28 12.91v36.78h13.84v-39.54q0-12.27-7.25-20t-18.98-7.68z" id="path17"/><path class="cls-2" d="M607 149q-9.09-9.34-23.72-9.35a31 31 0 0 0-22.8 9.75q-9.63 9.75-9.62 24.78.01 15.03 9.59 24.82a31 31 0 0 0 22.8 9.75q14.5 0 23.72-9.22v7.38h13.85V112H607Zm-6.45 41.39a21.06 21.06 0 0 1-15 6.2 20.48 20.48 0 0 1-15.16-6.13q-6.06-6.14-6.06-16.28t6-16.18a20.35 20.35 0 0 1 15.16-6.2 21 21 0 0 1 15 6.26q6.45 6.27 6.45 16.15 0 9.88-6.42 16.19z" id="path19"/><path class="cls-2" d="M682.64 171.68q0 12-5.14 18.2-5.14 6.2-14.23 6.19a14.35 14.35 0 0 1-11.4-4.94q-4.29-4.95-4.28-13V141.5h-13.71v39.41q0 12.39 7.18 20.1 7.18 7.71 19.05 7.71 14.24 0 22.53-9.88v8h13.71V141.5h-13.71z" id="path21"/><path class="cls-2" d="M860.21 140.05q-14.76 0-25 9.56T825 174.19q0 15 10.22 24.65 10.22 9.65 25 9.62a34.67 34.67 0 0 0 24.78-9.62q10.15-9.63 10.15-24.65 0-15.02-10.08-24.58-10.07-9.55-24.86-9.56zm15.16 50.29a21.72 21.72 0 0 1-30.51 0q-6.39-6.27-6.39-16.15 0-9.88 6.39-16.19a21.72 21.72 0 0 1 30.51 0q6.46 6.27 6.46 16.15 0 9.88-6.46 16.19z" id="path23"/><path class="cls-2" d="M944.1 140.71q-15.95 0-24.91 14.76v-14h-13.71v65.38h13.71v-23.04q0-13.83 6.33-21.68t18.48-7.84a36 36 0 0 1 3.82.13l.93-13.18a16.36 16.36 0 0 0-4.65-.53z" id="path25"/><path class="cls-2" d="M347.63 130.18a30.08 30.08 0 0 1 21 9.28 31.21 31.21 0 0 1 7.7 13.48h14.73a44.39 44.39 0 0 0-87.87 9.78q0 19.38 13.38 32.69a43 43 0 0 0 62.07 0 43.7 43.7 0 0 0 12.28-22.27h-14.75a31.37 31.37 0 0 1-7.52 12.86 28.48 28.48 0 0 1-42 0q-9.15-9.44-9.16-23.27-.01-13.83 9.16-23.26a30.08 30.08 0 0 1 20.98-9.29z" id="path27"/><path class="cls-2" d="M740.55 152.31a20.21 20.21 0 0 1 19.85 14.1h13.91a31.94 31.94 0 0 0-9.31-17 35.54 35.54 0 0 0-48.91 0Q706 159.16 706 174.19q0 15.03 10.09 24.81a35.7 35.7 0 0 0 48.91 0 31.68 31.68 0 0 0 9.23-16.67h-13.88a19.45 19.45 0 0 1-4.65 7.71 20.38 20.38 0 0 1-15.15 6q-9.24 0-15.16-6t-5.93-15.88q0-9.62 6-15.75a20.23 20.23 0 0 1 15.09-6.1z" id="path29"/><path class="cls-2" d="M808.24 195.81a10.32 10.32 0 0 1-7.91-3.1q-2.9-3.11-2.9-9v-30.87h22.41V141.5h-22.41v-20.3h-13.7v63.4q0 11.86 6.32 18 6.32 6.14 17.27 6.13 7.77 0 16.21-5l-4.22-11.46a19.91 19.91 0 0 1-11.07 3.54z" id="path31"/><path class="cls-3" d="m237.69 171.63-25.39 44a5.75 5.75 0 0 1-5 2.88h-8.51l27.06-46.86h-15.1l-27.06 46.86h-36.44a5.76 5.76 0 0 1-5-2.88l-30-52a5.74 5.74 0 0 1 0-5.75l30-52a5.75 5.75 0 0 1 5-2.87h28.86l-5.69-9.86a23 23 0 0 0-2.37-3.24h-20.8a18.88 18.88 0 0 0-16.31 9.42l-30 52a18.87 18.87 0 0 0 0 18.84l30 52a18.91 18.91 0 0 0 16.32 9.42h60.07a18.91 18.91 0 0 0 16.32-9.42l29.17-50.53z" id="path33"/><path class="cls-3" d="M167.15 238.13a23.94 23.94 0 0 1-9.88 2.18H143a24 24 0 0 1-20.73-12l-32.16-55.62a24 24 0 0 1 0-23.94l32.13-55.66a24 24 0 0 1 20.73-12h14.3a24 24 0 0 1 20.74 12l32.74 56.71h15.12L198.81 103h8.51a5.76 5.76 0 0 1 5 2.87l25.39 44h15.12l-29.19-50.6a18.91 18.91 0 0 0-16.32-9.42h-16.07l-1.9-3.31A37.15 37.15 0 0 0 157.27 68H143a37.12 37.12 0 0 0-32.1 18.54L78.77 142.2a37.1 37.1 0 0 0 0 37l32.13 55.66A37.12 37.12 0 0 0 143 253.4h14.3a37.11 37.11 0 0 0 29.9-15.27z" id="path35"/></g></svg>

After

Width:  |  Height:  |  Size: 3.8 KiB

3
v3.13.6/build/robots.txt Normal file
View File

@ -0,0 +1,3 @@
# https://www.robotstxt.org/robotstxt.html
User-agent: *
Disallow:

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,151 @@
/*
object-assign
(c) Sindre Sorhus
@license MIT
*/
/*! *****************************************************************************
Copyright (c) Microsoft Corporation.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
***************************************************************************** */
/*! Hammer.JS - v2.0.17-rc - 2019-12-16
* http://naver.github.io/egjs
*
* Forked By Naver egjs
* Copyright (c) hammerjs
* Licensed under the MIT license */
/*! regenerator-runtime -- Copyright (c) 2014-present, Facebook, Inc. -- license (MIT): https://github.com/facebook/regenerator/blob/main/LICENSE */
/**
* @license
* Copyright (c) 2012-2013 Chris Pettitt
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
/**
* @license
* Lodash <https://lodash.com/>
* Copyright OpenJS Foundation and other contributors <https://openjsf.org/>
* Released under MIT license <https://lodash.com/license>
* Based on Underscore.js 1.8.3 <http://underscorejs.org/LICENSE>
* Copyright Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
*/
/**
* A better abstraction over CSS.
*
* @copyright Oleg Isonen (Slobodskoi) / Isonen 2014-present
* @website https://github.com/cssinjs/jss
* @license MIT
*/
/**
* vis-timeline and vis-graph2d
* https://visjs.github.io/vis-timeline/
*
* Create a fully customizable, interactive timeline with items and ranges.
*
* @version 7.7.0
* @date 2022-07-10T21:34:08.601Z
*
* @copyright (c) 2011-2017 Almende B.V, http://almende.com
* @copyright (c) 2017-2019 visjs contributors, https://github.com/visjs
*
* @license
* vis.js is dual licensed under both
*
* 1. The Apache 2.0 License
* http://www.apache.org/licenses/LICENSE-2.0
*
* and
*
* 2. The MIT License
* http://opensource.org/licenses/MIT
*
* vis.js may be distributed under either license.
*/
/** @license React v0.19.1
* scheduler.production.min.js
*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
/** @license React v16.13.1
* react-is.production.min.js
*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
/** @license React v16.14.0
* react-dom.production.min.js
*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
/** @license React v16.14.0
* react-jsx-runtime.production.min.js
*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
/** @license React v16.14.0
* react.production.min.js
*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
/** @license React v17.0.2
* react-is.production.min.js
*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
//! moment.js

File diff suppressed because one or more lines are too long

183
v3.13.6/config.dev/App.jsx Normal file
View File

@ -0,0 +1,183 @@
import React, { Component } from "react";
import { Route, Switch } from "react-router-dom";
import { makeStyles } from "@material-ui/styles";
import { Button, AppBar, Toolbar } from "@material-ui/core";
import AppLogo from "./plugins/AppLogo";
import NavLink from "./components/NavLink";
import WorkflowSearch from "./pages/executions/WorkflowSearch";
import TaskSearch from "./pages/executions/TaskSearch";
import Execution from "./pages/execution/Execution";
import WorkflowDefinitions from "./pages/definitions/Workflow";
import WorkflowDefinition from "./pages/definition/WorkflowDefinition";
import TaskDefinitions from "./pages/definitions/Task";
import TaskDefinition from "./pages/definition/TaskDefinition";
import EventHandlerDefinitions from "./pages/definitions/EventHandler";
import EventHandlerDefinition from "./pages/definition/EventHandler";
import TaskQueue from "./pages/misc/TaskQueue";
import KitchenSink from "./pages/kitchensink/KitchenSink";
import DiagramTest from "./pages/kitchensink/DiagramTest";
import Examples from "./pages/kitchensink/Examples";
import Gantt from "./pages/kitchensink/Gantt";
import CustomRoutes from "./plugins/CustomRoutes";
import AppBarModules from "./plugins/AppBarModules";
import CustomAppBarButtons from "./plugins/CustomAppBarButtons";
import Workbench from "./pages/workbench/Workbench";
import { Helmet } from "react-helmet";
const useStyles = makeStyles((theme) => ({
root: {
backgroundColor: "#efefef",
display: "flex",
},
body: {
width: "100vw",
height: "100vh",
paddingTop: theme.overrides.MuiAppBar.root.height,
},
toolbarRight: {
marginLeft: "auto",
display: "flex",
flexDirection: "row",
},
toolbarRegular: {
minHeight: 80,
},
}));
class AppAuth extends Component{
render(){
return (
<div>
<Helmet>
<script src="https://cdn.dev.d4science.org/boot/d4s-boot.js"></script>
</Helmet>
<d4s-boot-2 url="https://accounts.dev.d4science.org/auth" redirect-url="http://localhost/login/callback" gateway="conductor-ui">
</d4s-boot-2>
</div>
)
}
}
class AppBody extends Component{
constructor(props){
super(props)
this.state = { open : false }
}
setOpen(v){
this.setState({ open : v })
}
componentDidMount() {
document.addEventListener("authenticated", ev=>{
this.setOpen(true)
})
}
render(){
const classes = this.props.classes;
return !this.state.open ? <div></div> : (
<div className={classes.root}>
<AppBar position="fixed">
<Toolbar
classes={{
regular: classes.toolbarRegular,
}}
>
<AppLogo />
<Button component={NavLink} path="/">
Executions
</Button>
<Button component={NavLink} path="/workflowDefs">
Definitions
</Button>
<Button component={NavLink} path="/taskQueue">
Task Queues
</Button>
<Button component={NavLink} path="/workbench">
Workbench
</Button>
<CustomAppBarButtons />
<div className={classes.toolbarRight}>
<AppBarModules />
</div>
</Toolbar>
</AppBar>
<div className={classes.body}>
<Switch>
<Route exact path="/">
<WorkflowSearch />
</Route>
<Route exact path="/search/by-tasks">
<TaskSearch />
</Route>
<Route path="/execution/:id/:taskId?">
<Execution />
</Route>
<Route exact path="/workflowDefs">
<WorkflowDefinitions />
</Route>
<Route exact path="/workflowDef/:name?/:version?">
<WorkflowDefinition />
</Route>
<Route exact path="/taskDefs">
<TaskDefinitions />
</Route>
<Route exact path="/taskDef/:name?">
<TaskDefinition />
</Route>
<Route exact path="/eventHandlerDef">
<EventHandlerDefinitions />
</Route>
<Route exact path="/eventHandlerDef/:name">
<EventHandlerDefinition />
</Route>
<Route exact path="/taskQueue/:name?">
<TaskQueue />
</Route>
<Route exact path="/workbench">
<Workbench />
</Route>
<Route exact path="/kitchen">
<KitchenSink />
</Route>
<Route exact path="/kitchen/diagram">
<DiagramTest />
</Route>
<Route exact path="/kitchen/examples">
<Examples />
</Route>
<Route exact path="/kitchen/gantt">
<Gantt />
</Route>
<CustomRoutes />
</Switch>
</div>
</div>
)
}
}
class AppContent extends Component{
render(){
return(
<div>
<AppAuth/>
<AppBody classes={this.props.classes}/>
</div>
)
}
}
//Keep functional constructor to avoid problems with useStyles
export default function App() {
const classes = useStyles();
return <AppContent classes={classes}/>
}

View File

@ -0,0 +1,11 @@
[common]
loglevel = info
threads = 1
pollrate = 1
[pymail]
server = smtp-relay.d4science.org
user = conductor_dev
password =
protocol = starttls
port = 587

View File

@ -13,6 +13,7 @@ spring.datasource.hikari.minimum-idle=2
conductor.indexing.enabled=true
conductor.elasticsearch.version=7
conductor.elasticsearch.url=http://es:9200
conductor.elasticsearch.clusterHealthColor=yellow
#Enable Prometheus
conductor.metrics-prometheus.enabled=true

View File

@ -0,0 +1,87 @@
upstream conductor_server {
ip_hash;
server conductor-server:8080;
}
map $http_authorization $source_auth {
default "";
}
js_var $auth_token;
js_var $pep_credentials;
server {
listen 80;
server_name conductor conductor.dev.d4science.org;
location / {
# This would be the directory where your React app's static files are stored at
root /usr/share/nginx/html;
try_files $uri /index.html;
}
location /health {
proxy_set_header Host $host;
proxy_pass http://conductor_server;
}
location /actuator/prometheus {
proxy_set_header Host $host;
proxy_pass http://conductor_server;
}
location /api/ {
js_content pep.enforce;
}
location @backend {
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-NginX-Proxy true;
proxy_cache_bypass $http_upgrade;
proxy_redirect off;
proxy_pass http://conductor_server;
}
location /jwt_verify_request {
internal;
proxy_method POST;
proxy_http_version 1.1;
proxy_set_header Authorization $pep_credentials;
proxy_set_header Content-Type "application/x-www-form-urlencoded";
proxy_pass "https://accounts.dev.d4science.org/auth/realms/d4science/protocol/openid-connect/token/introspect";
proxy_ignore_headers Cache-Control Expires Set-Cookie;
gunzip on;
proxy_cache token_responses; # Enable caching
proxy_cache_key $source_auth; # Cache for each source authentication
proxy_cache_lock on; # Duplicate tokens must wait
proxy_cache_valid 200 10s; # How long to use each response
}
location /jwt_request {
internal;
proxy_method POST;
proxy_http_version 1.1;
proxy_set_header Authorization $pep_credentials;
proxy_set_header Content-Type "application/x-www-form-urlencoded";
proxy_pass "https://accounts.dev.d4science.org/auth/realms/d4science/protocol/openid-connect/token";
gunzip on;
}
location /permission_request {
internal;
proxy_method POST;
proxy_http_version 1.1;
proxy_set_header Content-Type "application/x-www-form-urlencoded";
proxy_set_header Authorization "Bearer $auth_token";
proxy_pass "https://accounts.dev.d4science.org/auth/realms/d4science/protocol/openid-connect/token";
gunzip on;
}
}

183
v3.13.6/config.pre/App.jsx Normal file
View File

@ -0,0 +1,183 @@
import React, { Component } from "react";
import { Route, Switch } from "react-router-dom";
import { makeStyles } from "@material-ui/styles";
import { Button, AppBar, Toolbar } from "@material-ui/core";
import AppLogo from "./plugins/AppLogo";
import NavLink from "./components/NavLink";
import WorkflowSearch from "./pages/executions/WorkflowSearch";
import TaskSearch from "./pages/executions/TaskSearch";
import Execution from "./pages/execution/Execution";
import WorkflowDefinitions from "./pages/definitions/Workflow";
import WorkflowDefinition from "./pages/definition/WorkflowDefinition";
import TaskDefinitions from "./pages/definitions/Task";
import TaskDefinition from "./pages/definition/TaskDefinition";
import EventHandlerDefinitions from "./pages/definitions/EventHandler";
import EventHandlerDefinition from "./pages/definition/EventHandler";
import TaskQueue from "./pages/misc/TaskQueue";
import KitchenSink from "./pages/kitchensink/KitchenSink";
import DiagramTest from "./pages/kitchensink/DiagramTest";
import Examples from "./pages/kitchensink/Examples";
import Gantt from "./pages/kitchensink/Gantt";
import CustomRoutes from "./plugins/CustomRoutes";
import AppBarModules from "./plugins/AppBarModules";
import CustomAppBarButtons from "./plugins/CustomAppBarButtons";
import Workbench from "./pages/workbench/Workbench";
import { Helmet } from "react-helmet";
const useStyles = makeStyles((theme) => ({
root: {
backgroundColor: "#efefef",
display: "flex",
},
body: {
width: "100vw",
height: "100vh",
paddingTop: theme.overrides.MuiAppBar.root.height,
},
toolbarRight: {
marginLeft: "auto",
display: "flex",
flexDirection: "row",
},
toolbarRegular: {
minHeight: 80,
},
}));
class AppAuth extends Component{
render(){
return (
<div>
<Helmet>
<script src="https://cdn.pre.d4science.org/boot/d4s-boot.js"></script>
</Helmet>
<d4s-boot-2 url="https://accounts.pre.d4science.org/auth" redirect-url="http://localhost/login/callback" gateway="conductor-ui">
</d4s-boot-2>
</div>
)
}
}
class AppBody extends Component{
constructor(props){
super(props)
this.state = { open : false }
}
setOpen(v){
this.setState({ open : v })
}
componentDidMount() {
document.addEventListener("authenticated", ev=>{
this.setOpen(true)
})
}
render(){
const classes = this.props.classes;
return !this.state.open ? <div></div> : (
<div className={classes.root}>
<AppBar position="fixed">
<Toolbar
classes={{
regular: classes.toolbarRegular,
}}
>
<AppLogo />
<Button component={NavLink} path="/">
Executions
</Button>
<Button component={NavLink} path="/workflowDefs">
Definitions
</Button>
<Button component={NavLink} path="/taskQueue">
Task Queues
</Button>
<Button component={NavLink} path="/workbench">
Workbench
</Button>
<CustomAppBarButtons />
<div className={classes.toolbarRight}>
<AppBarModules />
</div>
</Toolbar>
</AppBar>
<div className={classes.body}>
<Switch>
<Route exact path="/">
<WorkflowSearch />
</Route>
<Route exact path="/search/by-tasks">
<TaskSearch />
</Route>
<Route path="/execution/:id/:taskId?">
<Execution />
</Route>
<Route exact path="/workflowDefs">
<WorkflowDefinitions />
</Route>
<Route exact path="/workflowDef/:name?/:version?">
<WorkflowDefinition />
</Route>
<Route exact path="/taskDefs">
<TaskDefinitions />
</Route>
<Route exact path="/taskDef/:name?">
<TaskDefinition />
</Route>
<Route exact path="/eventHandlerDef">
<EventHandlerDefinitions />
</Route>
<Route exact path="/eventHandlerDef/:name">
<EventHandlerDefinition />
</Route>
<Route exact path="/taskQueue/:name?">
<TaskQueue />
</Route>
<Route exact path="/workbench">
<Workbench />
</Route>
<Route exact path="/kitchen">
<KitchenSink />
</Route>
<Route exact path="/kitchen/diagram">
<DiagramTest />
</Route>
<Route exact path="/kitchen/examples">
<Examples />
</Route>
<Route exact path="/kitchen/gantt">
<Gantt />
</Route>
<CustomRoutes />
</Switch>
</div>
</div>
)
}
}
class AppContent extends Component{
render(){
return(
<div>
<AppAuth/>
<AppBody classes={this.props.classes}/>
</div>
)
}
}
//Keep functional constructor to avoid problems with useStyles
export default function App() {
const classes = useStyles();
return <AppContent classes={classes}/>
}

View File

@ -0,0 +1,11 @@
[common]
loglevel = info
threads = 1
pollrate = 1
[pymail]
server = smtp-relay.d4science.org
user = conductor_pre
password =
protocol = starttls
port = 587

View File

@ -0,0 +1,26 @@
# Database persistence type.
conductor.db.type=postgres
spring.datasource.url=jdbc:postgresql://postgres:5432/conductor
spring.datasource.username=conductor
spring.datasource.password=conductor
# Hikari pool sizes are -1 by default and prevent startup
spring.datasource.hikari.maximum-pool-size=10
spring.datasource.hikari.minimum-idle=2
# Elastic search instance indexing is disabled.
conductor.indexing.enabled=true
conductor.elasticsearch.version=7
conductor.elasticsearch.url=http://es:9200
conductor.elasticsearch.clusterHealthColor=yellow
#Enable Prometheus
conductor.metrics-prometheus.enabled=true
management.endpoints.web.exposure.include=prometheus,health,info,metrics
# GRPC disabled
conductor.grpc-server.enabled=false
# Load sample kitchen sink disabled
loadSample=false

View File

@ -0,0 +1,88 @@
upstream conductor_server {
ip_hash;
server conductor-server:8080;
}
map $http_authorization $source_auth {
default "";
}
js_var $auth_token;
js_var $pep_credentials;
server {
listen 80;
server_name conductor.pre.d4science.org;
location / {
# This would be the directory where your React app's static files are stored at
root /usr/share/nginx/html;
try_files $uri /index.html;
}
location /health {
proxy_set_header Host $host;
proxy_pass http://conductor_server;
}
location /actuator/prometheus {
proxy_set_header Host $host;
proxy_pass http://conductor_server;
}
location /api/ {
js_content pep.enforce;
}
location @backend {
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-NginX-Proxy true;
proxy_cache_bypass $http_upgrade;
proxy_redirect off;
proxy_pass http://conductor_server;
}
location /jwt_verify_request {
internal;
proxy_method POST;
proxy_http_version 1.1;
proxy_set_header Authorization $pep_credentials;
proxy_set_header Content-Type "application/x-www-form-urlencoded";
proxy_set_header Accept-Encoding identity;
proxy_pass "https://accounts.pre.d4science.org/auth/realms/d4science/protocol/openid-connect/token/introspect";
proxy_ignore_headers Cache-Control Expires Set-Cookie;
proxy_cache token_responses; # Enable caching
proxy_cache_key $source_auth; # Cache for each source authentication
proxy_cache_lock on; # Duplicate tokens must wait
proxy_cache_valid 200 10s; # How long to use each response
}
location /jwt_request {
internal;
proxy_method POST;
proxy_http_version 1.1;
proxy_set_header Authorization $pep_credentials;
proxy_set_header Content-Type "application/x-www-form-urlencoded";
proxy_set_header Accept-Encoding identity;
proxy_pass "https://accounts.pre.d4science.org/auth/realms/d4science/protocol/openid-connect/token";
}
location /permission_request {
internal;
proxy_method POST;
proxy_http_version 1.1;
proxy_set_header Content-Type "application/x-www-form-urlencoded";
proxy_set_header Authorization "Bearer $auth_token";
proxy_set_header Accept-Encoding identity;
proxy_pass "https://accounts.pre.d4science.org/auth/realms/d4science/protocol/openid-connect/token";
}
}

183
v3.13.6/config.prod/App.jsx Normal file
View File

@ -0,0 +1,183 @@
import React, { Component } from "react";
import { Route, Switch } from "react-router-dom";
import { makeStyles } from "@material-ui/styles";
import { Button, AppBar, Toolbar } from "@material-ui/core";
import AppLogo from "./plugins/AppLogo";
import NavLink from "./components/NavLink";
import WorkflowSearch from "./pages/executions/WorkflowSearch";
import TaskSearch from "./pages/executions/TaskSearch";
import Execution from "./pages/execution/Execution";
import WorkflowDefinitions from "./pages/definitions/Workflow";
import WorkflowDefinition from "./pages/definition/WorkflowDefinition";
import TaskDefinitions from "./pages/definitions/Task";
import TaskDefinition from "./pages/definition/TaskDefinition";
import EventHandlerDefinitions from "./pages/definitions/EventHandler";
import EventHandlerDefinition from "./pages/definition/EventHandler";
import TaskQueue from "./pages/misc/TaskQueue";
import KitchenSink from "./pages/kitchensink/KitchenSink";
import DiagramTest from "./pages/kitchensink/DiagramTest";
import Examples from "./pages/kitchensink/Examples";
import Gantt from "./pages/kitchensink/Gantt";
import CustomRoutes from "./plugins/CustomRoutes";
import AppBarModules from "./plugins/AppBarModules";
import CustomAppBarButtons from "./plugins/CustomAppBarButtons";
import Workbench from "./pages/workbench/Workbench";
import { Helmet } from "react-helmet";
const useStyles = makeStyles((theme) => ({
root: {
backgroundColor: "#efefef",
display: "flex",
},
body: {
width: "100vw",
height: "100vh",
paddingTop: theme.overrides.MuiAppBar.root.height,
},
toolbarRight: {
marginLeft: "auto",
display: "flex",
flexDirection: "row",
},
toolbarRegular: {
minHeight: 80,
},
}));
class AppAuth extends Component{
render(){
return (
<div>
<Helmet>
<script src="https://cdn.pre.d4science.org/boot/d4s-boot.js"></script>
</Helmet>
<d4s-boot-2 url="https://accounts.d4science.org/auth" redirect-url="http://localhost/login/callback" gateway="conductor-ui">
</d4s-boot-2>
</div>
)
}
}
class AppBody extends Component{
constructor(props){
super(props)
this.state = { open : false }
}
setOpen(v){
this.setState({ open : v })
}
componentDidMount() {
document.addEventListener("authenticated", ev=>{
this.setOpen(true)
})
}
render(){
const classes = this.props.classes;
return !this.state.open ? <div></div> : (
<div className={classes.root}>
<AppBar position="fixed">
<Toolbar
classes={{
regular: classes.toolbarRegular,
}}
>
<AppLogo />
<Button component={NavLink} path="/">
Executions
</Button>
<Button component={NavLink} path="/workflowDefs">
Definitions
</Button>
<Button component={NavLink} path="/taskQueue">
Task Queues
</Button>
<Button component={NavLink} path="/workbench">
Workbench
</Button>
<CustomAppBarButtons />
<div className={classes.toolbarRight}>
<AppBarModules />
</div>
</Toolbar>
</AppBar>
<div className={classes.body}>
<Switch>
<Route exact path="/">
<WorkflowSearch />
</Route>
<Route exact path="/search/by-tasks">
<TaskSearch />
</Route>
<Route path="/execution/:id/:taskId?">
<Execution />
</Route>
<Route exact path="/workflowDefs">
<WorkflowDefinitions />
</Route>
<Route exact path="/workflowDef/:name?/:version?">
<WorkflowDefinition />
</Route>
<Route exact path="/taskDefs">
<TaskDefinitions />
</Route>
<Route exact path="/taskDef/:name?">
<TaskDefinition />
</Route>
<Route exact path="/eventHandlerDef">
<EventHandlerDefinitions />
</Route>
<Route exact path="/eventHandlerDef/:name">
<EventHandlerDefinition />
</Route>
<Route exact path="/taskQueue/:name?">
<TaskQueue />
</Route>
<Route exact path="/workbench">
<Workbench />
</Route>
<Route exact path="/kitchen">
<KitchenSink />
</Route>
<Route exact path="/kitchen/diagram">
<DiagramTest />
</Route>
<Route exact path="/kitchen/examples">
<Examples />
</Route>
<Route exact path="/kitchen/gantt">
<Gantt />
</Route>
<CustomRoutes />
</Switch>
</div>
</div>
)
}
}
class AppContent extends Component{
render(){
return(
<div>
<AppAuth/>
<AppBody classes={this.props.classes}/>
</div>
)
}
}
//Keep functional constructor to avoid problems with useStyles
export default function App() {
const classes = useStyles();
return <AppContent classes={classes}/>
}

View File

@ -0,0 +1,11 @@
[common]
loglevel = info
threads = 1
pollrate = 1
[pymail]
server = smtp-relay.d4science.org
user = conductor_prod
password =
protocol = starttls
port = 587

View File

@ -0,0 +1,26 @@
# Database persistence type.
conductor.db.type=postgres
spring.datasource.url=jdbc:postgresql://postgresql-srv.d4science.org:5432/conductor
spring.datasource.username=conductor_u
spring.datasource.password=c36dda661add7c2b5093087ddb655992
# Hikari pool sizes are -1 by default and prevent startup
spring.datasource.hikari.maximum-pool-size=10
spring.datasource.hikari.minimum-idle=2
# Elastic search instance indexing is disabled.
conductor.indexing.enabled=true
conductor.elasticsearch.version=7
conductor.elasticsearch.url=http://es:9200
conductor.elasticsearch.clusterHealthColor=yellow
#Enable Prometheus
conductor.metrics-prometheus.enabled=true
management.endpoints.web.exposure.include=prometheus,health,info,metrics
# GRPC disabled
conductor.grpc-server.enabled=false
# Load sample kitchen sink disabled
loadSample=false

View File

@ -0,0 +1,88 @@
upstream conductor_server {
ip_hash;
server conductor-server:8080;
}
map $http_authorization $source_auth {
default "";
}
js_var $auth_token;
js_var $pep_credentials;
server {
listen 80;
server_name conductor.d4science.org;
location / {
# This would be the directory where your React app's static files are stored at
root /usr/share/nginx/html;
try_files $uri /index.html;
}
location /health {
proxy_set_header Host $host;
proxy_pass http://conductor_server;
}
location /actuator/prometheus {
proxy_set_header Host $host;
proxy_pass http://conductor_server;
}
location /api/ {
js_content pep.enforce;
}
location @backend {
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-NginX-Proxy true;
proxy_cache_bypass $http_upgrade;
proxy_redirect off;
proxy_pass http://conductor_server;
}
location /jwt_verify_request {
internal;
proxy_method POST;
proxy_http_version 1.1;
proxy_set_header Authorization $pep_credentials;
proxy_set_header Content-Type "application/x-www-form-urlencoded";
proxy_set_header Accept-Encoding identity;
proxy_pass "https://accounts.d4science.org/auth/realms/d4science/protocol/openid-connect/token/introspect";
proxy_ignore_headers Cache-Control Expires Set-Cookie;
proxy_cache token_responses; # Enable caching
proxy_cache_key $source_auth; # Cache for each source authentication
proxy_cache_lock on; # Duplicate tokens must wait
proxy_cache_valid 200 10s; # How long to use each response
}
location /jwt_request {
internal;
proxy_method POST;
proxy_http_version 1.1;
proxy_set_header Authorization $pep_credentials;
proxy_set_header Content-Type "application/x-www-form-urlencoded";
proxy_set_header Accept-Encoding identity;
proxy_pass "https://accounts.d4science.org/auth/realms/d4science/protocol/openid-connect/token";
}
location /permission_request {
internal;
proxy_method POST;
proxy_http_version 1.1;
proxy_set_header Content-Type "application/x-www-form-urlencoded";
proxy_set_header Authorization "Bearer $auth_token";
proxy_set_header Accept-Encoding identity;
proxy_pass "https://accounts.d4science.org/auth/realms/d4science/protocol/openid-connect/token";
}
}

42
v3.13.6/config/fetch.js Normal file
View File

@ -0,0 +1,42 @@
import { useEnv } from "./env";
export function useFetchContext() {
const { stack } = useEnv();
return {
stack,
ready: true,
};
}
export function fetchWithContext(
path,
context,
fetchParams,
isJsonResponse = true
) {
const newParams = { ...fetchParams };
const newPath = `/api/${path}`;
const cleanPath = newPath.replace(/([^:]\/)\/+/g, "$1"); // Cleanup duplicated slashes
const boot = document.querySelector("d4s-boot-2")
return boot.secureFetch(cleanPath, newParams)
.then((res) => Promise.all([res, res.text()]))
.then(([res, text]) => {
if (!res.ok) {
// get error message from body or default to response status
const error = text || res.status;
return Promise.reject(error);
} else if (!text || text.length === 0) {
return null;
} else if (!isJsonResponse) {
return text;
} else {
try {
return JSON.parse(text);
} catch (e) {
return text;
}
}
});
}

View File

@ -0,0 +1,139 @@
export default { config };
var config = {
"hosts" : [
{
"host": ["conductor.d4science.org", "conductor.pre.d4science.org", "conductor.dev.d4science.org", "conductor.int.d4science.net", "conductor"],
"audience" : "conductor-server",
"allow-basic-auth" : true,
"paths" : [
{
"name" : "metadata",
"path" : "^/api/metadata/(taskdefs|workflow)/?.*$",
"methods" : [
{
"method" : "GET",
"scopes" : ["get","list"]
}
]
},
{
"name" : "metadata.taskdefs",
"path" : "^/api/metadata/taskdefs/?.*$",
"methods" : [
{
"method" : "POST",
"scopes" : ["create"]
},
{
"method" : "DELETE",
"scopes" : ["delete"],
},
{
"method" : "PUT",
"scopes" : ["update"],
}
]
},
{
"name" : "metadata.workflow",
"path" : "^/api/metadata/workflow/?.*$",
"methods" : [
{
"method" : "POST",
"scopes" : ["create"]
},
{
"method" : "DELETE",
"scopes" : ["delete"],
},
{
"method" : "PUT",
"scopes" : ["update"],
}
]
},
{
"name" : "workflow",
"path" : "^/api/workflow/?.*$",
"methods" : [
{
"method" : "GET",
"scopes" : ["get"],
},
{
"method" : "POST",
"scopes" : ["start"],
},
{
"method" : "DELETE",
"scopes" : ["terminate"],
}
]
},
{
"name" : "event",
"path" : "^/api/event/?.*$",
"methods" : [
{
"method" : "GET",
"scopes" : ["get"],
},
{
"method" : "POST",
"scopes" : ["create"],
},
{
"method" : "DELETE",
"scopes" : ["delete"],
},
{
"method" : "PUT",
"scopes" : ["update"],
}
]
},
{
"name" : "task",
"path" : "^/api/tasks/poll/.+$",
"methods" : [
{
"method" : "GET",
"scopes" : ["poll"],
}
]
},
{
"name" : "queue",
"path" : "^/api/tasks/queue/.+$",
"methods" : [
{
"method" : "GET",
"scopes" : ["get"],
}
]
},
{
"name" : "task",
"path" : "^/api/tasks[/]?$",
"methods" : [
{
"method" : "POST",
"scopes" : ["update"],
}
]
},
{
"name" : "log",
"path" : "^/api/tasks/.+/log$",
"methods" : [
{
"method" : "GET",
"scopes" : ["get"],
}
]
}
]
}
]
}

View File

@ -0,0 +1,45 @@
# Added to load njs module
load_module modules/ngx_http_js_module.so;
user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log notice;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
}
env pep_credentials;
http {
# added to import pep script
js_import pep.js;
# added to bind enforce function
js_set $authorization pep.enforce;
# added to create cache for tokens and auth calls
proxy_cache_path /var/cache/nginx/pep keys_zone=token_responses:1m max_size=2m;
include /etc/nginx/mime.types;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
sendfile on;
#tcp_nopush on;
keepalive_timeout 65;
#gzip on;
include /etc/nginx/conf.d/*.conf;
}

332
v3.13.6/config/nginx/pep.js Normal file
View File

@ -0,0 +1,332 @@
export default { enforce };
import defaultExport from './config.js';
function log(c, s){
c.request.error(s)
}
var _debug = true
function debug(c, s){
if(_debug === true){
log(c, s)
}
}
function enforce(r) {
var context = {
request: r ,
config : defaultExport["config"],
backend : (defaultExport.backend ? defaultExport.backend : "@backend")
}
log(context, "Inside NJS enforce for " + r.method + " @ " + r.headersIn.host + "/" + r.uri)
context = computeProtection(context)
wkf.run(wkf.build(context), context)
}
// ######## WORKFLOW FUNCTIONS ###############
var wkf = {
build : (context)=>{
var actions = [
"export_pep_credentials",
"parse_authentication",
"check_authentication",
"export_authn_token",
"pip",
"pdp",
"export_backend_headers",
"pass"
]
return actions
},
run : (actions, context) => {
context.request.error("Starting workflow with " + njs.dump(actions))
var w = actions.reduce(
(acc, f) => { return acc.then(typeof(f) === "function" ? f : wkf[f]) },
Promise.resolve().then(()=>context)
)
w.catch(e => { context.request.error(njs.dump(e)); context.request.return(401)} )
},
export_pep_credentials : exportPepCredentials,
export_authn_token : exportAuthToken,
export_backend_headers : exportBackendHeaders,
parse_authentication : parseAuthentication,
check_authentication : checkAuthentication,
verify_token : verifyToken,
request_token : requestToken,
pip : pipExecutor,
pdp : pdpExecutor,
pass : pass,
//PIP utilities
"get-path-component" : (c, i) => c.request.uri.split("/")[i],
"get-token-field" : getTokenField,
"get-contexts" : (c) => {
var ra = c.authn.verified_token["resource_access"]
if(ra){
var out = [];
for(var k in ra){
if(ra[k].roles && ra[k].roles.length !== 0) out.push(k)
}
}
return out;
}
}
function getTokenField(context, f){
return context.authn.verified_token[f]
}
function exportVariable(context, name, value){
context.request.variables[name] = value
return context
}
function exportBackendHeaders(context){
return context
}
function exportPepCredentials(context){
if(process.env["pep_credentials"] || process.env["PEP_CREDENTIALS"]){
return exportVariable(context, "pep_credentials", "Basic " + process.env["PEP_CREDENTIALS"])
}else if(context.config["pep_credentials"]){
return exportVariable(context, "pep_credentials", "Basic " + context.config["pep_credentials"])
}else{
throw new Error("Need PEP credentials")
}
}
function exportAuthToken(context){
return exportVariable(context, "auth_token", context.authn.token)
}
function checkAuthentication(context){
return context.authn.type === "bearer" ? wkf.verify_token(context) : wkf.request_token(context)
}
function parseAuthentication(context){
context.request.log("Inside parseAuthentication")
var incomingauth = context.request.headersIn["Authorization"]
if(!incomingauth) throw new Error("Authentication required");
var arr = incomingauth.trim().replace(/\s\s+/g, " ").split(" ")
if(arr.length != 2) throw new Error("Unknown authentication scheme");
var type = arr[0].toLowerCase()
if(type === "basic" && context.authz.host && context.authz.host["allow-basic-auth"]){
var unamepass = Buffer.from(arr[1], 'base64').toString().split(":")
if(unamepass.length != 2) return null;
context.authn = { type : type, raw : arr[1], user : unamepass[0], password : unamepass[1]}
return context
}else if(type === "bearer"){
context.authn = { type : type, raw : arr[1], token : arr[1]}
return context
}
throw new Error("Unknown authentication scheme");
}
function verifyToken(context){
log(context, "Inside verifyToken")
debug(context, "Token is " + context.authn.token)
var options = {
"body" : "token=" + context.authn.token + "&token_type_hint=access_token"
}
return context.request.subrequest("/jwt_verify_request", options)
.then(reply=>{
if (reply.status === 200) {
var response = JSON.parse(reply.responseBody);
if (response.active === true) {
return response
} else {
throw new Error("Unauthorized: " + reply.responseBody)
}
} else {
throw new Error("Unauthorized: " + reply.responseBody)
}
}).then(verified_token => {
context.authn.verified_token =
JSON.parse(Buffer.from(context.authn.token.split('.')[1], 'base64url').toString())
return context
})
}
function requestToken(context){
log(context, "Inside requestToken")
var options = {
"body" : "grant_type=client_credentials&client_id="+context.authn.user+"&client_secret="+context.authn.password
}
return context.request.subrequest("/jwt_request", options)
.then(reply=>{
if (reply.status === 200) {
var response = JSON.parse(reply.responseBody);
context.authn.token = response.access_token
context.authn.verified_token =
JSON.parse(Buffer.from(context.authn.token.split('.')[1], 'base64url').toString())
return context
} else if (reply.status === 400 || reply.status === 401){
var options = {
"body" : "grant_type=password&username="+context.authn.user+"&password="+context.authn.password
}
return context.request.subrequest("/jwt_request", options)
.then( reply=>{
if (reply.status === 200) {
var response = JSON.parse(reply.responseBody);
context.authn.token = response.access_token
context.authn.verified_token =
JSON.parse(Buffer.from(context.authn.token.split('.')[1], 'base64url').toString())
return context
} else{
throw new Error("Unauthorized " + reply.status)
}
})
} else {
throw new Error("Unauthorized " + reply.status)
}
})
}
function pipExecutor(context){
log(context, "Inside extra claims PIP")
context.authz.pip.forEach(extra =>{
//call extra claim pip function
try{
var operator = extra.operator
var result = wkf[operator](context, extra.args)
//ensure array and add to extra_claims
if(!(result instanceof Array)) result = [result]
if(!context.extra_claims) context.extra_claims = {};
context.extra_claims[extra.claim] = result
} catch (error){
log(context, "Skipping invalid extra claim " + njs.dump(error))
}
})
log(context, "Extra claims are " + njs.dump(context.extra_claims))
return context
}
function pdpExecutor(context){
log(context, "Inside PDP")
return context.authz.pdp(context)
}
function umaCall(context){
log(context, "Inside UMA call")
var options = { "body" : computePermissionRequestBody(context) };
return context.request.subrequest("/permission_request", options)
.then(reply =>{
if(reply.status === 200){
debug(context, "UMA call reply is " + reply.status)
return context
}else{
throw new Error("Response for authorization request is not ok " + reply.status + " " + njs.dump(reply.responseBody))
}
})
}
function pass(context){
log(context, "Inside pass");
if(typeof(context.backend) === "string") context.request.internalRedirect(context.backend);
else if (typeof(context.backend) === "function") context.request.internalRedirect(context.backend(context))
return context;
}
// ######## AUTHORIZATION PART ###############
function computePermissionRequestBody(context){
if(!context.authz.host || !context.authz.path ){
throw new Error("Enforcemnt mode is always enforcing. Host or path not found...")
}
var audience = computeAudience(context)
var grant = "grant_type=urn:ietf:params:oauth:grant-type:uma-ticket"
var mode = "response_mode=decision"
var permissions = computePermissions(context)
var extra = ""
if(context.extra_claims){
extra =
"claim_token_format=urn:ietf:params:oauth:token-type:jwt&claim_token=" +
JSON.stringify(context.extra_claims).toString("base64url")
}
var body = audience + "&" + grant + "&" + permissions + "&" + mode + "&" + extra
context.request.error("Computed permission request body is " + body)
return body
}
function computeAudience(context){
var aud = context.request.headersIn.host
if(context.authz.host){
aud = context.authz.host.audience||context.authz.host.host
}
return "audience=" + aud
}
function computePermissions(context){
var resource = context.request.uri
if(context.authz.path){
resource = context.authz.path.name||context.authz.path.path
}
var scopes = []
if(context.authz.method && context.authz.method.scopes){
scopes = context.authz.method.scopes
}
if(scopes.length > 0){
return scopes.map(s=>"permission=" + resource + "#" + s).join("&")
}
return "permission=" + resource
}
function getPath(hostconfig, incomingpath, incomingmethod){
var paths = hostconfig.paths || []
var matchingpaths = paths
.filter(p => {return incomingpath.match(p.path) != null})
.reduce((acc, p) => {
if (!p.methods || p.methods.length === 0) acc.weak.push({ path: p});
else{
var matchingmethods = p.methods.filter(m=>m.method.toUpperCase() === incomingmethod)
if(matchingmethods.length > 0) acc.strong.push({ method : matchingmethods[0], path: p});
}
return acc;
}, { strong: [], weak: []})
return matchingpaths.strong.concat(matchingpaths.weak)[0]
}
function getHost(config, host){
var matching = config.hosts.filter(h=>{
//compare for both string and array of strings
return ((h.host.filter && h.host.indexOf(host) !== -1) || h.host === host)
})
return matching.length > 0 ? matching[0] : null
}
function computeProtection(context){
debug(context, "Getting by host " + context.request.headersIn.host)
context.authz = {}
context.authz.host = getHost(context.config, context.request.headersIn.host)
if(context.authz.host !== null){
log(context, "Host found:" + context.authz.host)
context.authz.pip = context.authz.host.pip ? context.authz.host.pip : [];
context.authz.pdp = context.authz.host.pdp ? context.authz.host.pdp : umaCall;
var pathandmethod = getPath(context.authz.host, context.request.uri, context.request.method);
if(pathandmethod){
context.authz.path = pathandmethod.path;
context.authz.pip = context.authz.path.pip ? context.authz.pip.concat(context.authz.path.pip) : context.authz.pip;
context.authz.pdp = context.authz.path.pdp ? context.authz.path.pdp : context.authz.pdp;
context.authz.method = pathandmethod.method;
if(context.authz.method){
context.authz.pip = context.authz.method.pip ? context.authz.pip.concat(context.authz.method.pip) : context.authz.pip;
context.authz.pdp = context.authz.method.pdp ? context.authz.method.pdp : context.authz.pdp;
}
}
}
debug(context, "Leaving protection computation: ")
return context
}

View File

@ -0,0 +1,150 @@
version: '3.6'
services:
postgres:
image: postgres:14
environment:
- POSTGRES_USER=conductor
- POSTGRES_PASSWORD=conductor
volumes:
- pg_db_data:/var/lib/postgresql/data
networks:
- conductor-network
healthcheck:
test: timeout 5 bash -c 'cat < /dev/null > /dev/tcp/localhost/5432'
interval: 5s
timeout: 5s
retries: 12
deploy:
mode: replicated
replicas: 1
restart_policy:
condition: any
delay: 5s
window: 120s
placement:
constraints: [node.role == worker]
logging:
driver: "journald"
es:
image: elasticsearch:7.6.2
environment:
- "ES_JAVA_OPTS=-Xms512m -Xmx1024m"
- transport.host=0.0.0.0
- discovery.type=single-node
- xpack.security.enabled=false
volumes:
- es_data:/usr/share/elasticsearch/data
networks:
- conductor-network
healthcheck:
test: timeout 5 bash -c 'cat < /dev/null > /dev/tcp/localhost/9300'
interval: 5s
timeout: 5s
retries: 12
deploy:
mode: replicated
replicas: 1
restart_policy:
condition: any
delay: 5s
window: 120s
placement:
constraints: [node.role == worker]
logging:
driver: "journald"
conductor-server:
environment:
- CONFIG_PROP=config.properties
image: "nubisware/conductor-server3:dev"
networks:
- conductor-network
deploy:
mode: replicated
replicas: 1
restart_policy:
condition: any
delay: 5s
window: 120s
placement:
constraints: [node.role == worker]
logging:
driver: "journald"
pep:
image: "nubisware/conductor-frontend:dev"
networks:
- conductor-network
- haproxy-public
deploy:
mode: replicated
endpoint_mode: dnsrr
replicas: 1
restart_policy:
condition: any
delay: 5s
window: 120s
placement:
constraints: [node.role == worker]
environment:
pep_credentials: ${pep_credentials}
workers:
environment:
CONDUCTOR_SERVER: http://conductor-server:8080/api/
CONDUCTOR_HEALTH: http://conductor-server:8080/health
worker_plugins: "Shell Eval Mail HttpBridge"
smtp_pass: ${smtp_pass}
smtp_user: ${smtp_user}
image: 'nubisware/nubisware-conductor-worker-py-d4s'
networks:
- conductor-network
deploy:
mode: replicated
replicas: 2
restart_policy:
condition: any
delay: 5s
window: 120s
logging:
driver: "journald"
pyrestworkers:
environment:
CONDUCTOR_SERVER: http://conductor-server:8080/api/
CONDUCTOR_HEALTH: http://conductor-server:8080/health
worker_plugins: Http
image: 'nubisware/nubisware-conductor-worker-py-d4s'
networks:
- conductor-network
deploy:
mode: replicated
replicas: 2
restart_policy:
condition: any
delay: 5s
window: 120s
logging:
driver: "journald"
networks:
conductor-network:
haproxy-public:
external: true
volumes:
pg_db_data:
driver: local
driver_opts:
type: nfs4
o: "nfsvers=4,addr=146.48.123.250,rw"
device: ":/nfs/conductor_pg_dev"
es_data:
driver: local
driver_opts:
type: nfs4
o: "nfsvers=4,addr=146.48.123.250,rw"
device: ":/nfs/conductor_es_dev"

View File

@ -0,0 +1,122 @@
version: '3.6'
services:
postgres:
image: postgres:14
environment:
- POSTGRES_USER=conductor
- POSTGRES_PASSWORD=conductor
networks:
- conductor-network
ports:
- "5432:5432"
healthcheck:
test: timeout 5 bash -c 'cat < /dev/null > /dev/tcp/localhost/5432'
interval: 5s
timeout: 5s
retries: 12
deploy:
mode: replicated
replicas: 1
restart_policy:
condition: any
delay: 5s
window: 120s
logging:
driver: "journald"
es:
image: elasticsearch:7.6.2
environment:
- "ES_JAVA_OPTS=-Xms512m -Xmx1024m"
- transport.host=0.0.0.0
- discovery.type=single-node
- xpack.security.enabled=false
networks:
- conductor-network
ports:
- "9200:9200"
healthcheck:
test: timeout 5 bash -c 'cat < /dev/null > /dev/tcp/localhost/9300'
interval: 5s
timeout: 5s
retries: 12
deploy:
mode: replicated
replicas: 1
restart_policy:
condition: any
delay: 5s
window: 120s
logging:
driver: "journald"
conductor-server:
image: "nubisware/conductor-server:3.13.6-dev"
networks:
- conductor-network
deploy:
mode: replicated
replicas: 1
restart_policy:
condition: any
delay: 5s
window: 120s
logging:
driver: "journald"
pep:
image: "nubisware/conductor-frontend:3.13.6-dev"
networks:
- conductor-network
ports:
- "80:80"
deploy:
mode: replicated
replicas: 1
restart_policy:
condition: any
delay: 5s
window: 120s
environment:
pep_credentials: ${pep_credentials}
workers:
environment:
CONDUCTOR_SERVER: http://conductor-server:8080/api/
CONDUCTOR_HEALTH: http://conductor-server:8080/health
worker_plugins: "Shell Eval Mail HttpBridge"
smtp_pass: ${smtp_pass}
image: 'nubisware/nubisware-conductor-worker-py-d4s:dev'
networks:
- conductor-network
deploy:
mode: replicated
replicas: 2
restart_policy:
condition: any
delay: 5s
window: 120s
logging:
driver: "journald"
pyrestworkers:
environment:
CONDUCTOR_SERVER: http://conductor-server:8080/api/
CONDUCTOR_HEALTH: http://conductor-server:8080/health
worker_plugins: Http
image: 'nubisware/nubisware-conductor-worker-py-d4s:dev'
networks:
- conductor-network
deploy:
mode: replicated
replicas: 2
restart_policy:
condition: any
delay: 5s
window: 120s
logging:
driver: "journald"
networks:
conductor-network:

View File

@ -0,0 +1,153 @@
version: '3.6'
services:
postgres:
image: postgres:14
environment:
- POSTGRES_USER=conductor
- POSTGRES_PASSWORD=conductor
volumes:
- pg_db_data:/var/lib/postgresql/data
networks:
- conductor-network
healthcheck:
test: timeout 5 bash -c 'cat < /dev/null > /dev/tcp/localhost/5432'
interval: 5s
timeout: 5s
retries: 12
deploy:
mode: replicated
replicas: 1
restart_policy:
condition: any
delay: 5s
window: 120s
placement:
constraints: [node.role == worker]
logging:
driver: "journald"
es:
image: elasticsearch:7.6.2
environment:
- "ES_JAVA_OPTS=-Xms512m -Xmx1024m"
- transport.host=0.0.0.0
- discovery.type=single-node
- xpack.security.enabled=false
volumes:
- es_data:/usr/share/elasticsearch/data
networks:
- conductor-network
healthcheck:
test: timeout 5 bash -c 'cat < /dev/null > /dev/tcp/localhost/9300'
interval: 5s
timeout: 5s
retries: 12
deploy:
mode: replicated
replicas: 1
restart_policy:
condition: any
delay: 5s
window: 120s
placement:
constraints: [node.role == worker]
logging:
driver: "journald"
conductor-server:
environment:
- CONFIG_PROP=config.properties
image: "nubisware/conductor-server3:pre"
networks:
- conductor-network
deploy:
mode: replicated
replicas: 1
restart_policy:
condition: any
delay: 5s
window: 120s
placement:
constraints: [node.role == worker]
logging:
driver: "journald"
pep:
image: "nubisware/conductor-frontend:pre"
networks:
- conductor-network
- haproxy-public
deploy:
mode: replicated
endpoint_mode: dnsrr
replicas: 1
restart_policy:
condition: any
delay: 5s
window: 120s
placement:
constraints: [node.role == worker]
environment:
pep_credentials: ${pep_credentials}
workers:
environment:
CONDUCTOR_SERVER: http://conductor-server:8080/api/
CONDUCTOR_HEALTH: http://conductor-server:8080/health
worker_plugins: "Shell Eval Mail HttpBridge"
smtp_pass: ${smtp_pass}
smtp_user: ${smtp_user}
image: 'nubisware/nubisware-conductor-worker-py-d4s'
networks:
- conductor-network
deploy:
mode: replicated
replicas: 2
restart_policy:
condition: any
delay: 5s
window: 120s
placement:
constraints: [node.role == worker]
logging:
driver: "journald"
pyrestworkers:
environment:
CONDUCTOR_SERVER: http://conductor-server:8080/api/
CONDUCTOR_HEALTH: http://conductor-server:8080/health
worker_plugins: Http
image: 'nubisware/nubisware-conductor-worker-py-d4s'
networks:
- conductor-network
deploy:
mode: replicated
replicas: 2
restart_policy:
condition: any
delay: 5s
window: 120s
placement:
constraints: [node.role == worker]
logging:
driver: "journald"
networks:
conductor-network:
haproxy-public:
external: true
volumes:
pg_db_data:
driver: local
driver_opts:
type: nfs4
o: "nfsvers=4,addr=146.48.123.250,rw"
device: ":/nfs/conductor_pg_pre"
es_data:
driver: local
driver_opts:
type: nfs4
o: "nfsvers=4,addr=146.48.123.250,rw"
device: ":/nfs/conductor_es_pre"

View File

@ -0,0 +1,122 @@
version: '3.6'
services:
es:
image: elasticsearch:7.6.2
volumes:
- es_data:/usr/share/elasticsearch/data
environment:
- "ES_JAVA_OPTS=-Xms512m -Xmx1024m"
- transport.host=0.0.0.0
- discovery.type=single-node
- xpack.security.enabled=false
networks:
- conductor-network
healthcheck:
test: timeout 5 bash -c 'cat < /dev/null > /dev/tcp/localhost/9300'
interval: 5s
timeout: 5s
retries: 12
deploy:
mode: replicated
replicas: 1
restart_policy:
condition: any
delay: 5s
window: 120s
placement:
constraints: [node.role == worker]
logging:
driver: "journald"
conductor-server:
environment:
- CONFIG_PROP=config.properties
image: "nubisware/conductor-server3:prod"
networks:
- conductor-network
deploy:
mode: replicated
replicas: 1
restart_policy:
condition: any
delay: 5s
window: 120s
placement:
constraints: [node.role == worker]
logging:
driver: "journald"
pep:
image: "nubisware/conductor-frontend:prod"
networks:
- conductor-network
- haproxy-public
deploy:
mode: replicated
endpoint_mode: dnsrr
replicas: 1
restart_policy:
condition: any
delay: 5s
window: 120s
placement:
constraints: [node.role == worker]
environment:
pep_credentials: ${pep_credentials}
workers:
environment:
CONDUCTOR_SERVER: http://conductor-server:8080/api/
CONDUCTOR_HEALTH: http://conductor-server:8080/health
worker_plugins: "Shell Eval Mail HttpBridge"
smtp_pass: ${smtp_pass}
smtp_user: ${smtp_user}
image: 'nubisware/nubisware-conductor-worker-py-d4s'
networks:
- conductor-network
deploy:
mode: replicated
replicas: 2
restart_policy:
condition: any
delay: 5s
window: 120s
placement:
constraints: [node.role == worker]
logging:
driver: "journald"
pyrestworkers:
environment:
CONDUCTOR_SERVER: http://conductor-server:8080/api/
CONDUCTOR_HEALTH: http://conductor-server:8080/health
worker_plugins: Http
image: 'nubisware/nubisware-conductor-worker-py-d4s'
networks:
- conductor-network
deploy:
mode: replicated
replicas: 4
restart_policy:
condition: any
delay: 5s
window: 120s
placement:
constraints: [node.role == worker]
logging:
driver: "journald"
networks:
conductor-network:
haproxy-public:
external: true
volumes:
es_data:
driver: local
driver_opts:
type: nfs4
o: "nfsvers=4,addr=146.48.123.250,rw"
device: ":/nfs/conductor_es_prod"

27
v3.13.6/startup.sh Executable file
View File

@ -0,0 +1,27 @@
#!/bin/sh
#
# Copyright 2021 Netflix, Inc.
# <p>
# Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
# <p>
# http://www.apache.org/licenses/LICENSE-2.0
# <p>
# Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
# an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
# specific language governing permissions and limitations under the License.
#
# startup.sh - startup script for the server docker image
echo "Starting Conductor server"
if curl es:9200; then echo ES found; else exit 1; fi;
# Start the server
cd /app/libs
config_file=/app/config.properties
echo "Using java options config: $JAVA_OPTS"
java ${JAVA_OPTS} -jar -DCONDUCTOR_CONFIG_FILE=$config_file conductor-server.jar 2>&1 | tee -a /app/logs/server.log

4
v3.13.6/yarn.lock Normal file
View File

@ -0,0 +1,4 @@
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
# yarn lockfile v1

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

View File

@ -0,0 +1,2 @@
#Mon Oct 09 18:00:18 CEST 2023
gradle.version=7.4.2

View File

View File

@ -0,0 +1,21 @@
FROM nginx:alpine
LABEL maintainer="Nubisware <info@nubisware.com>"
# Bake common configurations for Conductor PEP
COPY config/nginx/nginx.conf /etc/nginx/nginx.conf
COPY config/nginx/pep.js /etc/nginx/pep.js
COPY config/nginx/config.js /etc/nginx/config.js
# Ensure that cache is invalidated
ADD "https://www.random.org/cgi-bin/randbyte?nbytes=10&format=h" skipcache
# Copy compiled UI assets to nginx www directory
WORKDIR /usr/share/nginx/html
RUN rm -rf ./*
COPY build/ .
# Copy NGINX default configuration
COPY default.conf /etc/nginx/conf.d/default.conf

36
v3.13.8/Dockerfile-server Normal file
View File

@ -0,0 +1,36 @@
#
# ===========================================================================================================
# 0. Builder stage
# ===========================================================================================================
FROM eclipse-temurin:11-jdk-focal AS builder
LABEL maintainer="Nubisware SRL"
# Copy the project directly onto the image
COPY ./conductor-community /conductor
WORKDIR /conductor
# Build the server on run
RUN ./gradlew generateLock updateLock saveLock
RUN ./gradlew build -x test --stacktrace
# ===========================================================================================================
# 1. Bin stage
# ===========================================================================================================
FROM eclipse-temurin:11-jre-focal
LABEL maintainer="Nubisware SRL"
# Make app folders
RUN mkdir -p /app/config /app/logs /app/libs
# Copy the compiled output to new image
COPY --from=builder /conductor/community-server/build/libs/conductor-community-server-*-SNAPSHOT-boot.jar /app/libs/conductor-server.jar
COPY ./config.properties /app/config.properties
COPY ./startup.sh /app/startup.sh
HEALTHCHECK --interval=60s --timeout=30s --retries=10 CMD curl -I -XGET http://localhost:8080/health || exit 1
CMD [ "/app/startup.sh" ]
ENTRYPOINT [ "/bin/sh"]

43
v3.13.8/build-images.sh Executable file
View File

@ -0,0 +1,43 @@
#!/usr/bin/env bash
if [ $# -eq 0 ]
then
tag='dev'
else
tag=$1
fi
CONDUCTOR_VERSION=v3.13.8
rm -rf conductor conductor-community
git clone https://github.com/Netflix/conductor -b $CONDUCTOR_VERSION
git clone https://github.com/Netflix/conductor-community -b $CONDUCTOR_VERSION
find conductor-community/ -name dependencies.lock -exec rm -v {} \;
# Build conductor server
ln -s config.$tag/config.properties config.properties
ln -s config/startup.sh startup.sh
docker build --no-cache -t hub.dev.d4science.org/conductor/server:$CONDUCTOR_VERSION-$tag -f Dockerfile-server .
docker push hub.dev.d4science.org/conductor/server:$CONDUCTOR_VERSION-$tag
unlink config.properties
unlink startup.sh
exit 0
# Override fetch plugin with one that uses d4s-boot secure fetch
cp config/fetch.js conductor/ui/src/plugins/fetch.js
# Override root App with one instantiating d4s-boot configured for dev
cp config.$tag/App.jsx conductor/ui/src/App.jsx
# jump to ui code and build
cd conductor/ui/
yarn install && yarn build
cd -
# copy the built app to local folder and build Docker image. The clean up.
cp -r conductor/ui/build .
ln -s config.$tag/nginx/conf.d/default.conf default.conf
docker build --no-cache -t hub.dev.d4science.org/conductor/frontend:$CONDUCTOR_VERSION-$tag -f Dockerfile-frontend .
#docker push hub.dev.d4science.org/conductor/frontend:$CONDUCTOR_VERSION-$tag
rm -rf build
unlink default.conf

183
v3.13.8/config.dev/App.jsx Normal file
View File

@ -0,0 +1,183 @@
import React, { Component } from "react";
import { Route, Switch } from "react-router-dom";
import { makeStyles } from "@material-ui/styles";
import { Button, AppBar, Toolbar } from "@material-ui/core";
import AppLogo from "./plugins/AppLogo";
import NavLink from "./components/NavLink";
import WorkflowSearch from "./pages/executions/WorkflowSearch";
import TaskSearch from "./pages/executions/TaskSearch";
import Execution from "./pages/execution/Execution";
import WorkflowDefinitions from "./pages/definitions/Workflow";
import WorkflowDefinition from "./pages/definition/WorkflowDefinition";
import TaskDefinitions from "./pages/definitions/Task";
import TaskDefinition from "./pages/definition/TaskDefinition";
import EventHandlerDefinitions from "./pages/definitions/EventHandler";
import EventHandlerDefinition from "./pages/definition/EventHandler";
import TaskQueue from "./pages/misc/TaskQueue";
import KitchenSink from "./pages/kitchensink/KitchenSink";
import DiagramTest from "./pages/kitchensink/DiagramTest";
import Examples from "./pages/kitchensink/Examples";
import Gantt from "./pages/kitchensink/Gantt";
import CustomRoutes from "./plugins/CustomRoutes";
import AppBarModules from "./plugins/AppBarModules";
import CustomAppBarButtons from "./plugins/CustomAppBarButtons";
import Workbench from "./pages/workbench/Workbench";
import { Helmet } from "react-helmet";
const useStyles = makeStyles((theme) => ({
root: {
backgroundColor: "#efefef", // TODO: Use theme var
display: "flex",
},
body: {
width: "100vw",
height: "100vh",
paddingTop: theme.overrides.MuiAppBar.root.height,
},
toolbarRight: {
marginLeft: "auto",
display: "flex",
flexDirection: "row",
},
toolbarRegular: {
minHeight: 80,
},
}));
class AppAuth extends Component{
render(){
return (
<div>
<Helmet>
<script src="https://cdn.dev.d4science.org/boot/d4s-boot.js"></script>
</Helmet>
<d4s-boot-2 url="https://accounts.dev.d4science.org/auth" redirect-url="http://localhost/login/callback" gateway="conductor-ui">
</d4s-boot-2>
</div>
)
}
}
class AppBody extends Component{
constructor(props){
super(props)
this.state = { open : false }
}
setOpen(v){
this.setState({ open : v })
}
componentDidMount() {
document.addEventListener("authenticated", ev=>{
this.setOpen(true)
})
}
render(){
const classes = this.props.classes;
return !this.state.open ? <div></div> : (
<div className={classes.root}>
<AppBar position="fixed">
<Toolbar
classes={{
regular: classes.toolbarRegular,
}}
>
<AppLogo />
<Button component={NavLink} path="/">
Executions
</Button>
<Button component={NavLink} path="/workflowDefs">
Definitions
</Button>
<Button component={NavLink} path="/taskQueue">
Task Queues
</Button>
<Button component={NavLink} path="/workbench">
Workbench
</Button>
<CustomAppBarButtons />
<div className={classes.toolbarRight}>
<AppBarModules />
</div>
</Toolbar>
</AppBar>
<div className={classes.body}>
<Switch>
<Route exact path="/">
<WorkflowSearch />
</Route>
<Route exact path="/search/tasks">
<TaskSearch />
</Route>
<Route path="/execution/:id/:taskId?">
<Execution />
</Route>
<Route exact path="/workflowDefs">
<WorkflowDefinitions />
</Route>
<Route exact path="/workflowDef/:name?/:version?">
<WorkflowDefinition />
</Route>
<Route exact path="/taskDefs">
<TaskDefinitions />
</Route>
<Route exact path="/taskDef/:name?">
<TaskDefinition />
</Route>
<Route exact path="/eventHandlerDef">
<EventHandlerDefinitions />
</Route>
<Route exact path="/eventHandlerDef/:name">
<EventHandlerDefinition />
</Route>
<Route exact path="/taskQueue/:name?">
<TaskQueue />
</Route>
<Route exact path="/workbench">
<Workbench />
</Route>
<Route exact path="/kitchen">
<KitchenSink />
</Route>
<Route exact path="/kitchen/diagram">
<DiagramTest />
</Route>
<Route exact path="/kitchen/examples">
<Examples />
</Route>
<Route exact path="/kitchen/gantt">
<Gantt />
</Route>
<CustomRoutes />
</Switch>
</div>
</div>
)
}
}
class AppContent extends Component{
render(){
return(
<div>
<AppAuth/>
<AppBody classes={this.props.classes}/>
</div>
)
}
}
//Keep functional constructor to avoid problems with useStyles
export default function App() {
const classes = useStyles();
return <AppContent classes={classes}/>
}

View File

@ -0,0 +1,183 @@
import React, { Component } from "react";
import { Route, Switch } from "react-router-dom";
import { makeStyles } from "@material-ui/styles";
import { Button, AppBar, Toolbar } from "@material-ui/core";
import AppLogo from "./plugins/AppLogo";
import NavLink from "./components/NavLink";
import WorkflowSearch from "./pages/executions/WorkflowSearch";
import TaskSearch from "./pages/executions/TaskSearch";
import Execution from "./pages/execution/Execution";
import WorkflowDefinitions from "./pages/definitions/Workflow";
import WorkflowDefinition from "./pages/definition/WorkflowDefinition";
import TaskDefinitions from "./pages/definitions/Task";
import TaskDefinition from "./pages/definition/TaskDefinition";
import EventHandlerDefinitions from "./pages/definitions/EventHandler";
import EventHandlerDefinition from "./pages/definition/EventHandler";
import TaskQueue from "./pages/misc/TaskQueue";
import KitchenSink from "./pages/kitchensink/KitchenSink";
import DiagramTest from "./pages/kitchensink/DiagramTest";
import Examples from "./pages/kitchensink/Examples";
import Gantt from "./pages/kitchensink/Gantt";
import CustomRoutes from "./plugins/CustomRoutes";
import AppBarModules from "./plugins/AppBarModules";
import CustomAppBarButtons from "./plugins/CustomAppBarButtons";
import Workbench from "./pages/workbench/Workbench";
import { Helmet } from "react-helmet";
const useStyles = makeStyles((theme) => ({
root: {
backgroundColor: "#efefef",
display: "flex",
},
body: {
width: "100vw",
height: "100vh",
paddingTop: theme.overrides.MuiAppBar.root.height,
},
toolbarRight: {
marginLeft: "auto",
display: "flex",
flexDirection: "row",
},
toolbarRegular: {
minHeight: 80,
},
}));
class AppAuth extends Component{
render(){
return (
<div>
<Helmet>
<script src="https://cdn.dev.d4science.org/boot/d4s-boot.js"></script>
</Helmet>
<d4s-boot-2 url="https://accounts.dev.d4science.org/auth" redirect-url="http://localhost/login/callback" gateway="conductor-ui">
</d4s-boot-2>
</div>
)
}
}
class AppBody extends Component{
constructor(props){
super(props)
this.state = { open : false }
}
setOpen(v){
this.setState({ open : v })
}
componentDidMount() {
document.addEventListener("authenticated", ev=>{
this.setOpen(true)
})
}
render(){
const classes = this.props.classes;
return !this.state.open ? <div></div> : (
<div className={classes.root}>
<AppBar position="fixed">
<Toolbar
classes={{
regular: classes.toolbarRegular,
}}
>
<AppLogo />
<Button component={NavLink} path="/">
Executions
</Button>
<Button component={NavLink} path="/workflowDefs">
Definitions
</Button>
<Button component={NavLink} path="/taskQueue">
Task Queues
</Button>
<Button component={NavLink} path="/workbench">
Workbench
</Button>
<CustomAppBarButtons />
<div className={classes.toolbarRight}>
<AppBarModules />
</div>
</Toolbar>
</AppBar>
<div className={classes.body}>
<Switch>
<Route exact path="/">
<WorkflowSearch />
</Route>
<Route exact path="/search/by-tasks">
<TaskSearch />
</Route>
<Route path="/execution/:id/:taskId?">
<Execution />
</Route>
<Route exact path="/workflowDefs">
<WorkflowDefinitions />
</Route>
<Route exact path="/workflowDef/:name?/:version?">
<WorkflowDefinition />
</Route>
<Route exact path="/taskDefs">
<TaskDefinitions />
</Route>
<Route exact path="/taskDef/:name?">
<TaskDefinition />
</Route>
<Route exact path="/eventHandlerDef">
<EventHandlerDefinitions />
</Route>
<Route exact path="/eventHandlerDef/:name">
<EventHandlerDefinition />
</Route>
<Route exact path="/taskQueue/:name?">
<TaskQueue />
</Route>
<Route exact path="/workbench">
<Workbench />
</Route>
<Route exact path="/kitchen">
<KitchenSink />
</Route>
<Route exact path="/kitchen/diagram">
<DiagramTest />
</Route>
<Route exact path="/kitchen/examples">
<Examples />
</Route>
<Route exact path="/kitchen/gantt">
<Gantt />
</Route>
<CustomRoutes />
</Switch>
</div>
</div>
)
}
}
class AppContent extends Component{
render(){
return(
<div>
<AppAuth/>
<AppBody classes={this.props.classes}/>
</div>
)
}
}
//Keep functional constructor to avoid problems with useStyles
export default function App() {
const classes = useStyles();
return <AppContent classes={classes}/>
}

View File

@ -0,0 +1,11 @@
[common]
loglevel = info
threads = 1
pollrate = 1
[pymail]
server = smtp-relay.d4science.org
user = conductor_dev
password =
protocol = starttls
port = 587

View File

@ -0,0 +1,30 @@
# Database persistence type.
conductor.db.type=postgres
spring.datasource.url=jdbc:postgresql://postgres:5432/conductor
spring.datasource.username=conductor
spring.datasource.password=conductor
# Hikari pool sizes are -1 by default and prevent startup
spring.datasource.hikari.maximum-pool-size=20
#spring.datasource.hikari.minimum-idle=2
# Use Postgres for indexing
conductor.indexing.enabled=true
conductor.indexing.type=postgres
conductor.elasticsearch.version=postgres
# Elastic search instance indexing is disabled.
#conductor.elasticsearch.version=7
#conductor.elasticsearch.url=http://es:9200
#conductor.elasticsearch.clusterHealthColor=yellow
#Enable Prometheus
conductor.metrics-prometheus.enabled=true
management.endpoints.web.exposure.include=prometheus,health,info,metrics
# GRPC disabled
conductor.grpc-server.enabled=false
# Load sample kitchen sink disabled
loadSample=false

View File

@ -0,0 +1,87 @@
upstream conductor_server {
ip_hash;
server conductor-server:8080;
}
map $http_authorization $source_auth {
default "";
}
js_var $auth_token;
js_var $pep_credentials;
server {
listen 80;
server_name conductor conductor.dev.d4science.org conductor.cloud-dev.d4science.org;
location / {
# This would be the directory where your React app's static files are stored at
root /usr/share/nginx/html;
try_files $uri /index.html;
}
location /health {
proxy_set_header Host $host;
proxy_pass http://conductor_server;
}
location /actuator/prometheus {
proxy_set_header Host $host;
proxy_pass http://conductor_server;
}
location /api/ {
js_content pep.enforce;
}
location @backend {
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-NginX-Proxy true;
proxy_cache_bypass $http_upgrade;
proxy_redirect off;
proxy_pass http://conductor_server;
}
location /jwt_verify_request {
internal;
proxy_method POST;
proxy_http_version 1.1;
proxy_set_header Authorization $pep_credentials;
proxy_set_header Content-Type "application/x-www-form-urlencoded";
proxy_pass "https://accounts.dev.d4science.org/auth/realms/d4science/protocol/openid-connect/token/introspect";
proxy_ignore_headers Cache-Control Expires Set-Cookie;
gunzip on;
proxy_cache token_responses; # Enable caching
proxy_cache_key $source_auth; # Cache for each source authentication
proxy_cache_lock on; # Duplicate tokens must wait
proxy_cache_valid 200 10s; # How long to use each response
}
location /jwt_request {
internal;
proxy_method POST;
proxy_http_version 1.1;
proxy_set_header Authorization $pep_credentials;
proxy_set_header Content-Type "application/x-www-form-urlencoded";
proxy_pass "https://accounts.dev.d4science.org/auth/realms/d4science/protocol/openid-connect/token";
gunzip on;
}
location /permission_request {
internal;
proxy_method POST;
proxy_http_version 1.1;
proxy_set_header Content-Type "application/x-www-form-urlencoded";
proxy_set_header Authorization "Bearer $auth_token";
proxy_pass "https://accounts.dev.d4science.org/auth/realms/d4science/protocol/openid-connect/token";
gunzip on;
}
}

183
v3.13.8/config.pre/App.jsx Normal file
View File

@ -0,0 +1,183 @@
import React, { Component } from "react";
import { Route, Switch } from "react-router-dom";
import { makeStyles } from "@material-ui/styles";
import { Button, AppBar, Toolbar } from "@material-ui/core";
import AppLogo from "./plugins/AppLogo";
import NavLink from "./components/NavLink";
import WorkflowSearch from "./pages/executions/WorkflowSearch";
import TaskSearch from "./pages/executions/TaskSearch";
import Execution from "./pages/execution/Execution";
import WorkflowDefinitions from "./pages/definitions/Workflow";
import WorkflowDefinition from "./pages/definition/WorkflowDefinition";
import TaskDefinitions from "./pages/definitions/Task";
import TaskDefinition from "./pages/definition/TaskDefinition";
import EventHandlerDefinitions from "./pages/definitions/EventHandler";
import EventHandlerDefinition from "./pages/definition/EventHandler";
import TaskQueue from "./pages/misc/TaskQueue";
import KitchenSink from "./pages/kitchensink/KitchenSink";
import DiagramTest from "./pages/kitchensink/DiagramTest";
import Examples from "./pages/kitchensink/Examples";
import Gantt from "./pages/kitchensink/Gantt";
import CustomRoutes from "./plugins/CustomRoutes";
import AppBarModules from "./plugins/AppBarModules";
import CustomAppBarButtons from "./plugins/CustomAppBarButtons";
import Workbench from "./pages/workbench/Workbench";
import { Helmet } from "react-helmet";
const useStyles = makeStyles((theme) => ({
root: {
backgroundColor: "#efefef",
display: "flex",
},
body: {
width: "100vw",
height: "100vh",
paddingTop: theme.overrides.MuiAppBar.root.height,
},
toolbarRight: {
marginLeft: "auto",
display: "flex",
flexDirection: "row",
},
toolbarRegular: {
minHeight: 80,
},
}));
class AppAuth extends Component{
render(){
return (
<div>
<Helmet>
<script src="https://cdn.pre.d4science.org/boot/d4s-boot.js"></script>
</Helmet>
<d4s-boot-2 url="https://accounts.pre.d4science.org/auth" redirect-url="http://localhost/login/callback" gateway="conductor-ui">
</d4s-boot-2>
</div>
)
}
}
class AppBody extends Component{
constructor(props){
super(props)
this.state = { open : false }
}
setOpen(v){
this.setState({ open : v })
}
componentDidMount() {
document.addEventListener("authenticated", ev=>{
this.setOpen(true)
})
}
render(){
const classes = this.props.classes;
return !this.state.open ? <div></div> : (
<div className={classes.root}>
<AppBar position="fixed">
<Toolbar
classes={{
regular: classes.toolbarRegular,
}}
>
<AppLogo />
<Button component={NavLink} path="/">
Executions
</Button>
<Button component={NavLink} path="/workflowDefs">
Definitions
</Button>
<Button component={NavLink} path="/taskQueue">
Task Queues
</Button>
<Button component={NavLink} path="/workbench">
Workbench
</Button>
<CustomAppBarButtons />
<div className={classes.toolbarRight}>
<AppBarModules />
</div>
</Toolbar>
</AppBar>
<div className={classes.body}>
<Switch>
<Route exact path="/">
<WorkflowSearch />
</Route>
<Route exact path="/search/by-tasks">
<TaskSearch />
</Route>
<Route path="/execution/:id/:taskId?">
<Execution />
</Route>
<Route exact path="/workflowDefs">
<WorkflowDefinitions />
</Route>
<Route exact path="/workflowDef/:name?/:version?">
<WorkflowDefinition />
</Route>
<Route exact path="/taskDefs">
<TaskDefinitions />
</Route>
<Route exact path="/taskDef/:name?">
<TaskDefinition />
</Route>
<Route exact path="/eventHandlerDef">
<EventHandlerDefinitions />
</Route>
<Route exact path="/eventHandlerDef/:name">
<EventHandlerDefinition />
</Route>
<Route exact path="/taskQueue/:name?">
<TaskQueue />
</Route>
<Route exact path="/workbench">
<Workbench />
</Route>
<Route exact path="/kitchen">
<KitchenSink />
</Route>
<Route exact path="/kitchen/diagram">
<DiagramTest />
</Route>
<Route exact path="/kitchen/examples">
<Examples />
</Route>
<Route exact path="/kitchen/gantt">
<Gantt />
</Route>
<CustomRoutes />
</Switch>
</div>
</div>
)
}
}
class AppContent extends Component{
render(){
return(
<div>
<AppAuth/>
<AppBody classes={this.props.classes}/>
</div>
)
}
}
//Keep functional constructor to avoid problems with useStyles
export default function App() {
const classes = useStyles();
return <AppContent classes={classes}/>
}

View File

@ -0,0 +1,11 @@
[common]
loglevel = info
threads = 1
pollrate = 1
[pymail]
server = smtp-relay.d4science.org
user = conductor_pre
password =
protocol = starttls
port = 587

View File

@ -0,0 +1,26 @@
# Database persistence type.
conductor.db.type=postgres
spring.datasource.url=jdbc:postgresql://postgres:5432/conductor
spring.datasource.username=conductor
spring.datasource.password=conductor
# Hikari pool sizes are -1 by default and prevent startup
spring.datasource.hikari.maximum-pool-size=10
spring.datasource.hikari.minimum-idle=2
# Elastic search instance indexing is disabled.
conductor.indexing.enabled=true
conductor.elasticsearch.version=7
conductor.elasticsearch.url=http://es:9200
conductor.elasticsearch.clusterHealthColor=yellow
#Enable Prometheus
conductor.metrics-prometheus.enabled=true
management.endpoints.web.exposure.include=prometheus,health,info,metrics
# GRPC disabled
conductor.grpc-server.enabled=false
# Load sample kitchen sink disabled
loadSample=false

View File

@ -0,0 +1,88 @@
upstream conductor_server {
ip_hash;
server conductor-server:8080;
}
map $http_authorization $source_auth {
default "";
}
js_var $auth_token;
js_var $pep_credentials;
server {
listen 80;
server_name conductor.pre.d4science.org;
location / {
# This would be the directory where your React app's static files are stored at
root /usr/share/nginx/html;
try_files $uri /index.html;
}
location /health {
proxy_set_header Host $host;
proxy_pass http://conductor_server;
}
location /actuator/prometheus {
proxy_set_header Host $host;
proxy_pass http://conductor_server;
}
location /api/ {
js_content pep.enforce;
}
location @backend {
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-NginX-Proxy true;
proxy_cache_bypass $http_upgrade;
proxy_redirect off;
proxy_pass http://conductor_server;
}
location /jwt_verify_request {
internal;
proxy_method POST;
proxy_http_version 1.1;
proxy_set_header Authorization $pep_credentials;
proxy_set_header Content-Type "application/x-www-form-urlencoded";
proxy_set_header Accept-Encoding identity;
proxy_pass "https://accounts.pre.d4science.org/auth/realms/d4science/protocol/openid-connect/token/introspect";
proxy_ignore_headers Cache-Control Expires Set-Cookie;
proxy_cache token_responses; # Enable caching
proxy_cache_key $source_auth; # Cache for each source authentication
proxy_cache_lock on; # Duplicate tokens must wait
proxy_cache_valid 200 10s; # How long to use each response
}
location /jwt_request {
internal;
proxy_method POST;
proxy_http_version 1.1;
proxy_set_header Authorization $pep_credentials;
proxy_set_header Content-Type "application/x-www-form-urlencoded";
proxy_set_header Accept-Encoding identity;
proxy_pass "https://accounts.pre.d4science.org/auth/realms/d4science/protocol/openid-connect/token";
}
location /permission_request {
internal;
proxy_method POST;
proxy_http_version 1.1;
proxy_set_header Content-Type "application/x-www-form-urlencoded";
proxy_set_header Authorization "Bearer $auth_token";
proxy_set_header Accept-Encoding identity;
proxy_pass "https://accounts.pre.d4science.org/auth/realms/d4science/protocol/openid-connect/token";
}
}

183
v3.13.8/config.prod/App.jsx Normal file
View File

@ -0,0 +1,183 @@
import React, { Component } from "react";
import { Route, Switch } from "react-router-dom";
import { makeStyles } from "@material-ui/styles";
import { Button, AppBar, Toolbar } from "@material-ui/core";
import AppLogo from "./plugins/AppLogo";
import NavLink from "./components/NavLink";
import WorkflowSearch from "./pages/executions/WorkflowSearch";
import TaskSearch from "./pages/executions/TaskSearch";
import Execution from "./pages/execution/Execution";
import WorkflowDefinitions from "./pages/definitions/Workflow";
import WorkflowDefinition from "./pages/definition/WorkflowDefinition";
import TaskDefinitions from "./pages/definitions/Task";
import TaskDefinition from "./pages/definition/TaskDefinition";
import EventHandlerDefinitions from "./pages/definitions/EventHandler";
import EventHandlerDefinition from "./pages/definition/EventHandler";
import TaskQueue from "./pages/misc/TaskQueue";
import KitchenSink from "./pages/kitchensink/KitchenSink";
import DiagramTest from "./pages/kitchensink/DiagramTest";
import Examples from "./pages/kitchensink/Examples";
import Gantt from "./pages/kitchensink/Gantt";
import CustomRoutes from "./plugins/CustomRoutes";
import AppBarModules from "./plugins/AppBarModules";
import CustomAppBarButtons from "./plugins/CustomAppBarButtons";
import Workbench from "./pages/workbench/Workbench";
import { Helmet } from "react-helmet";
const useStyles = makeStyles((theme) => ({
root: {
backgroundColor: "#efefef",
display: "flex",
},
body: {
width: "100vw",
height: "100vh",
paddingTop: theme.overrides.MuiAppBar.root.height,
},
toolbarRight: {
marginLeft: "auto",
display: "flex",
flexDirection: "row",
},
toolbarRegular: {
minHeight: 80,
},
}));
class AppAuth extends Component{
render(){
return (
<div>
<Helmet>
<script src="https://cdn.cloud.d4science.org/boot/d4s-boot.js"></script>
</Helmet>
<d4s-boot-2 url="https://accounts.d4science.org/auth" redirect-url="http://localhost/login/callback" gateway="conductor-ui">
</d4s-boot-2>
</div>
)
}
}
class AppBody extends Component{
constructor(props){
super(props)
this.state = { open : false }
}
setOpen(v){
this.setState({ open : v })
}
componentDidMount() {
document.addEventListener("authenticated", ev=>{
this.setOpen(true)
})
}
render(){
const classes = this.props.classes;
return !this.state.open ? <div></div> : (
<div className={classes.root}>
<AppBar position="fixed">
<Toolbar
classes={{
regular: classes.toolbarRegular,
}}
>
<AppLogo />
<Button component={NavLink} path="/">
Executions
</Button>
<Button component={NavLink} path="/workflowDefs">
Definitions
</Button>
<Button component={NavLink} path="/taskQueue">
Task Queues
</Button>
<Button component={NavLink} path="/workbench">
Workbench
</Button>
<CustomAppBarButtons />
<div className={classes.toolbarRight}>
<AppBarModules />
</div>
</Toolbar>
</AppBar>
<div className={classes.body}>
<Switch>
<Route exact path="/">
<WorkflowSearch />
</Route>
<Route exact path="/search/by-tasks">
<TaskSearch />
</Route>
<Route path="/execution/:id/:taskId?">
<Execution />
</Route>
<Route exact path="/workflowDefs">
<WorkflowDefinitions />
</Route>
<Route exact path="/workflowDef/:name?/:version?">
<WorkflowDefinition />
</Route>
<Route exact path="/taskDefs">
<TaskDefinitions />
</Route>
<Route exact path="/taskDef/:name?">
<TaskDefinition />
</Route>
<Route exact path="/eventHandlerDef">
<EventHandlerDefinitions />
</Route>
<Route exact path="/eventHandlerDef/:name">
<EventHandlerDefinition />
</Route>
<Route exact path="/taskQueue/:name?">
<TaskQueue />
</Route>
<Route exact path="/workbench">
<Workbench />
</Route>
<Route exact path="/kitchen">
<KitchenSink />
</Route>
<Route exact path="/kitchen/diagram">
<DiagramTest />
</Route>
<Route exact path="/kitchen/examples">
<Examples />
</Route>
<Route exact path="/kitchen/gantt">
<Gantt />
</Route>
<CustomRoutes />
</Switch>
</div>
</div>
)
}
}
class AppContent extends Component{
render(){
return(
<div>
<AppAuth/>
<AppBody classes={this.props.classes}/>
</div>
)
}
}
//Keep functional constructor to avoid problems with useStyles
export default function App() {
const classes = useStyles();
return <AppContent classes={classes}/>
}

View File

@ -0,0 +1,11 @@
[common]
loglevel = info
threads = 1
pollrate = 1
[pymail]
server = smtp-relay.d4science.org
user = conductor_prod
password =
protocol = starttls
port = 587

View File

@ -0,0 +1,26 @@
# Database persistence type.
conductor.db.type=postgres
spring.datasource.url=jdbc:postgresql://postgresql-srv.d4science.org:5432/conductor
spring.datasource.username=conductor_u
spring.datasource.password=c36dda661add7c2b5093087ddb655992
# Hikari pool sizes are -1 by default and prevent startup
spring.datasource.hikari.maximum-pool-size=10
spring.datasource.hikari.minimum-idle=2
# Elastic search instance indexing is disabled.
conductor.indexing.enabled=true
conductor.elasticsearch.version=7
conductor.elasticsearch.url=http://es:9200
conductor.elasticsearch.clusterHealthColor=yellow
#Enable Prometheus
conductor.metrics-prometheus.enabled=true
management.endpoints.web.exposure.include=prometheus,health,info,metrics
# GRPC disabled
conductor.grpc-server.enabled=false
# Load sample kitchen sink disabled
loadSample=false

View File

@ -0,0 +1,30 @@
# Database persistence type.
conductor.db.type=postgres
spring.datasource.url=jdbc:postgresql://postgres:5432/conductor
spring.datasource.username=conductor
spring.datasource.password=conductor
# Hikari pool sizes are -1 by default and prevent startup
spring.datasource.hikari.maximum-pool-size=10
spring.datasource.hikari.minimum-idle=2
# Use Postgres for indexing
conductor.indexing.enabled=true
conductor.indexing.type=postgres
conductor.elasticsearch.version=postgres
# Elastic search instance indexing is disabled.
#conductor.elasticsearch.version=7
#conductor.elasticsearch.url=http://es:9200
#conductor.elasticsearch.clusterHealthColor=yellow
#Enable Prometheus
conductor.metrics-prometheus.enabled=true
management.endpoints.web.exposure.include=prometheus,health,info,metrics
# GRPC disabled
conductor.grpc-server.enabled=false
# Load sample kitchen sink disabled
loadSample=false

View File

@ -0,0 +1,88 @@
upstream conductor_server {
ip_hash;
server conductor-server:8080;
}
map $http_authorization $source_auth {
default "";
}
js_var $auth_token;
js_var $pep_credentials;
server {
listen 80;
server_name conductor.d4science.org conductor.cloud.d4science.org;
location / {
# This would be the directory where your React app's static files are stored at
root /usr/share/nginx/html;
try_files $uri /index.html;
}
location /health {
proxy_set_header Host $host;
proxy_pass http://conductor_server;
}
location /actuator/prometheus {
proxy_set_header Host $host;
proxy_pass http://conductor_server;
}
location /api/ {
js_content pep.enforce;
}
location @backend {
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-NginX-Proxy true;
proxy_cache_bypass $http_upgrade;
proxy_redirect off;
proxy_pass http://conductor_server;
}
location /jwt_verify_request {
internal;
proxy_method POST;
proxy_http_version 1.1;
proxy_set_header Authorization $pep_credentials;
proxy_set_header Content-Type "application/x-www-form-urlencoded";
proxy_set_header Accept-Encoding identity;
proxy_pass "https://accounts.d4science.org/auth/realms/d4science/protocol/openid-connect/token/introspect";
proxy_ignore_headers Cache-Control Expires Set-Cookie;
proxy_cache token_responses; # Enable caching
proxy_cache_key $source_auth; # Cache for each source authentication
proxy_cache_lock on; # Duplicate tokens must wait
proxy_cache_valid 200 10s; # How long to use each response
}
location /jwt_request {
internal;
proxy_method POST;
proxy_http_version 1.1;
proxy_set_header Authorization $pep_credentials;
proxy_set_header Content-Type "application/x-www-form-urlencoded";
proxy_set_header Accept-Encoding identity;
proxy_pass "https://accounts.d4science.org/auth/realms/d4science/protocol/openid-connect/token";
}
location /permission_request {
internal;
proxy_method POST;
proxy_http_version 1.1;
proxy_set_header Content-Type "application/x-www-form-urlencoded";
proxy_set_header Authorization "Bearer $auth_token";
proxy_set_header Accept-Encoding identity;
proxy_pass "https://accounts.d4science.org/auth/realms/d4science/protocol/openid-connect/token";
}
}

View File

@ -0,0 +1,12 @@
# In memory database persistence model.
conductor.db.type=memory
# Elastic search instance indexing is disabled.
conductor.indexing.enabled=false
conductor.elasticsearch.clusterHealthColor=yellow
# GRPC disabled
conductor.grpc-server.enabled=false
# Load sample kitchen sink disabled
loadSample=false

42
v3.13.8/config/fetch.js Normal file
View File

@ -0,0 +1,42 @@
import { useEnv } from "./env";
export function useFetchContext() {
const { stack } = useEnv();
return {
stack,
ready: true,
};
}
export function fetchWithContext(
path,
context,
fetchParams,
isJsonResponse = true
) {
const newParams = { ...fetchParams };
const newPath = `/api/${path}`;
const cleanPath = newPath.replace(/([^:]\/)\/+/g, "$1"); // Cleanup duplicated slashes
const boot = document.querySelector("d4s-boot-2")
return boot.secureFetch(cleanPath, newParams)
.then((res) => Promise.all([res, res.text()]))
.then(([res, text]) => {
if (!res.ok) {
// get error message from body or default to response status
const error = text || res.status;
return Promise.reject(error);
} else if (!text || text.length === 0) {
return null;
} else if (!isJsonResponse) {
return text;
} else {
try {
return JSON.parse(text);
} catch (e) {
return text;
}
}
});
}

View File

@ -0,0 +1,139 @@
export default { config };
var config = {
"hosts" : [
{
"host": ["conductor.d4science.org", "conductor.pre.d4science.org", "conductor.dev.d4science.org", "conductor.cloud-dev.d4science.org", "conductor.cloud.d4science.org", "conductor"],
"audience" : "conductor-server",
"allow-basic-auth" : true,
"paths" : [
{
"name" : "metadata",
"path" : "^/api/metadata/(taskdefs|workflow)/?.*$",
"methods" : [
{
"method" : "GET",
"scopes" : ["get","list"]
}
]
},
{
"name" : "metadata.taskdefs",
"path" : "^/api/metadata/taskdefs/?.*$",
"methods" : [
{
"method" : "POST",
"scopes" : ["create"]
},
{
"method" : "DELETE",
"scopes" : ["delete"],
},
{
"method" : "PUT",
"scopes" : ["update"],
}
]
},
{
"name" : "metadata.workflow",
"path" : "^/api/metadata/workflow/?.*$",
"methods" : [
{
"method" : "POST",
"scopes" : ["create"]
},
{
"method" : "DELETE",
"scopes" : ["delete"],
},
{
"method" : "PUT",
"scopes" : ["update"],
}
]
},
{
"name" : "workflow",
"path" : "^/api/workflow/?.*$",
"methods" : [
{
"method" : "GET",
"scopes" : ["get"],
},
{
"method" : "POST",
"scopes" : ["start"],
},
{
"method" : "DELETE",
"scopes" : ["terminate"],
}
]
},
{
"name" : "event",
"path" : "^/api/event/?.*$",
"methods" : [
{
"method" : "GET",
"scopes" : ["get"],
},
{
"method" : "POST",
"scopes" : ["create"],
},
{
"method" : "DELETE",
"scopes" : ["delete"],
},
{
"method" : "PUT",
"scopes" : ["update"],
}
]
},
{
"name" : "task",
"path" : "^/api/tasks/poll/.+$",
"methods" : [
{
"method" : "GET",
"scopes" : ["poll"],
}
]
},
{
"name" : "queue",
"path" : "^/api/tasks/queue/.+$",
"methods" : [
{
"method" : "GET",
"scopes" : ["get"],
}
]
},
{
"name" : "task",
"path" : "^/api/tasks[/]?$",
"methods" : [
{
"method" : "POST",
"scopes" : ["update"],
}
]
},
{
"name" : "log",
"path" : "^/api/tasks/.+/log$",
"methods" : [
{
"method" : "GET",
"scopes" : ["get"],
}
]
}
]
}
]
}

View File

@ -0,0 +1,45 @@
# Added to load njs module
load_module modules/ngx_http_js_module.so;
user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log notice;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
}
env pep_credentials;
http {
# added to import pep script
js_import pep.js;
# added to bind enforce function
js_set $authorization pep.enforce;
# added to create cache for tokens and auth calls
proxy_cache_path /var/cache/nginx/pep keys_zone=token_responses:1m max_size=2m;
include /etc/nginx/mime.types;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
sendfile on;
#tcp_nopush on;
keepalive_timeout 65;
#gzip on;
include /etc/nginx/conf.d/*.conf;
}

332
v3.13.8/config/nginx/pep.js Normal file
View File

@ -0,0 +1,332 @@
export default { enforce };
import defaultExport from './config.js';
function log(c, s){
c.request.error(s)
}
var _debug = true
function debug(c, s){
if(_debug === true){
log(c, s)
}
}
function enforce(r) {
var context = {
request: r ,
config : defaultExport["config"],
backend : (defaultExport.backend ? defaultExport.backend : "@backend")
}
log(context, "Inside NJS enforce for " + r.method + " @ " + r.headersIn.host + "/" + r.uri)
context = computeProtection(context)
wkf.run(wkf.build(context), context)
}
// ######## WORKFLOW FUNCTIONS ###############
var wkf = {
build : (context)=>{
var actions = [
"export_pep_credentials",
"parse_authentication",
"check_authentication",
"export_authn_token",
"pip",
"pdp",
"export_backend_headers",
"pass"
]
return actions
},
run : (actions, context) => {
context.request.error("Starting workflow with " + njs.dump(actions))
var w = actions.reduce(
(acc, f) => { return acc.then(typeof(f) === "function" ? f : wkf[f]) },
Promise.resolve().then(()=>context)
)
w.catch(e => { context.request.error(njs.dump(e)); context.request.return(401)} )
},
export_pep_credentials : exportPepCredentials,
export_authn_token : exportAuthToken,
export_backend_headers : exportBackendHeaders,
parse_authentication : parseAuthentication,
check_authentication : checkAuthentication,
verify_token : verifyToken,
request_token : requestToken,
pip : pipExecutor,
pdp : pdpExecutor,
pass : pass,
//PIP utilities
"get-path-component" : (c, i) => c.request.uri.split("/")[i],
"get-token-field" : getTokenField,
"get-contexts" : (c) => {
var ra = c.authn.verified_token["resource_access"]
if(ra){
var out = [];
for(var k in ra){
if(ra[k].roles && ra[k].roles.length !== 0) out.push(k)
}
}
return out;
}
}
function getTokenField(context, f){
return context.authn.verified_token[f]
}
function exportVariable(context, name, value){
context.request.variables[name] = value
return context
}
function exportBackendHeaders(context){
return context
}
function exportPepCredentials(context){
if(process.env["pep_credentials"] || process.env["PEP_CREDENTIALS"]){
return exportVariable(context, "pep_credentials", "Basic " + process.env["PEP_CREDENTIALS"])
}else if(context.config["pep_credentials"]){
return exportVariable(context, "pep_credentials", "Basic " + context.config["pep_credentials"])
}else{
throw new Error("Need PEP credentials")
}
}
function exportAuthToken(context){
return exportVariable(context, "auth_token", context.authn.token)
}
function checkAuthentication(context){
return context.authn.type === "bearer" ? wkf.verify_token(context) : wkf.request_token(context)
}
function parseAuthentication(context){
context.request.log("Inside parseAuthentication")
var incomingauth = context.request.headersIn["Authorization"]
if(!incomingauth) throw new Error("Authentication required");
var arr = incomingauth.trim().replace(/\s\s+/g, " ").split(" ")
if(arr.length != 2) throw new Error("Unknown authentication scheme");
var type = arr[0].toLowerCase()
if(type === "basic" && context.authz.host && context.authz.host["allow-basic-auth"]){
var unamepass = Buffer.from(arr[1], 'base64').toString().split(":")
if(unamepass.length != 2) return null;
context.authn = { type : type, raw : arr[1], user : unamepass[0], password : unamepass[1]}
return context
}else if(type === "bearer"){
context.authn = { type : type, raw : arr[1], token : arr[1]}
return context
}
throw new Error("Unknown authentication scheme");
}
function verifyToken(context){
log(context, "Inside verifyToken")
debug(context, "Token is " + context.authn.token)
var options = {
"body" : "token=" + context.authn.token + "&token_type_hint=access_token"
}
return context.request.subrequest("/jwt_verify_request", options)
.then(reply=>{
if (reply.status === 200) {
var response = JSON.parse(reply.responseText);
if (response.active === true) {
return response
} else {
throw new Error("Unauthorized: " + reply.responseText)
}
} else {
throw new Error("Unauthorized: " + reply.responseText)
}
}).then(verified_token => {
context.authn.verified_token =
JSON.parse(Buffer.from(context.authn.token.split('.')[1], 'base64url').toString())
return context
})
}
function requestToken(context){
log(context, "Inside requestToken")
var options = {
"body" : "grant_type=client_credentials&client_id="+context.authn.user+"&client_secret="+context.authn.password
}
return context.request.subrequest("/jwt_request", options)
.then(reply=>{
if (reply.status === 200) {
var response = JSON.parse(reply.responseText);
context.authn.token = response.access_token
context.authn.verified_token =
JSON.parse(Buffer.from(context.authn.token.split('.')[1], 'base64url').toString())
return context
} else if (reply.status === 400 || reply.status === 401){
var options = {
"body" : "grant_type=password&username="+context.authn.user+"&password="+context.authn.password
}
return context.request.subrequest("/jwt_request", options)
.then( reply=>{
if (reply.status === 200) {
var response = JSON.parse(reply.responseText);
context.authn.token = response.access_token
context.authn.verified_token =
JSON.parse(Buffer.from(context.authn.token.split('.')[1], 'base64url').toString())
return context
} else{
throw new Error("Unauthorized " + reply.status)
}
})
} else {
throw new Error("Unauthorized " + reply.status)
}
})
}
function pipExecutor(context){
log(context, "Inside extra claims PIP")
context.authz.pip.forEach(extra =>{
//call extra claim pip function
try{
var operator = extra.operator
var result = wkf[operator](context, extra.args)
//ensure array and add to extra_claims
if(!(result instanceof Array)) result = [result]
if(!context.extra_claims) context.extra_claims = {};
context.extra_claims[extra.claim] = result
} catch (error){
log(context, "Skipping invalid extra claim " + njs.dump(error))
}
})
log(context, "Extra claims are " + njs.dump(context.extra_claims))
return context
}
function pdpExecutor(context){
log(context, "Inside PDP")
return context.authz.pdp(context)
}
function umaCall(context){
log(context, "Inside UMA call")
var options = { "body" : computePermissionRequestBody(context) };
return context.request.subrequest("/permission_request", options)
.then(reply =>{
if(reply.status === 200){
debug(context, "UMA call reply is " + reply.status)
return context
}else{
throw new Error("Response for authorization request is not ok " + reply.status + " " + njs.dump(reply.responseText))
}
})
}
function pass(context){
log(context, "Inside pass");
if(typeof(context.backend) === "string") context.request.internalRedirect(context.backend);
else if (typeof(context.backend) === "function") context.request.internalRedirect(context.backend(context))
return context;
}
// ######## AUTHORIZATION PART ###############
function computePermissionRequestBody(context){
if(!context.authz.host || !context.authz.path ){
throw new Error("Enforcemnt mode is always enforcing. Host or path not found...")
}
var audience = computeAudience(context)
var grant = "grant_type=urn:ietf:params:oauth:grant-type:uma-ticket"
var mode = "response_mode=decision"
var permissions = computePermissions(context)
var extra = ""
if(context.extra_claims){
extra =
"claim_token_format=urn:ietf:params:oauth:token-type:jwt&claim_token=" +
JSON.stringify(context.extra_claims).toString("base64url")
}
var body = audience + "&" + grant + "&" + permissions + "&" + mode + "&" + extra
context.request.error("Computed permission request body is " + body)
return body
}
function computeAudience(context){
var aud = context.request.headersIn.host
if(context.authz.host){
aud = context.authz.host.audience||context.authz.host.host
}
return "audience=" + aud
}
function computePermissions(context){
var resource = context.request.uri
if(context.authz.path){
resource = context.authz.path.name||context.authz.path.path
}
var scopes = []
if(context.authz.method && context.authz.method.scopes){
scopes = context.authz.method.scopes
}
if(scopes.length > 0){
return scopes.map(s=>"permission=" + resource + "#" + s).join("&")
}
return "permission=" + resource
}
function getPath(hostconfig, incomingpath, incomingmethod){
var paths = hostconfig.paths || []
var matchingpaths = paths
.filter(p => {return incomingpath.match(p.path) != null})
.reduce((acc, p) => {
if (!p.methods || p.methods.length === 0) acc.weak.push({ path: p});
else{
var matchingmethods = p.methods.filter(m=>m.method.toUpperCase() === incomingmethod)
if(matchingmethods.length > 0) acc.strong.push({ method : matchingmethods[0], path: p});
}
return acc;
}, { strong: [], weak: []})
return matchingpaths.strong.concat(matchingpaths.weak)[0]
}
function getHost(config, host){
var matching = config.hosts.filter(h=>{
//compare for both string and array of strings
return ((h.host.filter && h.host.indexOf(host) !== -1) || h.host === host)
})
return matching.length > 0 ? matching[0] : null
}
function computeProtection(context){
debug(context, "Getting by host " + context.request.headersIn.host)
context.authz = {}
context.authz.host = getHost(context.config, context.request.headersIn.host)
if(context.authz.host !== null){
log(context, "Host found:" + context.authz.host)
context.authz.pip = context.authz.host.pip ? context.authz.host.pip : [];
context.authz.pdp = context.authz.host.pdp ? context.authz.host.pdp : umaCall;
var pathandmethod = getPath(context.authz.host, context.request.uri, context.request.method);
if(pathandmethod){
context.authz.path = pathandmethod.path;
context.authz.pip = context.authz.path.pip ? context.authz.pip.concat(context.authz.path.pip) : context.authz.pip;
context.authz.pdp = context.authz.path.pdp ? context.authz.path.pdp : context.authz.pdp;
context.authz.method = pathandmethod.method;
if(context.authz.method){
context.authz.pip = context.authz.method.pip ? context.authz.pip.concat(context.authz.method.pip) : context.authz.pip;
context.authz.pdp = context.authz.method.pdp ? context.authz.method.pdp : context.authz.pdp;
}
}
}
debug(context, "Leaving protection computation: ")
return context
}

25
v3.13.8/config/startup.sh Executable file
View File

@ -0,0 +1,25 @@
#!/bin/sh
#
# Copyright 2021 Netflix, Inc.
# <p>
# Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
# <p>
# http://www.apache.org/licenses/LICENSE-2.0
# <p>
# Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
# an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
# specific language governing permissions and limitations under the License.
#
# startup.sh - startup script for the server docker image
echo "Starting Conductor server"
# Start the server
cd /app/libs
config_file=/app/config.properties
echo "Using java options config: $JAVA_OPTS"
java ${JAVA_OPTS} -jar -DCONDUCTOR_CONFIG_FILE=$config_file conductor-server.jar 2>&1 | tee -a /app/logs/server.log

View File

@ -0,0 +1,117 @@
version: '3.6'
services:
postgres:
image: postgres:14
environment:
- POSTGRES_USER=conductor
- POSTGRES_PASSWORD=conductor
volumes:
- pg_db_data:/var/lib/postgresql/data
networks:
- conductor-network
healthcheck:
test: timeout 5 bash -c 'cat < /dev/null > /dev/tcp/localhost/5432'
interval: 5s
timeout: 5s
retries: 12
deploy:
mode: replicated
replicas: 1
restart_policy:
condition: any
delay: 5s
window: 120s
placement:
constraints: [node.role == worker]
logging:
driver: "journald"
conductor-server:
environment:
- CONFIG_PROP=config.properties
image: "hub.dev.d4science.org/conductor/server:v3.13.8-dev"
networks:
- conductor-network
deploy:
mode: replicated
replicas: 1
restart_policy:
condition: any
delay: 5s
window: 120s
placement:
constraints: [node.role == worker]
logging:
driver: "journald"
pep:
image: "hub.dev.d4science.org/conductor/frontend:v3.13.8-dev"
networks:
- conductor-network
- haproxy-public
deploy:
mode: replicated
endpoint_mode: dnsrr
replicas: 1
restart_policy:
condition: any
delay: 5s
window: 120s
placement:
constraints: [node.role == worker]
environment:
pep_credentials: ${pep_credentials}
workers:
environment:
CONDUCTOR_SERVER: http://conductor-server:8080/api/
CONDUCTOR_HEALTH: http://conductor-server:8080/health
worker_plugins: "Shell Eval Mail HttpBridge"
smtp_pass: ${smtp_pass}
smtp_user: ${smtp_user}
image: 'hub.dev.d4science.org/conductor/worker:dev'
networks:
- conductor-network
deploy:
mode: replicated
replicas: 2
restart_policy:
condition: any
delay: 5s
window: 120s
logging:
driver: "journald"
pyrestworkers:
environment:
CONDUCTOR_SERVER: http://conductor-server:8080/api/
CONDUCTOR_HEALTH: http://conductor-server:8080/health
worker_plugins: Http
image: 'hub.dev.d4science.org/conductor/worker:dev'
networks:
- conductor-network
deploy:
mode: replicated
replicas: 2
restart_policy:
condition: any
delay: 5s
window: 120s
logging:
driver: "journald"
networks:
conductor-network:
haproxy-public:
external: true
volumes:
# These settings are relative to dev-cloud
pg_db_data:
driver: local
driver_opts:
type: nfs4
o: "nfsvers=4,addr=192.168.1.222,rw"
device: "/nfs_conductor_pg_dev"

View File

@ -0,0 +1,98 @@
version: '3.6'
services:
postgres:
image: postgres:14
environment:
- POSTGRES_USER=conductor
- POSTGRES_PASSWORD=conductor
networks:
- conductor-network
ports:
- "5432:5432"
healthcheck:
test: timeout 5 bash -c 'cat < /dev/null > /dev/tcp/localhost/5432'
interval: 5s
timeout: 5s
retries: 12
deploy:
mode: replicated
replicas: 1
restart_policy:
condition: any
delay: 5s
window: 120s
logging:
driver: "journald"
conductor-server:
image: "hub.dev.d4science.org/conductor/server:v3.13.8-dev"
networks:
- conductor-network
deploy:
mode: replicated
replicas: 1
restart_policy:
condition: any
delay: 5s
window: 120s
volumes:
- /home/lettere/git/isti/conductor-setup/v3.13.8/testconfig.properties:/app/config.properties
logging:
driver: "journald"
pep:
image: "hub.dev.d4science.org/conductor/frontend:v3.13.8-dev"
networks:
- conductor-network
ports:
- "80:80"
deploy:
mode: replicated
replicas: 1
restart_policy:
condition: any
delay: 5s
window: 120s
environment:
pep_credentials: ${pep_credentials}
workers:
environment:
CONDUCTOR_SERVER: http://conductor-server:8080/api/
CONDUCTOR_HEALTH: http://conductor-server:8080/health
worker_plugins: "Ansible Eval Mail HttpBridge"
smtp_pass: ${smtp_pass}
image: 'hub.dev.d4science.org/conductor/worker:dev'
networks:
- conductor-network
deploy:
mode: replicated
replicas: 4
restart_policy:
condition: any
delay: 5s
window: 120s
logging:
driver: "journald"
pyrestworkers:
environment:
CONDUCTOR_SERVER: http://conductor-server:8080/api/
CONDUCTOR_HEALTH: http://conductor-server:8080/health
worker_plugins: Http
image: 'hub.dev.d4science.org/conductor/worker:dev'
networks:
- conductor-network
deploy:
mode: replicated
replicas: 6
restart_policy:
condition: any
delay: 5s
window: 120s
logging:
driver: "journald"
networks:
conductor-network:

View File

@ -0,0 +1,153 @@
version: '3.6'
services:
postgres:
image: postgres:14
environment:
- POSTGRES_USER=conductor
- POSTGRES_PASSWORD=conductor
volumes:
- pg_db_data:/var/lib/postgresql/data
networks:
- conductor-network
healthcheck:
test: timeout 5 bash -c 'cat < /dev/null > /dev/tcp/localhost/5432'
interval: 5s
timeout: 5s
retries: 12
deploy:
mode: replicated
replicas: 1
restart_policy:
condition: any
delay: 5s
window: 120s
placement:
constraints: [node.role == worker]
logging:
driver: "journald"
es:
image: elasticsearch:7.6.2
environment:
- "ES_JAVA_OPTS=-Xms512m -Xmx1024m"
- transport.host=0.0.0.0
- discovery.type=single-node
- xpack.security.enabled=false
volumes:
- es_data:/usr/share/elasticsearch/data
networks:
- conductor-network
healthcheck:
test: timeout 5 bash -c 'cat < /dev/null > /dev/tcp/localhost/9300'
interval: 5s
timeout: 5s
retries: 12
deploy:
mode: replicated
replicas: 1
restart_policy:
condition: any
delay: 5s
window: 120s
placement:
constraints: [node.role == worker]
logging:
driver: "journald"
conductor-server:
environment:
- CONFIG_PROP=config.properties
image: "nubisware/conductor-server3:pre"
networks:
- conductor-network
deploy:
mode: replicated
replicas: 1
restart_policy:
condition: any
delay: 5s
window: 120s
placement:
constraints: [node.role == worker]
logging:
driver: "journald"
pep:
image: "nubisware/conductor-frontend:pre"
networks:
- conductor-network
- haproxy-public
deploy:
mode: replicated
endpoint_mode: dnsrr
replicas: 1
restart_policy:
condition: any
delay: 5s
window: 120s
placement:
constraints: [node.role == worker]
environment:
pep_credentials: ${pep_credentials}
workers:
environment:
CONDUCTOR_SERVER: http://conductor-server:8080/api/
CONDUCTOR_HEALTH: http://conductor-server:8080/health
worker_plugins: "Shell Eval Mail HttpBridge"
smtp_pass: ${smtp_pass}
smtp_user: ${smtp_user}
image: 'nubisware/nubisware-conductor-worker-py-d4s'
networks:
- conductor-network
deploy:
mode: replicated
replicas: 2
restart_policy:
condition: any
delay: 5s
window: 120s
placement:
constraints: [node.role == worker]
logging:
driver: "journald"
pyrestworkers:
environment:
CONDUCTOR_SERVER: http://conductor-server:8080/api/
CONDUCTOR_HEALTH: http://conductor-server:8080/health
worker_plugins: Http
image: 'nubisware/nubisware-conductor-worker-py-d4s'
networks:
- conductor-network
deploy:
mode: replicated
replicas: 2
restart_policy:
condition: any
delay: 5s
window: 120s
placement:
constraints: [node.role == worker]
logging:
driver: "journald"
networks:
conductor-network:
haproxy-public:
external: true
volumes:
pg_db_data:
driver: local
driver_opts:
type: nfs4
o: "nfsvers=4,addr=146.48.123.250,rw"
device: ":/nfs/conductor_pg_pre"
es_data:
driver: local
driver_opts:
type: nfs4
o: "nfsvers=4,addr=146.48.123.250,rw"
device: ":/nfs/conductor_es_pre"

View File

@ -0,0 +1,120 @@
version: '3.6'
services:
postgres:
image: postgres:14
environment:
- POSTGRES_USER=conductor
- POSTGRES_PASSWORD=conductor
volumes:
- pg_db_data:/var/lib/postgresql/data
networks:
- conductor-network
healthcheck:
test: timeout 5 bash -c 'cat < /dev/null > /dev/tcp/localhost/5432'
interval: 15s
timeout: 15s
retries: 120
deploy:
mode: replicated
replicas: 1
restart_policy:
condition: any
delay: 5s
window: 120s
placement:
constraints: [node.role == worker]
logging:
driver: "journald"
conductor-server:
environment:
- CONFIG_PROP=config.properties
image: "hub.dev.d4science.org/conductor/server:v3.13.8-prod"
networks:
- conductor-network
deploy:
mode: replicated
replicas: 1
restart_policy:
condition: any
delay: 5s
window: 120s
placement:
constraints: [node.role == worker]
logging:
driver: "journald"
pep:
image: "hub.dev.d4science.org/conductor/frontend:v3.13.8-prod"
networks:
- conductor-network
- haproxy-public
deploy:
mode: replicated
endpoint_mode: dnsrr
replicas: 1
restart_policy:
condition: any
delay: 5s
window: 120s
placement:
constraints: [node.role == worker]
environment:
pep_credentials: ${pep_credentials}
workers:
environment:
CONDUCTOR_SERVER: http://conductor-server:8080/api/
CONDUCTOR_HEALTH: http://conductor-server:8080/health
worker_plugins: "Shell Eval Mail HttpBridge"
smtp_pass: ${smtp_pass}
smtp_user: ${smtp_user}
image: 'hub.dev.d4science.org/conductor/worker:prod'
networks:
- conductor-network
deploy:
mode: replicated
replicas: 2
restart_policy:
condition: any
delay: 5s
window: 120s
placement:
constraints: [node.role == worker]
logging:
driver: "journald"
pyrestworkers:
environment:
CONDUCTOR_SERVER: http://conductor-server:8080/api/
CONDUCTOR_HEALTH: http://conductor-server:8080/health
worker_plugins: Http
image: 'hub.dev.d4science.org/conductor/worker:prod'
networks:
- conductor-network
deploy:
mode: replicated
replicas: 4
restart_policy:
condition: any
delay: 5s
window: 120s
placement:
constraints: [node.role == worker]
logging:
driver: "journald"
networks:
conductor-network:
haproxy-public:
external: true
volumes:
pg_db_data:
driver: local
driver_opts:
type: nfs4
o: "nfsvers=4,addr=192.168.1.222,rw"
device: ":/nfs_conductor_pg_prod"

View File

@ -0,0 +1,31 @@
# Database persistence type.
conductor.db.type=postgres
spring.datasource.url=jdbc:postgresql://postgres:5432/conductor
spring.datasource.username=conductor
spring.datasource.password=conductor
# Hikari pool sizes are -1 by default and prevent startup
spring.datasource.hikari.maximum-pool-size=10
#spring.datasource.hikari.minimum-idle=2
# Use Postgres for indexing
conductor.indexing.enabled=true
conductor.indexing.type=postgres
conductor.elasticsearch.version=postgres
# Elastic search instance indexing is disabled.
#conductor.elasticsearch.version=7
#conductor.elasticsearch.url=http://es:9200
#conductor.elasticsearch.clusterHealthColor=yellow
#Enable Prometheus
conductor.metrics-prometheus.enabled=true
management.endpoints.web.exposure.include=prometheus,health,info,metrics
# GRPC disabled
conductor.grpc-server.enabled=false
# Load sample kitchen sink disabled
loadSample=false

4
v3.13.8/yarn.lock Normal file
View File

@ -0,0 +1,4 @@
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
# yarn lockfile v1

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

Some files were not shown because too many files have changed in this diff Show More