diff --git a/bundles.yml b/bundles.yml
new file mode 100644
index 0000000..5b9120e
--- /dev/null
+++ b/bundles.yml
@@ -0,0 +1,4 @@
+---
+
+dependencies:
+ - url: ../common.git
diff --git a/consul/config/service-defaults/diagrams.hcl b/consul/config/service-defaults/diagrams.hcl
new file mode 100644
index 0000000..a6d977d
--- /dev/null
+++ b/consul/config/service-defaults/diagrams.hcl
@@ -0,0 +1,3 @@
+Kind = "service-defaults"
+Name = "[[ .diagrams.instance ]][[ .consul.suffix ]]"
+Protocol = "http"
diff --git a/consul/config/service-intentions/diagrams.hcl b/consul/config/service-intentions/diagrams.hcl
new file mode 100644
index 0000000..6017f20
--- /dev/null
+++ b/consul/config/service-intentions/diagrams.hcl
@@ -0,0 +1,15 @@
+Kind = "service-intentions"
+Name = "[[ .diagrams.instance ]][[ .consul.suffix ]]"
+Sources = [
+ {
+ Name = "[[ .traefik.instance ]]"
+ Permissions = [
+ {
+ Action = "allow"
+ HTTP {
+ PathPrefix = "/"
+ }
+ }
+ ]
+ }
+]
diff --git a/diagrams.nomad.hcl b/diagrams.nomad.hcl
new file mode 100644
index 0000000..900532f
--- /dev/null
+++ b/diagrams.nomad.hcl
@@ -0,0 +1,89 @@
+[[ $c := merge .diagrams . -]]
+job [[ .diagrams.instance | toJSON ]] {
+
+[[ template "common/job_start.tpl" $c ]]
+
+ group "diagrams" {
+ network {
+ mode = "bridge"
+ }
+
+ service {
+ name = "[[ .diagrams.instance ]][[ .consul.suffix ]]"
+ port = 8282
+
+[[ template "common/connect.tpl" $c ]]
+
+ check {
+ type = "http"
+ path = "/health"
+ expose = true
+ interval = "1m"
+ timeout = "8s"
+
+ check_restart {
+ limit = 4
+ grace = "1m"
+ }
+ }
+
+ tags = [
+ "[[ $c.traefik.instance ]].enable=[[ $c.traefik.enabled ]]",
+
+ # Define a middleware to set custom CSP headers
+ "[[ $c.traefik.instance ]].http.middlewares.[[ .diagrams.instance ]]-headers[[ .consul.suffix ]].headers.contentsecuritypolicy=[[ range $k, $v := $c.traefik.csp ]][[ $k ]] [[ $v ]];[[ end ]]",
+
+[[- if not (regexp.Match "^/?$" (urlParse $c.public_url).Path) ]]
+ # Diagrams exposed by traefik on a subpath. Define a middleware to strip the prefix before passing the request to the backend
+ "[[ $c.traefik.instance ]].http.middlewares.[[ .diagrams.instance ]]-prefix[[ .consul.suffix ]].stripprefix.prefixes=[[ (urlParse .diagrams.public_url).Path ]]",
+[[- end ]]
+
+ # Main app router
+ "[[ $c.traefik.instance ]].http.routers.[[ .diagrams.instance ]][[ .consul.suffix ]].rule=Host(`[[ (urlParse $c.public_url).Hostname ]]`)
+ [[- if not (regexp.Match "^/?$" (urlParse $c.public_url).Path) ]] && PathPrefix(`[[ (urlParse $c.public_url).Path ]]`)[[ end ]]",
+ "[[ $c.traefik.instance ]].http.routers.[[ .diagrams.instance ]][[ .consul.suffix ]].entrypoints=[[ join $c.traefik.entrypoints "," ]]",
+[[- if not (regexp.Match "^/?$" (urlParse $c.public_url).Path) ]]
+ "[[ $c.traefik.instance ]].http.routers.[[ .diagrams.instance ]][[ .consul.suffix ]].middlewares=[[ .diagrams.instance ]]-prefix[[ $c.consul.suffix ]],[[ .diagrams.instance ]]-headers[[ .consul.suffix ]],[[ template "common/traefik_middlewares.tpl" $c.traefik ]]",
+[[- else ]]
+ "[[ $c.traefik.instance ]].http.routers.[[ .diagrams.instance ]][[ .consul.suffix ]].middlewares=[[ .diagrams.instance ]]-headers[[ .consul.suffix ]],[[ template "common/traefik_middlewares.tpl" $c.traefik ]]",
+[[- end ]]
+ ]
+ }
+
+ task "diagrams" {
+ driver = [[ $c.nomad.driver | toJSON ]]
+
+ config {
+ image = [[ $c.image | toJSON ]]
+ pids_limit = 100
+ readonly_rootfs = true
+ volumes = [
+ "local/PreConfig.js:/opt/tomcat/webapps/draw/js/PreConfig.js",
+ "local/PostConfig.js:/opt/tomcat/webapps/draw/js/PostConfig.js"
+ ]
+ }
+
+ env {
+ JAVA_OPTS = "-Djava.io.tmpdir=/local"
+ TOMCAT_ADDRESS = "127.0.0.1"
+ }
+
+ template {
+ data =<<_EOT
+[[ template "diagrams/PreConfig.js.tpl" $c ]]
+_EOT
+ destination = "local/PreConfig.js"
+ }
+
+ template {
+ data =<<_EOT
+[[ template "diagrams/PostConfig.js.tpl" $c ]]
+_EOT
+ destination = "local/PostConfig.js"
+ }
+
+[[ template "common/file_env.tpl" $c.env ]]
+[[ template "common/resources.tpl" $c.resources ]]
+ }
+ }
+}
diff --git a/images/diagrams/Dockerfile b/images/diagrams/Dockerfile
new file mode 100644
index 0000000..c8df6d0
--- /dev/null
+++ b/images/diagrams/Dockerfile
@@ -0,0 +1,36 @@
+FROM [[ .docker.repo ]][[ .docker.base_images.java17.image ]]
+MAINTAINER [[ .docker.maintainer ]]
+
+ARG TOMCAT_VERSION=9.0.83 \
+ DIAGRAMS_VERSION=22.1.5
+
+ENV CATALINA_HOME=/opt/tomcat \
+ TOMCAT_PORT=8282 \
+ TOMCAT_ADDRESS=0.0.0.0
+
+RUN set -euxo pipefail &&\
+ cd /tmp &&\
+ apk --no-cache update &&\
+ apk --no-cache add bash &&\
+ curl -sSLO https://dlcdn.apache.org/tomcat/tomcat-9/v${TOMCAT_VERSION}/bin/apache-tomcat-${TOMCAT_VERSION}.tar.gz &&\
+ curl -sSLO https://dlcdn.apache.org/tomcat/tomcat-9/v${TOMCAT_VERSION}/bin/apache-tomcat-${TOMCAT_VERSION}.tar.gz.sha512 &&\
+ sha512sum -c < apache-tomcat-${TOMCAT_VERSION}.tar.gz.sha512 &&\
+ mkdir -p /opt/tomcat &&\
+ tar xvzf apache-tomcat-${TOMCAT_VERSION}.tar.gz --strip-components 1 --directory ${CATALINA_HOME} &&\
+ find /opt/tomcat -type d -exec chmod 755 "{}" \; &&\
+ find /opt/tomcat -type f -exec chmod 644 "{}" \; &&\
+ chmod +x /opt/tomcat/bin/* &&\
+ rm -f apache-tomcat-${TOMCAT_VERSION}.tar.gz.sha512 apache-tomcat-${TOMCAT_VERSION}.tar.gz &&\
+ curl -sSLO https://github.com/jgraph/drawio/releases/download/v${DIAGRAMS_VERSION}/draw.war &&\
+ unzip draw.war -d ${CATALINA_HOME}/webapps/draw &&\
+ rm draw.war &&\
+ addgroup --gid 8282 diagrams &&\
+ adduser --system --ingroup diagrams --disabled-password --uid 8282 --home ${CATALINA_HOME} --shell /sbin/nologin diagrams
+
+COPY root/ /
+
+WORKDIR ${CATALINA_HOME}
+EXPOSE ${TOMCAT_PORT}
+USER diagrams
+CMD ["/opt/tomcat/bin/catalina.sh", "run"]
+
diff --git a/images/diagrams/root/entrypoint.d/91-diagrams-java-opts.env b/images/diagrams/root/entrypoint.d/91-diagrams-java-opts.env
new file mode 100755
index 0000000..f3d2297
--- /dev/null
+++ b/images/diagrams/root/entrypoint.d/91-diagrams-java-opts.env
@@ -0,0 +1,5 @@
+#!/bin/sh
+
+set -eu
+
+export CATALINA_OPTS="${JAVA_OPTS} -Dtomcat.port=${TOMCAT_PORT} -Dtomcat.address=${TOMCAT_ADDRESS}"
diff --git a/images/diagrams/root/opt/tomcat/conf/logging.properties b/images/diagrams/root/opt/tomcat/conf/logging.properties
new file mode 100644
index 0000000..471e556
--- /dev/null
+++ b/images/diagrams/root/opt/tomcat/conf/logging.properties
@@ -0,0 +1,16 @@
+handlers = java.util.logging.ConsoleHandler
+
+.handlers = java.util.logging.ConsoleHandler
+
+java.util.logging.ConsoleHandler.level = FINE
+java.util.logging.ConsoleHandler.formatter = org.apache.juli.OneLineFormatter
+java.util.logging.ConsoleHandler.encoding = UTF-8
+
+org.apache.catalina.core.ContainerBase.[Catalina].[localhost].level = INFO
+org.apache.catalina.core.ContainerBase.[Catalina].[localhost].handlers = java.util.logging.ConsoleHandler
+
+org.apache.catalina.core.ContainerBase.[Catalina].[localhost].[/manager].level = INFO
+org.apache.catalina.core.ContainerBase.[Catalina].[localhost].[/manager].handlers = java.util.logging.ConsoleHandler
+
+org.apache.catalina.core.ContainerBase.[Catalina].[localhost].[/host-manager].level = INFO
+org.apache.catalina.core.ContainerBase.[Catalina].[localhost].[/host-manager].handlers = java.util.logging.ConsoleHandler
diff --git a/images/diagrams/root/opt/tomcat/conf/server.xml b/images/diagrams/root/opt/tomcat/conf/server.xml
new file mode 100644
index 0000000..102f97a
--- /dev/null
+++ b/images/diagrams/root/opt/tomcat/conf/server.xml
@@ -0,0 +1,20 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/images/diagrams/root/opt/tomcat/webapps/draw/js/PostCOnfig.js b/images/diagrams/root/opt/tomcat/webapps/draw/js/PostCOnfig.js
new file mode 100644
index 0000000..5182b3b
--- /dev/null
+++ b/images/diagrams/root/opt/tomcat/webapps/draw/js/PostCOnfig.js
@@ -0,0 +1,5 @@
+window.VSD_CONVERT_URL = null;
+window.ICONSEARCH_PATH = null;
+EditorUi.enableLogging = false; //Disable logging
+window.EMF_CONVERT_URL = null;
+App.prototype.isDriveDomain = function() { return true; }
diff --git a/images/diagrams/root/opt/tomcat/webapps/draw/js/PreConfig.js b/images/diagrams/root/opt/tomcat/webapps/draw/js/PreConfig.js
new file mode 100644
index 0000000..b51241b
--- /dev/null
+++ b/images/diagrams/root/opt/tomcat/webapps/draw/js/PreConfig.js
@@ -0,0 +1,22 @@
+(function() {
+ try {
+ var s = document.createElement('meta');
+ s.setAttribute('content', 'default-src \'self\'; script-src \'self\' https://storage.googleapis.com https://apis.google.com https://docs.google.com https://code.jquery.com \'unsafe-inline\'; connect-src \'self\' https://*.dropboxapi.com https://api.trello.com https://api.github.com https://raw.githubusercontent.com https://*.googleapis.com https://*.googleusercontent.com https://graph.microsoft.com https://*.1drv.com https://*.sharepoint.com https://gitlab.com https://*.google.com https://fonts.gstatic.com https://fonts.googleapis.com; img-src * data:; media-src * data:; font-src * about:; style-src \'self\' \'unsafe-inline\' https://fonts.googleapis.com; frame-src \'self\' https://*.google.com;');
+ s.setAttribute('http-equiv', 'Content-Security-Policy');
+ var t = document.getElementsByTagName('meta')[0];
+ t.parentNode.insertBefore(s, t);
+ } catch (e) {} // ignore
+})();
+window.DRAWIO_BASE_URL = 'http://localhost:8080';
+window.DRAWIO_SERVER_URL = window.DRAWIO_BASE_URL + '/';
+window.DRAWIO_VIEWER_URL = '';
+window.DRAWIO_LIGHTBOX_URL = '';
+window.DRAW_MATH_URL = 'math/es5';
+window.DRAWIO_CONFIG = null;
+urlParams['sync'] = 'manual'; //Disable Real-Time
+urlParams['db'] = '0'; //dropbox
+urlParams['gh'] = '0'; //github
+urlParams['tr'] = '0'; //trello
+urlParams['gapi'] = '0'; //Google Drive
+urlParams['od'] = '0'; //OneDrive
+urlParams['gl'] = '0'; //Gitlab
diff --git a/prep.d/10-mv-conf.sh b/prep.d/10-mv-conf.sh
new file mode 100755
index 0000000..50c339d
--- /dev/null
+++ b/prep.d/10-mv-conf.sh
@@ -0,0 +1 @@
+[[ template "common/mv_conf.sh.tpl" dict "ctx" . "services" (dict "diagrams" .diagrams.instance) ]]
diff --git a/templates/PostConfig.js.tpl b/templates/PostConfig.js.tpl
new file mode 100644
index 0000000..5182b3b
--- /dev/null
+++ b/templates/PostConfig.js.tpl
@@ -0,0 +1,5 @@
+window.VSD_CONVERT_URL = null;
+window.ICONSEARCH_PATH = null;
+EditorUi.enableLogging = false; //Disable logging
+window.EMF_CONVERT_URL = null;
+App.prototype.isDriveDomain = function() { return true; }
diff --git a/templates/PreConfig.js.tpl b/templates/PreConfig.js.tpl
new file mode 100644
index 0000000..c588b43
--- /dev/null
+++ b/templates/PreConfig.js.tpl
@@ -0,0 +1,13 @@
+window.DRAWIO_BASE_URL = '[[ .diagrams.public_url ]]';
+window.DRAWIO_SERVER_URL = '[[ .diagrams.public_url | regexp.Replace "/$" "" ]]/';
+window.DRAWIO_VIEWER_URL = '[[ .diagrams.public_url | regexp.Replace "/$" "" ]]/js/viewer.min.js';
+window.DRAWIO_LIGHTBOX_URL = '';
+window.DRAW_MATH_URL = 'math/es5';
+window.DRAWIO_CONFIG = null;
+urlParams['sync'] = 'manual'; //Disable Real-Time
+urlParams['db'] = '0'; //dropbox
+urlParams['gh'] = '0'; //github
+urlParams['tr'] = '0'; //trello
+urlParams['gapi'] = '0'; //Google Drive
+urlParams['od'] = '0'; //OneDrive
+urlParams['gl'] = '0'; //Gitlab
diff --git a/templates/server.xml.tpl b/templates/server.xml.tpl
new file mode 100644
index 0000000..8bd6b9e
--- /dev/null
+++ b/templates/server.xml.tpl
@@ -0,0 +1,24 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/variables.yml b/variables.yml
new file mode 100644
index 0000000..fea2e09
--- /dev/null
+++ b/variables.yml
@@ -0,0 +1,21 @@
+---
+
+diagrams:
+ instance: diagrams
+ image: danielberteaud/diagrams:latest
+ env: {}
+ public_url: https://draw.example.org
+ traefik:
+ enabled: true
+ csp:
+ default-src: "'self'"
+ script-src: "'self' https://storage.googleapis.com https://apis.google.com https://docs.google.com https://code.jquery.com 'unsafe-inline'"
+ connect-src: "'self' https://*.dropboxapi.com https://api.trello.com https://api.github.com https://raw.githubusercontent.com https://*.googleapis.com https://*.googleusercontent.com https://graph.microsoft.com https://*.1drv.com https://*.sharepoint.com https://gitlab.com https://*.google.com https://fonts.gstatic.com https://fonts.googleapis.com"
+ img-src: " * data:"
+ media-src: "* data:"
+ font-src: "* about:"
+ style-src: "'self' 'unsafe-inline' https://fonts.googleapis.com"
+ frame-src: "'self' https://*.google.com"
+ resources:
+ cpu: 200
+ memory: 256